-
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); }); } });
-
I've used your veryfiyPassword and writePacket.
I've added the getReply logic and added getImage, image2Tz, fingerFastSearch
I can receive bytes, and for example the getImage seems to react correctly when a finger is present or not.
I cannot do more testing as the sensor is empy of registered fingers.
I need to add the Enroll methods -
Hi Gordon,
I've modified your code and implemented some additional methods.
I should have everything for reading, but cannot test as I need to add the Enroll (new fingerprint) part as there is no fingerID in the sensor yet :)I might have something within next few days...
And then ready for a module... -
-
Thanks all for sharing information.
I've successfully powered the NeoPixel Ring with the keypad via Espruino board, starting to play with. I found a wallplug to USB (5V 1A) converter and this is working fine for now :)
I have a better vision on powering stuff now, thanks to all of you.
Even if I might come up with a question (or two) in the future ;)In the meantime I found this article from Gordon about powering LED strip with MOSFET.
I might be wrong but I do not understand a point from the picture.
The yellow cable is for GND and each MOSFET is picking it and Espruino is connected to each MOSFET.
The black cable is for power but it seems the cable is not used ?
How it is powered ? Espruino board seems powered via USB...
Is something missing on the picture ?Sorry to bother you with potentially stupid question.
-
Thank you a lot for your response.
So ok.... I can use a 220v -> 5v to power Espruino and almost all things.
3.3v provide 150mA... if provide 5v/1A, using the Vbat pin can drive much power, to 1A I presume ?
Is there any power limitation with Vbat ? Espruino board take 3.6v to 15v for input, but what about amperage ?In case of high power requirement (LED strip) use another converter and not use Espruino (which seems fair :) )
If I provide 5v to be safe and almost all devices would be able to use it via Vbat.... and for the screen having to use the 3.3v pin.
But more generally, what would happend if one of the device would require, let say, 12v or 24v ?
In that scenario, it would mean 3 converter ? :- 220v -> 5v : espruino and stuff (Vbat or 3.3v pin)
- 220v -> 12v - 24v: the "special" device
- 220v -> ???v with high power : LED strip
Do you know any board (arduino, spark, etc) that could convert 220-240v ?
Best, a board which would supply different output voltage in parallel ? - 220v -> 5v : espruino and stuff (Vbat or 3.3v pin)
-
First, as a background, I'm a .Net developer with limited or no electrical knowledges linked to microcontroller usage.
Until now I've used Espruino board with USB to my computer, with limited devices connected on it.My question is : how and with what do we have to power our "stuff" ?
I mean that the goal would be to have an autonomous board.
And what if we have a 220-240v near the location of the board ?
Additionally, what about all the stuff (LEDs, devices, etc) that require different voltage or power ? Espruino has 3.3V output, right ?Example (I will detailed everything in the "Project" thread soon) :
- Espruino board (5v ?)
- FingerPrint (3.6v - 6v)
- KeyPad
- Wireless communication, like CC3000, NRF24L01+ or HC-05
- PN532 NFC/RFID module
- PCD8544 LCD driver (Nokia 5110) [Optional]
- NeoRing LED (4v-7v, ~300mA)
(But what about 5m LED strip that would require lot more power, for example)
So, in general, how do we power stuff with different voltage from 220-240v ?
Is there any small power converter board to use, to keep the footprint as small as possible (compared to the size of Espruino board) that can provide several different output voltage ?
And... in the case described above, can I power all of those ?Thanks for helping...
Chris
- Espruino board (5v ?)
-
-
Hi Gordon,
I'm a software developer but I'm kinda novice in term of electronic.Do you think that this fingerprint sensor could be used on the Espruino board ?
https://www.adafruit.com/products/751#Technical_Details
(some examples at http://learn.adafruit.com/category/biometric)It is using TTL Serial and I think I've read that Serial can be used on Espruino board (via usb converter) ?
Could you please tell me if this is feasible ?
Thanks,
Chris -
-
-
Hi Gordon,
I received the board few days ago, so exciting adventure.
Unfortunatly, not had time to play with it yet..... frustrating :)I have a question regarding interface.
I have a few ideas that might require the use of NFC (as I also pledged for the NFC ring on Kickstarter :) )I found this card that can use I2C : http://www.seeedstudio.com/depot/Xadow-NFC-p-1627.html?cPath=19_24
Do you think that it could be feasible to use NFC with Espruino ?
Thanks for your hard work :)
And here is some example using the library :
Async function series (Thanks Gordon) :
Enrollment example :
Recogniton example :