diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index f621286e..09d258af 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -109,6 +109,8 @@ add_executable (mhz16-example mhz16.cxx) add_executable (apds9002-example apds9002.cxx) add_executable (waterlevel-example waterlevel.cxx) add_executable (tm1637-example tm1637.cxx) +add_executable (zfm20-example zfm20.cxx) +add_executable (zfm20-register-example zfm20-register.cxx) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/grove) @@ -197,6 +199,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/mhz16) include_directories (${PROJECT_SOURCE_DIR}/src/apds9002) include_directories (${PROJECT_SOURCE_DIR}/src/waterlevel) include_directories (${PROJECT_SOURCE_DIR}/src/tm1637) +include_directories (${PROJECT_SOURCE_DIR}/src/zfm20) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) @@ -307,3 +310,5 @@ target_link_libraries (mhz16-example mhz16 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (apds9002-example apds9002 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (waterlevel-example waterlevel ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (tm1637-example tm1637 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (zfm20-example zfm20 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (zfm20-register-example zfm20 ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/c++/zfm20-register.cxx b/examples/c++/zfm20-register.cxx new file mode 100644 index 00000000..fb1292cf --- /dev/null +++ b/examples/c++/zfm20-register.cxx @@ -0,0 +1,140 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "zfm20.h" + +using namespace std; +using namespace upm; + +int main (int argc, char **argv) +{ +//! [Interesting] + // Instantiate a ZFM20 Fingerprint reader on UART 0 + + upm::ZFM20* fp = new upm::ZFM20(0); + + // make sure port is initialized properly. 57600 baud is the default. + if (!fp->setupTty(B57600)) + { + cerr << "Failed to setup tty port parameters" << endl; + return 1; + } + + // This example demonstrates registering a fingerprint on the zfm20 + // module. The procedure is as follows: + // + // 1. get an image, store it in characteristics buffer 1 + // 2. get another image, store it in characteristics buffer 2 + // 3. store the image, assuming the two fingerprints match + + // first, we need to register our address and password + + fp->setPassword(ZFM20_DEFAULT_PASSWORD); + fp->setAddress(ZFM20_DEFAULT_ADDRESS); + + // now verify the password. If this fails, any other commands + // will be ignored, so we just bail. + if (fp->verifyPassword()) + { + cout << "Password verified." << endl; + } + else + { + cerr << "Password verification failed." << endl; + return 1; + } + + cout << endl; + + uint8_t rv; + // get the first image + + cout << "Place a finger on the sensor." << endl; + while (fp->generateImage() != ZFM20::ERR_OK) + ; + + // in theory, we have an image + cout << "Image captured, converting..." << endl; + + if ((rv = fp->image2Tz(1)) != ZFM20::ERR_OK) + { + cerr << "Image conversion failed with error code " << int(rv) <generateImage() != ZFM20::ERR_NO_FINGER) + ; + + cout << endl; + cout << "Now place the same finger on the sensor." << endl; + + while (fp->generateImage() != ZFM20::ERR_OK) + ; + + cout << "Image captured, converting..." << endl; + + // save this one in slot 2 + if ((rv = fp->image2Tz(2)) != ZFM20::ERR_OK) + { + cerr << "Image conversion failed with error code " << int(rv) <createModel()) != ZFM20::ERR_OK) + { + if (rv == ZFM20::ERR_FP_ENROLLMISMATCH) + cerr << "Fingerprints did not match." << endl; + else + cerr << "createModel failed with error code " << int(rv) <storeModel(1, 1)) != ZFM20::ERR_OK) + { + cerr << "storeModel failed with error code " << int(rv) < + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "zfm20.h" + +using namespace std; +using namespace upm; + +int main (int argc, char **argv) +{ +//! [Interesting] + // Instantiate a ZFM20 Fingerprint reader on UART 0 + + upm::ZFM20* fp = new upm::ZFM20(0); + + // make sure port is initialized properly. 57600 baud is the default. + if (!fp->setupTty(B57600)) + { + cerr << "Failed to setup tty port parameters" << endl; + return 1; + } + + // first, set the default password and address + fp->setPassword(ZFM20_DEFAULT_PASSWORD); + fp->setAddress(ZFM20_DEFAULT_ADDRESS); + + // now verify the password. If this fails, any other commands + // will be ignored, so we just bail. + if (fp->verifyPassword()) + { + cout << "Password verified." << endl; + } + else + { + cerr << "Password verification failed." << endl; + return 1; + } + + // how many valid stored templates (fingerprints) do we have? + cout << "Total stored templates: " << fp->getNumTemplates() << endl; + cout << endl; + + // now spin waiting for a fingerprint to successfully image + cout << "Waiting for finger print..." << endl; + + while (fp->generateImage() == ZFM20::ERR_NO_FINGER) + ; + + // in theory, we have an image + cout << "Image captured, converting..." << endl; + + uint8_t rv; + if ((rv = fp->image2Tz(1)) != ZFM20::ERR_OK) + { + cerr << "Image conversion failed with error code " << int(rv) <search(1, &id, &score)) != ZFM20::ERR_OK) + { + if (rv == ZFM20::ERR_FP_NOTFOUND) + { + cout << "Finger Print not found" << endl; + return 0; + } + else + { + cerr << "Search failed with error code " << int(rv) < +* Copyright (c) 2015 Intel Corporation. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +var fingerprint_lib = require('jsupm_zfm20'); + +// Instantiate a ZFM20 Fingerprint reader on UART 0 +var myFingerprintSensor = new fingerprint_lib.ZFM20(0); + +// make sure port is initialized properly. 57600 baud is the default. +if (!myFingerprintSensor.setupTty(fingerprint_lib.int_B57600)) +{ + console.log("Failed to setup tty port parameters"); + process.exit(1); +} + +// This example demonstrates registering a fingerprint on the zfm20 +// module. The procedure is as follows: +// +// 1. get an image, store it in characteristics buffer 1 +// 2. get another image, store it in characteristics buffer 2 +// 3. store the image, assuming the two fingerprints match + +// first, we need to register our address and password +myFingerprintSensor.setPassword(fingerprint_lib.ZFM20_DEFAULT_PASSWORD); +myFingerprintSensor.setAddress(fingerprint_lib.ZFM20_DEFAULT_ADDRESS); + +// now verify the password. If this fails, any other commands +// will be ignored, so we just bail. +if (myFingerprintSensor.verifyPassword()) + console.log("Password verified."); +else +{ + console.log("Password verification failed."); + process.exit(1); +} + +console.log(" "); + +// get the first image +console.log("Place a finger on the sensor."); +while (myFingerprintSensor.generateImage() != fingerprint_lib.ZFM20.ERR_OK) + ; + +// in theory, we have an image +console.log("Image captured, converting..."); + +var rv = myFingerprintSensor.image2Tz(1); + +if (rv != fingerprint_lib.ZFM20.ERR_OK) +{ + console.log("Image conversion failed with error code " + rv); + process.exit(1) +} + +console.log("Image conversion succeeded, remove finger."); +setTimeout(function() +{ + while (myFingerprintSensor.generateImage() != fingerprint_lib.ZFM20.ERR_NO_FINGER) + ; + + console.log(" "); + console.log("Now place the same finger on the sensor."); + + while (myFingerprintSensor.generateImage() == fingerprint_lib.ZFM20.ERR_NO_FINGER) + ; + + console.log("Image captured, converting..."); + + // save this one in slot 2 + rv = myFingerprintSensor.image2Tz(2) + if (rv != fingerprint_lib.ZFM20.ERR_OK) + { + console.log("Image conversion failed with error code %d" + rv); + process.exit(1); + } + + console.log("Image conversion succeeded, remove finger."); + console.log(" "); + + console.log("Storing fingerprint at id 1"); + + // create the model + rv = myFingerprintSensor.createModel() + if (rv != fingerprint_lib.ZFM20.ERR_OK) + { + if (rv == fingerprint_lib.ZFM20.ERR_FP_ENROLLMISMATCH) + console.log("Fingerprints did not match."); + else + console.log("createModel failed with error code " + rv); + process.exit(1); + } + + // now store it, we hard code the id (second arg) to 1 here + rv = myFingerprintSensor.storeModel(1, 1); + if (rv != fingerprint_lib.ZFM20.ERR_OK) + { + console.log("storeModel failed with error code " + rv); + process.exit(1); + } + + console.log(" "); + console.log("Fingerprint stored at id 1."); +}, 1000); + +// Print message when exiting +function exit() +{ + myFingerprintSensor = null; + fingerprint_lib.cleanUp(); + fingerprint_lib = null; + console.log("Exiting"); + process.exit(0); +} +process.on('exit', exit); +process.on('SIGINT', exit); diff --git a/examples/javascript/zfm20.js b/examples/javascript/zfm20.js new file mode 100644 index 00000000..5733e9dd --- /dev/null +++ b/examples/javascript/zfm20.js @@ -0,0 +1,97 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ +/* +* Author: Zion Orent +* Copyright (c) 2015 Intel Corporation. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +var fingerprint_lib = require('jsupm_zfm20'); + +// Instantiate a ZFM20 Fingerprint reader on UART 0 +var myFingerprintSensor = new fingerprint_lib.ZFM20(0); + +// make sure port is initialized properly. 57600 baud is the default. +if (!myFingerprintSensor.setupTty(fingerprint_lib.int_B57600)) +{ + console.log("Failed to setup tty port parameters"); + process.exit(1); +} + +// how many valid stored templates (fingerprints) do we have? +console.log("Total stored templates: " + myFingerprintSensor.getNumTemplates()); +console.log(" "); + +// now spin waiting for a fingerprint to successfully image +console.log("Waiting for finger print..."); + +while (myFingerprintSensor.generateImage() == fingerprint_lib.ZFM20.ERR_NO_FINGER) + ; + +// in theory, we have an image +console.log("Image captured, converting..."); + +var rv = myFingerprintSensor.image2Tz(1); +if (rv != fingerprint_lib.ZFM20.ERR_OK) +{ + console.log("Image conversion failed with error code " + rv); + process.exit(1); +} + +console.log("Image conversion succeeded."); +console.log("Searching database..."); + +var myid = new fingerprint_lib.uint16Array(0); +myid.setitem(0, 0); +var myscore = new fingerprint_lib.uint16Array(0); +myscore.setitem(0, 0); + +// we search for a print matching slot 1, where we stored our last +// converted fingerprint +rv = myFingerprintSensor.search(1, myid, myscore) +if (rv != fingerprint_lib.ZFM20.ERR_OK) +{ + if (rv == fingerprint_lib.ZFM20.ERR_FP_NOTFOUND) + { + console.log("Finger Print not found"); + process.exit(0); + } + else + { + console.log("Search failed with error code " + rv); + process.exit(1); + } +} + +console.log("Fingerprint found!"); +console.log("ID: " + myid.getitem(0) + ", Score: " + myscore.getitem(0)); + + +// Print message when exiting +function exit() +{ + myFingerprintSensor = null; + fingerprint_lib.cleanUp(); + fingerprint_lib = null; + console.log("Exiting"); + process.exit(0); +} +process.on('SIGINT', exit); +process.on('exit', exit); diff --git a/examples/python/zfm20-register.py b/examples/python/zfm20-register.py new file mode 100644 index 00000000..589a4dfc --- /dev/null +++ b/examples/python/zfm20-register.py @@ -0,0 +1,132 @@ +#!/usr/bin/python +# Author: Zion Orent +# Copyright (c) 2015 Intel Corporation. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import time, sys, signal, atexit +import pyupm_zfm20 as upmZfm20 + +# Instantiate a ZFM20 Fingerprint reader on UART 0 +myFingerprintSensor = upmZfm20.ZFM20(0) + + +## Exit handlers ## +# This stops python from printing a stacktrace when you hit control-C +def SIGINTHandler(signum, frame): + raise SystemExit + +# This function lets you run code on exit, +# including functions from myFingerprintSensor +def exitHandler(): + print "Exiting" + sys.exit(0) + +# Register exit handlers +atexit.register(exitHandler) +signal.signal(signal.SIGINT, SIGINTHandler) + + +# make sure port is initialized properly. 57600 baud is the default. +if (not myFingerprintSensor.setupTty(upmZfm20.cvar.int_B57600)): + print "Failed to setup tty port parameters" + sys.exit(1) + + +# This example demonstrates registering a fingerprint on the zfm20 +# module. The procedure is as follows: +# +# 1. get an image, store it in characteristics buffer 1 +# 2. get another image, store it in characteristics buffer 2 +# 3. store the image, assuming the two fingerprints match + +# first, we need to register our address and password + +myFingerprintSensor.setPassword(upmZfm20.ZFM20_DEFAULT_PASSWORD) +myFingerprintSensor.setAddress(upmZfm20.ZFM20_DEFAULT_ADDRESS) + +# now verify the password. If this fails, any other commands +# will be ignored, so we just bail. +if (myFingerprintSensor.verifyPassword()): + print "Password verified." +else: + print "Password verification failed." + sys.exit(1) + + +print " " + +# get the first image +print "Place a finger on the sensor." +while (myFingerprintSensor.generateImage() != upmZfm20.ZFM20.ERR_OK): + pass + +# in theory, we have an image +print "Image captured, converting..." + +rv = myFingerprintSensor.image2Tz(1) + +if (rv != upmZfm20.ZFM20.ERR_OK): + print "Image conversion failed with error code %d" % rv + sys.exit(1) + +print "Image conversion succeeded, remove finger." +time.sleep(1) + +while (myFingerprintSensor.generateImage() != upmZfm20.ZFM20.ERR_NO_FINGER): + pass + +print " " +print "Now place the same finger on the sensor." + +while (myFingerprintSensor.generateImage() == upmZfm20.ZFM20.ERR_NO_FINGER): + pass + +print "Image captured, converting..." + +# save this one in slot 2 +rv = myFingerprintSensor.image2Tz(2) +if (rv != upmZfm20.ZFM20.ERR_OK): + print "Image conversion failed with error code %d" % rv + sys.exit(1) + +print "Image conversion succeeded, remove finger." +print " " + +print "Storing fingerprint at id 1" + +# create the model +rv = myFingerprintSensor.createModel() +if (rv != upmZfm20.ZFM20.ERR_OK): + if (rv == upmZfm20.ZFM20.ERR_FP_ENROLLMISMATCH): + print "Fingerprints did not match." + else: + print "createModel failed with error code %d" % rv + sys.exit(1) + +# now store it, we hard code the id (second arg) to 1 here +rv = myFingerprintSensor.storeModel(1, 1) +if (rv != upmZfm20.ZFM20.ERR_OK): + print "storeModel failed with error code %d" % rv + sys.exit(1) + +print " " +print "Fingerprint stored at id 1." + diff --git a/examples/python/zfm20.py b/examples/python/zfm20.py new file mode 100644 index 00000000..e813e474 --- /dev/null +++ b/examples/python/zfm20.py @@ -0,0 +1,90 @@ +#!/usr/bin/python +# Author: Zion Orent +# Copyright (c) 2015 Intel Corporation. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import time, sys, signal, atexit +import pyupm_zfm20 as upmZfm20 + +# Instantiate a ZFM20 Fingerprint reader on UART 0 +myFingerprintSensor = upmZfm20.ZFM20(0) + + +## Exit handlers ## +# This stops python from printing a stacktrace when you hit control-C +def SIGINTHandler(signum, frame): + raise SystemExit + +# This function lets you run code on exit, +# including functions from myFingerprintSensor +def exitHandler(): + print "Exiting" + sys.exit(0) + +# Register exit handlers +atexit.register(exitHandler) +signal.signal(signal.SIGINT, SIGINTHandler) + + +# make sure port is initialized properly. 57600 baud is the default. +if (not myFingerprintSensor.setupTty(upmZfm20.cvar.int_B57600)): + print "Failed to setup tty port parameters" + sys.exit(1) + +# how many valid stored templates (fingerprints) do we have? +print "Total stored templates: %d" % myFingerprintSensor.getNumTemplates() +print " " + +# now spin waiting for a fingerprint to successfully image +print "Waiting for finger print..." + +while (myFingerprintSensor.generateImage() == upmZfm20.ZFM20.ERR_NO_FINGER): + pass + +# in theory, we have an image +print "Image captured, converting..." + +rv = myFingerprintSensor.image2Tz(1) +if (rv != upmZfm20.ZFM20.ERR_OK): + print "Image conversion failed with error code %d" % rv + sys.exit(1) + +print "Image conversion succeeded." +print "Searching database..." + +myid = upmZfm20.uint16Array(0) +myid.__setitem__(0, 0) +myscore = upmZfm20.uint16Array(0) +myscore.__setitem__(0, 0) + +# we search for a print matching slot 1, where we stored our last +# converted fingerprint +rv = myFingerprintSensor.search(1, myid, myscore) +if (rv != upmZfm20.ZFM20.ERR_OK): + if (rv == upmZfm20.ZFM20.ERR_FP_NOTFOUND): + print "Finger Print not found" + sys.exit(0) + else: + print "Search failed with error code %d" % rv + sys.exit(1) + +print "Fingerprint found!" +print "ID: %d, Score: %d" % (myid.__getitem__(0), myscore.__getitem__(0)) diff --git a/src/zfm20/CMakeLists.txt b/src/zfm20/CMakeLists.txt new file mode 100644 index 00000000..1ad514bb --- /dev/null +++ b/src/zfm20/CMakeLists.txt @@ -0,0 +1,5 @@ +set (libname "zfm20") +set (libdescription "upm grove zfm20 fingerprint sensor module") +set (module_src ${libname}.cxx) +set (module_h ${libname}.h) +upm_module_init() diff --git a/src/zfm20/jsupm_zfm20.i b/src/zfm20/jsupm_zfm20.i new file mode 100644 index 00000000..089e2882 --- /dev/null +++ b/src/zfm20/jsupm_zfm20.i @@ -0,0 +1,26 @@ +%module jsupm_zfm20 +%include "../upm.i" +%include "../carrays_uint16_t.i" +%include "../carrays_uint32_t.i" +%include "cpointer.i" + +%typemap(in) uint16_t * { + void *argp = 0 ; + int res = SWIG_ConvertPtr($input, &argp,SWIGTYPE_p_uint16Array, 0 | 0 ); + $1 = (uint16_t *)(argp); +} + +/*$input is a v8::object, which inherits from v8::value */ +%typemap(in) uint32_t { + $1 = ($input)->Uint32Value(); +} + +/* Send "int *" to JavaScript as intp */ +%pointer_functions(int, intp); +%{ + #include "zfm20.h" + speed_t int_B57600 = B57600; +%} + +%include "zfm20.h" +speed_t int_B57600 = B57600; diff --git a/src/zfm20/pyupm_zfm20.i b/src/zfm20/pyupm_zfm20.i new file mode 100644 index 00000000..574b003c --- /dev/null +++ b/src/zfm20/pyupm_zfm20.i @@ -0,0 +1,26 @@ +%module pyupm_zfm20 +%include "../upm.i" +%include "../carrays_uint16_t.i" +%include "../carrays_uint32_t.i" +%include "cpointer.i" + +%feature("autodoc", "3"); + +%typemap(in) uint16_t * { + void *argp = 0 ; + int res = SWIG_ConvertPtr($input, &argp,SWIGTYPE_p_uint16Array, 0 | 0 ); + $1 = reinterpret_cast< uint16_t * >(argp); +} + +%typemap(in) uint32_t { + $1 = PyInt_AsLong($input); +} + +/* Send "int *" to python as intp */ +%pointer_functions(int, intp); +%{ + #include "zfm20.h" + speed_t int_B57600 = B57600; +%} +%include "zfm20.h" +speed_t int_B57600 = B57600; diff --git a/src/zfm20/zfm20.cxx b/src/zfm20/zfm20.cxx new file mode 100644 index 00000000..74a6891f --- /dev/null +++ b/src/zfm20/zfm20.cxx @@ -0,0 +1,671 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "zfm20.h" + +using namespace upm; +using namespace std; + +static const int defaultDelay = 100; // max wait time for read + +ZFM20::ZFM20(int uart) +{ + m_ttyFd = -1; + + if ( !(m_uart = mraa_uart_init(uart)) ) + { + cerr << __FUNCTION__ << ": mraa_uart_init() failed" << endl; + return; + } + + // This requires a recent MRAA (1/2015) + char *devPath = mraa_uart_get_dev_path(m_uart); + + if (!devPath) + { + cerr << __FUNCTION__ << ": mraa_uart_get_dev_path() failed" << endl; + return; + } + + // now open the tty + if ( (m_ttyFd = open(devPath, O_RDWR)) == -1) + { + cerr << __FUNCTION__ << ": open of " << devPath << " failed: " + << strerror(errno) << endl; + return; + } + + // Set the default password and address + setPassword(ZFM20_DEFAULT_PASSWORD); + setAddress(ZFM20_DEFAULT_ADDRESS); + + initClock(); +} + +ZFM20::~ZFM20() +{ + if (m_ttyFd != -1) + close(m_ttyFd); + + mraa_deinit(); +} + +bool ZFM20::dataAvailable(unsigned int millis) +{ + if (m_ttyFd == -1) + return false; + + struct timeval timeout; + + // no waiting + timeout.tv_sec = 0; + timeout.tv_usec = millis * 1000; + + int nfds; + fd_set readfds; + + FD_ZERO(&readfds); + + FD_SET(m_ttyFd, &readfds); + + if (select(m_ttyFd + 1, &readfds, NULL, NULL, &timeout) > 0) + return true; // data is ready + else + return false; +} + +int ZFM20::readData(char *buffer, size_t len) +{ + if (m_ttyFd == -1) + return(-1); + + if (!dataAvailable(defaultDelay)) + return 0; // timed out + + int rv = read(m_ttyFd, buffer, len); + + if (rv < 0) + cerr << __FUNCTION__ << ": read failed: " << strerror(errno) << endl; + + return rv; +} + +int ZFM20::writeData(char *buffer, size_t len) +{ + if (m_ttyFd == -1) + return(-1); + + // first, flush any pending but unread input + tcflush(m_ttyFd, TCIFLUSH); + + int rv = write(m_ttyFd, buffer, len); + + if (rv < 0) + { + cerr << __FUNCTION__ << ": write failed: " << strerror(errno) << endl; + return rv; + } + + tcdrain(m_ttyFd); + + return rv; +} + +bool ZFM20::setupTty(speed_t baud) +{ + if (m_ttyFd == -1) + return(false); + + struct termios termio; + + // get current modes + tcgetattr(m_ttyFd, &termio); + + // setup for a 'raw' mode. 81N, no echo or special character + // handling, such as flow control. + cfmakeraw(&termio); + + // set our baud rates + cfsetispeed(&termio, baud); + cfsetospeed(&termio, baud); + + // make it so + if (tcsetattr(m_ttyFd, TCSAFLUSH, &termio) < 0) + { + cerr << __FUNCTION__ << ": tcsetattr failed: " << strerror(errno) << endl; + return false; + } + + return true; +} + +int ZFM20::writeCmdPacket(unsigned char *pkt, int len) +{ + unsigned char rPkt[ZFM20_MAX_PKT_LEN]; + + rPkt[0] = ZFM20_START1; // header bytes + rPkt[1] = ZFM20_START2; + + rPkt[2] = (m_address >> 24) & 0xff; // address + rPkt[3] = (m_address >> 16) & 0xff; + rPkt[4] = (m_address >> 8) & 0xff; + rPkt[5] = m_address & 0xff; + + rPkt[6] = PKT_COMMAND; + + rPkt[7] = ((len + 2) >> 8) & 0xff; // length (+ len bytes) + rPkt[8] = (len + 2) & 0xff; + + // compute the starting checksum + uint16_t cksum = rPkt[7] + rPkt[8] + PKT_COMMAND; + + int j = 9; + for (int i=0; i> 8) & 0xff; // store the cksum + rPkt[j++] = cksum & 0xff; + + return writeData((char *)rPkt, j); +} + +void ZFM20::initClock() +{ + gettimeofday(&m_startTime, NULL); +} + +uint32_t ZFM20::getMillis() +{ + struct timeval elapsed, now; + uint32_t elapse; + + // get current time + gettimeofday(&now, NULL); + + // compute the delta since m_startTime + if( (elapsed.tv_usec = now.tv_usec - m_startTime.tv_usec) < 0 ) + { + elapsed.tv_usec += 1000000; + elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec - 1; + } + else + { + elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec; + } + + elapse = (uint32_t)((elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000)); + + // never return 0 + if (elapse == 0) + elapse = 1; + + return elapse; +} + +bool ZFM20::verifyPacket(unsigned char *pkt) +{ + // verify packet header + if (pkt[0] != ZFM20_START1 || pkt[1] != ZFM20_START2) + { + cerr << __FUNCTION__ << ": Invalid packet header." << endl; + return false; + } + + // check the ack byte + if (pkt[6] != PKT_ACK) + { + cerr << __FUNCTION__ << ": Invalid ACK code: " + << int(pkt[6]) << ", expected: " << int(PKT_ACK) << endl; + return false; + } + + return true; +} + +bool ZFM20::getResponse(unsigned char *pkt, int len) +{ + char buf[ZFM20_MAX_PKT_LEN]; + + initClock(); + + int idx = 0; + int timer = 0; + int rv; + int plen = 0; + + while (idx < len) + { + // wait for some data + if (!dataAvailable(100)) + { + timer += getMillis(); + if (timer > ZFM20_TIMEOUT) + { + cerr << __FUNCTION__ << ": Timed out waiting for packet" << endl; + return false; + } + + continue; + } + + if ((rv = readData(buf, ZFM20_MAX_PKT_LEN)) <= 0) + { + cerr << __FUNCTION__ << ": Read failed" << endl; + return false; + } + + // copy it into the user supplied buffer + for (int i=0; i= len) + break; + } + } + + // now verify it. + return verifyPacket(pkt); +} + +bool ZFM20::verifyPassword() +{ + const int pktLen = 5; + uint8_t pkt[pktLen] = {CMD_VERIFY_PASSWORD, + (m_password >> 24) & 0xff, + (m_password >> 16) & 0xff, + (m_password >> 8) & 0xff, + m_password & 0xff }; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return false; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return false; + } + + return true; +} + +int ZFM20::getNumTemplates() +{ + const int pktLen = 1; + uint8_t pkt[pktLen] = {CMD_GET_TMPL_COUNT}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return 0; + } + + // now read a response + const int rPktLen = 14; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return 0; + } + + // check confirmation code + if (rPkt[9] != 0x00) + { + cerr << __FUNCTION__ << ": Invalid confirmation code:" << int(rPkt[9]) + << endl; + return 0; + } + + return ((rPkt[10] << 8) | rPkt[11]); +} + +bool ZFM20::setNewPassword(uint32_t pwd) +{ + const int pktLen = 5; + uint8_t pkt[pktLen] = {CMD_SET_PASSWORD, + (pwd >> 24) & 0xff, + (pwd >> 16) & 0xff, + (pwd >> 8) & 0xff, + pwd & 0xff }; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return false; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return false; + } + + // check confirmation code + if (rPkt[9] != 0x00) + { + cerr << __FUNCTION__ << ": Invalid confirmation code:" << int(rPkt[9]) + << endl; + return false; + } + + m_password = pwd; + + return true; +} + +bool ZFM20::setNewAddress(uint32_t addr) +{ + const int pktLen = 5; + uint8_t pkt[pktLen] = {CMD_SET_ADDRESS, + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + addr & 0xff }; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return false; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return false; + } + + // check confirmation code + if (rPkt[9] != 0x00) + { + cerr << __FUNCTION__ << ": Invalid confirmation code:" << int(rPkt[9]) + << endl; + return false; + } + + m_address = addr; + + return true; +} + +uint8_t ZFM20::generateImage() +{ + const int pktLen = 1; + uint8_t pkt[pktLen] = {CMD_GEN_IMAGE}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return ERR_INTERNAL_ERR; + } + + return rPkt[9]; +} + +uint8_t ZFM20::image2Tz(int slot) +{ + if (slot != 1 && slot != 2) + { + cerr << __FUNCTION__ << ": slot must be 1 or 2" << endl; + return ERR_INTERNAL_ERR; + } + + const int pktLen = 2; + uint8_t pkt[pktLen] = {CMD_IMG2TZ, + (slot & 0xff)}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return ERR_INTERNAL_ERR; + } + + return rPkt[9]; +} + +uint8_t ZFM20::createModel() +{ + const int pktLen = 1; + uint8_t pkt[pktLen] = {CMD_REGMODEL}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return ERR_INTERNAL_ERR; + } + + return rPkt[9]; +} + +uint8_t ZFM20::storeModel(int slot, uint16_t id) +{ + if (slot != 1 && slot != 2) + { + cerr << __FUNCTION__ << ": slot must be 1 or 2" << endl; + return ERR_INTERNAL_ERR; + } + + const int pktLen = 4; + uint8_t pkt[pktLen] = {CMD_STORE, + (slot & 0xff), + (id >> 8) & 0xff, + id & 0xff}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return ERR_INTERNAL_ERR; + } + + return rPkt[9]; +} + +uint8_t ZFM20::deleteModel(uint16_t id) +{ + const int pktLen = 5; + uint8_t pkt[pktLen] = {CMD_DELETE_TMPL, + (id >> 8) & 0xff, + id & 0xff, + 0x00, + 0x01}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return ERR_INTERNAL_ERR; + } + + return rPkt[9]; +} + +uint8_t ZFM20::deleteDB() +{ + const int pktLen = 1; + uint8_t pkt[pktLen] = {CMD_EMPTYDB}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // now read a response + const int rPktLen = 12; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return ERR_INTERNAL_ERR; + } + + return rPkt[9]; +} + +uint8_t ZFM20::search(int slot, uint16_t *id, uint16_t *score) +{ + *id = 0; + *score = 0; + + if (slot != 1 && slot != 2) + { + cerr << __FUNCTION__ << ": slot must be 1 or 2" << endl; + return ERR_INTERNAL_ERR; + } + + // search from page 0x0000 to page 0x00a3 + const int pktLen = 6; + uint8_t pkt[pktLen] = {CMD_SEARCH, + (slot & 0xff), + 0x00, + 0x00, + 0x00, + 0xa3}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // now read a response + const int rPktLen = 16; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // if it was found, extract the location and the score + if (rPkt[9] == ERR_OK) + { + *id = (rPkt[10] << 8) & 0xff | rPkt[11] & 0xff; + *score = (rPkt[12] << 8) & 0xff | rPkt[13] & 0xff; + } + + return rPkt[9]; +} + +uint8_t ZFM20::match(uint16_t *score) +{ + *score = 0; + + const int pktLen = 1; + uint8_t pkt[pktLen] = {CMD_MATCH}; + + if (!writeCmdPacket(pkt, pktLen)) + { + cerr << __FUNCTION__ << ": writePacket() failed" << endl; + return ERR_INTERNAL_ERR; + } + + // now read a response + const int rPktLen = 14; + unsigned char rPkt[rPktLen]; + + if (!getResponse(rPkt, rPktLen)) + { + cerr << __FUNCTION__ << ": getResponse() failed" << endl; + return ERR_INTERNAL_ERR; + } + + *score = (rPkt[10] << 8) & 0xff | rPkt[11] & 0xff; + + return rPkt[9]; +} + + diff --git a/src/zfm20/zfm20.h b/src/zfm20/zfm20.h new file mode 100644 index 00000000..afecaa65 --- /dev/null +++ b/src/zfm20/zfm20.h @@ -0,0 +1,377 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Thanks to Adafruit for supplying a google translated version of the + * Chinese datasheet and some clues in their code. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ZFM20_DEFAULT_UART 0 + +// protocol start codes +#define ZFM20_START1 0xef +#define ZFM20_START2 0x01 + +#define ZFM20_MAX_PKT_LEN 256 + +#define ZFM20_TIMEOUT 5000 // in ms + +#define ZFM20_DEFAULT_PASSWORD 0x00000000 +#define ZFM20_DEFAULT_ADDRESS 0xffffffff + + +namespace upm { + /** + * @brief UPM library for the ZFM-20 fingerprint sensor module + * @defgroup zfm20 libupm-zfm20 + * @ingroup seeed serial gas + */ + + /** + * @sensor zfm20 + * @library zfm20 + * @comname ZFM-20 Fingerprint Sensor Module + * @category other + * @manufacturer seeed + * @connection uart + * + * @brief C++ API for the ZFM-20 fingerprint sensor module + * + * This class was tested on the Grove Fingerprint Sensor + * Module. It can store up to 163 fingerprints. + * + * It is connected via a UART at 57600 baud. + * + * This example demonstrates how to register and store a new fingerprint + * @snippet zfm20-register.cxx Interesting + * This example demonstrates reading a fingerprint and locating it in the DB + * @snippet zfm20.cxx Interesting + */ + class ZFM20 { + public: + + // commands + typedef enum { + CMD_GEN_IMAGE = 0x01, + CMD_IMG2TZ = 0x02, + CMD_MATCH = 0x03, + CMD_SEARCH = 0x04, + CMD_REGMODEL = 0x05, + CMD_STORE = 0x06, + CMD_LOAD_TMPL = 0x07, + CMD_UPLOAD_TMPL = 0x08, + CMD_DOWNLOAD_TMPL = 0x09, + CMD_UPLOAD_IMAGE = 0x0a, + CMD_DOWNLOAD_IMAGE = 0x0b, + CMD_DELETE_TMPL = 0x0c, + CMD_EMPTYDB = 0x0d, + CMD_SET_SYSPARAMS = 0x0e, + CMD_GET_SYSPARAMS = 0x0f, + CMD_SET_PASSWORD = 0x12, + CMD_VERIFY_PASSWORD = 0x13, + CMD_GET_RANDOM_NUMBER = 0x14, + CMD_SET_ADDRESS = 0x15, + CMD_GET_TMPL_COUNT = 0x1d, + CMD_GET_INDEX_TABLE = 0x1f + } ZFM20_COMMAND_T; + + // Error response codes + typedef enum { + ERR_OK = 0x00, + ERR_PACKET_RX_ERROR = 0x01, + ERR_NO_FINGER = 0x02, + ERR_FP_IMAGE_FAILED = 0x03, + ERR_FP_TOO_MESSY = 0x06, + ERR_FP_IMAGE_FEW_FEATURES = 0x07, + ERR_FP_NOMATCH = 0x08, + ERR_FP_NOTFOUND = 0x09, + ERR_FP_ENROLLMISMATCH = 0x0a, + ERR_BAD_LOCATION = 0x0b, + ERR_DB_ERROR = 0x0c, + ERR_UPLOAD_FEAT_FAILED = 0x0d, + ERR_NO_MORE_PACKETS = 0x0e, + ERR_UPLOAD_IMG_FAILED = 0x0f, + ERR_RM_TMPL_FAILED = 0x10, + ERR_EMPTY_DB_FAILED = 0x11, + ERR_INVALID_PWD = 0x13, + ERR_INVALID_IMAGE = 0x15, + ERR_RW_FLASH_ERROR = 0x18, + ERR_INVALID_REG = 0x1a, + ERR_INVALID_ADDR = 0x20, + ERR_NEEDS_PWD = 0x21, + // end of module specific errors + ERR_INTERNAL_ERR = 0xff // API internal error + } ZFM20_ERRORS_T; + + typedef enum { + PKT_COMMAND = 0x01, + PKT_DATA = 0x02, + PKT_ACK = 0x07, + PKT_END_DATA = 0x08 + } ZFM20_PKTCODES_T; + + /** + * ZFM20 module constructor + * + * @param uart default uart to use (0 or 1) + */ + ZFM20(int uart); + + /** + * ZFM20 module Destructor + */ + ~ZFM20(); + + /** + * check to see if there is data available for reading + * + * @param millis number of milliseconds to wait, 0 means no wait. + * @return true if there is data available to be read + */ + bool dataAvailable(unsigned int millis); + + /** + * read any available data into a user-supplied buffer. Note, the + * call will block until data is available to be read. Use + * dataAvailable() to determine whether there is data available + * beforehand, to avoid blocking. + * + * @param buffer the buffer to hold the data read + * @param len the length of the buffer + * @return the number of bytes read + */ + int readData(char *buffer, size_t len); + + /** + * write the data in buffer to the device + * + * @param buffer the buffer to hold the data read + * @param len the length of the buffer + * @return the number of bytes written + */ + int writeData(char *buffer, size_t len); + + /** + * setup the proper tty i/o modes and the baudrate. The default + * baud rate is 57600 (B57600) for this device. + * + * @param baud the desired baud rate. + * @return true if successful + */ + bool setupTty(speed_t baud=B57600); + + /** + * compose and write a command packet + * + * @param pkt the packet + * @param len length of packet + * @return the number of bytes written + */ + int writeCmdPacket(unsigned char *pkt, int len); + + /** + * verify the packet header and indicate it's validity + * + * @param pkt the packet to check + * @return true if valid checksum, false otherwise + */ + bool verifyPacket(unsigned char *pkt); + + /** + * Return the number of milliseconds elapsed since initClock() + * was last called. + * + * @return elapsed milliseconds + */ + uint32_t getMillis(); + + /** + * Reset the Clock + * + */ + void initClock(); + + /** + * set the address that should be used to access the module + * + * @param addr the address to use + */ + void setAddress(uint32_t addr) { m_address = addr; }; + + /** + * set the password that should be used to access the module + * + * @param pw password to use + */ + void setPassword(uint32_t pw) { m_password = pw; }; + + /** + * get the returned data from a request + * + * @param pkt the buffer to store the returned data into + * @param len the expected response length. pkt should be at least this + * big. + * @return true if successful + */ + bool getResponse(unsigned char *pkt, int len); + + /** + * verify and authenticate to the module. The password used is + * the one last set by setPassword(). + * + * @return true if successful + */ + bool verifyPassword(); + + /** + * query the module for the number of stored templates + * (fingerprints). + * + * @return the number of currently stored templates + */ + int getNumTemplates(); + + /** + * set a new password for the module. This passowrd will be + * stored on the module, and will be required in order to access + * the module in the future. + * + * @param pwd the new password to set on the module + * @return true if successful + */ + bool setNewPassword(uint32_t pwd); + + /** + * set a new address for the module. This address will be + * stored on the module, and will be required in order to access + * the module in the future. + * + * @param addr the new address to set on the module + * @return true if successful + */ + bool setNewAddress(uint32_t addr); + + /** + * generate a new fingerprint image (scan a fingerprint) + * + * @return one of the ZFM20_ERRORS_T values + */ + uint8_t generateImage(); + + /** + * convert the image in the image buffer (generated by + * generateImage()) and store it in one of the two characteristics + * buffers, 1 or 2 + * + * @param slot the characteristics buffer to use. Must be 1 or 2. + * @return one of the ZFM20_ERRORS_T values + */ + uint8_t image2Tz(int slot); + + /** + * based on the two characteristics bufferes (1 & 2), create a + * fingerprint model. Once a model has been successfully created, + * it can be stored in the module with storeModel(). + * + * @return one of the ZFM20_ERRORS_T values + */ + uint8_t createModel(); + + /** + * once a fingerprint model has been created, this method can be + * used to store it (via one of the characteristics buffers) in a + * given location. + * + * @param slot the characteristics buffer to store (1 or 2) + * @param id the location in which to store the model + * @return one of the ZFM20_ERRORS_T values + */ + uint8_t storeModel(int slot, uint16_t id); + + /** + * delete a stored model. + * + * @param id the location containing the model to delete + * @return one of the ZFM20_ERRORS_T values + */ + uint8_t deleteModel(uint16_t id); + + /** + * delete the model database + * + * @return one of the ZFM20_ERRORS_T values + */ + uint8_t deleteDB(); + + /** + * search the fingerprint DB and return the id and score, if found + * + * + * @param slot the slot containing a converted image to search for + * @param id the returned id if found, 0 otherwise + * @param score the returned score if found, 0 otherwise + * @return one of the ZFM20_ERRORS_T values + */ + uint8_t search(int slot, uint16_t *id, uint16_t *score); + + /** + * compares the features in characteristic buffers 1 and 2 and + * returns a score if they match + * + * @param score the returned score + * @return one of the ZFM20_ERRORS_T values + */ + uint8_t match(uint16_t *score); + + + protected: + int ttyFd() { return m_ttyFd; }; + int setTtyFd(int fd) { m_ttyFd = fd; }; + + private: + mraa_uart_context m_uart; + int m_ttyFd; + uint32_t m_password; + uint32_t m_address; + struct timeval m_startTime; + }; +} + +