je_nfc_sdk
Version:
A comprehensive React Native SDK for NFC-based device control and communication
348 lines (347 loc) • 19.8 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from 'react';
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, SafeAreaView, } from 'react-native';
import NfcManager, { NfcTech } from 'react-native-nfc-manager';
import FrameServer from '../logic/NfcServer';
import LoggerService from '../utils/LoggerService';
export const DeviceInfoScreenSDK = ({ deviceId, theme = 'light', onInfoFetched, onError, }) => {
// State for all device info
const [info, setInfo] = useState({});
const [loading, setLoading] = useState(null);
const [error, setError] = useState(null);
// Generalized two-step NFC fetch (write then read)
const [opStep, setOpStep] = useState({});
const [opWriteSuccess, setOpWriteSuccess] = useState({});
const [opLoading, setOpLoading] = useState({});
const fetchNfcData = async (cmd, param, apdu, key, label, needsWrite = true, writeData = [0x00]) => {
if (!needsWrite) {
setLoading(key);
setError(null);
try {
await NfcManager.start();
await NfcManager.requestTechnology(NfcTech.IsoDep);
const result = await FrameServer.readReq(cmd, param, apdu);
if (!result.success)
throw new Error(`Failed to read ${label}`);
setInfo((prev) => (Object.assign(Object.assign({}, prev), { [key]: result.data })));
if (onInfoFetched)
onInfoFetched({ [key]: result.data });
LoggerService.success(`${label} fetched`);
}
catch (e) {
setError(e.message || 'Unknown error');
if (onError)
onError(e.message || 'Unknown error');
LoggerService.error(`${label} fetch error: ${e}`);
}
finally {
setLoading(null);
NfcManager.cancelTechnologyRequest().catch(() => { });
}
}
else {
// Two-step: write then read
if (opStep[key] !== 'read') {
setOpLoading(prev => (Object.assign(Object.assign({}, prev), { [key]: true })));
setError(null);
try {
await NfcManager.start();
await NfcManager.requestTechnology(NfcTech.IsoDep);
LoggerService.info(`Writing request for ${label}...`);
const writeResult = await FrameServer.writeData(cmd, param, writeData);
if (writeResult.success) {
setOpWriteSuccess(prev => (Object.assign(Object.assign({}, prev), { [key]: true })));
setOpStep(prev => (Object.assign(Object.assign({}, prev), { [key]: 'read' })));
LoggerService.success(`Write for ${label} successful. Please tap again to read.`);
Alert.alert('Ready', `Write successful. Please tap again to read ${label}.`);
}
else {
setOpWriteSuccess(prev => (Object.assign(Object.assign({}, prev), { [key]: false })));
setOpStep(prev => (Object.assign(Object.assign({}, prev), { [key]: 'write' })));
throw new Error(`Write for ${label} failed`);
}
}
catch (e) {
setError(e.message || 'Unknown error');
if (onError)
onError(e.message || 'Unknown error');
LoggerService.error(`${label} write failed: ${e}`);
Alert.alert('Error', `Failed to write for ${label}: ${e.message || 'Unknown error'}`);
}
finally {
setOpLoading(prev => (Object.assign(Object.assign({}, prev), { [key]: false })));
NfcManager.cancelTechnologyRequest().catch(() => { });
}
}
else {
setOpLoading(prev => (Object.assign(Object.assign({}, prev), { [key]: true })));
setError(null);
try {
await NfcManager.start();
await NfcManager.requestTechnology(NfcTech.IsoDep);
LoggerService.info(`Reading ${label}...`);
const result = await FrameServer.readReq(cmd, param, apdu);
if (!result.success)
throw new Error(`Failed to read ${label}`);
setInfo((prev) => (Object.assign(Object.assign({}, prev), { [key]: result.data })));
if (onInfoFetched)
onInfoFetched({ [key]: result.data });
setOpStep(prev => (Object.assign(Object.assign({}, prev), { [key]: 'idle' })));
setOpWriteSuccess(prev => (Object.assign(Object.assign({}, prev), { [key]: false })));
LoggerService.success(`${label} extracted`);
}
catch (e) {
setError(e.message || 'Unknown error');
if (onError)
onError(e.message || 'Unknown error');
LoggerService.error(`${label} read failed: ${e}`);
Alert.alert('Error', `Failed to read ${label}: ${e.message || 'Unknown error'}`);
}
finally {
setOpLoading(prev => (Object.assign(Object.assign({}, prev), { [key]: false })));
NfcManager.cancelTechnologyRequest().catch(() => { });
}
}
}
};
// Example: all operations use two-step (write then read)
// Removed old two-step functions, now using single-action combined functions below
// NFC Info fetch (using getTag)
const fetchNfcInfo = async () => {
setLoading('nfcInfo');
setError(null);
try {
await NfcManager.start();
await NfcManager.requestTechnology(NfcTech.IsoDep);
const tag = await NfcManager.getTag();
if (!tag)
throw new Error('No NFC tag detected');
setInfo((prev) => (Object.assign(Object.assign({}, prev), { nfcInfo: tag })));
if (onInfoFetched)
onInfoFetched({ nfcInfo: tag });
LoggerService.success('NFC Info fetched');
}
catch (e) {
setError(e.message || 'Unknown error');
if (onError)
onError(e.message || 'Unknown error');
LoggerService.error(`NFC Info fetch error: ${e}`);
}
finally {
setLoading(null);
NfcManager.cancelTechnologyRequest().catch(() => { });
}
};
// const handleCombinedNfcOp = async (
// cmd: number,
// param: number,
// apdu: number[],
// key: string,
// label: string,
// writeData: number[] = [0x00]
// ) => {
// setOpLoading(prev => ({ ...prev, [key]: true }));
// setError(null);
// try {
// await NfcManager.start();
// await NfcManager.requestTechnology(NfcTech.IsoDep);
// LoggerService.info(`Writing request for ${label}...`);
// const writeResult = await FrameServer.writeData(cmd, param, writeData);
// if (!writeResult.success) throw new Error(`Write for ${label} failed`);
// LoggerService.success(`Write for ${label} successful. Reading...`);
// const result = await FrameServer.readReq(cmd, param, apdu);
// if (!result.success) throw new Error(`Failed to read ${label}`);
// setInfo((prev: any) => ({ ...prev, [key]: result.data }));
// if (onInfoFetched) onInfoFetched({ [key]: result.data });
// LoggerService.success(`${label} fetched`);
// } catch (e: any) {
// setError(e.message || 'Unknown error');
// if (onError) onError(e.message || 'Unknown error');
// LoggerService.error(`${label} op failed: ${e}`);
// Alert.alert('Error', `Failed to fetch ${label}: ${e.message || 'Unknown error'}`);
// } finally {
// setOpLoading(prev => ({ ...prev, [key]: false }));
// NfcManager.cancelTechnologyRequest().catch(() => {});
// }
// };
// const fetchFirmwareVersion = () => handleCombinedNfcOp(0x02, 0x01, [0,0,0,0,0], 'firmwareVersion', 'Firmware Version');
// const fetchHardwareVersion = () => handleCombinedNfcOp(0x42, 0x12, [0,0,0,0,0,0], 'hardwareVersion', 'Hardware Version');
// const fetchBoardVersion = () => handleCombinedNfcOp(0x44, 0x13, [0,0,0,0,0,0,0,0], 'boardVersion', 'Board Version');
// const fetchLoraClass = () => handleCombinedNfcOp(0x32, 0x11, [0], 'loraClass', 'LoRa Class');
// const fetchBatteryLevel = () => handleCombinedNfcOp(0x12, 0x01, [0], 'batteryLevel', 'Battery Level');
// const fetchResetReason = () => handleCombinedNfcOp(0x36, 0x09, [0], 'resetReason', 'Reset Reason');
const handleStepNfcOp = async (cmd, param, apdu, key, label, writeData = [0x00]) => {
if (opStep[key] !== 'read') {
// Write step
setOpLoading(prev => (Object.assign(Object.assign({}, prev), { [key]: true })));
setError(null);
try {
await NfcManager.start();
await NfcManager.requestTechnology(NfcTech.IsoDep);
LoggerService.info(`Writing request for ${label}...`);
const writeResult = await FrameServer.writeData(cmd, param, writeData);
if (writeResult.success) {
setOpWriteSuccess(prev => (Object.assign(Object.assign({}, prev), { [key]: true })));
setOpStep(prev => (Object.assign(Object.assign({}, prev), { [key]: 'read' })));
LoggerService.success(`Write for ${label} successful. Please tap again to read.`);
Alert.alert('Ready', `Write successful. Please tap again to read ${label}.`);
}
else {
setOpWriteSuccess(prev => (Object.assign(Object.assign({}, prev), { [key]: false })));
setOpStep(prev => (Object.assign(Object.assign({}, prev), { [key]: 'write' })));
throw new Error(`Write for ${label} failed`);
}
}
catch (e) {
setError(e.message || 'Unknown error');
if (onError)
onError(e.message || 'Unknown error');
LoggerService.error(`${label} write failed: ${e}`);
Alert.alert('Error', `Failed to write for ${label}: ${e.message || 'Unknown error'}`);
}
finally {
setOpLoading(prev => (Object.assign(Object.assign({}, prev), { [key]: false })));
NfcManager.cancelTechnologyRequest().catch(() => { });
}
}
else {
// Read step
setOpLoading(prev => (Object.assign(Object.assign({}, prev), { [key]: true })));
setError(null);
try {
await NfcManager.start();
await NfcManager.requestTechnology(NfcTech.IsoDep);
LoggerService.info(`Reading ${label}...`);
const result = await FrameServer.readReq(cmd, param, apdu);
if (!result.success)
throw new Error(`Failed to read ${label}`);
setInfo((prev) => (Object.assign(Object.assign({}, prev), { [key]: result.data })));
if (onInfoFetched)
onInfoFetched({ [key]: result.data });
setOpStep(prev => (Object.assign(Object.assign({}, prev), { [key]: 'idle' })));
setOpWriteSuccess(prev => (Object.assign(Object.assign({}, prev), { [key]: false })));
LoggerService.success(`${label} extracted`);
}
catch (e) {
setError(e.message || 'Unknown error');
if (onError)
onError(e.message || 'Unknown error');
LoggerService.error(`${label} read failed: ${e}`);
Alert.alert('Error', `Failed to read ${label}: ${e.message || 'Unknown error'}`);
}
finally {
setOpLoading(prev => (Object.assign(Object.assign({}, prev), { [key]: false })));
NfcManager.cancelTechnologyRequest().catch(() => { });
}
}
};
const firmwareKey = 'firmwareVersion';
const hardwareKey = 'hardwareVersion';
const boardKey = 'boardVersion';
const loraKey = 'loraClass';
const batteryKey = 'batteryLevel';
const resetKey = 'resetReason';
// UI
return (_jsx(SafeAreaView, Object.assign({ style: [styles.container, theme === 'dark' && styles.containerDark] }, { children: _jsxs(ScrollView, Object.assign({ style: styles.scrollView }, { children: [_jsx(Text, Object.assign({ style: styles.title }, { children: "Device Info SDK Panel" })), _jsxs(Text, Object.assign({ style: styles.label }, { children: ["Device ID: ", deviceId] })), _jsxs(View, Object.assign({ style: styles.section }, { children: [_jsx(Text, Object.assign({ style: styles.sectionTitle }, { children: "Device Operations" })), _jsx(Text, Object.assign({ style: { color: '#007bff', marginBottom: 10, textAlign: 'center' } }, { children: "Each button toggles between Write and Read. Tap once to write, again to read." })), _jsx(TouchableOpacity, Object.assign({ style: styles.button, onPress: () => handleStepNfcOp(0x02, 0x01, [0, 0, 0, 0, 0], firmwareKey, 'Firmware Version'), disabled: opLoading[firmwareKey] }, { children: _jsx(Text, Object.assign({ style: styles.buttonText }, { children: opLoading[firmwareKey]
? (opStep[firmwareKey] === 'read' ? 'Reading...' : 'Writing...')
: opStep[firmwareKey] === 'read'
? 'Step 2: Read Firmware Version'
: 'Step 1: Write Firmware Version Request' })) })), _jsx(TouchableOpacity, Object.assign({ style: styles.button, onPress: () => handleStepNfcOp(0x42, 0x12, [0, 0, 0, 0, 0, 0], hardwareKey, 'Hardware Version'), disabled: opLoading[hardwareKey] }, { children: _jsx(Text, Object.assign({ style: styles.buttonText }, { children: opLoading[hardwareKey]
? (opStep[hardwareKey] === 'read' ? 'Reading...' : 'Writing...')
: opStep[hardwareKey] === 'read'
? 'Step 2: Read Hardware Version'
: 'Step 1: Write Hardware Version Request' })) })), _jsx(TouchableOpacity, Object.assign({ style: styles.button, onPress: () => handleStepNfcOp(0x44, 0x13, [0, 0, 0, 0, 0, 0, 0, 0], boardKey, 'Board Version'), disabled: opLoading[boardKey] }, { children: _jsx(Text, Object.assign({ style: styles.buttonText }, { children: opLoading[boardKey]
? (opStep[boardKey] === 'read' ? 'Reading...' : 'Writing...')
: opStep[boardKey] === 'read'
? 'Step 2: Read Board Version'
: 'Step 1: Write Board Version Request' })) })), _jsx(TouchableOpacity, Object.assign({ style: styles.button, onPress: () => handleStepNfcOp(0x32, 0x11, [0], loraKey, 'LoRa Class'), disabled: opLoading[loraKey] }, { children: _jsx(Text, Object.assign({ style: styles.buttonText }, { children: opLoading[loraKey]
? (opStep[loraKey] === 'read' ? 'Reading...' : 'Writing...')
: opStep[loraKey] === 'read'
? 'Step 2: Read LoRa Class'
: 'Step 1: Write LoRa Class Request' })) })), _jsx(TouchableOpacity, Object.assign({ style: styles.button, onPress: () => handleStepNfcOp(0x12, 0x01, [0], batteryKey, 'Battery Level'), disabled: opLoading[batteryKey] }, { children: _jsx(Text, Object.assign({ style: styles.buttonText }, { children: opLoading[batteryKey]
? (opStep[batteryKey] === 'read' ? 'Reading...' : 'Writing...')
: opStep[batteryKey] === 'read'
? 'Step 2: Read Battery Level'
: 'Step 1: Write Battery Level Request' })) })), _jsx(TouchableOpacity, Object.assign({ style: styles.button, onPress: () => handleStepNfcOp(0x36, 0x09, [0], resetKey, 'Reset Reason'), disabled: opLoading[resetKey] }, { children: _jsx(Text, Object.assign({ style: styles.buttonText }, { children: opLoading[resetKey]
? (opStep[resetKey] === 'read' ? 'Reading...' : 'Writing...')
: opStep[resetKey] === 'read'
? 'Step 2: Read Reset Reason'
: 'Step 1: Write Reset Reason Request' })) })), _jsx(TouchableOpacity, Object.assign({ style: styles.button, onPress: fetchNfcInfo, disabled: loading === 'nfcInfo' }, { children: _jsx(Text, Object.assign({ style: styles.buttonText }, { children: loading === 'nfcInfo' ? 'Fetching...' : 'Fetch NFC Info' })) }))] })), _jsxs(View, Object.assign({ style: styles.section }, { children: [_jsx(Text, Object.assign({ style: styles.sectionTitle }, { children: "Device Info Results" })), Object.keys(info).length === 0 && _jsx(Text, Object.assign({ style: styles.noLogsText }, { children: "No info fetched yet..." })), Object.entries(info).map(([key, value]) => (_jsxs(View, Object.assign({ style: styles.infoBox }, { children: [_jsxs(Text, Object.assign({ style: styles.infoLabel }, { children: [key, ":"] })), _jsx(Text, Object.assign({ style: styles.infoValue }, { children: typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value) }))] }), key)))] })), error && (_jsx(Text, Object.assign({ style: styles.errorText }, { children: error })))] })) })));
};
const styles = StyleSheet.create({
section: {
marginBottom: 30,
},
sectionTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#333',
marginBottom: 15,
},
noLogsText: {
color: '#666',
fontStyle: 'italic',
textAlign: 'center',
},
container: {
flex: 1,
backgroundColor: '#f8f9fa',
},
containerDark: {
backgroundColor: '#1a1a1a',
},
scrollView: {
flex: 1,
padding: 20,
},
title: {
fontSize: 20,
fontWeight: 'bold',
color: '#333',
textAlign: 'center',
marginBottom: 20,
},
label: {
fontSize: 16,
color: '#555',
marginBottom: 10,
},
button: {
backgroundColor: '#1976d2',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 8,
alignItems: 'center',
marginBottom: 20,
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
},
infoBox: {
backgroundColor: '#fff',
borderRadius: 8,
padding: 16,
marginBottom: 16,
borderWidth: 1,
borderColor: '#e0e0e0',
},
infoLabel: {
fontSize: 14,
color: '#333',
fontWeight: 'bold',
marginBottom: 4,
},
infoValue: {
fontSize: 14,
color: '#007bff',
},
errorText: {
color: '#c82333',
fontSize: 14,
marginTop: 10,
textAlign: 'center',
},
});
export default DeviceInfoScreenSDK;