UNPKG

je_nfc_sdk

Version:

A comprehensive React Native SDK for NFC-based device control and communication

348 lines (347 loc) 19.8 kB
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;