/**
|
* @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<NfcConfig>} 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;
|