const serial = chrome.serial;
|
|
var showDebugLog = false;
|
|
|
|
var SerialConnection = function() {
|
|
this.connectionId = -1;
|
|
this.boundOnReceive = this.onReceive.bind(this);
|
|
this.boundOnReceiveError = this.onReceiveError.bind(this);
|
|
this.onConnect = new MyEvent();
|
|
this.onReceive = new MyEvent();
|
|
this.onError = new MyEvent();
|
|
this.recvBuffer = new Uint8Array(8*1024);
|
|
this.recvView = new DataView(this.recvBuffer.buffer);
|
|
this.recvCursor = 0;
|
|
this.bitrate = 57600;
|
|
};
|
|
|
|
SerialConnection.prototype.onConnectComplete = function(connectionInfo) {
|
|
if (!connectionInfo) {
|
|
if (chrome.runtime.lastError != undefined) {
|
|
logln('chrome.serial.connect error: ' + chrome.runtime.lastError.message);
|
|
}
|
|
return;
|
|
}
|
|
this.connectionId = connectionInfo.connectionId;
|
|
chrome.serial.onReceive.addListener(this.boundOnReceive);
|
|
chrome.serial.onReceiveError.addListener(this.boundOnReceiveError);
|
|
this.onConnect.dispatch();
|
|
};
|
|
|
|
SerialConnection.prototype.onReceive = function(receiveInfo) {
|
|
|
|
if (receiveInfo.connectionId !== this.connectionId) {
|
|
return;
|
|
}
|
|
this.recvBuffer.set(new Uint8Array(receiveInfo.data), this.recvCursor);
|
|
this.recvCursor += receiveInfo.data.byteLength;
|
|
//console.log(buf2hex(receiveInfo.data));
|
|
if (this.recvCursor < 6) {
|
|
return;
|
|
}
|
|
this._dispathReceiveData();
|
|
};
|
|
SerialConnection.prototype.clearRecvData = function() {
|
|
this.recvCursor = 0;
|
|
this.recvBuffer.fill(0);
|
|
}
|
|
SerialConnection.prototype._dispathReceiveData = function() {
|
|
var dLen = this.recvView.getUint16(7);
|
|
if (this.recvCursor < dLen + 9) {
|
|
return;
|
|
}
|
|
|
|
var dataBuffer = new Uint8Array(dLen + 9);
|
|
dataBuffer.set(this.recvBuffer.subarray(0, dLen + 9));
|
|
if (showDebugLog) {
|
|
logln("recv: " + buf2hex(dataBuffer.buffer));
|
|
}
|
|
|
|
|
|
var realCrc = calcCRC(dataBuffer, 6, dLen + 7);
|
|
var crc = dataBuffer[dLen+7] * 256 + dataBuffer[dLen+8];
|
|
if (crc != realCrc) {
|
|
logln("invalid crc " + crc + " ,real= " + realCrc);
|
|
}else {
|
|
var packet = new Packet().fromDataBuffer(dataBuffer);
|
|
this.onReceive.dispatch(packet);
|
|
}
|
|
|
|
|
|
|
|
if (this.recvCursor > dLen + 9) {
|
|
dataBuffer = new Uint8Array(this.recvCursor - dLen - 6);
|
|
dataBuffer.set(this.recvBuffer.subarray(dLen + 9, this.recvCursor));
|
|
this.recvBuffer.fill(0);
|
|
this.recvBuffer.set(dataBuffer);
|
|
this.recvCursor -= dLen + 9;
|
|
this._dispathReceiveData();
|
|
}else {
|
|
this.recvCursor = 0;
|
|
this.recvBuffer.fill(0);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
SerialConnection.prototype.onReceiveError = function(errorInfo) {
|
|
if (errorInfo.connectionId === this.connectionId) {
|
|
this.onError.dispatch(errorInfo.error);
|
|
}
|
|
};
|
|
|
|
SerialConnection.prototype.update = function(conf, cb) {
|
|
if (!this.connectionId) {return;}
|
|
serial.update(this.connectionId, conf, cb);
|
|
}
|
|
SerialConnection.prototype.connect = function(path, bitrate=57600) {
|
|
this.clearRecvData();
|
|
this.bitrate = bitrate;
|
|
serial.connect(path, { bitrate: this.bitrate },this.onConnectComplete.bind(this))
|
|
};
|
|
|
|
SerialConnection.prototype.send = function(packet) {
|
|
if (this.connectionId < 0) {
|
|
throw 'Invalid connection';
|
|
}
|
|
var data = packet.getDataBuffer();
|
|
if (showDebugLog) {
|
|
logln("send: " + buf2hex(data));
|
|
}
|
|
serial.send(this.connectionId, data, function() {});
|
|
};
|
|
|
|
SerialConnection.prototype.disconnect = function() {
|
|
if (this.connectionId < 0) {
|
|
throw 'Invalid connection';
|
|
}
|
|
serial.disconnect(this.connectionId, function() {});
|
|
};
|
|
|
|
////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
|
function logln(msg) {
|
|
var buffer = document.querySelector('#buffer');
|
|
buffer.innerHTML += msg + '<br/>';
|
|
var msgEnd = document.querySelector('#msg_end');
|
|
msgEnd.scrollIntoView();
|
|
}
|
|
|
|
function log(msg) {
|
|
var buffer = document.querySelector('#buffer');
|
|
buffer.innerHTML += msg;
|
|
var msgEnd = document.querySelector('#msg_end');
|
|
msgEnd.scrollIntoView();
|
|
}
|
|
|
|
function buf2hex(buffer) {
|
|
return '0x' + Array.prototype.map.call(new Uint8Array(buffer), x => ('0x00' + x.toString(16)).slice(-2)).join(' 0x');
|
|
}
|
|
|
|
function calcCRC(buffer, start, end) {
|
|
var crc = 0;
|
|
for (var i = start; i < end; i++) {
|
|
crc += buffer[i] & 0xff;
|
|
}
|
|
return crc & 0xffff;
|
|
}
|
|
|
|
const PacketTypeCmd = 0x01;
|
|
const PacketTypeData = 0x02;
|
|
const PacketTypeDataEnd = 0x08;
|
|
const PacketTypeCmdResp = 0x07;
|
|
const PacketTypeDataResp = 0x09;
|
|
|
|
var Packet = function(data=new Uint8Array([0x35]), dataLen=1, type=PacketTypeCmd) {
|
|
this.dataBuffer = new Uint8Array(512);
|
|
this.dataBuffer.set([0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF]);
|
|
|
|
this.type = type;
|
|
this.dataLen = dataLen;
|
|
this.data = data;
|
|
this.result = 0;
|
|
}
|
|
Packet.prototype.setCmd = function(cmd) {
|
|
this.type = PacketTypeCmd;
|
|
this.data = Uint8Array.of(cmd);
|
|
this.dataLen = 1;
|
|
}
|
|
Packet.prototype.getDataBuffer = function () {
|
|
var dataView = new DataView(this.dataBuffer.buffer);
|
|
dataView.setUint8(6, this.type);
|
|
|
|
var len = this.dataLen + 2;
|
|
dataView.setUint16(7, len);
|
|
this.dataBuffer.set(this.data, 9);
|
|
|
|
var crc = calcCRC(this.dataBuffer, 6, this.dataLen + 9);
|
|
dataView.setUint16(9 + this.dataLen, crc);
|
|
|
|
return new Uint8Array(this.dataBuffer.buffer, 0, this.dataLen + 11);
|
|
}
|
|
|
|
Packet.prototype.fromDataBuffer = function(buffer) {
|
|
this.dataBuffer.set(buffer);
|
|
var dataView = new DataView(this.dataBuffer.buffer);
|
|
|
|
this.type = dataView.getUint8(6);
|
|
var len = dataView.getUint16(7);
|
|
this.dataLen = len - 2;
|
|
|
|
this.data = new Uint8Array(buffer.buffer, 9, this.dataLen);
|
|
|
|
if (this.type == PacketTypeCmdResp) {
|
|
this.result = this.data[0];
|
|
}
|
|
return this;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////
|
|
var curDevice = null;
|
|
|
|
function tryHandshake(device) {
|
|
|
|
return new Promise((resolve, reject) =>{
|
|
logln("try handshake with " + device.path);
|
|
var connection = new SerialConnection();
|
|
var isValidDevice = 0;
|
|
device.bitrate = 57600;
|
|
connection.onConnect.addListener(function() {
|
|
logln("device " + device.path + " connected");
|
|
connection.send(new Packet());
|
|
|
|
});
|
|
connection.onReceive.addListener(function(packet) {
|
|
if (packet.type == PacketTypeCmdResp && packet.result == 0) {
|
|
isValidDevice = 1;
|
|
connection.disconnect();
|
|
resolve(1)
|
|
}
|
|
});
|
|
connection.connect(device.path, device.bitrate);
|
|
|
|
setTimeout(() => {
|
|
if (isValidDevice) {
|
|
}else {
|
|
device.bitrate = 115200;
|
|
connection.update({
|
|
bitrate: device.bitrate
|
|
}, (result) => {
|
|
if (result) {
|
|
connection.send(new Packet());
|
|
setTimeout(() => {
|
|
connection.disconnect();
|
|
if (!isValidDevice) {
|
|
resolve(0);
|
|
}
|
|
}, 500);
|
|
}else {
|
|
connection.disconnect();
|
|
resolve(0);
|
|
}
|
|
})
|
|
}
|
|
|
|
}, 500);
|
|
})
|
|
|
|
}
|
|
|
|
async function checkDevices(devices) {
|
|
for (var device of devices) {
|
|
logln("found device, path = " + device.path);
|
|
var res = await tryHandshake(device);
|
|
if (res) {
|
|
curDevice = device;
|
|
logln("found valid device " + device.path);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
////////////////////////////////////////////////////////
|
|
var EnrollSchedule = function(device, enrollCount=6, callback=((err=null, step=0, state=0, data=null)=>{}), timeout = 60 * 1000) {
|
|
this.step = 0;
|
|
this.enrollCount = enrollCount;
|
|
this.callback = callback;
|
|
this.device = device;
|
|
this.connection = null;
|
|
this.timeout = timeout;
|
|
this.timeoutFlag = 0;
|
|
this.responseTime = 1000;
|
|
this.responseTimeout = 0;
|
|
this.responseCallback = null;
|
|
this.canceled = false;
|
|
|
|
}
|
|
const STATE_WAIT_FINGER_DOWN = 1;
|
|
const STATE_WAIT_FINGER_LEAVE = 2;
|
|
const STATE_FINGER_DOWN = 3;
|
|
const STATE_FINGER_LEAVE = 4;
|
|
const STATE_EXTRACT_TEMPLATE = 5;
|
|
const STATE_DOWNLOAD_TEMPLATE = 6;
|
|
const STATE_EXTRACT_TEMPLATE_FAIL = 100;
|
|
const STATE_EXTRACT_TEMPLATE_DIRTY = 101;
|
|
const STATE_EXTRACT_TEMPLATE_POINTS_FEW = 102;
|
|
const STATE_EXTRACT_TEMPLATE_MERGE_FAIL = 103;
|
|
|
|
|
|
const ErrorReceiveDataErr = 1;
|
|
const ErrorEnrollTimeout = 2;
|
|
const ErrorDeviceNotFound = 3;
|
|
const ErrorEmptyFail = 4;
|
|
|
|
function printError(err) {
|
|
logln( "enroll err with code: " + err);
|
|
}
|
|
|
|
|
|
EnrollSchedule.prototype.start = async function() {
|
|
|
|
this.step = 0;
|
|
this.canceled = false;
|
|
try {
|
|
await this._connect();
|
|
if(this.canceled) { return this._disConnect(); }
|
|
|
|
var ret = await this._sendAndWaitRecvCmd(0x0d);
|
|
if (ret == 0x11) {
|
|
throw ErrorEmptyFail;
|
|
}
|
|
|
|
while(this.step < this.enrollCount) {
|
|
this.step += 1;
|
|
ret = await this._enrollOne(this.step);
|
|
|
|
if (ret) {
|
|
let stateErr = STATE_EXTRACT_TEMPLATE_FAIL;
|
|
if(ret == 0x06) {
|
|
stateErr = STATE_EXTRACT_TEMPLATE_DIRTY;
|
|
}else if (ret == 0x07) {
|
|
stateErr = STATE_EXTRACT_TEMPLATE_POINTS_FEW;
|
|
}else if (ret == 0x0a) {
|
|
stateErr = STATE_EXTRACT_TEMPLATE_MERGE_FAIL;
|
|
}
|
|
this.callback(null, this.step, stateErr, null);
|
|
this.step -= 1;
|
|
}
|
|
if(this.canceled) { return this._disConnect(); }
|
|
}
|
|
logln("receive tempalte");
|
|
|
|
this.callback(null, this.step, STATE_DOWNLOAD_TEMPLATE, null);
|
|
|
|
var ret = await this._mergeTemplate();
|
|
if(this.canceled) { return this._disConnect(); }
|
|
var recvBuffer = await this._receiveTemplate();
|
|
if(this.canceled) { return this._disConnect(); }
|
|
this.callback(null, this.step, 0, recvBuffer);
|
|
|
|
}catch(e) {
|
|
this.callback(e, this.step, 0, null);
|
|
}
|
|
this._disConnect();
|
|
}
|
|
|
|
EnrollSchedule.prototype._mergeTemplate = function() {
|
|
return this._sendAndWaitRecvCmd(0x05);
|
|
}
|
|
EnrollSchedule.prototype._receiveTemplate = function() {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
var that = this;
|
|
var data = Uint8Array.of(0x08, 0x01);
|
|
var packet = new Packet(data, 2);
|
|
var recvDataLen = 4 * 1024 * 1024;
|
|
var recvData = new Uint8Array(recvDataLen);
|
|
var recvDataCursor = 0;
|
|
var resetTimeoutCheck = function() {
|
|
if (that.responseTimeout) {
|
|
clearTimeout(that.responseTimeout);
|
|
}
|
|
that.responseTimeout = setTimeout(() => {
|
|
var dummy = new Packet();
|
|
that.connection.send(dummy);
|
|
that.responseTimeout = setTimeout(() => {
|
|
reject(ErrorReceiveDataErr);
|
|
}, that.responseTime);
|
|
}, that.responseTime);
|
|
}
|
|
this.responseCallback = (packet) => {
|
|
resetTimeoutCheck();
|
|
if (packet.type == PacketTypeCmdResp) {
|
|
|
|
}else if (packet.type == PacketTypeData || packet.type == PacketTypeDataEnd) {
|
|
if (recvDataCursor + packet.dataLen < recvDataLen) {
|
|
recvData.set(packet.data, recvDataCursor);
|
|
recvDataCursor += packet.dataLen;
|
|
}else {
|
|
if (that.responseTimeout) {
|
|
clearTimeout(that.responseTimeout);
|
|
}
|
|
reject("recv buffer full");
|
|
}
|
|
}
|
|
|
|
if (packet.type == PacketTypeDataEnd) {
|
|
if (that.responseTimeout) {
|
|
clearTimeout(that.responseTimeout);
|
|
}
|
|
resolve(recvData.slice(0, recvDataCursor));
|
|
}
|
|
}
|
|
|
|
this.connection.send(packet);
|
|
resetTimeoutCheck();
|
|
});
|
|
|
|
}
|
|
|
|
EnrollSchedule.prototype._sendAndWaitRecvCmd = function(cmd) {
|
|
return new Promise((resolve, reject) =>{
|
|
var packet = new Packet();
|
|
packet.setCmd(cmd);
|
|
this._sendAndWaitRecv(packet).then(packet => {
|
|
if (packet.type == PacketTypeCmdResp) {
|
|
resolve(packet.result);
|
|
}
|
|
}).catch(err => {
|
|
reject(err);
|
|
});
|
|
});
|
|
}
|
|
|
|
EnrollSchedule.prototype._enrollOne = async function(step) {
|
|
|
|
var down = false;
|
|
var leave = false;
|
|
var isTimeout = false;
|
|
this.timeoutFlag = setTimeout(() => {
|
|
if (!down) {
|
|
isTimeout = true;
|
|
}
|
|
}, this.timeout);
|
|
//wait finger leave
|
|
logln("wait leave")
|
|
this.callback(null, this.step, STATE_WAIT_FINGER_LEAVE, null);
|
|
while (leave == false && !isTimeout) {
|
|
if(this.canceled) { return; }
|
|
leave = !(await this.captureOne());
|
|
}
|
|
this.callback(null, this.step, STATE_FINGER_LEAVE, null);
|
|
|
|
|
|
if (isTimeout) {
|
|
throw ErrorEnrollTimeout;
|
|
}
|
|
this.callback(null, this.step, STATE_WAIT_FINGER_DOWN, null);
|
|
//wait finger down
|
|
logln("wait down")
|
|
|
|
while (!down && !isTimeout) {
|
|
if(this.canceled) { return; }
|
|
down = await this.captureOne();
|
|
}
|
|
|
|
if (isTimeout) {
|
|
throw ErrorEnrollTimeout;
|
|
}
|
|
this.callback(null, this.step, STATE_FINGER_DOWN, null);
|
|
|
|
logln("finger down step = " + step);
|
|
if(this.canceled) { return; }
|
|
this.callback(null, this.step, STATE_EXTRACT_TEMPLATE, null);
|
|
var ret = await this.extractOne(step);
|
|
if (ret != 0) {
|
|
logln("extract tempate err " + ret);
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
EnrollSchedule.prototype.extractOne = function(step) {
|
|
return new Promise((resolve, reject) =>{
|
|
var data = Uint8Array.of(0x02, step);
|
|
var packet = new Packet(data, 2);
|
|
this._sendAndWaitRecv(packet).then(packet => {
|
|
if (packet.type == PacketTypeCmdResp) {
|
|
resolve(packet.result);
|
|
}
|
|
}).catch(err => {
|
|
reject(err);
|
|
});
|
|
});
|
|
}
|
|
EnrollSchedule.prototype.captureOne = function() {
|
|
return new Promise((resolve, reject) => {
|
|
var packet = new Packet();
|
|
packet.setCmd(0x01);
|
|
this._sendAndWaitRecv(packet).then(packet => {
|
|
if (packet.type == PacketTypeCmdResp) {
|
|
resolve(packet.result == 0);
|
|
}
|
|
}).catch(err => {
|
|
reject(err);
|
|
});
|
|
});
|
|
}
|
|
EnrollSchedule.prototype._sendAndWaitRecv = function(packet) {
|
|
return new Promise((resolve, reject) => {
|
|
var that = this;
|
|
this.responseCallback = (packet) => {
|
|
if (packet.type == PacketTypeCmdResp) {
|
|
if (that.responseTimeout) {
|
|
clearTimeout(that.responseTimeout);
|
|
that.responseTimeout = 0;
|
|
}
|
|
if (packet.result == 0x01) {
|
|
reject(ErrorReceiveDataErr);
|
|
}else {
|
|
resolve(packet);
|
|
}
|
|
}
|
|
}
|
|
this.connection.send(packet);
|
|
|
|
this.responseTimeout = setTimeout(() => {
|
|
that.connection.send(packet);
|
|
this.responseTimeout = setTimeout(() => {
|
|
reject(ErrorReceiveDataErr);
|
|
}, this.responseTime);
|
|
}, this.responseTime);
|
|
});
|
|
}
|
|
|
|
|
|
EnrollSchedule.prototype._resolvePacket = function(packet) {
|
|
if (this.responseCallback) {
|
|
this.responseCallback(packet);
|
|
}
|
|
}
|
|
EnrollSchedule.prototype._connect = function() {
|
|
return new Promise((resolve, reject) => {
|
|
var that = this;
|
|
this.connection = new SerialConnection();
|
|
this.connection.onConnect.addListener(function() {
|
|
logln("device " + that.device.path + " connected");
|
|
resolve();
|
|
});
|
|
this.connection.onReceive.addListener(function(packet) {
|
|
that._resolvePacket(packet);
|
|
});
|
|
|
|
this.connection.connect(this.device.path, this.device.bitrate);
|
|
setTimeout(() => {
|
|
reject("connect timeout");
|
|
}, 500);
|
|
});
|
|
}
|
|
EnrollSchedule.prototype._disConnect = function() {
|
|
if (this.connection) {
|
|
this.connection.disconnect();
|
|
this.connection = null;
|
|
}
|
|
if (this.responseTimeout) {
|
|
clearTimeout(this.responseTimeout);
|
|
this.responseTimeout = 0;
|
|
}
|
|
if (this.timeoutFlag) {
|
|
clearTimeout(this.timeoutFlag);
|
|
this.timeoutFlag = 0;
|
|
}
|
|
}
|
|
|
|
EnrollSchedule.prototype.stop = function() {
|
|
this.canceled = true;
|
|
}
|
|
|
|
|
|
|
|
var enrollSchedule = null;
|
|
var tempData = null;
|
|
function startEnroll(enrollCount=6, timeout=10*1000, cb) {
|
|
if (!curDevice) {
|
|
logln("device not found");
|
|
cb.call(null, {
|
|
err: ErrorDeviceNotFound
|
|
}, 0, null);
|
|
return;
|
|
|
|
}
|
|
|
|
enrollSchedule = new EnrollSchedule(curDevice, enrollCount, (err, step, state, data) => {
|
|
if (err) {
|
|
printError(status.err);
|
|
}
|
|
|
|
if(cb) {
|
|
cb.call(null, {
|
|
err: err,
|
|
state: state,
|
|
step: step,
|
|
data: data
|
|
});
|
|
}
|
|
if (data) {
|
|
tempData = data;
|
|
}
|
|
}, timeout);
|
|
logln("start enroll");
|
|
enrollSchedule.start();
|
|
}
|
|
function stopEnroll() {
|
|
if (enrollSchedule) {
|
|
enrollSchedule.stop();
|
|
enrollSchedule = null;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
//test
|
|
EnrollSchedule.prototype.sleep = function(time) {
|
|
return new Promise((resolve, reject) => {
|
|
setTimeout(() => {
|
|
resolve();
|
|
}, time);
|
|
});
|
|
}
|
|
EnrollSchedule.prototype.downloadTemplate = async function(data) {
|
|
var cmdData = Uint8Array.of(0x09, 0x02);
|
|
var packet = new Packet(cmdData, 2);
|
|
this.connection.send(packet);
|
|
|
|
await this.sleep(1000);
|
|
var dataLength = data.length;
|
|
var packetLen = 256;
|
|
var sendCursor = 0;
|
|
var sendLen = 0;
|
|
var sendType = PacketTypeData;
|
|
logln("downloading");
|
|
while (sendCursor < dataLength) {
|
|
sendLen = (dataLength-sendCursor > packetLen) ? packetLen : (dataLength-sendCursor);
|
|
sendType = (dataLength-sendCursor > packetLen) ? PacketTypeData : PacketTypeDataEnd;
|
|
var sendData = new Uint8Array(data.buffer, sendCursor, sendLen);
|
|
var dataPack = new Packet(sendData, sendLen, sendType);
|
|
this.connection.send(dataPack);
|
|
console.log("send "+ sendLen)
|
|
log('.');
|
|
sendCursor += sendLen;
|
|
await this.sleep(100);
|
|
}
|
|
cmdData = Uint8Array.of(0x06, 0x02, 0x00, 0x03);
|
|
packet = new Packet(cmdData, 4);
|
|
this.connection.send(packet);
|
|
logln('.');
|
|
await this.sleep(500);
|
|
|
|
}
|
|
|
|
async function downloadTemplate() {
|
|
if (!curDevice) {
|
|
var err = "device not found";
|
|
logln(err);
|
|
return;
|
|
}
|
|
if (!tempData) {
|
|
var err = "please enroll";
|
|
logln(err);
|
|
return;
|
|
}
|
|
var enroll = new EnrollSchedule(curDevice);
|
|
try {
|
|
await enroll._connect();
|
|
await enroll.downloadTemplate(tempData);
|
|
logln("download complete");
|
|
}catch(err) {
|
|
logln("download err: " + err);
|
|
}
|
|
|
|
await enroll._disConnect();
|
|
|
|
}
|
|
|
|
async function matchTemplate() {
|
|
if (!curDevice) {
|
|
var err = "device not found";
|
|
logln(err);
|
|
return;
|
|
}
|
|
var enroll = new EnrollSchedule(curDevice);
|
|
try {
|
|
await enroll._connect();
|
|
await enroll._enrollOne(1);
|
|
var packData = Uint8Array.of(0x04, 0x01, 0x00, 0x03, 0x00, 0x03);
|
|
var packet = new Packet(packData, 6);
|
|
await new Promise((resolve, reject) =>{
|
|
enroll._sendAndWaitRecv(packet).then(packet => {
|
|
if (packet.type == PacketTypeCmdResp) {
|
|
if(packet.result) {
|
|
logln("match fail");
|
|
}else {
|
|
logln("match success score " + (packet.data[3] * 256 + packet.data[4]));
|
|
|
|
}
|
|
resolve();
|
|
}
|
|
}).catch(err => {
|
|
reject("match err: " + err);
|
|
});
|
|
})
|
|
|
|
|
|
}catch(err) {
|
|
logln("download err: " + err);
|
|
}
|
|
|
|
await enroll._disConnect();
|
|
}
|
|
////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////
|
|
function disableAll() {
|
|
document.querySelector("#enroll").disabled = true;
|
|
document.querySelector("#down").disabled = true;
|
|
document.querySelector("#match").disabled = true;
|
|
document.querySelector("#refresh").disabled = true;
|
|
document.querySelector("#export").disabled = true;
|
|
document.querySelector("#import").disabled = true;
|
|
|
|
}
|
|
function enableAll() {
|
|
document.querySelector("#enroll").disabled = false;
|
|
document.querySelector("#down").disabled = false;
|
|
document.querySelector("#match").disabled = false;
|
|
document.querySelector("#refresh").disabled = false;
|
|
document.querySelector("#export").disabled = false;
|
|
document.querySelector("#import").disabled = false;
|
|
|
|
}
|
|
var server = null;
|
|
onload = function() {
|
|
document.querySelector('#show-log').checked = showDebugLog;
|
|
|
|
document.querySelector('#show-log').onchange = function(e) {
|
|
showDebugLog = e.target.checked;
|
|
}
|
|
document.querySelector('#enroll').onclick = function(e) {
|
|
if (e.currentTarget.innerText == "Enroll") {
|
|
e.currentTarget.innerText = "Stop";
|
|
startEnroll(6, 10* 1000, (status) => {
|
|
console.log(status.step);
|
|
if (status.err) {
|
|
console.log(status.err);
|
|
}
|
|
if (status.err || status.data) {
|
|
document.querySelector('#enroll').innerText = "Enroll";
|
|
}
|
|
if (status.data) {
|
|
// console.log(data);
|
|
// console.log(buf2hex(data.buffer));
|
|
}
|
|
});
|
|
}else {
|
|
e.currentTarget.innerText = "Enroll";
|
|
stopEnroll();
|
|
}
|
|
|
|
}
|
|
document.querySelector('.msg').style="height:" + (window.innerHeight - 70) + "px";
|
|
|
|
chrome.serial.getDevices((devices) => {
|
|
checkDevices(devices);
|
|
});
|
|
document.querySelector("#down").onclick = async function(e) {
|
|
disableAll();
|
|
try {
|
|
await downloadTemplate();
|
|
}catch(err) {
|
|
logln("download err: " + err);
|
|
}
|
|
enableAll();
|
|
}
|
|
document.querySelector("#match").onclick = async function(e) {
|
|
disableAll();
|
|
try {
|
|
await matchTemplate();
|
|
}catch(err) {
|
|
logln("match err: " + err);
|
|
}
|
|
enableAll();
|
|
}
|
|
|
|
document.querySelector("#refresh").onclick = function(e) {
|
|
disableAll();
|
|
chrome.serial.getDevices(async function(devices) {
|
|
try {
|
|
await checkDevices(devices);
|
|
}catch (e) {
|
|
console.log(e)
|
|
}
|
|
enableAll();
|
|
});
|
|
}
|
|
document.querySelector("#export").onclick = function(e) {
|
|
if (!tempData) {
|
|
logln("please enroll");
|
|
return;
|
|
}
|
|
let reader = new FileReader();
|
|
reader.onload = function(eve) {
|
|
if (eve.target.readyState == FileReader.DONE)
|
|
{
|
|
let a = document.createElement('a');
|
|
a.download = "mafp_template.bin";
|
|
a.href = this.result;
|
|
a.click();
|
|
}
|
|
}
|
|
reader.readAsDataURL(new Blob([tempData]));
|
|
}
|
|
|
|
document.querySelector("#import").onclick = function(e) {
|
|
let fileInput = document.querySelector("#import-file");
|
|
fileInput.value = "";
|
|
fileInput.click();
|
|
}
|
|
document.querySelector("#import-file").onchange = function(e) {
|
|
let files = e.target.files;
|
|
if (files && files.length) {
|
|
let reader = new FileReader();
|
|
reader.onload = async function(ev) {
|
|
if (ev.total == 4096) {
|
|
tempData = new Uint8Array(this.result);
|
|
disableAll();
|
|
try {
|
|
await downloadTemplate();
|
|
}catch(err) {
|
|
logln("download err: " + err);
|
|
}
|
|
enableAll();
|
|
}else {
|
|
logln("invalid file length " + ev.total);
|
|
}
|
|
}
|
|
reader.readAsArrayBuffer(files[0]);
|
|
}
|
|
}
|
|
|
|
const port = 9897;
|
|
if (http.Server && http.WebSocketServer) {
|
|
server = new http.Server();
|
|
var wsServer = new http.WebSocketServer(server);
|
|
server.listen(port);
|
|
logln("ws socket server listen at " + port);
|
|
var connectedSocket = null;
|
|
wsServer.addEventListener('request', function(req) {
|
|
if (connectedSocket) {
|
|
req.reject();
|
|
return;
|
|
}
|
|
console.log('Client connected');
|
|
var socket = req.accept();
|
|
connectedSocket = socket;
|
|
|
|
socket.addEventListener('message', function(e) {
|
|
var reqData = JSON.parse(e.data);
|
|
if (reqData.cmd == "enrollStart") {
|
|
startEnroll(reqData.config.enrollCount,
|
|
reqData.config.enrollTimeout,
|
|
(status) =>{
|
|
var resp = {
|
|
err: status.err ? status.err : "",
|
|
state: status.state ? status.state : 0,
|
|
step: status.step
|
|
}
|
|
if (status.data) {
|
|
resp.data = Array.from(status.data);
|
|
}
|
|
connectedSocket.send(JSON.stringify(resp));
|
|
});
|
|
}else if (reqData.cmd == "enrollCancel") {
|
|
stopEnroll();
|
|
}
|
|
});
|
|
|
|
socket.addEventListener('close', function() {
|
|
connectedSocket = null;
|
|
stopEnroll();
|
|
console.log('Client disconnected');
|
|
if (chrome.runtime.lastError != undefined) {
|
|
console.log(chrome.runtime.lastError.message);
|
|
}
|
|
});
|
|
return true;
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
onresize = function(e) {
|
|
document.querySelector('.msg').style="height:" + (e.currentTarget.innerHeight - 70) + "px";
|
|
document.querySelector('#msg_end').scrollIntoView();
|
|
|
|
}
|