Most recent activity
-
Hi,
I finally managed to make the fingerprint sensor working,
with print recognition and code for enrollment.
Here is the code :var C = { FINGERPRINT_OK : 0x00, FINGERPRINT_PACKETRECIEVEERR : 0x01, FINGERPRINT_NOFINGER : 0x02, FINGERPRINT_IMAGEFAIL : 0x03, FINGERPRINT_IMAGEMESS : 0x06, FINGERPRINT_FEATUREFAIL : 0x07, FINGERPRINT_NOMATCH : 0x08, FINGERPRINT_NOTFOUND : 0x09, FINGERPRINT_ENROLLMISMATCH : 0x0A, FINGERPRINT_BADLOCATION : 0x0B, FINGERPRINT_DBRANGEFAIL : 0x0C, FINGERPRINT_UPLOADFEATUREFAIL : 0x0D, FINGERPRINT_PACKETRESPONSEFAIL : 0x0E, FINGERPRINT_UPLOADFAIL : 0x0F, FINGERPRINT_DELETEFAIL : 0x10, FINGERPRINT_DBCLEARFAIL : 0x11, FINGERPRINT_PASSFAIL : 0x13, FINGERPRINT_INVALIDIMAGE : 0x15, FINGERPRINT_FLASHERR : 0x18, FINGERPRINT_INVALIDREG : 0x1A, FINGERPRINT_ADDRCODE : 0x20, FINGERPRINT_PASSVERIFY : 0x21, // FINGERPRINT_STARTCODE : 0xEF01, // FINGERPRINT_COMMANDPACKET : 0x1, FINGERPRINT_DATAPACKET : 0x2, FINGERPRINT_ACKPACKET : 0x7, FINGERPRINT_ENDDATAPACKET : 0x8, // FINGERPRINT_TIMEOUT : 0xFF, FINGERPRINT_BADPACKET : 0xFE, // FINGERPRINT_GETIMAGE : 0x01, FINGERPRINT_IMAGE2TZ : 0x02, FINGERPRINT_REGMODEL : 0x05, FINGERPRINT_STORE : 0x06, FINGERPRINT_EMPTY : 0x0D, FINGERPRINT_VERIFYPASSWORD : 0x13, FINGERPRINT_HISPEEDSEARCH : 0x1B, FINGERPRINT_TEMPLATECOUNT : 0x1D, // DEFAULTTIMEOUT : 5000 // milliseconds }; var serialTTL = null; var thePassword = 0; var theAddress = 0xFFFFFFFF; function connect(serial) { serialTTL = serial; serialTTL.setup(57600); } function checkSensor(callback) { var packet = [ C.FINGERPRINT_VERIFYPASSWORD, (thePassword >> 24) & 0xFF, (thePassword >> 16) & 0xFF, (thePassword >> 8) & 0xFF, thePassword & 0xFF ]; sendPacket(packet, callback); } function getImage(callback) { sendPacket([C.FINGERPRINT_GETIMAGE], callback); } function image2Tz(slot, callback) { sendPacket([C.FINGERPRINT_IMAGE2TZ, (slot & 0xFF)], callback); } function createModel(callback) { sendPacket([C.FINGERPRINT_REGMODEL], callback); } function storeModel(id, callback) { sendPacket([C.FINGERPRINT_STORE, 0x01, (id >> 8) & 0xFF, id & 0xFF], callback); } function emptyDatabase(callback) { sendPacket([C.FINGERPRINT_EMPTY], callback); } function fingerFastSearch(callback) { var fingerID = 0xFFFF; var confidence = 0xFFFF; var packet = [C.FINGERPRINT_HISPEEDSEARCH, 0x01 & 0xFF, 0x00 & 0xFF, 0x00 & 0xFF, 0x00 & 0xFF, 0xA3 & 0xFF]; writePacket(theAddress, C.FINGERPRINT_COMMANDPACKET, packet); getReply(packet, function(len, packet) { if ((len != 1) && (packet[0] != C.FINGERPRINT_ACKPACKET)) { callback(-1, null); return; } fingerID = packet[2]; fingerID <<= 8; fingerID |= packet[3]; confidence = packet[4]; confidence <<= 8; confidence |= packet[5]; callback(null, {'responseCode': packet[1], 'fingerID': fingerID, 'confidence': confidence}); }); } function getTemplateCount(callback) { var templateCount = 0xFFFF; var packet = [C.FINGERPRINT_TEMPLATECOUNT]; writePacket(theAddress, C.FINGERPRINT_COMMANDPACKET, packet); getReply(packet, function(len, packet) { if ((len != 1) && (packet[0] != C.FINGERPRINT_ACKPACKET)) { callback(-1, null); return; } templateCount = packet[2]; templateCount <<= 8; templateCount |= packet[3]; callback(null, {'responseCode': packet[1], 'templateCount': templateCount}); }); } function writePacket(addr, packetType, packet) { var len = packet.length+2; serialTTL.write([ (C.FINGERPRINT_STARTCODE >> 8) & 0xFF, C.FINGERPRINT_STARTCODE & 0xFF, (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, packetType, (len >> 8) & 0xFF, len &0xFF ]); var sum = (len>>8) + (len&0xFF) + packetType; serialTTL.write(packet); for (var i in packet) sum += packet[i]; serialTTL.write([(sum>>8)&0xFF, sum&0xFF]); } function getReply(packet, callback) { var receivedData = []; serialTTL.onData(function (e) { receivedData.push(e.data.charCodeAt(0)); if ( (idx === 0) && (receivedData[0] != ( (C.FINGERPRINT_STARTCODE >> 8) & 0xFF) )) return; if (receivedData.length >= 9) { if (( receivedData[0] != (C.FINGERPRINT_STARTCODE >> 8)) || ( receivedData[1] != (C.FINGERPRINT_STARTCODE & 0xFF))) { callback(-1, {'responseCode': C.FINGERPRINT_BADPACKET}); return; } var packettype = receivedData[6]; var len = receivedData[7]; len <<= 8; len |= receivedData[8]; len -= 2; if (receivedData.length <= (len+10)) return; packet[0] = packettype; for (var i=0; i<len; i++) { packet[1+i] = receivedData[9+i]; } callback(len, packet); } }); } function sendPacket(packet, callback) { writePacket(theAddress, C.FINGERPRINT_COMMANDPACKET, packet); getReply(packet, function(len, packet) { if ((len != 1) && (packet[0] != C.FINGERPRINT_ACKPACKET)) callback(-1, null); else callback(len, {'responseCode': packet[1]}); }); } function getErrorCode(responseCode) { var res = null; switch (responseCode & 0xFF) { case C.FINGERPRINT_OK: res = null; break; case C.FINGERPRINT_NOFINGER: res = "No Finger"; break; case C.FINGERPRINT_PACKETRECIEVEERR: res = "Communication error"; break; case C.FINGERPRINT_IMAGEFAIL: res = "Imaging error"; break; case C.FINGERPRINT_IMAGEMESS: res = "Image too messy"; break; case C.FINGERPRINT_FEATUREFAIL: res = "Could not find fingerprint features"; break; case C.FINGERPRINT_INVALIDIMAGE: res = "Could not find fingerprint features"; break; case C.FINGERPRINT_ENROLLMISMATCH: res = "Prints did not match"; break; case C.FINGERPRINT_BADLOCATION: res = "Could not store in that location"; break; case C.FINGERPRINT_BADPACKET: res = "Communication error"; break; case C.FINGERPRINT_FLASHERR: res = "Error writing to flash"; break; default: res = "Unknown error"; } return res; }
-
I agree that async.js might be a bit heavy for the simple fact of doing series :)
But this library do a lot more and I had in mine to port this library to have something similar in Espruino, by also adding then the doWhile, etc etc with asynchronous management.... but you are right :)Thanks for fixing the first two points.
Is the first point fixing the line :
° callback = callback || function () {};
° if (fn)
° if(arr.map)But for me the for(.... in ... ) is also "wrong" ? In the code I'm ususally do it used to return the value (the item) and not the index (as an integer) in the array.
what I except isfor (var i in ["a","b","c"]) console.log(i)link "a" "b" "c"
Is Espruino "standard" javascript ? or is it mine code that is not standard :) ?
I have to admit that I have worked more with node.js so I might be wrong in some of my comments -
Using the library is working like this :
var ac = new async(); console.log('start'); ac.series([ function(done) { console.log('func1 called'); done(null); } ], function(err, result) { console.log('end'); } );
but fails like this
var ac = new async(); console.log('start'); ac.series([ function(done) { console.log('func1 called'); done(null); }, function(done) { console.log('func2 called'); done(null); } ], function(err, result) { console.log('end'); } );
En error message from Espruino says that it reached the stack limitation for recursivity functions.
I tried to add a setTimeout(fn(function (err) ...., 0) in this.series to 'empty' the stack.
I used this trick in some of my code to create recursivity :
using setTimeout allow the stack to continue the program (and do not fill it) and then call the recursive function. But even with this trick this is not wokring.Even if I can make the code working, I'm afraid the board has not enough 'power' or memory.
What do you think ?
-
Hi Gordon,
I used jsfiddle.net in Google Chrome (for the console)
to test and compare the original code of async library.
Here is the modified code with comments of portion of code that do not react the same in Espruino. I do not know what should work or not in Espruino, what should be standard or not, but async.js is normally using standard javascript (I think :) ).function async() { var eachSeries = function (arr, iterator, callback) { //Commented next statement as it fails. callback is always assigned to function () {}; //even if callback has an value. //callback = callback || function () {}; if (!arr.length) { return callback(); } var completed = 0; var iterate = function () { iterator(arr[completed], function (err) { if (err) { callback(err); callback = function () {}; } else { completed += 1; if (completed >= arr.length) { callback(null); } else { iterate(); } } }); }; iterate(); }; var _map = function (arr, iterator) { //commented if(arr.map)fails and never enter the if even if arr has a value //if (arr.map) { return arr.map(iterator); //} //this is th original code when previous if is not commented //var results = []; //_each(arr, function (x, i, a) { // results.push(iterator(x, i, a)); //}); //return results; }; var _asyncMap = function (eachfn, arr, iterator, callback) { var results = []; arr = _map(arr, function (x, i) { return {index: i, value: x}; }); eachfn(arr, function (x, callback) { iterator(x.value, function (err, v) { results[x.index] = v; callback(err); }); }, function (err) { callback(err, results); }); }; var doSeries = function (fn) { //original code //return function () { // var args = Array.prototype.slice.call(arguments); // return fn.apply(null, [async.eachSeries].concat(args)); //}; return function () { //arguments.slice replace Array.prototype.slice.call var args = arguments.slice(0); //the following statements replace [eachSeries].concat(args) //as .concat is not recognized var r = [eachSeries]; for(var i in args) { //i should be the value of args and not an integer //i is equal to 0,1,2 (args has 3 items) and normally should be //the value of args[i], isn't it ??? r.push(args[i]); } return fn.apply(null, r); }; }; var mapSeries = doSeries(_asyncMap); this.series = function (tasks, callback) { //even if callback has a value, the following line fails //callback = callback || function () {}; mapSeries(tasks, function (fn, callback) { // statement if(fn) fails even if fn has a value, so updated it to if (fn !=== null) if (fn !== null) { fn(function (err) { var args = arguments.slice(1); if (args.length <= 1) { args = args[0]; } callback.call(null, err, args); }); } }, callback); }; }
-
Used to work with node.js Async library and like this library.
Having to do lot of asynchronous (so with callback) chaining functions in my project,
such library might miss in Espruino.
Example of async.js library transfered :function async() { var only_once = function(fn) { var called = false; return function() { if (called) throw new Error("Callback was already called."); called = true; fn.apply(root, arguments); }; }; var doSeries = function (fn) { return function () { var args = Array.prototype.slice.call(arguments); return fn.apply(null, [async.eachSeries].concat(args)); }; }; var eachSeries = function (arr, iterator, callback) { callback = callback || function () {}; if (!arr.length) { return callback(); } var completed = 0; var iterate = function () { iterator(arr[completed], function (err) { if (err) { callback(err); callback = function () {}; } else { completed += 1; if (completed >= arr.length) { callback(null); } else { iterate(); } } }); }; iterate(); }; var mapSeries = doSeries(_asyncMap); this.series = function (tasks, callback) { callback = callback || function () {}; if (tasks.constructor === Array) { async.mapSeries(tasks, function (fn, callback) { if (fn) { fn(function (err) { var args = Array.prototype.slice.call(arguments, 1); if (args.length <= 1) { args = args[0]; } callback.call(null, err, args); }); } }, callback); } }; } var async = new async(); async.series([ function(done) { getImage(function(err, result) { //some logic) done(err, result); }); }, function(done) { image2Tz(function(err, result) { //some ogic done(err, result); }); }, function(done) { fingerFastSearch(function(err, result) { //some logic done(err, result); }); } ], function(err, result) { if(err !== null) { console.log('Error : ' + err); //do logic return; } console.log(result); } );
If something similar is already present in Espruino, let me know...
Any question or feedback, please let me know...
I planned to use functions around control flow for the moment.[EDITED]
PS : Sorry.... :(
the code is not working so well..... I'll update it once fully working -
I will see....
The logic for enrollment will definitely use the interface module.
This module have to contains all the logic to interface the sensor.But the logic to enroll a fingerID is quite long, as it require for example to take three image, compare, etc etc.
And I thought that all those code might make the base module heavier in term of size. That's why I thought about additional module.. will see...
But code example at minimum :) -
-
And here is the code I have so far.
Please note it was late, not necessarly optimized and the way the onData is done might change later :)
Also I will add an 'err' as first parameter for each callback in case,
and adapt some part of code.
Once Enroll is done, I will start transforming and prepare for modulevar C = { FINGERPRINT_OK : 0x00, FINGERPRINT_PACKETRECIEVEERR : 0x01, FINGERPRINT_NOFINGER : 0x02, FINGERPRINT_IMAGEFAIL : 0x03, FINGERPRINT_IMAGEMESS : 0x06, FINGERPRINT_FEATUREFAIL : 0x07, FINGERPRINT_NOMATCH : 0x08, FINGERPRINT_NOTFOUND : 0x09, FINGERPRINT_ENROLLMISMATCH : 0x0A, FINGERPRINT_BADLOCATION : 0x0B, FINGERPRINT_DBRANGEFAIL : 0x0C, FINGERPRINT_UPLOADFEATUREFAIL : 0x0D, FINGERPRINT_PACKETRESPONSEFAIL : 0x0E, FINGERPRINT_UPLOADFAIL : 0x0F, FINGERPRINT_DELETEFAIL : 0x10, FINGERPRINT_DBCLEARFAIL : 0x11, FINGERPRINT_PASSFAIL : 0x13, FINGERPRINT_INVALIDIMAGE : 0x15, FINGERPRINT_FLASHERR : 0x18, FINGERPRINT_INVALIDREG : 0x1A, FINGERPRINT_ADDRCODE : 0x20, FINGERPRINT_PASSVERIFY : 0x21, FINGERPRINT_STARTCODE : 0xEF01, FINGERPRINT_COMMANDPACKET : 0x1, FINGERPRINT_DATAPACKET : 0x2, FINGERPRINT_ACKPACKET : 0x7, FINGERPRINT_ENDDATAPACKET : 0x8, FINGERPRINT_TIMEOUT : 0xFF, FINGERPRINT_BADPACKET : 0xFE, FINGERPRINT_GETIMAGE : 0x01, FINGERPRINT_IMAGE2TZ : 0x02, FINGERPRINT_REGMODEL : 0x05, FINGERPRINT_STORE : 0x06, FINGERPRINT_EMPTY : 0x0D, FINGERPRINT_VERIFYPASSWORD : 0x13, FINGERPRINT_HISPEEDSEARCH : 0x1B, FINGERPRINT_TEMPLATECOUNT : 0x1D, DEFAULTTIMEOUT : 5000 // milliseconds }; Serial4.setup(57600); var thePassword = 0; var theAddress = 0xFFFFFFFF; function writePacket(addr, packetType, packet) { var len = packet.length+2; Serial4.write([ (C.FINGERPRINT_STARTCODE >> 8) & 0xFF, C.FINGERPRINT_STARTCODE & 0xFF, (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF, packetType, (len >> 8) & 0xFF, len &0xFF ]); var sum = (len>>8) + (len&0xFF) + packetType; Serial4.write(packet); for (var i in packet) sum += packet[i]; Serial4.write([(sum>>8)&0xFF, sum&0xFF]); } function getReply(packet, callback) { var receivedData = [];// new Uint8Array(20); Serial4.onData(function (e) { receivedData.push(e.data.charCodeAt(0)); if ( (idx === 0) && (receivedData[0] != ( (C.FINGERPRINT_STARTCODE >> 8) & 0xFF) )) return; if (receivedData.length >= 9) { if (( receivedData[0] != (C.FINGERPRINT_STARTCODE >> 8)) || ( receivedData[1] != (C.FINGERPRINT_STARTCODE & 0xFF))) console.log('bad packet'); var packettype = receivedData[6]; var len = receivedData[7]; len = len << 8 & 0xFF; len = len | (receivedData[8] & 0xFF); len -= 2; if (receivedData.length <= (len+10)) return; packet[0] = packettype; for (var i=0; i<len; i++) { packet[1+i] = receivedData[9+i]; } console.log('end'); callback(len, packet); } }); } function verifyPassword(callback) { var packet = [ C.FINGERPRINT_VERIFYPASSWORD, (thePassword >> 24) & 0xFF, (thePassword >> 16) & 0xFF, (thePassword >> 8) & 0xFF, thePassword & 0xFF ]; writePacket(theAddress, C.FINGERPRINT_COMMANDPACKET, packet); getReply(packet, function(len, packet) { if ((len == 1) && (packet[0] == C.FINGERPRINT_ACKPACKET) && (packet[1] == C.FINGERPRINT_OK)) callback(true); else callback(false); }); } function getImage(callback) { var packet = [C.FINGERPRINT_GETIMAGE]; writePacket(theAddress, C.FINGERPRINT_COMMANDPACKET, packet); getReply(packet, function(len, packet) { if ((len != 1) && (packet[0] != C.FINGERPRINT_ACKPACKET)) callback(-1); else callback(packet[1]); }); } function image2Tz(slot, callback) { var packet = [C.FINGERPRINT_IMAGE2TZ, (slot & 0xFF)]; writePacket(theAddress, C.FINGERPRINT_COMMANDPACKET, packet); getReply(packet, function(len, packet) { if ((len != 1) && (packet[0] != C.FINGERPRINT_ACKPACKET)) callback(-1); else callback(packet[1]); }); } function fingerFastSearch(callback) { var fingerID = 0xFFFF; var confidence = 0xFFFF; var packet = [C.FINGERPRINT_HISPEEDSEARCH, 0x01, 0x00, 0x00, 0x00, 0xA3]; writePacket(theAddress, C.FINGERPRINT_COMMANDPACKET, packet); getReply(packet, function(len, packet) { if ((len != 1) && (packet[0] != C.FINGERPRINT_ACKPACKET)) { callback(-1); return; } fingerID = packet[2]; fingerID <<= 8; fingerID |= packet[3]; confidence = packet[4]; confidence <<= 8; confidence |= packet[5]; callback(packet[1], fingerID, confidence); }); } function getFingerprintIDez(callback) { getImage(function(f) { if (f != C.FINGERPRINT_OK) { callback(-1); return; } image2Tz(null, function(g) { if (g != C.FINGERPRINT_OK) { callback(-1); return; } fingerFastSearch(function(res, fingerID, confidence) { if (res != C.FINGERPRINT_OK) { callback(-1); return; } callback(fingerID); }); }); }); } //setup verifyPassword(function(e) { if(e) { getFingerprintIDez(function(e) { console.log(e); }); } });
And here is some example using the library :
Async function series (Thanks Gordon) :
Enrollment example :
Recogniton example :