Browse Source

zfm20: Initial implementation

This driver implements support for the ZFM20 fingerprint module.  It
was tested on a Grove Fingerprint Sensor.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
Signed-off-by: Zion Orent <zorent@ics.com>
Signed-off-by: John Van Drasek <john.r.van.drasek@intel.com>
Jon Trulson 9 years ago
parent
commit
8bf92be1ab

+ 5
- 0
examples/c++/CMakeLists.txt View File

@@ -109,6 +109,8 @@ add_executable (mhz16-example mhz16.cxx)
109 109
 add_executable (apds9002-example apds9002.cxx)
110 110
 add_executable (waterlevel-example waterlevel.cxx)
111 111
 add_executable (tm1637-example tm1637.cxx)
112
+add_executable (zfm20-example zfm20.cxx)
113
+add_executable (zfm20-register-example zfm20-register.cxx)
112 114
 
113 115
 include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l)
114 116
 include_directories (${PROJECT_SOURCE_DIR}/src/grove)
@@ -197,6 +199,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/mhz16)
197 199
 include_directories (${PROJECT_SOURCE_DIR}/src/apds9002)
198 200
 include_directories (${PROJECT_SOURCE_DIR}/src/waterlevel)
199 201
 include_directories (${PROJECT_SOURCE_DIR}/src/tm1637)
202
+include_directories (${PROJECT_SOURCE_DIR}/src/zfm20)
200 203
 
201 204
 target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT})
202 205
 target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT})
@@ -307,3 +310,5 @@ target_link_libraries (mhz16-example mhz16 ${CMAKE_THREAD_LIBS_INIT})
307 310
 target_link_libraries (apds9002-example apds9002 ${CMAKE_THREAD_LIBS_INIT})
308 311
 target_link_libraries (waterlevel-example waterlevel ${CMAKE_THREAD_LIBS_INIT})
309 312
 target_link_libraries (tm1637-example tm1637 ${CMAKE_THREAD_LIBS_INIT})
313
+target_link_libraries (zfm20-example zfm20 ${CMAKE_THREAD_LIBS_INIT})
314
+target_link_libraries (zfm20-register-example zfm20 ${CMAKE_THREAD_LIBS_INIT})

+ 140
- 0
examples/c++/zfm20-register.cxx View File

@@ -0,0 +1,140 @@
1
+/*
2
+ * Author: Jon Trulson <jtrulson@ics.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+#include <unistd.h>
26
+#include <iostream>
27
+#include <signal.h>
28
+#include "zfm20.h"
29
+
30
+using namespace std;
31
+using namespace upm;
32
+
33
+int main (int argc, char **argv)
34
+{
35
+//! [Interesting]
36
+  // Instantiate a ZFM20 Fingerprint reader on UART 0
37
+
38
+  upm::ZFM20* fp = new upm::ZFM20(0);
39
+
40
+  // make sure port is initialized properly.  57600 baud is the default.
41
+  if (!fp->setupTty(B57600))
42
+    {
43
+      cerr << "Failed to setup tty port parameters" << endl;
44
+      return 1;
45
+    }
46
+
47
+  // This example demonstrates registering a fingerprint on the zfm20
48
+  // module.  The procedure is as follows:
49
+  //
50
+  // 1. get an image, store it in characteristics buffer 1
51
+  // 2. get another image, store it in characteristics buffer 2
52
+  // 3. store the image, assuming the two fingerprints match
53
+
54
+  // first, we need to register our address and password
55
+  
56
+  fp->setPassword(ZFM20_DEFAULT_PASSWORD);
57
+  fp->setAddress(ZFM20_DEFAULT_ADDRESS);
58
+  
59
+  // now verify the password.  If this fails, any other commands
60
+  // will be ignored, so we just bail.
61
+  if (fp->verifyPassword())
62
+    {
63
+      cout << "Password verified." << endl;
64
+    }
65
+  else
66
+    {
67
+      cerr << "Password verification failed." << endl;
68
+      return 1;
69
+    }
70
+  
71
+  cout << endl;
72
+
73
+  uint8_t rv;
74
+  // get the first image
75
+
76
+  cout << "Place a finger on the sensor." << endl;
77
+  while (fp->generateImage() != ZFM20::ERR_OK)
78
+    ;
79
+
80
+  // in theory, we have an image
81
+  cout << "Image captured, converting..." << endl;
82
+
83
+  if ((rv = fp->image2Tz(1)) != ZFM20::ERR_OK)
84
+    {
85
+      cerr << "Image conversion failed with error code " << int(rv) <<endl;
86
+      return 1;
87
+    }
88
+
89
+  cout << "Image conversion succeeded, remove finger." << endl;
90
+  sleep(1);
91
+
92
+  while (fp->generateImage() != ZFM20::ERR_NO_FINGER)
93
+    ;
94
+  
95
+  cout << endl;
96
+  cout << "Now place the same finger on the sensor." << endl;
97
+
98
+  while (fp->generateImage() != ZFM20::ERR_OK)
99
+    ;
100
+
101
+  cout << "Image captured, converting..." << endl;
102
+
103
+  // save this one in slot 2
104
+  if ((rv = fp->image2Tz(2)) != ZFM20::ERR_OK)
105
+    {
106
+      cerr << "Image conversion failed with error code " << int(rv) <<endl;
107
+      return 1;
108
+    }
109
+
110
+  cout << "Image conversion succeeded, remove finger." << endl;
111
+  cout << endl;
112
+
113
+  cout << "Storing fingerprint at id 1" << endl;
114
+  
115
+  // create the model
116
+  if ((rv = fp->createModel()) != ZFM20::ERR_OK)
117
+    {
118
+      if (rv == ZFM20::ERR_FP_ENROLLMISMATCH)
119
+        cerr << "Fingerprints did not match." << endl;
120
+      else
121
+        cerr << "createModel failed with error code " << int(rv) <<endl;
122
+ 
123
+      return 1;
124
+    }
125
+  
126
+  // now store it, we hard code the id (second arg) to 1 here
127
+  if ((rv = fp->storeModel(1, 1)) != ZFM20::ERR_OK)
128
+    {
129
+      cerr << "storeModel failed with error code " << int(rv) <<endl;
130
+      return 1;
131
+    }
132
+
133
+  cout << endl;
134
+  cout << "Fingerprint stored at id 1." << endl;
135
+  
136
+//! [Interesting]
137
+
138
+  delete fp;
139
+  return 0;
140
+}

+ 112
- 0
examples/c++/zfm20.cxx View File

@@ -0,0 +1,112 @@
1
+/*
2
+ * Author: Jon Trulson <jtrulson@ics.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+#include <unistd.h>
26
+#include <iostream>
27
+#include <signal.h>
28
+#include "zfm20.h"
29
+
30
+using namespace std;
31
+using namespace upm;
32
+
33
+int main (int argc, char **argv)
34
+{
35
+//! [Interesting]
36
+  // Instantiate a ZFM20 Fingerprint reader on UART 0
37
+
38
+  upm::ZFM20* fp = new upm::ZFM20(0);
39
+
40
+  // make sure port is initialized properly.  57600 baud is the default.
41
+  if (!fp->setupTty(B57600))
42
+    {
43
+      cerr << "Failed to setup tty port parameters" << endl;
44
+      return 1;
45
+    }
46
+
47
+  // first, set the default password and address
48
+  fp->setPassword(ZFM20_DEFAULT_PASSWORD);
49
+  fp->setAddress(ZFM20_DEFAULT_ADDRESS);
50
+      
51
+  // now verify the password.  If this fails, any other commands
52
+  // will be ignored, so we just bail.
53
+  if (fp->verifyPassword())
54
+    {
55
+      cout << "Password verified." << endl;
56
+    }
57
+  else
58
+    {
59
+      cerr << "Password verification failed." << endl;
60
+      return 1;
61
+    }
62
+
63
+  // how many valid stored templates (fingerprints) do we have?
64
+  cout << "Total stored templates: " << fp->getNumTemplates() << endl;
65
+  cout << endl;
66
+
67
+  // now spin waiting for a fingerprint to successfully image
68
+  cout << "Waiting for finger print..." << endl;
69
+
70
+  while (fp->generateImage() == ZFM20::ERR_NO_FINGER)
71
+    ;
72
+
73
+  // in theory, we have an image
74
+  cout << "Image captured, converting..." << endl;
75
+
76
+  uint8_t rv;
77
+  if ((rv = fp->image2Tz(1)) != ZFM20::ERR_OK)
78
+    {
79
+      cerr << "Image conversion failed with error code " << int(rv) <<endl;
80
+      return 1;
81
+    }
82
+
83
+  cout << "Image conversion succeeded." << endl;
84
+  cout << "Searching database..." << endl;
85
+
86
+  uint16_t id = 0;
87
+  uint16_t score = 0;
88
+
89
+  // we search for a print matching slot 1, where we shored our last
90
+  // converted fingerprint
91
+  if ((rv = fp->search(1, &id, &score)) != ZFM20::ERR_OK)
92
+    {
93
+      if (rv == ZFM20::ERR_FP_NOTFOUND)
94
+        {
95
+          cout << "Finger Print not found" << endl;
96
+          return 0;
97
+        }
98
+      else
99
+        {
100
+          cerr << "Search failed with error code " << int(rv) <<endl;
101
+          return 1;
102
+        }
103
+    }
104
+
105
+  cout << "Fingerprint found!" << endl;
106
+  cout << "ID: " << int(id) << ", Score: " << int(score) << endl;
107
+
108
+//! [Interesting]
109
+
110
+  delete fp;
111
+  return 0;
112
+}

+ 137
- 0
examples/javascript/zfm20-register.js View File

@@ -0,0 +1,137 @@
1
+/*jslint node:true, vars:true, bitwise:true, unparam:true */
2
+/*jshint unused:true */
3
+/*
4
+* Author: Zion Orent <zorent@ics.com>
5
+* Copyright (c) 2015 Intel Corporation.
6
+*
7
+* Permission is hereby granted, free of charge, to any person obtaining
8
+* a copy of this software and associated documentation files (the
9
+* "Software"), to deal in the Software without restriction, including
10
+* without limitation the rights to use, copy, modify, merge, publish,
11
+* distribute, sublicense, and/or sell copies of the Software, and to
12
+* permit persons to whom the Software is furnished to do so, subject to
13
+* the following conditions:
14
+*
15
+* The above copyright notice and this permission notice shall be
16
+* included in all copies or substantial portions of the Software.
17
+*
18
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+*/
26
+var fingerprint_lib = require('jsupm_zfm20');
27
+
28
+// Instantiate a ZFM20 Fingerprint reader on UART 0
29
+var myFingerprintSensor = new fingerprint_lib.ZFM20(0);
30
+
31
+// make sure port is initialized properly.  57600 baud is the default.
32
+if (!myFingerprintSensor.setupTty(fingerprint_lib.int_B57600))
33
+{
34
+	console.log("Failed to setup tty port parameters");
35
+	process.exit(1);
36
+}
37
+
38
+// This example demonstrates registering a fingerprint on the zfm20
39
+// module.  The procedure is as follows:
40
+//
41
+// 1. get an image, store it in characteristics buffer 1
42
+// 2. get another image, store it in characteristics buffer 2
43
+// 3. store the image, assuming the two fingerprints match
44
+
45
+// first, we need to register our address and password
46
+myFingerprintSensor.setPassword(fingerprint_lib.ZFM20_DEFAULT_PASSWORD);
47
+myFingerprintSensor.setAddress(fingerprint_lib.ZFM20_DEFAULT_ADDRESS);
48
+
49
+// now verify the password.  If this fails, any other commands
50
+// will be ignored, so we just bail.
51
+if (myFingerprintSensor.verifyPassword())
52
+	console.log("Password verified.");
53
+else
54
+{
55
+	console.log("Password verification failed.");
56
+	process.exit(1);
57
+}
58
+
59
+console.log(" ");
60
+
61
+// get the first image
62
+console.log("Place a finger on the sensor.");
63
+while (myFingerprintSensor.generateImage() != fingerprint_lib.ZFM20.ERR_OK)
64
+	;
65
+
66
+// in theory, we have an image
67
+console.log("Image captured, converting...");
68
+
69
+var rv = myFingerprintSensor.image2Tz(1);
70
+
71
+if (rv != fingerprint_lib.ZFM20.ERR_OK)
72
+{
73
+	console.log("Image conversion failed with error code " + rv);
74
+	process.exit(1)
75
+}
76
+
77
+console.log("Image conversion succeeded, remove finger.");
78
+setTimeout(function()
79
+{
80
+	while (myFingerprintSensor.generateImage() != fingerprint_lib.ZFM20.ERR_NO_FINGER)
81
+		;
82
+
83
+	console.log(" ");
84
+	console.log("Now place the same finger on the sensor.");
85
+
86
+	while (myFingerprintSensor.generateImage() == fingerprint_lib.ZFM20.ERR_NO_FINGER)
87
+		;
88
+
89
+	console.log("Image captured, converting...");
90
+
91
+	// save this one in slot 2
92
+	rv = myFingerprintSensor.image2Tz(2)
93
+	if (rv != fingerprint_lib.ZFM20.ERR_OK)
94
+	{
95
+		console.log("Image conversion failed with error code %d" + rv);
96
+		process.exit(1);
97
+	}
98
+
99
+	console.log("Image conversion succeeded, remove finger.");
100
+	console.log(" ");
101
+
102
+	console.log("Storing fingerprint at id 1");
103
+
104
+	// create the model
105
+	rv = myFingerprintSensor.createModel()
106
+	if (rv != fingerprint_lib.ZFM20.ERR_OK)
107
+	{
108
+		if (rv == fingerprint_lib.ZFM20.ERR_FP_ENROLLMISMATCH)
109
+			console.log("Fingerprints did not match.");
110
+		else
111
+			console.log("createModel failed with error code " + rv);
112
+		process.exit(1);
113
+	}
114
+
115
+	// now store it, we hard code the id (second arg) to 1 here
116
+	rv = myFingerprintSensor.storeModel(1, 1);
117
+	if (rv != fingerprint_lib.ZFM20.ERR_OK)
118
+	{
119
+		console.log("storeModel failed with error code " + rv);
120
+		process.exit(1);
121
+	}
122
+
123
+	console.log(" ");
124
+	console.log("Fingerprint stored at id 1.");
125
+}, 1000);
126
+
127
+// Print message when exiting
128
+function exit()
129
+{
130
+	myFingerprintSensor = null;
131
+	fingerprint_lib.cleanUp();
132
+	fingerprint_lib = null;
133
+	console.log("Exiting");
134
+	process.exit(0);
135
+}
136
+process.on('exit', exit);
137
+process.on('SIGINT', exit);

+ 97
- 0
examples/javascript/zfm20.js View File

@@ -0,0 +1,97 @@
1
+/*jslint node:true, vars:true, bitwise:true, unparam:true */
2
+/*jshint unused:true */
3
+/*
4
+* Author: Zion Orent <zorent@ics.com>
5
+* Copyright (c) 2015 Intel Corporation.
6
+*
7
+* Permission is hereby granted, free of charge, to any person obtaining
8
+* a copy of this software and associated documentation files (the
9
+* "Software"), to deal in the Software without restriction, including
10
+* without limitation the rights to use, copy, modify, merge, publish,
11
+* distribute, sublicense, and/or sell copies of the Software, and to
12
+* permit persons to whom the Software is furnished to do so, subject to
13
+* the following conditions:
14
+*
15
+* The above copyright notice and this permission notice shall be
16
+* included in all copies or substantial portions of the Software.
17
+*
18
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+*/
26
+var fingerprint_lib = require('jsupm_zfm20');
27
+
28
+// Instantiate a ZFM20 Fingerprint reader on UART 0
29
+var myFingerprintSensor = new fingerprint_lib.ZFM20(0);
30
+
31
+// make sure port is initialized properly.  57600 baud is the default.
32
+if (!myFingerprintSensor.setupTty(fingerprint_lib.int_B57600))
33
+{
34
+	console.log("Failed to setup tty port parameters");
35
+	process.exit(1);
36
+}
37
+
38
+// how many valid stored templates (fingerprints) do we have?
39
+console.log("Total stored templates: " + myFingerprintSensor.getNumTemplates());
40
+console.log(" ");
41
+
42
+// now spin waiting for a fingerprint to successfully image
43
+console.log("Waiting for finger print...");
44
+
45
+while (myFingerprintSensor.generateImage() == fingerprint_lib.ZFM20.ERR_NO_FINGER)
46
+	;
47
+
48
+// in theory, we have an image
49
+console.log("Image captured, converting...");
50
+
51
+var rv = myFingerprintSensor.image2Tz(1);
52
+if (rv != fingerprint_lib.ZFM20.ERR_OK)
53
+{
54
+	console.log("Image conversion failed with error code " + rv);
55
+	process.exit(1);
56
+}
57
+
58
+console.log("Image conversion succeeded.");
59
+console.log("Searching database...");
60
+
61
+var myid = new fingerprint_lib.uint16Array(0);
62
+myid.setitem(0, 0);
63
+var myscore = new fingerprint_lib.uint16Array(0);
64
+myscore.setitem(0, 0);
65
+
66
+// we search for a print matching slot 1, where we stored our last
67
+// converted fingerprint
68
+rv = myFingerprintSensor.search(1, myid, myscore)
69
+if (rv != fingerprint_lib.ZFM20.ERR_OK)
70
+{
71
+	if (rv == fingerprint_lib.ZFM20.ERR_FP_NOTFOUND)
72
+	{
73
+		console.log("Finger Print not found");
74
+		process.exit(0);
75
+	}
76
+	else
77
+	{
78
+		console.log("Search failed with error code " + rv);
79
+		process.exit(1);
80
+	}
81
+}
82
+
83
+console.log("Fingerprint found!");
84
+console.log("ID: " + myid.getitem(0) + ", Score: " + myscore.getitem(0));
85
+
86
+
87
+// Print message when exiting
88
+function exit()
89
+{
90
+	myFingerprintSensor = null;
91
+	fingerprint_lib.cleanUp();
92
+	fingerprint_lib = null;
93
+	console.log("Exiting");
94
+	process.exit(0);
95
+}
96
+process.on('SIGINT', exit);
97
+process.on('exit', exit);

+ 132
- 0
examples/python/zfm20-register.py View File

@@ -0,0 +1,132 @@
1
+#!/usr/bin/python
2
+# Author: Zion Orent <zorent@ics.com>
3
+# Copyright (c) 2015 Intel Corporation.
4
+#
5
+# Permission is hereby granted, free of charge, to any person obtaining
6
+# a copy of this software and associated documentation files (the
7
+# "Software"), to deal in the Software without restriction, including
8
+# without limitation the rights to use, copy, modify, merge, publish,
9
+# distribute, sublicense, and/or sell copies of the Software, and to
10
+# permit persons to whom the Software is furnished to do so, subject to
11
+# the following conditions:
12
+#
13
+# The above copyright notice and this permission notice shall be
14
+# included in all copies or substantial portions of the Software.
15
+#
16
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+import time, sys, signal, atexit
25
+import pyupm_zfm20 as upmZfm20
26
+
27
+# Instantiate a ZFM20 Fingerprint reader on UART 0
28
+myFingerprintSensor = upmZfm20.ZFM20(0)
29
+
30
+
31
+## Exit handlers ##
32
+# This stops python from printing a stacktrace when you hit control-C
33
+def SIGINTHandler(signum, frame):
34
+	raise SystemExit
35
+
36
+# This function lets you run code on exit,
37
+# including functions from myFingerprintSensor
38
+def exitHandler():
39
+	print "Exiting"
40
+	sys.exit(0)
41
+
42
+# Register exit handlers
43
+atexit.register(exitHandler)
44
+signal.signal(signal.SIGINT, SIGINTHandler)
45
+
46
+
47
+# make sure port is initialized properly.  57600 baud is the default.
48
+if (not myFingerprintSensor.setupTty(upmZfm20.cvar.int_B57600)):
49
+	print "Failed to setup tty port parameters"
50
+	sys.exit(1)
51
+
52
+
53
+# This example demonstrates registering a fingerprint on the zfm20
54
+# module.  The procedure is as follows:
55
+#
56
+# 1. get an image, store it in characteristics buffer 1
57
+# 2. get another image, store it in characteristics buffer 2
58
+# 3. store the image, assuming the two fingerprints match
59
+
60
+# first, we need to register our address and password
61
+
62
+myFingerprintSensor.setPassword(upmZfm20.ZFM20_DEFAULT_PASSWORD)
63
+myFingerprintSensor.setAddress(upmZfm20.ZFM20_DEFAULT_ADDRESS)
64
+
65
+# now verify the password.  If this fails, any other commands
66
+# will be ignored, so we just bail.
67
+if (myFingerprintSensor.verifyPassword()):
68
+	print "Password verified."
69
+else:
70
+	print "Password verification failed."
71
+	sys.exit(1)
72
+
73
+
74
+print " "
75
+
76
+# get the first image
77
+print "Place a finger on the sensor."
78
+while (myFingerprintSensor.generateImage() != upmZfm20.ZFM20.ERR_OK):
79
+	pass
80
+
81
+# in theory, we have an image
82
+print "Image captured, converting..."
83
+
84
+rv = myFingerprintSensor.image2Tz(1)
85
+
86
+if (rv != upmZfm20.ZFM20.ERR_OK):
87
+	print "Image conversion failed with error code %d" % rv
88
+	sys.exit(1)
89
+
90
+print "Image conversion succeeded, remove finger."
91
+time.sleep(1)
92
+
93
+while (myFingerprintSensor.generateImage() != upmZfm20.ZFM20.ERR_NO_FINGER):
94
+	pass
95
+
96
+print " "
97
+print "Now place the same finger on the sensor."
98
+
99
+while (myFingerprintSensor.generateImage() == upmZfm20.ZFM20.ERR_NO_FINGER):
100
+	pass
101
+
102
+print "Image captured, converting..."
103
+
104
+# save this one in slot 2
105
+rv = myFingerprintSensor.image2Tz(2)
106
+if (rv != upmZfm20.ZFM20.ERR_OK):
107
+	print "Image conversion failed with error code %d" % rv
108
+	sys.exit(1)
109
+
110
+print "Image conversion succeeded, remove finger."
111
+print " "
112
+
113
+print "Storing fingerprint at id 1"
114
+
115
+# create the model
116
+rv = myFingerprintSensor.createModel()
117
+if (rv != upmZfm20.ZFM20.ERR_OK):
118
+	if (rv == upmZfm20.ZFM20.ERR_FP_ENROLLMISMATCH):
119
+		print "Fingerprints did not match."
120
+	else:
121
+		print "createModel failed with error code %d" % rv
122
+	sys.exit(1)
123
+
124
+# now store it, we hard code the id (second arg) to 1 here
125
+rv = myFingerprintSensor.storeModel(1, 1)
126
+if (rv != upmZfm20.ZFM20.ERR_OK):
127
+	print "storeModel failed with error code %d" % rv
128
+	sys.exit(1)
129
+
130
+print " "
131
+print "Fingerprint stored at id 1."
132
+

+ 90
- 0
examples/python/zfm20.py View File

@@ -0,0 +1,90 @@
1
+#!/usr/bin/python
2
+# Author: Zion Orent <zorent@ics.com>
3
+# Copyright (c) 2015 Intel Corporation.
4
+#
5
+# Permission is hereby granted, free of charge, to any person obtaining
6
+# a copy of this software and associated documentation files (the
7
+# "Software"), to deal in the Software without restriction, including
8
+# without limitation the rights to use, copy, modify, merge, publish,
9
+# distribute, sublicense, and/or sell copies of the Software, and to
10
+# permit persons to whom the Software is furnished to do so, subject to
11
+# the following conditions:
12
+#
13
+# The above copyright notice and this permission notice shall be
14
+# included in all copies or substantial portions of the Software.
15
+#
16
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+import time, sys, signal, atexit
25
+import pyupm_zfm20 as upmZfm20
26
+
27
+# Instantiate a ZFM20 Fingerprint reader on UART 0
28
+myFingerprintSensor = upmZfm20.ZFM20(0)
29
+
30
+
31
+## Exit handlers ##
32
+# This stops python from printing a stacktrace when you hit control-C
33
+def SIGINTHandler(signum, frame):
34
+	raise SystemExit
35
+
36
+# This function lets you run code on exit,
37
+# including functions from myFingerprintSensor
38
+def exitHandler():
39
+	print "Exiting"
40
+	sys.exit(0)
41
+
42
+# Register exit handlers
43
+atexit.register(exitHandler)
44
+signal.signal(signal.SIGINT, SIGINTHandler)
45
+
46
+
47
+# make sure port is initialized properly.  57600 baud is the default.
48
+if (not myFingerprintSensor.setupTty(upmZfm20.cvar.int_B57600)):
49
+	print "Failed to setup tty port parameters"
50
+	sys.exit(1)
51
+
52
+# how many valid stored templates (fingerprints) do we have?
53
+print "Total stored templates: %d" % myFingerprintSensor.getNumTemplates()
54
+print " "
55
+
56
+# now spin waiting for a fingerprint to successfully image
57
+print "Waiting for finger print..."
58
+
59
+while (myFingerprintSensor.generateImage() == upmZfm20.ZFM20.ERR_NO_FINGER):
60
+	pass
61
+
62
+# in theory, we have an image
63
+print "Image captured, converting..."
64
+
65
+rv = myFingerprintSensor.image2Tz(1)
66
+if (rv != upmZfm20.ZFM20.ERR_OK):
67
+	print "Image conversion failed with error code %d" % rv
68
+	sys.exit(1)
69
+
70
+print "Image conversion succeeded."
71
+print "Searching database..."
72
+
73
+myid = upmZfm20.uint16Array(0)
74
+myid.__setitem__(0, 0)
75
+myscore = upmZfm20.uint16Array(0)
76
+myscore.__setitem__(0, 0)
77
+
78
+# we search for a print matching slot 1, where we stored our last
79
+# converted fingerprint
80
+rv = myFingerprintSensor.search(1, myid, myscore)
81
+if (rv != upmZfm20.ZFM20.ERR_OK):
82
+	if (rv == upmZfm20.ZFM20.ERR_FP_NOTFOUND):
83
+		print "Finger Print not found"
84
+		sys.exit(0)
85
+	else:
86
+		print "Search failed with error code %d" % rv
87
+		sys.exit(1)
88
+
89
+print "Fingerprint found!"
90
+print "ID: %d, Score: %d" % (myid.__getitem__(0), myscore.__getitem__(0))

+ 5
- 0
src/zfm20/CMakeLists.txt View File

@@ -0,0 +1,5 @@
1
+set (libname "zfm20")
2
+set (libdescription "upm grove zfm20 fingerprint sensor module")
3
+set (module_src ${libname}.cxx)
4
+set (module_h ${libname}.h)
5
+upm_module_init()

+ 26
- 0
src/zfm20/jsupm_zfm20.i View File

@@ -0,0 +1,26 @@
1
+%module jsupm_zfm20
2
+%include "../upm.i"
3
+%include "../carrays_uint16_t.i"
4
+%include "../carrays_uint32_t.i"
5
+%include "cpointer.i"
6
+
7
+%typemap(in) uint16_t * {
8
+  void *argp = 0 ;
9
+  int res = SWIG_ConvertPtr($input, &argp,SWIGTYPE_p_uint16Array, 0 |  0 );
10
+  $1 = (uint16_t *)(argp);
11
+}
12
+
13
+/*$input is a v8::object, which inherits from v8::value */
14
+%typemap(in) uint32_t {
15
+   $1 = ($input)->Uint32Value();
16
+}
17
+
18
+/* Send "int *" to JavaScript as intp */
19
+%pointer_functions(int, intp);
20
+%{
21
+    #include "zfm20.h"
22
+    speed_t int_B57600 = B57600;
23
+%}
24
+
25
+%include "zfm20.h"
26
+speed_t int_B57600 = B57600;

+ 26
- 0
src/zfm20/pyupm_zfm20.i View File

@@ -0,0 +1,26 @@
1
+%module pyupm_zfm20
2
+%include "../upm.i"
3
+%include "../carrays_uint16_t.i"
4
+%include "../carrays_uint32_t.i"
5
+%include "cpointer.i"
6
+
7
+%feature("autodoc", "3");
8
+
9
+%typemap(in) uint16_t * {
10
+  void *argp = 0 ;
11
+  int res = SWIG_ConvertPtr($input, &argp,SWIGTYPE_p_uint16Array, 0 |  0 );
12
+  $1 = reinterpret_cast< uint16_t * >(argp);
13
+}
14
+
15
+%typemap(in) uint32_t {
16
+   $1 = PyInt_AsLong($input);
17
+}
18
+
19
+/* Send "int *" to python as intp */
20
+%pointer_functions(int, intp);
21
+%{
22
+    #include "zfm20.h"
23
+    speed_t int_B57600 = B57600;
24
+%}
25
+%include "zfm20.h"
26
+speed_t int_B57600 = B57600;

+ 671
- 0
src/zfm20/zfm20.cxx View File

@@ -0,0 +1,671 @@
1
+/*
2
+ * Author: Jon Trulson <jtrulson@ics.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+#include <iostream>
26
+
27
+#include "zfm20.h"
28
+
29
+using namespace upm;
30
+using namespace std;
31
+
32
+static const int defaultDelay = 100;     // max wait time for read
33
+
34
+ZFM20::ZFM20(int uart)
35
+{
36
+  m_ttyFd = -1;
37
+
38
+  if ( !(m_uart = mraa_uart_init(uart)) )
39
+    {
40
+      cerr << __FUNCTION__ << ": mraa_uart_init() failed" << endl;
41
+      return;
42
+    }
43
+
44
+  // This requires a recent MRAA (1/2015)
45
+  char *devPath = mraa_uart_get_dev_path(m_uart);
46
+
47
+  if (!devPath)
48
+    {
49
+      cerr << __FUNCTION__ << ": mraa_uart_get_dev_path() failed" << endl;
50
+      return;
51
+    }
52
+
53
+  // now open the tty
54
+  if ( (m_ttyFd = open(devPath, O_RDWR)) == -1)
55
+    {
56
+      cerr << __FUNCTION__ << ": open of " << devPath << " failed: " 
57
+           << strerror(errno) << endl;
58
+      return;
59
+    }
60
+
61
+  // Set the default password and address
62
+  setPassword(ZFM20_DEFAULT_PASSWORD);
63
+  setAddress(ZFM20_DEFAULT_ADDRESS);
64
+
65
+  initClock();
66
+}
67
+
68
+ZFM20::~ZFM20()
69
+{
70
+  if (m_ttyFd != -1)
71
+    close(m_ttyFd);
72
+
73
+  mraa_deinit();
74
+}
75
+
76
+bool ZFM20::dataAvailable(unsigned int millis)
77
+{
78
+  if (m_ttyFd == -1)
79
+    return false;
80
+
81
+  struct timeval timeout;
82
+
83
+  // no waiting
84
+  timeout.tv_sec = 0;
85
+  timeout.tv_usec = millis * 1000;
86
+
87
+  int nfds;  
88
+  fd_set readfds;
89
+
90
+  FD_ZERO(&readfds);
91
+
92
+  FD_SET(m_ttyFd, &readfds);
93
+  
94
+  if (select(m_ttyFd + 1, &readfds, NULL, NULL, &timeout) > 0)
95
+    return true;                // data is ready
96
+  else
97
+    return false;
98
+}
99
+
100
+int ZFM20::readData(char *buffer, size_t len)
101
+{
102
+  if (m_ttyFd == -1)
103
+    return(-1);
104
+
105
+  if (!dataAvailable(defaultDelay))
106
+    return 0;               // timed out
107
+
108
+  int rv = read(m_ttyFd, buffer, len);
109
+
110
+  if (rv < 0)
111
+    cerr << __FUNCTION__ << ": read failed: " << strerror(errno) << endl;
112
+
113
+  return rv;
114
+}
115
+
116
+int ZFM20::writeData(char *buffer, size_t len)
117
+{
118
+  if (m_ttyFd == -1)
119
+    return(-1);
120
+
121
+  // first, flush any pending but unread input
122
+  tcflush(m_ttyFd, TCIFLUSH);
123
+
124
+  int rv = write(m_ttyFd, buffer, len);
125
+
126
+  if (rv < 0)
127
+    {
128
+      cerr << __FUNCTION__ << ": write failed: " << strerror(errno) << endl;
129
+      return rv;
130
+    }
131
+
132
+  tcdrain(m_ttyFd);
133
+
134
+  return rv;
135
+}
136
+
137
+bool ZFM20::setupTty(speed_t baud)
138
+{
139
+  if (m_ttyFd == -1)
140
+    return(false);
141
+  
142
+  struct termios termio;
143
+
144
+  // get current modes
145
+  tcgetattr(m_ttyFd, &termio);
146
+
147
+  // setup for a 'raw' mode.  81N, no echo or special character
148
+  // handling, such as flow control.
149
+  cfmakeraw(&termio);
150
+
151
+  // set our baud rates
152
+  cfsetispeed(&termio, baud);
153
+  cfsetospeed(&termio, baud);
154
+
155
+  // make it so
156
+  if (tcsetattr(m_ttyFd, TCSAFLUSH, &termio) < 0)
157
+    {
158
+      cerr << __FUNCTION__ << ": tcsetattr failed: " << strerror(errno) << endl;
159
+      return false;
160
+    }
161
+
162
+  return true;
163
+}
164
+
165
+int ZFM20::writeCmdPacket(unsigned char *pkt, int len)
166
+{
167
+  unsigned char rPkt[ZFM20_MAX_PKT_LEN];
168
+
169
+  rPkt[0] = ZFM20_START1;             // header bytes
170
+  rPkt[1] = ZFM20_START2;
171
+
172
+  rPkt[2] = (m_address >> 24) & 0xff; // address
173
+  rPkt[3] = (m_address >> 16) & 0xff;
174
+  rPkt[4] = (m_address >> 8) & 0xff;
175
+  rPkt[5] = m_address & 0xff;
176
+
177
+  rPkt[6] = PKT_COMMAND;
178
+
179
+  rPkt[7] = ((len + 2) >> 8) & 0xff;  // length (+ len bytes)
180
+  rPkt[8] = (len + 2) & 0xff;
181
+
182
+  // compute the starting checksum
183
+  uint16_t cksum = rPkt[7] + rPkt[8] + PKT_COMMAND;
184
+
185
+  int j = 9;
186
+  for (int i=0; i<len; i++)
187
+    {
188
+      rPkt[j] = pkt[i];
189
+      cksum += rPkt[j];
190
+      j++;
191
+    }
192
+
193
+  rPkt[j++] = (cksum >> 8) & 0xff;    // store the cksum
194
+  rPkt[j++] = cksum & 0xff;
195
+
196
+  return writeData((char *)rPkt, j);
197
+}
198
+
199
+void ZFM20::initClock()
200
+{
201
+  gettimeofday(&m_startTime, NULL);
202
+}
203
+
204
+uint32_t ZFM20::getMillis()
205
+{
206
+  struct timeval elapsed, now;
207
+  uint32_t elapse;
208
+
209
+  // get current time
210
+  gettimeofday(&now, NULL);
211
+
212
+  // compute the delta since m_startTime
213
+  if( (elapsed.tv_usec = now.tv_usec - m_startTime.tv_usec) < 0 ) 
214
+    {
215
+      elapsed.tv_usec += 1000000;
216
+      elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec - 1;
217
+    } 
218
+  else 
219
+    {
220
+      elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec;
221
+    }
222
+
223
+  elapse = (uint32_t)((elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000));
224
+
225
+  // never return 0
226
+  if (elapse == 0)
227
+    elapse = 1;
228
+
229
+  return elapse;
230
+}
231
+
232
+bool ZFM20::verifyPacket(unsigned char *pkt)
233
+{
234
+  // verify packet header
235
+  if (pkt[0] != ZFM20_START1 || pkt[1] != ZFM20_START2)
236
+    {
237
+      cerr << __FUNCTION__ << ": Invalid packet header." << endl;
238
+      return false;
239
+    }
240
+
241
+  // check the ack byte
242
+  if (pkt[6] != PKT_ACK)
243
+    {
244
+      cerr << __FUNCTION__ << ": Invalid ACK code: " 
245
+           << int(pkt[6]) << ", expected: " << int(PKT_ACK) << endl;
246
+      return false;
247
+    }
248
+  
249
+  return true;
250
+}
251
+
252
+bool ZFM20::getResponse(unsigned char *pkt, int len)
253
+{
254
+  char buf[ZFM20_MAX_PKT_LEN];
255
+
256
+  initClock();
257
+
258
+  int idx = 0;
259
+  int timer = 0;
260
+  int rv;
261
+  int plen = 0;
262
+
263
+  while (idx < len)
264
+    {
265
+      // wait for some data
266
+      if (!dataAvailable(100))
267
+        {
268
+          timer += getMillis();
269
+          if (timer > ZFM20_TIMEOUT)
270
+            {
271
+              cerr << __FUNCTION__ << ": Timed out waiting for packet" << endl;
272
+              return false;
273
+            }
274
+
275
+          continue;
276
+        }
277
+
278
+      if ((rv = readData(buf, ZFM20_MAX_PKT_LEN)) <= 0)
279
+        {
280
+          cerr << __FUNCTION__ << ": Read failed" << endl;
281
+          return false;
282
+        }
283
+
284
+      // copy it into the user supplied buffer
285
+      for (int i=0; i<rv; i++)
286
+        {
287
+          pkt[idx++] = buf[i];
288
+          if (idx >= len)
289
+            break;
290
+        }
291
+    }
292
+
293
+  // now verify it.
294
+  return verifyPacket(pkt);
295
+}
296
+
297
+bool ZFM20::verifyPassword()
298
+{
299
+  const int pktLen = 5;
300
+  uint8_t pkt[pktLen] = {CMD_VERIFY_PASSWORD, 
301
+                         (m_password >> 24) & 0xff,
302
+                         (m_password >> 16) & 0xff,
303
+                         (m_password >> 8) & 0xff,
304
+                         m_password & 0xff };
305
+
306
+  if (!writeCmdPacket(pkt, pktLen))
307
+    {
308
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
309
+      return false;
310
+    }
311
+
312
+  // now read a response
313
+  const int rPktLen = 12;
314
+  unsigned char rPkt[rPktLen];
315
+
316
+  if (!getResponse(rPkt, rPktLen))
317
+    {
318
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
319
+      return false;
320
+    }
321
+
322
+  return true;
323
+}
324
+
325
+int ZFM20::getNumTemplates()
326
+{
327
+  const int pktLen = 1;
328
+  uint8_t pkt[pktLen] = {CMD_GET_TMPL_COUNT};
329
+
330
+  if (!writeCmdPacket(pkt, pktLen))
331
+    {
332
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
333
+      return 0;
334
+    }
335
+
336
+  // now read a response
337
+  const int rPktLen = 14;
338
+  unsigned char rPkt[rPktLen];
339
+
340
+  if (!getResponse(rPkt, rPktLen))
341
+    {
342
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
343
+      return 0;
344
+    }
345
+
346
+  // check confirmation code
347
+  if (rPkt[9] != 0x00)
348
+    {
349
+      cerr << __FUNCTION__ << ": Invalid confirmation code:" << int(rPkt[9])
350
+           << endl;
351
+      return 0;
352
+    }      
353
+
354
+  return ((rPkt[10] << 8) | rPkt[11]);
355
+}
356
+
357
+bool ZFM20::setNewPassword(uint32_t pwd)
358
+{
359
+  const int pktLen = 5;
360
+  uint8_t pkt[pktLen] = {CMD_SET_PASSWORD, 
361
+                         (pwd >> 24) & 0xff,
362
+                         (pwd >> 16) & 0xff,
363
+                         (pwd >> 8) & 0xff,
364
+                         pwd & 0xff };
365
+
366
+  if (!writeCmdPacket(pkt, pktLen))
367
+    {
368
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
369
+      return false;
370
+    }
371
+
372
+  // now read a response
373
+  const int rPktLen = 12;
374
+  unsigned char rPkt[rPktLen];
375
+
376
+  if (!getResponse(rPkt, rPktLen))
377
+    {
378
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
379
+      return false;
380
+    }
381
+
382
+  // check confirmation code
383
+  if (rPkt[9] != 0x00)
384
+    {
385
+      cerr << __FUNCTION__ << ": Invalid confirmation code:" << int(rPkt[9])
386
+           << endl;
387
+      return false;
388
+    }      
389
+
390
+  m_password = pwd;
391
+
392
+  return true;
393
+}
394
+
395
+bool ZFM20::setNewAddress(uint32_t addr)
396
+{
397
+  const int pktLen = 5;
398
+  uint8_t pkt[pktLen] = {CMD_SET_ADDRESS, 
399
+                         (addr >> 24) & 0xff,
400
+                         (addr >> 16) & 0xff,
401
+                         (addr >> 8) & 0xff,
402
+                         addr & 0xff };
403
+
404
+  if (!writeCmdPacket(pkt, pktLen))
405
+    {
406
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
407
+      return false;
408
+    }
409
+
410
+  // now read a response
411
+  const int rPktLen = 12;
412
+  unsigned char rPkt[rPktLen];
413
+
414
+  if (!getResponse(rPkt, rPktLen))
415
+    {
416
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
417
+      return false;
418
+    }
419
+
420
+  // check confirmation code
421
+  if (rPkt[9] != 0x00)
422
+    {
423
+      cerr << __FUNCTION__ << ": Invalid confirmation code:" << int(rPkt[9])
424
+           << endl;
425
+      return false;
426
+    }      
427
+
428
+  m_address = addr;
429
+
430
+  return true;
431
+}
432
+
433
+uint8_t ZFM20::generateImage()
434
+{
435
+  const int pktLen = 1;
436
+  uint8_t pkt[pktLen] = {CMD_GEN_IMAGE};
437
+
438
+  if (!writeCmdPacket(pkt, pktLen))
439
+    {
440
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
441
+      return ERR_INTERNAL_ERR;
442
+    }
443
+
444
+  // now read a response
445
+  const int rPktLen = 12;
446
+  unsigned char rPkt[rPktLen];
447
+
448
+  if (!getResponse(rPkt, rPktLen))
449
+    {
450
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
451
+      return ERR_INTERNAL_ERR;
452
+    }
453
+
454
+  return rPkt[9];
455
+}
456
+
457
+uint8_t ZFM20::image2Tz(int slot)
458
+{
459
+  if (slot != 1 && slot != 2)
460
+    {
461
+      cerr << __FUNCTION__ << ": slot must be 1 or 2" << endl;
462
+      return ERR_INTERNAL_ERR;
463
+    }
464
+
465
+  const int pktLen = 2;
466
+  uint8_t pkt[pktLen] = {CMD_IMG2TZ,
467
+                         (slot & 0xff)};
468
+
469
+  if (!writeCmdPacket(pkt, pktLen))
470
+    {
471
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
472
+      return ERR_INTERNAL_ERR;
473
+    }
474
+
475
+  // now read a response
476
+  const int rPktLen = 12;
477
+  unsigned char rPkt[rPktLen];
478
+
479
+  if (!getResponse(rPkt, rPktLen))
480
+    {
481
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
482
+      return ERR_INTERNAL_ERR;
483
+    }
484
+
485
+  return rPkt[9];
486
+}
487
+
488
+uint8_t ZFM20::createModel()
489
+{
490
+  const int pktLen = 1;
491
+  uint8_t pkt[pktLen] = {CMD_REGMODEL};
492
+
493
+  if (!writeCmdPacket(pkt, pktLen))
494
+    {
495
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
496
+      return ERR_INTERNAL_ERR;
497
+    }
498
+
499
+  // now read a response
500
+  const int rPktLen = 12;
501
+  unsigned char rPkt[rPktLen];
502
+
503
+  if (!getResponse(rPkt, rPktLen))
504
+    {
505
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
506
+      return ERR_INTERNAL_ERR;
507
+    }
508
+
509
+  return rPkt[9];
510
+}
511
+
512
+uint8_t ZFM20::storeModel(int slot, uint16_t id)
513
+{
514
+  if (slot != 1 && slot != 2)
515
+    {
516
+      cerr << __FUNCTION__ << ": slot must be 1 or 2" << endl;
517
+      return ERR_INTERNAL_ERR;
518
+    }
519
+
520
+  const int pktLen = 4;
521
+  uint8_t pkt[pktLen] = {CMD_STORE,
522
+                         (slot & 0xff),
523
+                         (id >> 8) & 0xff,
524
+                         id & 0xff};
525
+
526
+  if (!writeCmdPacket(pkt, pktLen))
527
+    {
528
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
529
+      return ERR_INTERNAL_ERR;
530
+    }
531
+
532
+  // now read a response
533
+  const int rPktLen = 12;
534
+  unsigned char rPkt[rPktLen];
535
+
536
+  if (!getResponse(rPkt, rPktLen))
537
+    {
538
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
539
+      return ERR_INTERNAL_ERR;
540
+    }
541
+
542
+  return rPkt[9];
543
+}
544
+
545
+uint8_t ZFM20::deleteModel(uint16_t id)
546
+{
547
+  const int pktLen = 5;
548
+  uint8_t pkt[pktLen] = {CMD_DELETE_TMPL,
549
+                         (id >> 8) & 0xff,
550
+                         id & 0xff,
551
+                         0x00,
552
+                         0x01};
553
+
554
+  if (!writeCmdPacket(pkt, pktLen))
555
+    {
556
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
557
+      return ERR_INTERNAL_ERR;
558
+    }
559
+
560
+  // now read a response
561
+  const int rPktLen = 12;
562
+  unsigned char rPkt[rPktLen];
563
+
564
+  if (!getResponse(rPkt, rPktLen))
565
+    {
566
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
567
+      return ERR_INTERNAL_ERR;
568
+    }
569
+
570
+  return rPkt[9];
571
+}
572
+
573
+uint8_t ZFM20::deleteDB()
574
+{
575
+  const int pktLen = 1;
576
+  uint8_t pkt[pktLen] = {CMD_EMPTYDB};
577
+
578
+  if (!writeCmdPacket(pkt, pktLen))
579
+    {
580
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
581
+      return ERR_INTERNAL_ERR;
582
+    }
583
+
584
+  // now read a response
585
+  const int rPktLen = 12;
586
+  unsigned char rPkt[rPktLen];
587
+
588
+  if (!getResponse(rPkt, rPktLen))
589
+    {
590
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
591
+      return ERR_INTERNAL_ERR;
592
+    }
593
+
594
+  return rPkt[9];
595
+}
596
+
597
+uint8_t ZFM20::search(int slot, uint16_t *id, uint16_t *score)
598
+{
599
+  *id = 0;
600
+  *score = 0;
601
+
602
+  if (slot != 1 && slot != 2)
603
+    {
604
+      cerr << __FUNCTION__ << ": slot must be 1 or 2" << endl;
605
+      return ERR_INTERNAL_ERR;
606
+    }
607
+
608
+  // search from page 0x0000 to page 0x00a3
609
+  const int pktLen = 6;
610
+  uint8_t pkt[pktLen] = {CMD_SEARCH,
611
+                         (slot & 0xff),
612
+                         0x00,
613
+                         0x00,
614
+                         0x00,
615
+                         0xa3};
616
+
617
+  if (!writeCmdPacket(pkt, pktLen))
618
+    {
619
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
620
+      return ERR_INTERNAL_ERR;
621
+    }
622
+
623
+  // now read a response
624
+  const int rPktLen = 16;
625
+  unsigned char rPkt[rPktLen];
626
+
627
+  if (!getResponse(rPkt, rPktLen))
628
+    {
629
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
630
+      return ERR_INTERNAL_ERR;
631
+    }
632
+
633
+  // if it was found, extract the location and the score
634
+  if (rPkt[9] == ERR_OK)
635
+    {
636
+      *id = (rPkt[10] << 8) & 0xff | rPkt[11] & 0xff;
637
+      *score = (rPkt[12] << 8) & 0xff | rPkt[13] & 0xff;
638
+    }
639
+
640
+  return rPkt[9];
641
+}
642
+
643
+uint8_t ZFM20::match(uint16_t *score)
644
+{
645
+  *score = 0;
646
+
647
+  const int pktLen = 1;
648
+  uint8_t pkt[pktLen] = {CMD_MATCH};
649
+
650
+  if (!writeCmdPacket(pkt, pktLen))
651
+    {
652
+      cerr << __FUNCTION__ << ": writePacket() failed" << endl;
653
+      return ERR_INTERNAL_ERR;
654
+    }
655
+
656
+  // now read a response
657
+  const int rPktLen = 14;
658
+  unsigned char rPkt[rPktLen];
659
+
660
+  if (!getResponse(rPkt, rPktLen))
661
+    {
662
+      cerr << __FUNCTION__ << ": getResponse() failed" << endl;
663
+      return ERR_INTERNAL_ERR;
664
+    }
665
+
666
+  *score = (rPkt[10] << 8) & 0xff | rPkt[11] & 0xff;
667
+
668
+  return rPkt[9];
669
+}
670
+
671
+

+ 377
- 0
src/zfm20/zfm20.h View File

@@ -0,0 +1,377 @@
1
+/*
2
+ * Author: Jon Trulson <jtrulson@ics.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Thanks to Adafruit for supplying a google translated version of the
6
+ * Chinese datasheet and some clues in their code.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining
9
+ * a copy of this software and associated documentation files (the
10
+ * "Software"), to deal in the Software without restriction, including
11
+ * without limitation the rights to use, copy, modify, merge, publish,
12
+ * distribute, sublicense, and/or sell copies of the Software, and to
13
+ * permit persons to whom the Software is furnished to do so, subject to
14
+ * the following conditions:
15
+ *
16
+ * The above copyright notice and this permission notice shall be
17
+ * included in all copies or substantial portions of the Software.
18
+ *
19
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ */
27
+#pragma once
28
+
29
+#include <string>
30
+#include <iostream>
31
+
32
+#include <stdint.h>
33
+#include <stdlib.h>
34
+#include <unistd.h>
35
+#include <string.h>
36
+#include <fcntl.h>
37
+#include <errno.h>
38
+#include <termios.h>
39
+#include <sys/time.h>
40
+#include <sys/select.h>
41
+#include <sys/types.h>
42
+#include <sys/stat.h>
43
+
44
+#include <mraa/uart.h>
45
+
46
+#define ZFM20_DEFAULT_UART 0
47
+
48
+// protocol start codes
49
+#define ZFM20_START1 0xef
50
+#define ZFM20_START2 0x01
51
+
52
+#define ZFM20_MAX_PKT_LEN 256
53
+
54
+#define ZFM20_TIMEOUT 5000 // in ms
55
+
56
+#define ZFM20_DEFAULT_PASSWORD 0x00000000
57
+#define ZFM20_DEFAULT_ADDRESS  0xffffffff
58
+
59
+
60
+namespace upm {
61
+    /**
62
+     * @brief UPM library for the ZFM-20 fingerprint sensor module
63
+     * @defgroup zfm20 libupm-zfm20
64
+     * @ingroup seeed serial gas
65
+     */
66
+
67
+    /**
68
+     * @sensor zfm20
69
+     * @library zfm20
70
+     * @comname ZFM-20 Fingerprint Sensor Module
71
+     * @category other
72
+     * @manufacturer seeed
73
+     * @connection uart
74
+     *
75
+     * @brief C++ API for the ZFM-20 fingerprint sensor module
76
+     *
77
+     * This class was tested on the Grove Fingerprint Sensor
78
+     * Module. It can store up to 163 fingerprints.
79
+     *
80
+     * It is connected via a UART at 57600 baud.
81
+     * 
82
+     * This example demonstrates how to register and store a new fingerprint
83
+     * @snippet zfm20-register.cxx Interesting
84
+     * This example demonstrates reading a fingerprint and locating it in the DB
85
+     * @snippet zfm20.cxx Interesting
86
+     */
87
+  class ZFM20 {
88
+  public:
89
+
90
+    // commands
91
+    typedef enum {
92
+      CMD_GEN_IMAGE                     = 0x01,
93
+      CMD_IMG2TZ                        = 0x02,
94
+      CMD_MATCH                         = 0x03,
95
+      CMD_SEARCH                        = 0x04,
96
+      CMD_REGMODEL                      = 0x05,
97
+      CMD_STORE                         = 0x06,
98
+      CMD_LOAD_TMPL                     = 0x07,
99
+      CMD_UPLOAD_TMPL                   = 0x08,
100
+      CMD_DOWNLOAD_TMPL                 = 0x09,
101
+      CMD_UPLOAD_IMAGE                  = 0x0a,
102
+      CMD_DOWNLOAD_IMAGE                = 0x0b,
103
+      CMD_DELETE_TMPL                   = 0x0c,
104
+      CMD_EMPTYDB                       = 0x0d,
105
+      CMD_SET_SYSPARAMS                 = 0x0e,
106
+      CMD_GET_SYSPARAMS                 = 0x0f,
107
+      CMD_SET_PASSWORD                  = 0x12,
108
+      CMD_VERIFY_PASSWORD               = 0x13,
109
+      CMD_GET_RANDOM_NUMBER             = 0x14,
110
+      CMD_SET_ADDRESS                   = 0x15,
111
+      CMD_GET_TMPL_COUNT                = 0x1d,
112
+      CMD_GET_INDEX_TABLE               = 0x1f
113
+    } ZFM20_COMMAND_T;
114
+
115
+    // Error response codes
116
+    typedef enum {
117
+      ERR_OK                            = 0x00,
118
+      ERR_PACKET_RX_ERROR               = 0x01,
119
+      ERR_NO_FINGER                     = 0x02,
120
+      ERR_FP_IMAGE_FAILED               = 0x03,
121
+      ERR_FP_TOO_MESSY                  = 0x06,
122
+      ERR_FP_IMAGE_FEW_FEATURES         = 0x07,
123
+      ERR_FP_NOMATCH                    = 0x08,
124
+      ERR_FP_NOTFOUND                   = 0x09,
125
+      ERR_FP_ENROLLMISMATCH             = 0x0a,
126
+      ERR_BAD_LOCATION                  = 0x0b,
127
+      ERR_DB_ERROR                      = 0x0c,
128
+      ERR_UPLOAD_FEAT_FAILED            = 0x0d,
129
+      ERR_NO_MORE_PACKETS               = 0x0e,
130
+      ERR_UPLOAD_IMG_FAILED             = 0x0f,
131
+      ERR_RM_TMPL_FAILED                = 0x10,
132
+      ERR_EMPTY_DB_FAILED               = 0x11,
133
+      ERR_INVALID_PWD                   = 0x13,
134
+      ERR_INVALID_IMAGE                 = 0x15,
135
+      ERR_RW_FLASH_ERROR                = 0x18,
136
+      ERR_INVALID_REG                   = 0x1a,
137
+      ERR_INVALID_ADDR                  = 0x20,
138
+      ERR_NEEDS_PWD                     = 0x21,
139
+      // end of module specific errors
140
+      ERR_INTERNAL_ERR                  = 0xff  // API internal error
141
+    } ZFM20_ERRORS_T;
142
+    
143
+    typedef enum {
144
+      PKT_COMMAND                       = 0x01,
145
+      PKT_DATA                          = 0x02,
146
+      PKT_ACK                           = 0x07,
147
+      PKT_END_DATA                      = 0x08
148
+    } ZFM20_PKTCODES_T;
149
+
150
+    /**
151
+     * ZFM20 module constructor
152
+     *
153
+     * @param uart default uart to use (0 or 1)
154
+     */
155
+    ZFM20(int uart);
156
+
157
+    /**
158
+     * ZFM20 module Destructor
159
+     */
160
+    ~ZFM20();
161
+
162
+    /**
163
+     * check to see if there is data available for reading
164
+     *
165
+     * @param millis number of milliseconds to wait, 0 means no wait.
166
+     * @return true if there is data available to be read
167
+     */
168
+    bool dataAvailable(unsigned int millis);
169
+
170
+    /**
171
+     * read any available data into a user-supplied buffer.  Note, the
172
+     * call will block until data is available to be read.  Use
173
+     * dataAvailable() to determine whether there is data available
174
+     * beforehand, to avoid blocking.
175
+     *
176
+     * @param buffer the buffer to hold the data read
177
+     * @param len the length of the buffer
178
+     * @return the number of bytes read
179
+     */
180
+    int readData(char *buffer, size_t len);
181
+
182
+    /**
183
+     * write the data in buffer to the device
184
+     *
185
+     * @param buffer the buffer to hold the data read
186
+     * @param len the length of the buffer
187
+     * @return the number of bytes written
188
+     */
189
+    int writeData(char *buffer, size_t len);
190
+
191
+    /**
192
+     * setup the proper tty i/o modes and the baudrate.  The default
193
+     * baud rate is 57600 (B57600) for this device.
194
+     *
195
+     * @param baud the desired baud rate.  
196
+     * @return true if successful
197
+     */
198
+    bool setupTty(speed_t baud=B57600);
199
+
200
+    /**
201
+     * compose and write a command packet
202
+     *
203
+     * @param pkt the packet
204
+     * @param len length of packet
205
+     * @return the number of bytes written
206
+     */
207
+    int writeCmdPacket(unsigned char *pkt, int len);
208
+
209
+    /**
210
+     * verify the packet header and indicate it's validity
211
+     *
212
+     * @param pkt the packet to check
213
+     * @return true if valid checksum, false otherwise
214
+     */
215
+    bool verifyPacket(unsigned char *pkt);
216
+
217
+    /**
218
+     * Return the number of milliseconds elapsed since initClock()
219
+     * was last called.
220
+     *
221
+     * @return elapsed milliseconds
222
+     */
223
+    uint32_t getMillis();
224
+
225
+    /**
226
+     * Reset the Clock
227
+     *
228
+     */
229
+    void initClock();
230
+
231
+    /**
232
+     * set the address that should be used to access the module
233
+     *
234
+     * @param addr the address to use
235
+     */
236
+    void setAddress(uint32_t addr) { m_address = addr; };
237
+
238
+    /**
239
+     * set the password that should be used to access the module
240
+     *
241
+     * @param pw password to use
242
+     */
243
+    void setPassword(uint32_t pw) { m_password = pw; };
244
+
245
+    /**
246
+     * get the returned data from a request
247
+     *
248
+     * @param pkt the buffer to store the returned data into
249
+     * @param len the expected response length.  pkt should be at least this 
250
+     * big.
251
+     * @return true if successful
252
+     */
253
+    bool getResponse(unsigned char *pkt, int len);
254
+
255
+    /**
256
+     * verify and authenticate to the module.  The password used is
257
+     * the one last set by setPassword().
258
+     *
259
+     * @return true if successful
260
+     */
261
+    bool verifyPassword();
262
+
263
+    /**
264
+     * query the module for the number of stored templates
265
+     * (fingerprints).
266
+     *
267
+     * @return the number of currently stored templates
268
+     */
269
+    int getNumTemplates();
270
+
271
+    /**
272
+     * set a new password for the module.  This passowrd will be
273
+     * stored on the module, and will be required in order to access
274
+     * the module in the future.
275
+     *
276
+     * @param pwd the new password to set on the module
277
+     * @return true if successful
278
+     */
279
+    bool setNewPassword(uint32_t pwd);
280
+
281
+    /**
282
+     * set a new address for the module.  This address will be
283
+     * stored on the module, and will be required in order to access
284
+     * the module in the future.
285
+     *
286
+     * @param addr the new address to set on the module
287
+     * @return true if successful
288
+     */
289
+    bool setNewAddress(uint32_t addr);
290
+
291
+    /**
292
+     * generate a new fingerprint image (scan a fingerprint)
293
+     *
294
+     * @return one of the ZFM20_ERRORS_T values
295
+     */
296
+    uint8_t generateImage();
297
+
298
+    /**
299
+     * convert the image in the image buffer (generated by
300
+     * generateImage()) and store it in one of the two characteristics
301
+     * buffers, 1 or 2
302
+     *
303
+     * @param slot the characteristics buffer to use.  Must be 1 or 2.
304
+     * @return one of the ZFM20_ERRORS_T values
305
+     */
306
+    uint8_t image2Tz(int slot);
307
+
308
+    /**
309
+     * based on the two characteristics bufferes (1 & 2), create a
310
+     * fingerprint model.  Once a model has been successfully created,
311
+     * it can be stored in the module with storeModel().
312
+     *
313
+     * @return one of the ZFM20_ERRORS_T values
314
+     */
315
+    uint8_t createModel();
316
+
317
+    /**
318
+     * once a fingerprint model has been created, this method can be
319
+     * used to store it (via one of the characteristics buffers) in a
320
+     * given location.
321
+     *
322
+     * @param slot the characteristics buffer to store (1 or 2)
323
+     * @param id the location in which to store the model
324
+     * @return one of the ZFM20_ERRORS_T values
325
+     */
326
+    uint8_t storeModel(int slot, uint16_t id);
327
+
328
+    /**
329
+     * delete a stored model.
330
+     *
331
+     * @param id the location containing the model to delete
332
+     * @return one of the ZFM20_ERRORS_T values
333
+     */
334
+    uint8_t deleteModel(uint16_t id);
335
+
336
+    /**
337
+     * delete the model database
338
+     *
339
+     * @return one of the ZFM20_ERRORS_T values
340
+     */
341
+    uint8_t deleteDB();
342
+
343
+    /**
344
+     * search the fingerprint DB and return the id and score, if found
345
+     *
346
+     *
347
+     * @param slot the slot containing a converted image to search for
348
+     * @param id the returned id if found, 0 otherwise
349
+     * @param score the returned score if found, 0 otherwise
350
+     * @return one of the ZFM20_ERRORS_T values
351
+     */
352
+    uint8_t search(int slot, uint16_t *id, uint16_t *score);
353
+
354
+    /**
355
+     * compares the features in characteristic buffers 1 and 2 and
356
+     * returns a score if they match
357
+     *
358
+     * @param score the returned score
359
+     * @return one of the ZFM20_ERRORS_T values
360
+     */
361
+    uint8_t match(uint16_t *score);
362
+
363
+
364
+  protected:
365
+    int ttyFd() { return m_ttyFd; };
366
+    int setTtyFd(int fd) { m_ttyFd = fd; };
367
+
368
+  private:
369
+    mraa_uart_context m_uart;
370
+    int m_ttyFd;
371
+    uint32_t m_password;
372
+    uint32_t m_address;
373
+    struct timeval m_startTime;
374
+  };
375
+}
376
+
377
+