/** * @file dxNfcCard.js * @module dxNfcCard * @description * NFC module based on the native nfc_bridge C library. * This module provides a singleton interface for interacting with NFC cards. * It supports detecting, reading, and writing various basic NFC card types, * including M1, CPU, and NTAG cards. * * Additionally, the module integrates eID (Chinese 2nd Generation ID card) reading functionality. * **Note**: The eID feature requires a network connection and currently only supports Chinese 2nd Generation ID cards. * * @usage * // 1. Import the module * import { dxNfcCard } from 'dxNfcCard.js'; * * // 2. Initialize * dxNfcCard.init(); * * // 3. (Optional) Initialize eID functionality * dxNfcCard.eidInit({ * config: { * device_model: "your_device_model" * } * }); * * // 4. Set callbacks * dxNfcCard.setCallbacks({ * onCardDetected: (cardInfo) => { console.log('NFC Card:', cardInfo); }, * onEidDetected: (eidInfo) => { console.log('eID Card:', eidInfo); } * }); * * // 5. Poll for events in a timer * setInterval(dxNfcCard.loop, 100); * * // 6. Call specific operations, e.g., read M1 block * // const data = dxNfcCard.m1ReadBlock(...); */ import { nfc } from './libvbar-m-dxnfccard.so'; const dxNfcCard = {}; let _callbacks = {}; /** * Initializes the NFC module. Must be called before any other operations. * @returns {void} */ dxNfcCard.init = function () { nfc.init(); }; /** * Deinitializes the NFC module and releases all resources. * @returns {void} */ dxNfcCard.deinit = function () { nfc.deinit(); }; /** * @typedef {object} NfcConfig * @property {boolean} afi_enable - Enable Application Family Identifier. * @property {number} afi - Application Family Identifier value. * @property {number} card_protocol - Bitmask for card protocols to support. * @property {boolean} identity_card_enable - Enable reading of identity cards. * @property {number} read_timeout_ms - Read timeout in milliseconds. * @property {number} braud_tx - TX baud rate. * @property {number} braud_rx - RX baud rate. * @property {boolean} i14443p4_switch - Enable ISO14443-4 protocol. * @property {number} felica_braud - FeliCa baud rate. * @property {number} nfc_sak28 - SAK value handling for specific cards. * @property {number} felica_syscode - FeliCa system code. * @property {number} felica_request_code - FeliCa request code. */ /** * Retrieves the current NFC configuration. * @returns {NfcConfig} The current configuration object. */ dxNfcCard.getConfig = function () { return nfc.getConfig(); }; /** * Updates the NFC configuration. * Not neccecary to modify, use default values unless special requirements. * @param {Partial} config - A configuration object with properties to update. * @returns {void} */ dxNfcCard.updateConfig = function (config) { return nfc.updateConfig(config); }; /** * Checks if a card is currently present in the NFC field. * @returns {boolean} True if a card is present, false otherwise. */ dxNfcCard.isCardIn = function () { return nfc.isCardIn(); }; /** * Reads a 16-byte block from an M1 card. * @param {number} blockNumber - The block number to read (0-63 for 1K, 0-255 for 4K). * @param {ArrayBuffer} key - A 6-byte ArrayBuffer containing the key (A or B). * @param {number} keyType - The key type: 0x60 for Key A, 0x61 for Key B. * @param {number} [taskFlag=0] - Optional task flag for card selection (0: AUTO, 1: ACTIVE, 2: IDLE). * @returns {ArrayBuffer} A 16-byte ArrayBuffer containing the block data. */ dxNfcCard.m1ReadBlock = function (blockNumber, key, keyType, taskFlag = 0x00) { return nfc.m1ReadBlock(blockNumber, key, keyType, taskFlag); }; /** * Writes a 16-byte block to an M1 card. * @param {number} blockNumber - The block number to write. * @param {ArrayBuffer} data - A 16-byte ArrayBuffer containing the data to write. * @param {ArrayBuffer} key - A 6-byte ArrayBuffer containing the key (A or B). * @param {number} keyType - The key type: 0x60 for Key A, 0x61 for Key B. * @param {number} [taskFlag=0] - Optional task flag for card selection. * @returns {number} 0 on success. */ dxNfcCard.m1WriteBlock = function (blockNumber, data, key, keyType, taskFlag = 0x00) { return nfc.m1WriteBlock(blockNumber, data, key, keyType, taskFlag); }; /** * Reads one or more blocks from a sector of an M1 card. * @param {number} sectorNum - The sector number to read from (0-39). * @param {number} logicBlkNum - The starting block number within the sector (0-3 for small sectors, 0-15 for large sectors). * @param {number} blkCount - The number of blocks to read. * @param {ArrayBuffer} key - A 6-byte ArrayBuffer for authentication. * @param {number} keyType - The key type (0x60 for Key A, 0x61 for Key B). * @param {number} [taskFlag=0] - Optional task flag for card selection. * @returns {ArrayBuffer} An ArrayBuffer containing the data read from the sector. */ dxNfcCard.m1ReadSector = function (sectorNum, logicBlkNum, blkCount, key, keyType, taskFlag = 0x00) { return nfc.m1ReadSector(sectorNum, logicBlkNum, blkCount, key, keyType, taskFlag); }; /** * Writes one or more blocks to a sector of an M1 card. * @param {number} sectorNum - The sector number to write to (0-39). * @param {number} logicBlkNum - The starting block number within the sector. * @param {ArrayBuffer} data - Data to write. The length must be a multiple of 16. The number of blocks to write is determined by data.length / 16. * @param {ArrayBuffer} key - A 6-byte ArrayBuffer for authentication. * @param {number} keyType - The key type (0x60 for Key A, 0x61 for Key B). * @param {number} [taskFlag=0] - Optional task flag for card selection. * @returns {number} The number of bytes written on success. */ dxNfcCard.m1WriteSector = function (sectorNum, logicBlkNum, data, key, keyType, taskFlag = 0x00) { return nfc.m1WriteSector(sectorNum, logicBlkNum, data, key, keyType, taskFlag); }; /** * Reads the version information from an NTAG card. * @returns {ArrayBuffer} An ArrayBuffer containing the version data. */ dxNfcCard.ntagReadVersion = function () { return nfc.ntagReadVersion(); }; /** * Reads 4 pages (16 bytes) from an NTAG card, starting at the specified page number. * @param {number} pageNum - The starting page number to read from. * @returns {ArrayBuffer} A 16-byte ArrayBuffer containing the data from 4 pages. */ dxNfcCard.ntagReadPage = function (pageNum) { return nfc.ntagReadPage(pageNum); }; /** * Writes one page (4 bytes) to an NTAG card. * @param {number} pageNum - The page number to write to. * @param {ArrayBuffer} data - A 4-byte ArrayBuffer containing the data to write. * @returns {void} */ dxNfcCard.ntagWritePage = function (pageNum, data) { return nfc.ntagWritePage(pageNum, data); }; /** * Reads a range of pages from an NTAG card quickly. * @param {number} startPage - The starting page number. * @param {number} endPage - The ending page number. * @returns {ArrayBuffer} An ArrayBuffer containing the data from the specified page range. */ dxNfcCard.ntagFastReadPage = function (startPage, endPage) { return nfc.ntagFastReadPage(startPage, endPage); }; /** * Sends an ISO14443-A APDU command to the card. * @param {ArrayBuffer} command - The APDU command to send. * @param {number} [taskFlag=0] - Optional task flag for card selection. * @returns {ArrayBuffer} An ArrayBuffer containing the APDU response from the card. */ dxNfcCard.iso14443Apdu = function (command, taskFlag = 0x00) { return nfc.iso14443Apdu(command, taskFlag); }; /** * Initializes the eID (electronic ID) reading functionality. * After calling this, swiping a supported ID card will trigger the `onEidDetected` callback. * This function requires an active network connection. * @param {object} [options] - Configuration for the eID service. Can be omitted to use default values. * @param {string} [options.ip="deviceid.dxiot.com"] - The IP address of the eID server. * @param {number} [options.port=9889] - The port of the eID server. * @param {object} options.config - Advanced eID parameters. * @param {number} [options.config.read_len=54] - Read length per transaction, default is 0x36 (54). * @param {number} [options.config.declevel=2] - Whether to read the photo (1: no, 2: yes). * @param {number} [options.config.loglevel] - Log level (0, 1, or 2). * @param {number} [options.config.model=0] - 0: return ID info, 1: return reqid for forwarding. * @param {number} [options.config.type=0] - Card type (0: ID card, 1: e-license). * @param {number} [options.config.pic_type=1] - Photo data type (0: wlt, 1: jpg). * @param {number} [options.config.envCode=52302] - Environment code. * @param {string} options.config.device_model - Device model. * @param {number} [options.config.info_type=0] - Return type (0: struct, 1: raw data). * @returns {void} * @throws {Error} If required config properties are missing. */ dxNfcCard.eidInit = function (options = { ip: "deviceid.dxiot.com", port: 9889 }) { if (!options.config || typeof options.config.device_model !== 'string') { throw new Error("eidInit requires options.config with string properties: device_model."); } return nfc.eidInit(options); } /** * Activates the eID module using an activation code and device information. * This is typically done once to bind the device to the eID service. * This function requires an active network connection. * @param {object} options - Activation options. * @param {string} options.codeMsg - The activation code message. * @param {string} options.version - Firmware version. * @param {string} options.macAddr - Device MAC address. * @returns {number} 0 on success, negative value on failure. * @throws {Error} If any of the required options are missing or invalid. */ dxNfcCard.eidActive = function (options) { if (!options || typeof options.codeMsg !== 'string' || typeof options.version !== 'string' || typeof options.macAddr !== 'string') { throw new Error("eidActive requires an object with string properties: codeMsg, version, and macAddr."); } return nfc.eidActive(options); } /** * Deinitializes the eID functionality. * @returns {void} */ dxNfcCard.eidDeinit = function () { return nfc.eidDeinit(); } /** * Sets callback handlers for NFC events. * @typedef {object} CardInfo * @property {number} card_type - The type of the card. * @property {string} id - The card's unique identifier as a hex string. * @property {number} id_len - The length of the card's ID in bytes. * @property {number} type - Detailed card type. * @property {number} sak - SAK value (Select Acknowledge). * @property {number} timestamp - The timestamp of the event (system time). * @property {number} monotonic_timestamp - The monotonic timestamp of the event. * * @typedef {object} EidInfo * @property {string} name - Full name. * @property {string} sex - Sex / Gender. * @property {string} nation - Ethnic group. * @property {string} birthday - Date of birth (Format: YYYYMMDD). * @property {string} address - Residential address. * @property {string} idCardNo - Citizen identification number. * @property {string} grantDept - Issuing authority. * @property {string} userLifeBegin - Valid from date (Format: YYYYMMDD). * @property {string} userLifeEnd - Valid until date (Format: YYYYMMDD or "长期" for long-term). * @property {string} picture - Base64 encoded string of the ID photo. * * @param {object} callbacks - An object containing callback functions. * @param {function(cardInfo: CardInfo)} [callbacks.onCardDetected] - Called when a standard NFC card is detected. * @param {function(eidInfo: EidInfo)} [callbacks.onEidDetected] - Called when an eID (ID card) is successfully read. * @returns {void} */ dxNfcCard.setCallbacks = function (callbacks) { _callbacks = callbacks; }; /** * Processes events from the NFC event queue. Should be called periodically (e.g., in setInterval). * @example * setInterval(() => { * try { * dxNfcCard.loop(); * } catch (e) { * logger.error('Error in NFC loop:', e); * } * }, 50); // Process events every 50ms */ dxNfcCard.loop = function () { // Process regular card events let card_ev = nfc.getEvent(); if (card_ev && _callbacks.onCardDetected) { _callbacks.onCardDetected(card_ev); } // Process eID events let eid_ev_str = nfc.getEidEvent(); if (eid_ev_str && _callbacks.onEidDetected) { const eid_info = JSON.parse(eid_ev_str); _callbacks.onEidDetected(eid_info); } }; /** * Gets the native NFC client object. * @returns {object} The native client object. */ dxNfcCard.getNative = function () { return nfc; }; /** * @readonly * @enum {number} * Enum for card types. */ dxNfcCard.CARD_TYPE = Object.freeze({ /** Unspecified Type A protocol card */ TYPE_A: 64, /** Mifare Ultralight card */ MIFARE_ULTRALIGHT: 65, /** Mifare Classic EV1 1K (4-byte UID) */ MIFARE_CLASSIC_1K_4B: 66, /** Mifare Classic EV1 4K */ MIFARE_CLASSIC_4K: 67, /** CPU card (Type A protocol) */ CPU_A: 68, /** Mifare Desfire series */ MIFARE_DESFIRE: 69, /** Physical ID card (Type B protocol) */ IDENTITY_CARD: 70, /** ISO15693 protocol card (long-range IC card) */ ISO15693: 71, /** Unspecified Type B protocol card */ TYPE_B: 74, /** CPU card (Type B protocol) */ CPU_B: 75, /** Generic M1 card (sometimes synonymous with 66) */ M1: 76, /** Japanese Felica card (Sony standard) */ FELICA: 77, /** Mifare Plus series */ MIFARE_PLUS: 78, /** Also an ID card (sometimes an IDCard type read by the logical layer or CPU) */ IDCARD: 97, /** Unsupported or unrecognized card */ NOT_SUPPORT: 127, }); export default dxNfcCard;