1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/**
 * @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;