'use strict'; // Private constance const err_msg = 'Serial port already opened. Please close old connection to use new one.'; const SFM_SERIAL_TIMEOUT = 8000 // serial timeout (ms) const SFM_DEFAULT_USERROLE = 0x03 // Default user role for register const SFM_ACK_SUCCESS = 0x00 // Command successful const SFM_ACK_FAIL = 0x01 // Command failed const SFM_ACK_FULL = 0x04 // Database full const SFM_ACK_NOUSER = 0x05 // User does not exist const SFM_ACK_USER_EXIST = 0x07 // User exists const SFM_ACK_TIMEOUT = 0x08 // Image collection timeout const SFM_ACK_HWERROR = 0x0A // Hardware error const SFM_ACK_IMGERROR = 0x10 // Image error const SFM_ACK_BREAK = 0x18 // Stop current cmd const SFM_ACK_ALGORITHMFAIL = 0x11 // Film/Mask attack detected const SFM_ACK_HOMOLOGYFAIL = 0x12 // Homology check fail const SFM_ACK_SERIALTIMEOUT = 0x13 // Serial receive time exceeds SFM_SERIAL_TIMEOUT const SFM_ACK_IDLE = 0x14 // Module idle // Public constance exports.SFM_RING_OFF = 0x07 // Ring LED Off exports.SFM_RING_RED = 0x03 // Ring Color Red exports.SFM_RING_GREEN = 0x05 // Ring Color Green exports.SFM_RING_BLUE = 0x06 // Ring Color Blue exports.SFM_RING_YELLOW = 0x01 // Ring Color Yellow exports.SFM_RING_PURPLE = 0x02 // Ring Color Purple exports.SFM_RING_CYAN = 0x04 // Ring Color Cyan // Public variables exports.last_status = 0; // Private variables let rg; let ser_hand = -1; // Private Functions // Delay usec const delay = microsec => new Promise(r => setTimeout(r, microsec)); // Calculate XOR checksum const getCheckSum = buffer => { let result = 0; for (let i = 1; i <= 5; i++) { result ^= buffer[i]; } return result; } // Send command to uart and retruns responce tuple const sendCmd = async (cmdType, p1, p2, p3) => { while (await rg.serial_data_available(ser_hand)) rg.serial_read(ser_hand); let cmdBuffer = [0xF5, cmdType, p1, p2, p3, 0, 0, 0xF5]; cmdBuffer[6] = getCheckSum(cmdBuffer); await rg.serial_write(ser_hand, cmdBuffer); } const getAck = async () => { let ackBuffer = Buffer.from([]); let timer = SFM_SERIAL_TIMEOUT; while (timer--) { if (await rg.serial_data_available(ser_hand) > 0) { ackBuffer = Buffer.concat([ackBuffer, await rg.serial_read(ser_hand, 0, true)]); } else if (ackBuffer.length >= 8) { // 1/100秒待ってデバイス側にデータが残っていないか再チェック await delay(10); timer -= 10; if (await rg.serial_data_available(ser_hand) > 0) continue; // もうデータは残っていないらしい if (ackBuffer[6] == getCheckSum(ackBuffer)) if (ackBuffer.length > 8) { // Has data field if (ackBuffer[ackBuffer.length - 1] == 0xF5) { let dataBuffer = Buffer.alloc(ackBuffer.length - 8); ackBuffer.copy(dataBuffer, 0, 8); return [ackBuffer[1], ackBuffer[2], ackBuffer[3], ackBuffer[4], dataBuffer]; } } else return [ackBuffer[1], ackBuffer[2], ackBuffer[3], ackBuffer[4]]; else return [null, null, null, SFM_ACK_FAIL]; } await delay(1); } return [null, null, null, SFM_ACK_SERIALTIMEOUT]; } // Rapping sendCmd... Returns tuple const sendAndGet = async (cmdType, p1 = 0, p2 = 0, p3 = 0) => { await sendCmd(cmdType, p1, p2, p3); let [ackType, q1, q2, q3, dataBuffer] = await getAck(); this.last_status = q3; // コマンド実行結果ステータスを保存 if (ackType == cmdType) return [ackType, q1, q2, q3, dataBuffer]; else return [SFM_ACK_FAIL, 0, 0, 0]; } // Initialize module... just connect uart exports.init = async (_rg, serial_port, baud = 115200) => { rg = _rg; if (ser_hand >= 0) { throw new Error(err_msg); return; } ser_hand = await rg.serial_open(serial_port, baud); return ser_hand; } // LED ring exports.setRingColor = async (start_color, end_color = -1, period = 500) => { period /= 10; if (period < 30) period = 30; else if (period > 200) period = 200; if (end_color == -1) end_color = start_color; let [ackType, q1, q2, q3] = await sendAndGet(0xC3, start_color, end_color, period); return q3; } // Count users exports.getUserCount = async () => { let [ackType, q1, q2, q3] = await sendAndGet(0x09, 0x00, 0x00, 0x00); let userCount = -1; if (q3 != SFM_ACK_FAIL) userCount = (q1 << 8) | q2; // else userCount = -1; return userCount; } // Recognize fingerprint... returns userID / 0: not found / -1: error exports.recognition_1vN = async () => { let [ackType, q1, q2, q3] = await sendAndGet(0x0C, 0x00, 0x00, 0x00); let uid = (q1 << 8) | q2; if (uid == 0 && q3 != SFM_ACK_SUCCESS) return -1; else return uid; } // Registration : // step 1... returns success: 0 / fail: -1 // step 2... returns success: 0 / fail: -1 // step 3... returns new userID / fail: -1 exports.register_3c3r = async (step, uid = 0) => { let q3, ackType, q1, q2; if (step == 1) { [ackType, q1, q2, q3] = await sendAndGet(0x01, (uid >> 8) & 0xFF, uid & 0xFF, SFM_DEFAULT_USERROLE); if (q3 == SFM_ACK_SUCCESS) return 0; else return -1; } else if (step == 2) { [ackType, q1, q2, q3] = await sendAndGet(0x02); if (q3 == SFM_ACK_SUCCESS) return 0; else return -1; } else if (step == 3) { [ackType, q1, q2, q3] = await sendAndGet(0x03, 0x00, 0x00, 0x00); let uid = -1; if (q3 == SFM_ACK_SUCCESS) uid = (q1 << 8) | q2; return uid; } } // Get fingerprint image exports.getImage = async () => { let [ackType, q1, q2, q3, dataBuffer] = await sendAndGet(0x24); if (q3 == SFM_ACK_SUCCESS) { // console.log(dataBuffer) let width = q1 << 2; let height = q2 << 2; let len = width * height; let imgBuffer = Buffer.alloc(len);//dataBuffer.slice(1, 1 + len); dataBuffer.copy(imgBuffer, 0, 1, 1 + len); // const imgblob = new Blob([imgBuffer], { type: "image/bmp" }); return imgBuffer; } // return [, ]; else return -1; } // Delete user(s) exports.deleteUser = async (uid) => { let ackType, q1, q2, q3; if (uid == 0) // Delete All users [ackType, q1, q2, q3] = await sendAndGet(0x05); else // Delete specific user [ackType, q1, q2, q3] = await sendAndGet(0x04, (uid >> 8) & 0xFF, uid & 0xFF, SFM_DEFAULT_USERROLE); if (q3 == SFM_ACK_SUCCESS) return 0; else return -1; } // Disconnect from uart exports.stop = async () => { if (ser_hand >= 0) { await rg.serial_close(ser_hand); ser_hand = -1; } } /** * This library is forked from https://github.com/Matrixchung/SFM-V1.7/ */