ocoge/local_modules/sfmv17/sfmv17.js

199 lines
6.7 KiB
JavaScript
Raw Permalink Normal View History

'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/
*/