2024-05-18 14:15:46 +00:00
|
|
|
'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));
|
|
|
|
|
2024-05-27 14:00:31 +00:00
|
|
|
// Calculate XOR checksum
|
2024-05-18 14:15:46 +00:00
|
|
|
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);
|
2024-05-27 14:00:31 +00:00
|
|
|
}
|
|
|
|
const getAck = async () => {
|
2024-05-18 14:15:46 +00:00
|
|
|
let ackBuffer = Buffer.from([]);
|
|
|
|
let timer = SFM_SERIAL_TIMEOUT;
|
|
|
|
while (timer--) {
|
2024-05-27 14:00:31 +00:00
|
|
|
if (await rg.serial_data_available(ser_hand) > 0) {
|
2024-05-18 14:15:46 +00:00
|
|
|
ackBuffer = Buffer.concat([ackBuffer, await rg.serial_read(ser_hand, 0, true)]);
|
|
|
|
}
|
|
|
|
else if (ackBuffer.length >= 8) {
|
2024-05-27 14:00:31 +00:00
|
|
|
// 1/100秒待ってデバイス側にデータが残っていないか再チェック
|
|
|
|
await delay(10);
|
|
|
|
timer -= 10;
|
|
|
|
if (await rg.serial_data_available(ser_hand) > 0) continue;
|
|
|
|
// もうデータは残っていないらしい
|
2024-05-18 14:15:46 +00:00
|
|
|
if (ackBuffer[6] == getCheckSum(ackBuffer))
|
2024-05-27 14:00:31 +00:00
|
|
|
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]];
|
2024-05-18 14:15:46 +00:00
|
|
|
else
|
2024-05-27 14:00:31 +00:00
|
|
|
return [null, null, null, SFM_ACK_FAIL];
|
2024-05-18 14:15:46 +00:00
|
|
|
}
|
|
|
|
await delay(1);
|
|
|
|
}
|
2024-05-27 14:00:31 +00:00
|
|
|
return [null, null, null, SFM_ACK_SERIALTIMEOUT];
|
2024-05-18 14:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Rapping sendCmd... Returns tuple
|
2024-05-27 14:00:31 +00:00
|
|
|
const sendAndGet = async (cmdType, p1 = 0, p2 = 0, p3 = 0) => {
|
|
|
|
await sendCmd(cmdType, p1, p2, p3);
|
|
|
|
let [ackType, q1, q2, q3, dataBuffer] = await getAck();
|
2024-05-18 14:15:46 +00:00
|
|
|
this.last_status = q3; // コマンド実行結果ステータスを保存
|
2024-05-27 14:00:31 +00:00
|
|
|
if (ackType == cmdType) return [ackType, q1, q2, q3, dataBuffer];
|
2024-05-18 14:15:46 +00:00
|
|
|
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;
|
2024-05-27 14:00:31 +00:00
|
|
|
let [ackType, q1, q2, q3] = await sendAndGet(0xC3, start_color, end_color, period);
|
2024-05-18 14:15:46 +00:00
|
|
|
return q3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Count users
|
|
|
|
exports.getUserCount = async () => {
|
2024-05-27 14:00:31 +00:00
|
|
|
let [ackType, q1, q2, q3] = await sendAndGet(0x09, 0x00, 0x00, 0x00);
|
2024-05-18 14:15:46 +00:00
|
|
|
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 () => {
|
2024-05-27 14:00:31 +00:00
|
|
|
let [ackType, q1, q2, q3] = await sendAndGet(0x0C, 0x00, 0x00, 0x00);
|
2024-05-18 14:15:46 +00:00
|
|
|
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) {
|
2024-05-27 14:00:31 +00:00
|
|
|
[ackType, q1, q2, q3] = await sendAndGet(0x01, (uid >> 8) & 0xFF, uid & 0xFF, SFM_DEFAULT_USERROLE);
|
2024-05-18 14:15:46 +00:00
|
|
|
if (q3 == SFM_ACK_SUCCESS) return 0;
|
|
|
|
else return -1;
|
|
|
|
} else if (step == 2) {
|
2024-05-27 14:00:31 +00:00
|
|
|
[ackType, q1, q2, q3] = await sendAndGet(0x02);
|
2024-05-18 14:15:46 +00:00
|
|
|
if (q3 == SFM_ACK_SUCCESS) return 0;
|
|
|
|
else return -1;
|
|
|
|
} else if (step == 3) {
|
2024-05-27 14:00:31 +00:00
|
|
|
[ackType, q1, q2, q3] = await sendAndGet(0x03, 0x00, 0x00, 0x00);
|
2024-05-18 14:15:46 +00:00
|
|
|
let uid = -1;
|
|
|
|
if (q3 == SFM_ACK_SUCCESS) uid = (q1 << 8) | q2;
|
|
|
|
return uid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-27 14:00:31 +00:00
|
|
|
// 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);
|
2024-05-18 14:15:46 +00:00
|
|
|
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/
|
|
|
|
*/
|