├── .vscode ├── settings.json ├── arduino.json └── c_cpp_properties.json ├── .gitignore ├── library.properties ├── library.json ├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── keywords.txt ├── src ├── R30X_FPS.h └── R30X_FPS.cpp └── examples └── R30X-FPS-Test └── R30X-FPS-Test.ino /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.dimInactiveRegions": false 3 | } -------------------------------------------------------------------------------- /.vscode/arduino.json: -------------------------------------------------------------------------------- 1 | { 2 | "board": "arduino:avr:uno", 3 | "programmer": "USBasp", 4 | "port": "COM32", 5 | "sketch": "Examples\\R30X_FPS_Test\\R30X_FPS_Test.ino" 6 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | #folders 35 | /.vscode 36 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=R30X-Fingerprint-Sensor-Library 2 | version=1.3.1 3 | author=vishnumaiea 4 | maintainer=vishnumaiea 5 | sentence=Arduino library for interfacing R30X series optical fingerprint scanners. 6 | paragraph=Helps you interface R30X series optical fingerprint scanners with Arduino compatible boards. The scanner uses SPI interface. 7 | category=Device Control 8 | url=https://github.com/vishnumaiea/R30X-Fingerprint-Sensor-Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R30X-Fingerprint-Sensor-Library", 3 | "keywords": "r307,r303,fingerprint,scanner,sensor,r30x,spi,optical,biometric,security", 4 | "description": "Arduino library for interfacing R30X series optical fingerprint scanners.", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/vishnumaiea/R30X-Fingerprint-Sensor-Library.git" 9 | }, 10 | "authors": 11 | { 12 | "name": "Vishnu M Aiea", 13 | "url": "https://github.com/vishnumaiea", 14 | "maintainer": true 15 | }, 16 | "version": "1.3.1", 17 | "license": "MIT", 18 | "frameworks": "arduino", 19 | "platforms": "*" 20 | } 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://www.paypal.com/paypalme/vishnumaiea'] 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | <<<<<<< HEAD 4 | Copyright (c) 2018 Vishnu M Aiea 5 | ======= 6 | Copyright (c) 2019 Vishnu M Aiea 7 | >>>>>>> 67719c1b8f7987414f849f34aafd29ac8b64bdd4 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "C:\\Program Files (x86)\\Arduino\\tools\\**", 7 | "C:\\Program Files (x86)\\Arduino\\hardware\\arduino\\avr\\**", 8 | "C:\\Users\\AYGENT543\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\**", 9 | "C:\\Users\\AYGENT543\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\sam\\1.6.12\\**", 10 | "C:\\Users\\AYGENT543\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.2\\**", 11 | "C:\\Users\\VISHNU-MAGNIMOUS\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.3\\**", 12 | "C:\\Users\\VISHNU-MAGNIMOUS\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\**" 13 | ], 14 | "forcedInclude": [ 15 | "C:\\Program Files (x86)\\Arduino\\hardware\\arduino\\avr\\cores\\arduino\\Arduino.h", 16 | "C:\\Users\\AYGENT543\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.2\\cores\\arduino\\Arduino.h", 17 | "C:\\Users\\VISHNU-MAGNIMOUS\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.3\\cores\\arduino\\Arduino.h" 18 | ], 19 | "intelliSenseMode": "msvc-x64", 20 | "compilerPath": "C:\\Program Files\\LLVM\\bin\\clang.exe", 21 | "cStandard": "c11", 22 | "cppStandard": "c++17" 23 | } 24 | ], 25 | "version": 4 26 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # R30X-Fingerprint-Sensor-Library 2 | An Arduino compatible library for **R30X** series optical fingerprint sensor/scanner from Hangzhou Grow Technology. The library is written in a manner to be easily readable and thus modifiable. 3 | 4 | - Latest version : ![GitHub release (latest by date)](https://img.shields.io/github/v/release/vishnumaiea/R30X-Fingerprint-Sensor-Library?style=flat) 5 | - Author : **Vishnu Mohanan** (@vishnumaiea) 6 | - Source : https://github.com/vishnumaiea/R30X-Fingerprint-Sensor-Library 7 | - Author's website : www.vishnumaiea.in 8 | - Initial release : +05:30 07:35 PM, 08-04-2019, Monday 9 | - Last updated : +05:30 06:10:01 PM, 20-07-2020 Monday 10 | - License : [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) 11 | 12 | ## Tutorial 13 | 14 | A detailed tutorial on interfacing the modules and using the library is available on my project website : https://circuitstate.com/tutorials/interfacing-r307-optical-fingerprint-scanner-with-arduino/ (this repo may be newer than what's described in the tutorial). I still need to implement two functions for importing and exporting fingerprint templates and images from and to the sensor. 15 | 16 | ## Installing 17 | 18 | To install the library to your computer, open the _**Library Manager**_ from the _**Arduino IDE**_ and search for "R30X fingerprint scanner". Then install the latest version from the list. 19 | 20 | ## Tested Boards 21 | 22 | The library was tested with **Arduino Due** and **Arduino Uno** using **R307** fingerprint scanner. To wire up, connect the TX and RX pins to the TX1 and RX1 pins of Due or Mega. If you're using Uno or similar boards with only one hardware UART, use **SoftwareSerial** for the fingerprint sensor and hardware UART for debugging. 23 | 24 | Even though not tested, the library is expected to work with other Arduino compatible microcontrollers and boards such as ESP8266, ESP32, STM32 Nucleo, TI Launchpad etc. 25 | 26 | ## Example 27 | 28 | The example sketch can invoke all implemented functions from a serial terminal with short commands and input parameters. Below is the list of available commands. 29 | 30 | All commands and parameters must be separated by **single whitespace**. 31 | 32 | - **clrlib** - clear library 33 | - **tmpcnt** - get templates count 34 | - **readsys** - read system parameters 35 | - **setdatlen \** - set data length 36 | - **capranser \ \ \** - capture and range search library for fingerprint 37 | - **capfulser** - capture and full search the library for fingerprint 38 | - **enroll \** - enroll new fingerprint 39 | - **verpwd \** - verify 4 byte device password 40 | - **setpwd \** - set new 4 byte device password 41 | - **setaddr \** - set new 4 byte device address 42 | - **setbaud \** - set the baudrate 43 | - **reinitprt \** - reinitialize the port without changing device configuration 44 | - **setseclvl \** - set security level 45 | - **genimg** - generate image 46 | - **genchar \** - generate character file from image 47 | - **gentmp** - generate template from character buffers 48 | - **savtmp \ \** - save template to library from buffer 49 | - **lodtmp \ \** - load template from library to buffer 50 | - **deltmp \ \** - delete one or more templates from library 51 | - **mattmp** - precisely match two templates available on buffers 52 | - **serlib \ \ \** - search library for content on the buffer 53 | 54 | ## Troubleshooting 55 | 56 | When something is not working, upload the example sketch to your board and run the commands to check if they're working as expected. 57 | 58 | 1. **Getting "Password is not correct" message** 59 | 60 | New modules will be coming with the default password and device address 0xFFFFFFFF. If the example sketch complains about wrong password, then try running the **setpwd** command. For example, 61 | 62 | ``` setpwd FFFFFFFF ``` 63 | 64 | 65 | 2. **Getting "Invalid command" message** 66 | 67 | If your serial terminal application is sending NL/CR characters automatically, try turing this off. For example, you can turn this feature off at Arduino serial monitor. 68 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for R30X_FPS 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | R30X_FPS KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | resetParameters KEYWORD2 17 | verifyPassword KEYWORD2 18 | setPassword KEYWORD2 19 | setAddress KEYWORD2 20 | setBaudrate KEYWORD2 21 | reinitializePort KEYWORD2 22 | setSecurityLevel KEYWORD2 23 | setDataLength KEYWORD2 24 | portControl KEYWORD2 25 | sendPacket KEYWORD2 26 | receivePacket KEYWORD2 27 | readSysPara KEYWORD2 28 | captureAndRangeSearch KEYWORD2 29 | captureAndFullSearch KEYWORD2 30 | generateImage KEYWORD2 31 | exportImage KEYWORD2 32 | importImage KEYWORD2 33 | generateCharacter KEYWORD2 34 | generateTemplate KEYWORD2 35 | exportCharacter KEYWORD2 36 | importCharacter KEYWORD2 37 | saveTemplate KEYWORD2 38 | loadTemplate KEYWORD2 39 | deleteTemplate KEYWORD2 40 | clearLibrary KEYWORD2 41 | matchTemplates KEYWORD2 42 | searchLibrary KEYWORD2 43 | getTemplateCount KEYWORD2 44 | 45 | ####################################### 46 | # Constants (LITERAL1) 47 | ####################################### 48 | 49 | FPS_RESP_OK LITERAL1 50 | FPS_RESP_RECIEVEERR LITERAL1 51 | FPS_RESP_NOFINGER LITERAL1 52 | FPS_RESP_ENROLLFAIL LITERAL1 53 | FPS_RESP_OVERDISORDERFAIL LITERAL1 54 | FPS_RESP_OVERWETFAIL LITERAL1 55 | FPS_RESP_OVERDISORDERFAIL2 LITERAL1 56 | FPS_RESP_FEATUREFAIL LITERAL1 57 | FPS_RESP_DONOTMATCH LITERAL1 58 | FPS_RESP_NOTFOUND LITERAL1 59 | FPS_RESP_ENROLLMISMATCH LITERAL1 60 | FPS_RESP_BADLOCATION LITERAL1 61 | FPS_RESP_INVALIDTEMPLATE LITERAL1 62 | FPS_RESP_TEMPLATEUPLOADFAIL LITERAL1 63 | FPS_RESP_PACKETACCEPTFAIL LITERAL1 64 | FPS_RESP_IMAGEUPLOADFAIL LITERAL1 65 | FPS_RESP_TEMPLATEDELETEFAIL LITERAL1 66 | FPS_RESP_DBCLEARFAIL LITERAL1 67 | FPS_RESP_WRONGPASSOWRD LITERAL1 68 | FPS_RESP_IMAGEGENERATEFAIL LITERAL1 69 | FPS_RESP_FLASHWRITEERR LITERAL1 70 | FPS_RESP_NODEFINITIONERR LITERAL1 71 | FPS_RESP_INVALIDREG LITERAL1 72 | FPS_RESP_INCORRECTCONFIG LITERAL1 73 | FPS_RESP_WRONGNOTEPADPAGE LITERAL1 74 | FPS_RESP_COMPORTERR LITERAL1 75 | FPS_RESP_INVALIDREG LITERAL1 76 | FPS_RESP_SECONDSCANNOFINGER LITERAL1 77 | FPS_RESP_SECONDENROLLFAIL LITERAL1 78 | FPS_RESP_SECONDFEATUREFAIL LITERAL1 79 | FPS_RESP_SECONDOVERDISORDERFAIL LITERAL1 80 | FPS_RESP_DUPLICATEFINGERPRINT LITERAL1 81 | 82 | FPS_RX_OK LITERAL1 83 | FPS_RX_BADPACKET LITERAL1 84 | FPS_RX_WRONG_RESPONSE LITERAL1 85 | FPS_RX_TIMEOUT LITERAL1 86 | 87 | FPS_ID_STARTCODE LITERAL1 88 | FPS_ID_STARTCODEHIGH LITERAL1 89 | FPS_ID_STARTCODELOW LITERAL1 90 | FPS_ID_COMMANDPACKET LITERAL1 91 | FPS_ID_DATAPACKET LITERAL1 92 | FPS_ID_ACKPACKET LITERAL1 93 | FPS_ID_ENDDATAPACKET LITERAL1 94 | 95 | FPS_CMD_SCANFINGER LITERAL1 96 | FPS_CMD_IMAGETOCHARACTER LITERAL1 97 | FPS_CMD_MATCHTEMPLATES LITERAL1 98 | FPS_CMD_SEARCHLIBRARY LITERAL1 99 | FPS_CMD_GENERATETEMPLATE LITERAL1 100 | FPS_CMD_STORETEMPLATE LITERAL1 101 | FPS_CMD_LOADTEMPLATE LITERAL1 102 | FPS_CMD_EXPORTTEMPLATE LITERAL1 103 | FPS_CMD_IMPORTTEMPLATE LITERAL1 104 | FPS_CMD_EXPORTIMAGE LITERAL1 105 | FPS_CMD_IMPORTIMAGE LITERAL1 106 | FPS_CMD_DELETETEMPLATE LITERAL1 107 | FPS_CMD_CLEARLIBRARY LITERAL1 108 | FPS_CMD_SETSYSPARA LITERAL1 109 | FPS_CMD_READSYSPARA LITERAL1 110 | FPS_CMD_SETPASSWORD LITERAL1 111 | FPS_CMD_VERIFYPASSWORD LITERAL1 112 | FPS_CMD_GETRANDOMCODE LITERAL1 113 | FPS_CMD_SETDEVICEADDRESS LITERAL1 114 | FPS_CMD_PORTCONTROL LITERAL1 115 | FPS_CMD_WRITENOTEPAD LITERAL1 116 | FPS_CMD_READNOTEPAD LITERAL1 117 | FPS_CMD_HISPEEDSEARCH LITERAL1 118 | FPS_CMD_TEMPLATECOUNT LITERAL1 119 | FPS_CMD_SCANANDRANGESEARCH LITERAL1 120 | FPS_CMD_SCANANDFULLSEARCH LITERAL1 121 | FPS_DEFAULT_TIMEOUT LITERAL1 122 | FPS_DEFAULT_BAUDRATE LITERAL1 123 | FPS_DEFAULT_RX_DATA_LENGTH LITERAL1 124 | FPS_DEFAULT_SECURITY_LEVEL LITERAL1 125 | FPS_DEFAULT_SERIAL_BUFFER_LENGTH LITERAL1 126 | FPS_DEFAULT_PASSWORD LITERAL1 127 | FPS_DEFAULT_ADDRESS LITERAL1 128 | FPS_BAD_VALUE LITERAL1 129 | 130 | -------------------------------------------------------------------------------- /src/R30X_FPS.h: -------------------------------------------------------------------------------- 1 | 2 | //=========================================================================// 3 | // // 4 | // ## R30X Fingerprint Sensor Library ## // 5 | // // 6 | // Filename : R30X_FPS.h // 7 | // Description : Header file for R30X_FPS library for R30X series // 8 | // fingerprint sensors. // 9 | // Library version : 1.3.1 // 10 | // Author : Vishnu M Aiea // 11 | // Src : https://github.com/vishnumaiea/R30X-Fingerprint-Sensor-Library // 12 | // Author's website : https://www.vishnumaiea.in // 13 | // Initial release : IST 07:35 PM, 08-04-2019, Monday // 14 | // License : MIT // 15 | // // 16 | // Last modified : +05:30 05:58:28 PM, 20-07-2020 Monday 17 | // // 18 | //=========================================================================// 19 | 20 | #ifndef R30X_FPS_H 21 | #define R30X_FPS_H 22 | 23 | #include "Arduino.h" 24 | 25 | #if defined(__AVR__) || defined(ESP8266) //if more than one hardware serial ports are not present 26 | #include "SoftwareSerial.h" 27 | #endif 28 | 29 | // #include "SoftwareSerial.h" 30 | 31 | //=========================================================================// 32 | 33 | // #if !defined(ARDUINO_AVR_UNO) && !defined(ARDUINO_AVR_MINI) && !defined(ARDUINO_AVR_NANO) 34 | // #define FPS_DEBUG //uncomment this line to enable debug info to be printed 35 | // #endif 36 | 37 | #define FPS_DEBUG //uncomment this line to enable debug info to be printed 38 | 39 | #define debugPort Serial //the serisl port to which debug info will be sent 40 | 41 | //=========================================================================// 42 | //Response codes from FPS to the commands sent to it 43 | //FPS = Fingerprint Scanner 44 | 45 | #define FPS_RESP_OK 0x00U //command executed successfully 46 | #define FPS_RESP_RECIEVEERR 0x01U //packet receive error 47 | #define FPS_RESP_NOFINGER 0x02U //no finger detected 48 | #define FPS_RESP_ENROLLFAIL 0x03U //failed to enroll the finger 49 | #define FPS_RESP_OVERDISORDERFAIL 0x04U //failed to generate character file due to over-disorderly fingerprint image 50 | #define FPS_RESP_OVERWETFAIL 0x05U //failed to generate character file due to over-wet fingerprint image 51 | #define FPS_RESP_OVERDISORDERFAIL2 0x06U //failed to generate character file due to over-disorderly fingerprint image 52 | #define FPS_RESP_FEATUREFAIL 0x07U //failed to generate character file due to over-wet fingerprint image 53 | #define FPS_RESP_DONOTMATCH 0x08U //fingers do not match 54 | #define FPS_RESP_NOTFOUND 0x09U //no valid match found 55 | #define FPS_RESP_ENROLLMISMATCH 0x0AU //failed to combine character files (two character files (images) are used to create a template) 56 | #define FPS_RESP_BADLOCATION 0x0BU //addressing PageID is beyond the finger library 57 | #define FPS_RESP_INVALIDTEMPLATE 0x0CU //error when reading template from library or the template is invalid 58 | #define FPS_RESP_TEMPLATEUPLOADFAIL 0x0DU //error when uploading template 59 | #define FPS_RESP_PACKETACCEPTFAIL 0x0EU //module can not accept more packets 60 | #define FPS_RESP_IMAGEUPLOADFAIL 0x0FU //error when uploading image 61 | #define FPS_RESP_TEMPLATEDELETEFAIL 0x10U //error when deleting template 62 | #define FPS_RESP_DBCLEARFAIL 0x11U //failed to clear fingerprint library 63 | #define FPS_RESP_WRONGPASSOWRD 0x13U //wrong password 64 | #define FPS_RESP_IMAGEGENERATEFAIL 0x15U //fail to generate the image due to lackness of valid primary image 65 | #define FPS_RESP_FLASHWRITEERR 0x18U //error when writing flash 66 | #define FPS_RESP_NODEFINITIONERR 0x19U //no definition error 67 | #define FPS_RESP_INVALIDREG 0x1AU //invalid register number 68 | #define FPS_RESP_INCORRECTCONFIG 0x1BU //incorrect configuration of register 69 | #define FPS_RESP_WRONGNOTEPADPAGE 0x1CU //wrong notepad page number 70 | #define FPS_RESP_COMPORTERR 0x1DU //failed to operate the communication port 71 | #define FPS_RESP_INVALIDREG 0x1AU //invalid register number 72 | #define FPS_RESP_SECONDSCANNOFINGER 0x41U //secondary fingerprint scan failed due to no finger 73 | #define FPS_RESP_SECONDENROLLFAIL 0x42U //failed to enroll second fingerprint 74 | #define FPS_RESP_SECONDFEATUREFAIL 0x43U //failed to generate character file due to lack of enough features 75 | #define FPS_RESP_SECONDOVERDISORDERFAIL 0x44U //failed to generate character file due to over-disorderliness 76 | #define FPS_RESP_DUPLICATEFINGERPRINT 0x45U //duplicate fingerprint 77 | 78 | //-------------------------------------------------------------------------// 79 | //Received packet verification status codes from host device 80 | 81 | #define FPS_RX_OK 0x00U //when the response is correct 82 | #define FPS_RX_BADPACKET 0x01U //if the packet received from FPS is badly formatted 83 | #define FPS_RX_WRONG_RESPONSE 0x02U //unexpected response 84 | #define FPS_RX_TIMEOUT 0x03U //when no response was received 85 | 86 | //-------------------------------------------------------------------------// 87 | //Packet IDs 88 | 89 | #define FPS_ID_STARTCODE 0xEF01U 90 | #define FPS_ID_STARTCODEHIGH 0xEFU 91 | #define FPS_ID_STARTCODELOW 0x01U 92 | #define FPS_ID_COMMANDPACKET 0x01U 93 | #define FPS_ID_DATAPACKET 0x02U 94 | #define FPS_ID_ACKPACKET 0x07U 95 | #define FPS_ID_ENDDATAPACKET 0x08U 96 | 97 | //-------------------------------------------------------------------------// 98 | //Command codes 99 | 100 | #define FPS_CMD_SCANFINGER 0x01U //scans the finger and collect finger image 101 | #define FPS_CMD_IMAGETOCHARACTER 0x02U //generate char file from a single image and store it to one of the buffers 102 | #define FPS_CMD_MATCHTEMPLATES 0x03U //match two fingerprints precisely 103 | #define FPS_CMD_SEARCHLIBRARY 0x04U //search the fingerprint library 104 | #define FPS_CMD_GENERATETEMPLATE 0x05U //combine both character buffers and generate a template 105 | #define FPS_CMD_STORETEMPLATE 0x06U //store the template on one of the buffers to flash memory 106 | #define FPS_CMD_LOADTEMPLATE 0x07U //load a template from flash memory to one of the buffers 107 | #define FPS_CMD_EXPORTTEMPLATE 0x08U //export a template file from buffer to computer 108 | #define FPS_CMD_IMPORTTEMPLATE 0x09U //import a template file from computer to sensor buffer 109 | #define FPS_CMD_EXPORTIMAGE 0x0AU //export fingerprint image from buffer to computer 110 | #define FPS_CMD_IMPORTIMAGE 0x0BU //import an image from computer to sensor buffer 111 | #define FPS_CMD_DELETETEMPLATE 0x0CU //delete a template from flash memory 112 | #define FPS_CMD_CLEARLIBRARY 0x0DU //clear fingerprint library 113 | #define FPS_CMD_SETSYSPARA 0x0EU //set system configuration register 114 | #define FPS_CMD_READSYSPARA 0x0FU //read system configuration register 115 | #define FPS_CMD_SETPASSWORD 0x12U //set device password 116 | #define FPS_CMD_VERIFYPASSWORD 0x13U //verify device password 117 | #define FPS_CMD_GETRANDOMCODE 0x14U //get random code from device 118 | #define FPS_CMD_SETDEVICEADDRESS 0x15U //set 4 byte device address 119 | #define FPS_CMD_PORTCONTROL 0x17U //enable or disable comm port 120 | #define FPS_CMD_WRITENOTEPAD 0x18U //write to device notepad 121 | #define FPS_CMD_READNOTEPAD 0x19U //read from device notepad 122 | #define FPS_CMD_HISPEEDSEARCH 0x1BU //highspeed search of fingerprint 123 | #define FPS_CMD_TEMPLATECOUNT 0x1DU //read total template count 124 | #define FPS_CMD_SCANANDRANGESEARCH 0x32U //read total template count 125 | #define FPS_CMD_SCANANDFULLSEARCH 0x34U //read total template count 126 | 127 | #define FPS_DEFAULT_TIMEOUT 2000 //UART reading timeout in milliseconds 128 | #define FPS_DEFAULT_BAUDRATE 57600 //9600*6 129 | #define FPS_DEFAULT_RX_DATA_LENGTH 64 //the max length of data in a received packet 130 | #define FPS_DEFAULT_SECURITY_LEVEL 3 //the threshold at which the fingerprints will be matched 131 | #define FPS_DEFAULT_SERIAL_BUFFER_LENGTH 300 //length of the buffer used to read the serial data 132 | #define FPS_DEFAULT_PASSWORD 0xFFFFFFFF 133 | #define FPS_DEFAULT_ADDRESS 0xFFFFFFFF 134 | #define FPS_BAD_VALUE 0x1FU //some bad value or paramter was delivered 135 | 136 | //=========================================================================// 137 | //main class 138 | 139 | class R30X_FPS { 140 | public: 141 | 142 | #if defined(__AVR__) || defined(ESP8266) 143 | R30X_FPS (SoftwareSerial *ss, uint32_t password = FPS_DEFAULT_PASSWORD, uint32_t address = FPS_DEFAULT_ADDRESS); 144 | #endif 145 | 146 | R30X_FPS (HardwareSerial *hs, uint32_t password = FPS_DEFAULT_PASSWORD, uint32_t address = FPS_DEFAULT_ADDRESS); 147 | 148 | //common parameters 149 | uint16_t startCodeL; //packet start marker 150 | uint8_t startCode[2]; //packet start marker 151 | 152 | uint32_t devicePasswordL; //32-bit single value version of password (L = long) 153 | uint32_t deviceAddressL; //module's address 154 | uint8_t devicePassword[4]; //array version of password 155 | uint8_t deviceAddress[4]; //device address as an array 156 | 157 | uint16_t statusRegister; //contents of the FPS status register 158 | uint16_t systemID; //fixed value 0x0009 159 | uint16_t librarySize; //library memory size 160 | uint16_t securityLevel; //threshold level for fingerprint matching 161 | uint16_t dataPacketLengthCode; 162 | uint16_t dataPacketLength; //the max length of data in packet. can be 32, 64, 128 or 256 163 | uint16_t baudMultiplier; //value between 1-12 164 | uint32_t deviceBaudrate; //UART speed (9600 * baud multiplier) 165 | 166 | //transmit packet parameters 167 | uint8_t txPacketType; //type of packet 168 | uint16_t txPacketLengthL; //length of packet (Data + Checksum) 169 | uint8_t txInstructionCode; //instruction to be sent to FPS 170 | uint16_t txPacketChecksumL; //checksum long value 171 | uint8_t txPacketLength[2]; //packet length as an array 172 | uint8_t* txDataBuffer; //packet data buffer 173 | uint16_t txDataBufferLength; //length of actual data in a packet 174 | uint8_t txPacketChecksum[2]; //packet checksum as an array 175 | 176 | //receive packet parameters 177 | uint8_t rxPacketType; //type of packet 178 | uint16_t rxPacketLengthL; //packet length long 179 | uint8_t rxConfirmationCode; //the return codes from the FPS 180 | uint16_t rxPacketChecksumL; //packet checksum long 181 | uint8_t rxPacketLength[2]; //packet length as an array 182 | uint8_t* rxDataBuffer; //packet data buffer 183 | uint32_t rxDataBufferLength; //the length of the data only. this doesn't include instruction or confirmation code 184 | uint8_t rxPacketChecksum[2]; //packet checksum as array 185 | 186 | uint16_t fingerId; //location of fingerprint in the library 187 | uint16_t matchScore; //the match score of comparison of two fingerprints 188 | uint16_t templateCount; //total number of fingerprint templates in the library 189 | 190 | void begin (uint32_t baud); //initializes the communication port 191 | void resetParameters (void); //initialize and reset and all parameters 192 | uint8_t verifyPassword (uint32_t password = FPS_DEFAULT_PASSWORD); //verify the user supplied password 193 | uint8_t setPassword (uint32_t password); //set FPS password 194 | uint8_t setAddress (uint32_t address = FPS_DEFAULT_ADDRESS); //set FPS address 195 | uint8_t setBaudrate (uint32_t baud); //set UART baudrate, default is 57000 196 | uint8_t reinitializePort (uint32_t baud); 197 | uint8_t setSecurityLevel (uint8_t level); //set the threshold for fingerprint matching 198 | uint8_t setDataLength (uint16_t length); //set the max length of data in a packet 199 | uint8_t portControl (uint8_t value); //turn the comm port on or off 200 | uint8_t sendPacket (uint8_t type, uint8_t command, uint8_t* data = NULL, uint16_t dataLength = 0); //assemble and send packets to FPS 201 | uint8_t receivePacket (uint32_t timeout=FPS_DEFAULT_TIMEOUT); //receive packet from FPS 202 | uint8_t readSysPara (void); //read FPS system configuration 203 | uint8_t captureAndRangeSearch (uint16_t captureTimeout, uint16_t startId, uint16_t count); //scan a finger and search a range of locations 204 | uint8_t captureAndFullSearch (void); //scan a finger and search the entire library 205 | uint8_t generateImage (void); //scan a finger, generate an image and store it in the buffer 206 | uint8_t exportImage (void); //export a fingerprint image from the sensor to the computer 207 | uint8_t importImage (uint8_t* dataBuffer); //import a fingerprint image from the computer to sensor 208 | uint8_t generateCharacter (uint8_t bufferId); //generate character file from image 209 | uint8_t generateTemplate (void); //combine the two character files and generate a single template 210 | uint8_t exportCharacter (uint8_t bufferId); //export a character file from the sensor to computer 211 | uint8_t importCharacter (uint8_t bufferId, uint8_t* dataBuffer); //import a character file to the sensor from computer 212 | uint8_t saveTemplate (uint8_t bufferId, uint16_t location); //store the template in the buffer to a location in the library 213 | uint8_t loadTemplate (uint8_t bufferId, uint16_t location); //load a template from library to one of the buffers 214 | uint8_t deleteTemplate (uint16_t startLocation, uint16_t count); //delete a set of templates from library 215 | uint8_t clearLibrary (void); //delete all templates from library 216 | uint8_t matchTemplates (void); //match the templates stored in the two character buffers 217 | uint8_t searchLibrary (uint8_t bufferId, uint16_t startLocation, uint16_t count); //search the library for a template stored in the buffer 218 | uint8_t getTemplateCount (void); //get the total no. of templates in the library 219 | 220 | private: 221 | 222 | Stream *mySerial; //stream class is used to facilitate communication 223 | 224 | #if defined(__AVR__) || defined(ESP8266) 225 | SoftwareSerial *swSerial; //for those devices with only one hardware UART 226 | #endif 227 | 228 | HardwareSerial *hwSerial; //for those devices with multiple hardware UARTs 229 | }; 230 | 231 | //=========================================================================// 232 | 233 | #endif 234 | 235 | //=========================================================================// -------------------------------------------------------------------------------- /examples/R30X-FPS-Test/R30X-FPS-Test.ino: -------------------------------------------------------------------------------- 1 | 2 | //=========================================================================// 3 | // 4 | // ## R30X Fingerprint Sensor Library Example-01 ## 5 | // 6 | // Filename : R30X_FPS_Test.ino 7 | // Description : Arduino compatible test program for Fingerprint_VMA 8 | // library for R30X series fingerprint sensors. 9 | // Library version : 1.3.1 10 | // Author : Vishnu M Aiea 11 | // Src : https://github.com/vishnumaiea/R30X-Fingerprint-Sensor-Library 12 | // Author's website : https://www.vishnumaiea.in 13 | // Initial release : IST 07:35 PM, 08-04-2019, Monday 14 | // License : MIT 15 | // 16 | // Last modified : +05:30 06:21:15 PM, 20-07-2020 Monday 17 | // 18 | //=========================================================================// 19 | // 20 | // Some tips and info. 21 | // 22 | // Example sketch was tested with Arduino Due and Uno. 23 | // Disable debug info by commenting out FPS_DEBUG line to save memory. 24 | // Strings are stored in flash memroy. 25 | // Use correct baud rate, device address and device passowrd. 26 | // Use software serial port if a second hardware port is not available 27 | // Not all boards support all baud rates. If the data you receive is 28 | // corrupted, then use a lower baud rate. 29 | // 30 | //=========================================================================// 31 | 32 | #include "R30X_FPS.h" 33 | 34 | 35 | //=========================================================================// 36 | //defines 37 | 38 | //add your fingerprint scanner's password and device address here 39 | #define FPS_PASSWORD 0xFFFFFFFF //default password and address is 0xFFFFFFFF 40 | #define FPS_ADDRESS 0xFFFFFFFF 41 | 42 | //=========================================================================// 43 | //initialize the object with the correct password and address 44 | //if you want to use the deafault values, pass nothing 45 | //Serial1, Serial2 etc are only available for Due and Mega. Pass SoftwareSerial object for Uno, Nano etc 46 | 47 | //------------------------------------------------------------------------// 48 | // # # # # # # Arduino Due 49 | // R30X_FPS fps = R30X_FPS (&Serial1, FPS_PASSWORD, FPS_ADDRESS); //custom password and address 50 | // R30X_FPS fps = R30X_FPS (&Serial1); //use deafault password and address 51 | 52 | //------------------------------------------------------------------------// 53 | // # # # # # Arduino Uno 54 | SoftwareSerial Serial1(2, 3); //RX, TX 55 | R30X_FPS fps = R30X_FPS (&Serial1, FPS_PASSWORD, FPS_ADDRESS); //custom password and address 56 | // R30X_FPS fps = R30X_FPS (&Serial1); //use deafault password and address 57 | 58 | //========================================================================// 59 | //this implements the fingerprint enrolling process 60 | //simply send the location of where you want to save the new fingerprint. 61 | //the location can be from #1 to #1000 62 | //the library location actually starts at 0, but I have made it to 1 to avoid confusion 63 | //therefore a 1 will be substracted from your location automatically 64 | //The finger needs to be scanend twice at steps #1 and #2 65 | 66 | uint8_t enrollFinger(uint16_t location) { 67 | //enroll new fingerprint 68 | debugPort.println(F("=========================")); 69 | debugPort.println(F("Enrolling New Fingerprint")); 70 | debugPort.println(F("=========================")); 71 | 72 | if((location > 1000) || (location < 1)) { //if not in range (1-1000) 73 | debugPort.println(); 74 | debugPort.println(F("Enrolling failed.")); 75 | debugPort.println(F("Bad location.")); 76 | debugPort.print(F("location = #")); 77 | debugPort.println(location); 78 | debugPort.println(F("Please try again.")); 79 | return 1; 80 | } 81 | 82 | delay(4000); 83 | debugPort.println(); 84 | debugPort.println(F("Scan #1: Please put your finger on the sensor.")); 85 | debugPort.println(); 86 | delay(5000); 87 | 88 | uint8_t response = fps.generateImage(); //scan the finger 89 | 90 | if(response != 0) { 91 | debugPort.println(F("Scan #1: ERROR - Scanning failed. Please try again.")); 92 | } 93 | else { 94 | debugPort.println(F("Scan #1: Scanning success.")); 95 | debugPort.println(); 96 | delay(2000); 97 | response = fps.generateCharacter(1); //generate the character file from image and save to buffer 1 98 | 99 | if(response != 0) { 100 | debugPort.println(F("Scan #1: ERROR - Template generation failed. Please try again.")); 101 | } 102 | else { 103 | debugPort.println(); 104 | debugPort.println(F("Scan #1: Template generation success.")); 105 | delay(2000); 106 | 107 | debugPort.println(F("Scan #2: Please put your finger on the sensor.")); 108 | delay(5000); 109 | 110 | debugPort.println(); 111 | response = fps.generateImage(); //scan the finger for second time 112 | 113 | if(response != 0) { 114 | debugPort.println(F("Scan #2: ERROR - Scanning failed. Please try again.")); 115 | } 116 | else { 117 | debugPort.println(); 118 | debugPort.println(F("Scan #2: Scanning success.")); 119 | delay(2000); 120 | response = fps.generateCharacter(2); //generate the character file from image and save to buffer 2 121 | 122 | if(response != 0) { 123 | debugPort.println(F("Scan #2: Template generation failed. Please try again.")); 124 | } 125 | else { 126 | debugPort.println(); 127 | response = fps.generateTemplate(); //combine the two buffers and generate a template 128 | 129 | if(response == 0) { 130 | debugPort.println(); 131 | response = fps.saveTemplate(1, location); //save the template to the specified location in library 132 | 133 | if(response == 0) { 134 | debugPort.print(F("-- Fingerprint enrolled at ID #")); 135 | debugPort.print(location); 136 | debugPort.println(F(" successfully --")); 137 | } 138 | } 139 | else if(response == FPS_RESP_ENROLLMISMATCH) { 140 | debugPort.println(F("ERROR : Fingerprints do not belong to same finger. Please try again.")); 141 | } 142 | } 143 | } 144 | } 145 | } 146 | 147 | debugPort.println(); 148 | } 149 | 150 | //=========================================================================// 151 | //Arduino setup function 152 | 153 | void setup() { 154 | //not all boards support all baud rates 155 | //check your board's documentation for more info 156 | Serial.begin(115200); 157 | fps.begin(57600); 158 | 159 | Serial.println(); 160 | Serial.println(F("R30X Fingerprint Example Sketch")); 161 | Serial.println(F("===============================")); 162 | Serial.println(F("Source : https://github.com/vishnumaiea/R30X-Fingerprint-Sensor-Library")); 163 | Serial.println(F("All commands and parameters must be separated by single whitespace.")); 164 | Serial.println(); 165 | 166 | //fps.portControl(0); 167 | 168 | //you need to verify the password before you can do anything else 169 | Serial.print(F("Verifying password 0x")); 170 | Serial.println(FPS_PASSWORD, HEX); 171 | uint8_t response = fps.verifyPassword(FPS_PASSWORD); 172 | //uint8_t response = fps.verifyPassword(); 173 | //uint8_t response = 1; 174 | 175 | if(response == 0) { 176 | #if !defined(FPS_DEBUG) 177 | Serial.println(F("Successful\n")); 178 | #else 179 | Serial.println(); 180 | #endif 181 | } 182 | else { 183 | Serial.println(F("Failed. Check your password. Otherwise try with default one.\n")); 184 | } 185 | 186 | Serial.println(F("----- COMMANDS -----")); 187 | Serial.println(F("clrlib - clear library")); 188 | Serial.println(F("tmpcnt - get templates count")); 189 | Serial.println(F("readsys - read system parameters")); 190 | Serial.println(F("setdatlen - set data length")); 191 | Serial.println(F("capranser - capture and range search library for fingerprint")); 192 | Serial.println(F("capfulser - capture and full search the library for fingerprint")); 193 | Serial.println(F("enroll - enroll new fingerprint")); 194 | Serial.println(F("verpwd - verify 4 byte device password")); 195 | Serial.println(F("setpwd - set new 4 byte device password")); 196 | Serial.println(F("setaddr
- set new 4 byte device address")); 197 | Serial.println(F("setbaud - set the baudrate")); 198 | Serial.println(F("reinitprt - reinitialize the port without changing device configuration")); 199 | Serial.println(F("setseclvl - set security level")); 200 | Serial.println(F("genimg - generate image")); 201 | Serial.println(F("genchar - generate character file from image")); 202 | Serial.println(F("gentmp - generate template from character buffers")); 203 | Serial.println(F("savtmp - save template to library from buffer")); 204 | Serial.println(F("lodtmp - load template from library to buffer")); 205 | Serial.println(F("deltmp - delete one or more templates from library")); 206 | Serial.println(F("mattmp - precisely match two templates available on buffers")); 207 | Serial.println(F("serlib - search library for content on the buffer")); 208 | Serial.println(F("")); 209 | 210 | //this is optional 211 | // Serial.println(F("Setting new address..")); 212 | // response = fps.setAddress(0xFFFFFFFF); 213 | // Serial.println(); 214 | } 215 | 216 | //=========================================================================// 217 | //infinite loop 218 | 219 | void loop() { 220 | 221 | uint8_t response = 0; 222 | String inputString = ""; 223 | String commandString = ""; 224 | String firstParam = ""; 225 | String secondParam = ""; 226 | String thirdParam = ""; 227 | 228 | //send commands and parameters for each operation 229 | //items are separated by single whitespace 230 | //you can send up to 3 parameters 231 | if(Serial.available()) { //monitor the serial interface 232 | inputString = Serial.readString(); //read the contents of serial buffer as string 233 | Serial.print(F("Command : ")); 234 | Serial.println(inputString); 235 | // Serial.println(); 236 | 237 | //-------------------------------------------------------------------------// 238 | 239 | uint8_t posCount = 0; 240 | int indexOfSpace = 0; 241 | 242 | while(inputString.indexOf(" ") != -1) { //loop until all whitespace chars are found 243 | indexOfSpace = inputString.indexOf(" "); //get the position of first whitespace 244 | if(indexOfSpace != -1) { //if a whitespace is found 245 | if(posCount == 0) //the first one will be command string 246 | commandString = inputString.substring(0, indexOfSpace); //end char is exclusive 247 | if(posCount == 1) //second will be second param 248 | firstParam = inputString.substring(0, indexOfSpace); 249 | if(posCount == 2) //and so on 250 | secondParam = inputString.substring(0, indexOfSpace); 251 | else if(posCount == 3) 252 | thirdParam = inputString.substring(0, indexOfSpace); 253 | inputString = inputString.substring(indexOfSpace+1); //trim the input string 254 | posCount++; 255 | } 256 | } 257 | 258 | //saves the last part of the string is no more whitespace is found 259 | if(posCount == 0) //if there's just the command 260 | commandString = inputString; 261 | if(posCount == 1) 262 | firstParam = inputString; 263 | if(posCount == 2) 264 | secondParam = inputString; 265 | if(posCount == 3) 266 | thirdParam = inputString; 267 | 268 | //-------------------------------------------------------------------------// 269 | //separate and print the received command and parameters 270 | 271 | Serial.print(F("Command string = ")); 272 | Serial.println(commandString); 273 | 274 | if(firstParam != "") { 275 | Serial.print(F("First param = ")); 276 | Serial.println(firstParam); 277 | } 278 | if(secondParam != "") { 279 | Serial.print(F("Second param = ")); 280 | Serial.println(secondParam); 281 | } 282 | if(thirdParam != "") { 283 | Serial.print(F("Third param = ")); 284 | Serial.println(thirdParam); 285 | } 286 | 287 | Serial.println(); 288 | 289 | //-------------------------------------------------------------------------// 290 | //deletes all the templates in the library 291 | //this command has no parameters 292 | //eg. clrlib 293 | 294 | if(commandString == "clrlib") { 295 | response = fps.clearLibrary(); 296 | } 297 | 298 | //-------------------------------------------------------------------------// 299 | //get templates count 300 | //eg. tmpcnt 301 | 302 | else if(commandString == "tmpcnt") { 303 | Serial.println(F("Reading templates count..")); 304 | response = fps.getTemplateCount(); 305 | } 306 | 307 | //-------------------------------------------------------------------------// 308 | //read system parameters 309 | //eg. readsys 310 | 311 | else if(commandString == "readsys") { 312 | response = fps.readSysPara(); 313 | } 314 | 315 | //-------------------------------------------------------------------------// 316 | //set data length 317 | //this command has a single parameter 318 | //value should be 32, 64, 128 or 256 319 | //eg. setdatlen 256 320 | 321 | else if(commandString == "setdatlen") { 322 | uint16_t length = firstParam.toInt(); 323 | response = fps.setDataLength(length); 324 | } 325 | 326 | //-------------------------------------------------------------------------// 327 | //capture and range search library 328 | //this command has three parameters 329 | //eg. capranser 3000 1 10 330 | 331 | else if(commandString == "capranser") { 332 | uint16_t timeOut = firstParam.toInt(); //first parameter in milliseconds 333 | uint16_t startLocation = secondParam.toInt(); //second parameter 334 | uint16_t count = thirdParam.toInt(); //third parameter 335 | Serial.println(F("Capture and range search fingerprint..")); 336 | delay(1000); 337 | Serial.println(F("Put your finger on the sensor..")); 338 | delay(3000); 339 | response = fps.captureAndRangeSearch(timeOut, startLocation, count); 340 | } 341 | 342 | //-------------------------------------------------------------------------// 343 | //capture and full search library 344 | //eg. capfulser 345 | 346 | else if(commandString == "capfulser") { 347 | Serial.println(F("Capture and full search fingerprint..")); 348 | delay(1000); 349 | Serial.println(F("Put your finger on the sensor..")); 350 | delay(3000); 351 | response = fps.captureAndFullSearch(); 352 | } 353 | 354 | //-------------------------------------------------------------------------// 355 | //enroll a new fingerprint 356 | //you need to scan the finger twice 357 | //follow the on-screen instructions 358 | //eg. enroll 359 | 360 | else if(commandString == "enroll") { 361 | uint16_t location = firstParam.toInt(); //converts String object to int 362 | enrollFinger(location); 363 | } 364 | 365 | //-------------------------------------------------------------------------// 366 | //verify 4 byte password 367 | //password should be sent as hex string 368 | //eg. verpwd FF16FF16 369 | 370 | else if(commandString == "verpwd") { 371 | const char* hexString = firstParam.c_str(); //convert String object to C-style string 372 | uint32_t password = strtoul(hexString, NULL, 16); //convert hex formatted C-style string to int value 373 | response = fps.verifyPassword(password); 374 | } 375 | 376 | //-------------------------------------------------------------------------// 377 | //set 4 byte password sent in hex format 378 | //password should be sent as hex string 379 | //eg. setpwd FF16FF16 380 | 381 | else if(commandString == "setpwd") { 382 | const char* hexString = firstParam.c_str(); //convert String object to C-style string 383 | uint32_t password = strtoul(hexString, NULL, 16); //convert hex formatted C-style string to int value 384 | response = fps.setPassword(password); 385 | } 386 | 387 | //-------------------------------------------------------------------------// 388 | //set 4 byte address sent in hex format 389 | //address should be sent as hex string 390 | //eg. setaddr FF16FF16 391 | 392 | else if(commandString == "setaddr") { 393 | const char *hexString = firstParam.c_str(); //convert String object to C-style string 394 | uint32_t address = strtoul(hexString, NULL, 16); //convert hex formatted C-style string to int value 395 | response = fps.setAddress(address); 396 | } 397 | 398 | //-------------------------------------------------------------------------// 399 | //set baudrate 400 | //baudrate must be integer multiple of 96000. max is 115200 401 | //eg. setbaud 115200 402 | 403 | else if(commandString == "setbaud") { 404 | uint32_t baudrate = firstParam.toInt(); 405 | response = fps.setBaudrate(baudrate); 406 | } 407 | 408 | //-------------------------------------------------------------------------// 409 | //set baudrate 410 | //baudrate must be integer multiple of 96000. max is 115200 411 | //eg. setbaud 115200 412 | 413 | else if(commandString == "reinitprt") { 414 | uint32_t baudrate = firstParam.toInt(); 415 | fps.reinitializePort(baudrate); 416 | Serial.println(F("No change in device configuration.")); 417 | } 418 | 419 | //-------------------------------------------------------------------------// 420 | //set security level 421 | //security level value must be 1-5 422 | //deafault is usually 2 423 | //eg. setseclvl 4 424 | 425 | else if(commandString == "setseclvl") { 426 | uint8_t level = firstParam.toInt(); 427 | response = fps.setSecurityLevel(level); 428 | } 429 | 430 | //-------------------------------------------------------------------------// 431 | //scan finger image and save to image buffer 432 | //eg. genimg 433 | 434 | else if(commandString == "genimg") { 435 | response = fps.generateImage(); 436 | } 437 | 438 | //-------------------------------------------------------------------------// 439 | //generate character file from image 440 | //buffer Id should be 1 or 2 441 | //eg. genchar 1 442 | 443 | else if(commandString == "genchar") { 444 | uint8_t bufferId = firstParam.toInt(); 445 | response = fps.generateCharacter(bufferId); 446 | } 447 | 448 | //-------------------------------------------------------------------------// 449 | //generate template from char buffers 450 | //template is the digital format of a fingerprint 451 | //generated template will be available on both buffers 1 and 2 452 | //eg. gentmp 453 | 454 | else if(commandString == "gentmp") { 455 | response = fps.generateTemplate(); 456 | } 457 | 458 | //-------------------------------------------------------------------------// 459 | //save template on buffer to library 460 | //buffer ID should be 1 or 2 461 | //location should be #1 - #10000 (don't send the "#" with command) 462 | //eg. savtmp 1 32 463 | 464 | else if(commandString == "savtmp") { 465 | uint8_t bufferId = firstParam.toInt(); 466 | uint16_t location = secondParam.toInt(); 467 | response = fps.saveTemplate(bufferId, location); 468 | } 469 | 470 | //-------------------------------------------------------------------------// 471 | //load template from library to buffer 1 or 2 472 | //buffer ID should be 1 or 2 473 | //location should be #1 - #10000 (don't send the "#" with command) 474 | //eg. lodtmp 1 32 475 | 476 | else if(commandString == "lodtmp") { 477 | uint8_t bufferId = firstParam.toInt(); 478 | uint16_t location = secondParam.toInt(); 479 | response = fps.loadTemplate(bufferId, location); 480 | } 481 | 482 | //-------------------------------------------------------------------------// 483 | //delete one or more templates from library 484 | //to delete a single template, simply send 1 as quantity or count 485 | //eg. deltmp 5 1 486 | 487 | else if(commandString == "deltmp") { 488 | uint16_t startLocation = firstParam.toInt(); //start location in library 489 | uint16_t count = secondParam.toInt(); //quantity to delete 490 | response = fps.deleteTemplate(startLocation, count); 491 | } 492 | 493 | //-------------------------------------------------------------------------// 494 | //precisely match templates on the buffers 1 and 2 495 | //returns match score (matchScore) 496 | //eg. mattmp 497 | 498 | else if(commandString == "mattmp") { 499 | response = fps.matchTemplates(); 500 | } 501 | 502 | //-------------------------------------------------------------------------// 503 | //search the library for content on the buffer 504 | //buffer ID should be 1 or 2 505 | //start location cane be #1 to #1000 (don't send the "#" with command) 506 | //eg. serlib 1 10 50 507 | 508 | else if(commandString == "serlib") { 509 | uint8_t bufferId = firstParam.toInt(); 510 | uint16_t startLocation = secondParam.toInt(); 511 | uint16_t count = thirdParam.toInt(); 512 | response = fps.searchLibrary(bufferId, startLocation, count); 513 | } 514 | 515 | //-------------------------------------------------------------------------// 516 | //unknown command 517 | 518 | else { 519 | Serial.print(F("Invalid command : ")); 520 | Serial.println(commandString); 521 | } 522 | 523 | //if (response) { 524 | // Serial.print("response == "); 525 | // Serial.println(response); 526 | //} 527 | 528 | Serial.println(F("\n.......END OF OPERATION.......\n")); 529 | delay(2000); 530 | } 531 | } 532 | 533 | //=========================================================================// 534 | -------------------------------------------------------------------------------- /src/R30X_FPS.cpp: -------------------------------------------------------------------------------- 1 | 2 | //=========================================================================// 3 | // // 4 | // ## R30X Fingerprint Sensor Library ## // 5 | // // 6 | // Filename : R30X_FPS.cpp // 7 | // Description : CPP file for R30X_FPS library for R30X series // 8 | // fingerprint sensors. // 9 | // Library version : 1.3.1 // 10 | // Author : Vishnu M Aiea // 11 | // Src : https://github.com/vishnumaiea/R30X-Fingerprint-Sensor-Library // 12 | // Author's website : https://www.vishnumaiea.in // 13 | // Initial release : IST 07:35 PM, 08-04-2019, Monday // 14 | // License : MIT // 15 | // // 16 | // Last modified : +05:30 06:10:01 PM, 20-07-2020 Monday 17 | // // 18 | //=========================================================================// 19 | 20 | #include "R30X_FPS.h" 21 | 22 | //=========================================================================// 23 | //constructor for SoftwareSerial interface 24 | 25 | #if defined(__AVR__) || defined(ESP8266) 26 | R30X_FPS::R30X_FPS (SoftwareSerial *ss, uint32_t password, uint32_t address) { 27 | hwSerial = NULL; //set to null since we won't be using hardware serial 28 | swSerial = ss; 29 | mySerial = swSerial; //will be working with sw serial 30 | 31 | //storing 32-bit values as 8-bit values in arrays can make many operations easier later 32 | devicePassword[0] = password & 0xFFU; 33 | devicePassword[1] = (password >> 8) & 0xFFU; 34 | devicePassword[2] = (password >> 16) & 0xFFU; 35 | devicePassword[3] = (password >> 24) & 0xFFU; 36 | devicePasswordL = password; 37 | 38 | deviceAddress[0] = address & 0xFFU; 39 | deviceAddress[1] = (address >> 8) & 0xFFU; 40 | deviceAddress[2] = (address >> 16) & 0xFFU; 41 | deviceAddress[3] = (address >> 24) & 0xFFU; 42 | deviceAddressL = address; 43 | 44 | startCode[0] = FPS_ID_STARTCODE & 0xFFU; //packet start marker 45 | startCode[1] = (FPS_ID_STARTCODE >> 8) & 0xFFU; 46 | 47 | resetParameters(); //initialize and reset and all parameters 48 | } 49 | #endif 50 | 51 | //=========================================================================// 52 | //constructor for hardware serial interface 53 | 54 | R30X_FPS::R30X_FPS (HardwareSerial *hs, uint32_t password, uint32_t address) { 55 | #if defined(__AVR__) || defined(ESP8266) 56 | swSerial = NULL; 57 | #endif 58 | hwSerial = hs; 59 | mySerial = hwSerial; 60 | 61 | //storing 32-bit values as 8-bit values in arrays can make many operations easier later 62 | devicePassword[0] = password & 0xFFU; //these can be altered later 63 | devicePassword[1] = (password >> 8) & 0xFFU; 64 | devicePassword[2] = (password >> 16) & 0xFFU; 65 | devicePassword[3] = (password >> 24) & 0xFFU; 66 | devicePasswordL = password; 67 | 68 | deviceAddress[0] = address & 0xFFU; 69 | deviceAddress[1] = (address >> 8) & 0xFFU; 70 | deviceAddress[2] = (address >> 16) & 0xFFU; 71 | deviceAddress[3] = (address >> 24) & 0xFFU; 72 | deviceAddressL = address; 73 | 74 | startCode[0] = FPS_ID_STARTCODE & 0xFFU; //packet start marker 75 | startCode[1] = (FPS_ID_STARTCODE >> 8) & 0xFFU; 76 | 77 | resetParameters(); //initialize and reset and all parameters 78 | } 79 | 80 | //=========================================================================// 81 | //initializes the serial port 82 | //the baudrate received here will override the default one 83 | 84 | void R30X_FPS::begin (uint32_t baudrate) { 85 | delay(1000); //one second delay to let the sensor 'boot up' 86 | 87 | deviceBaudrate = baudrate; //save the new baudrate 88 | 89 | if (hwSerial) hwSerial->begin(baudrate); 90 | 91 | #if defined(__AVR__) || defined(ESP8266) 92 | if (swSerial) swSerial->begin(baudrate); 93 | #endif 94 | } 95 | 96 | //=========================================================================// 97 | //reset some parameters 98 | 99 | void R30X_FPS::resetParameters (void) { 100 | deviceBaudrate = FPS_DEFAULT_BAUDRATE; //this will be later altered by begin() 101 | baudMultiplier = uint16_t(FPS_DEFAULT_BAUDRATE / 9600); 102 | securityLevel = FPS_DEFAULT_SECURITY_LEVEL; //threshold level for fingerprint matching 103 | dataPacketLength = FPS_DEFAULT_RX_DATA_LENGTH; 104 | librarySize = 1000; 105 | systemID = 0; 106 | 107 | txPacketType = FPS_ID_COMMANDPACKET; //type of packet 108 | txInstructionCode = FPS_CMD_VERIFYPASSWORD; // 109 | txPacketLength[0] = 0; 110 | txPacketLength[1] = 0; 111 | txPacketLengthL = 0; 112 | txDataBuffer = NULL; //packet data buffer 113 | txDataBufferLength = 0; 114 | txPacketChecksum[0] = 0; 115 | txPacketChecksum[1] = 0; 116 | txPacketChecksumL = 0; 117 | 118 | rxPacketType = FPS_ID_COMMANDPACKET; //type of packet 119 | rxConfirmationCode = FPS_CMD_VERIFYPASSWORD; // 120 | rxPacketLength[0] = 0; 121 | rxPacketLength[1] = 0; 122 | rxPacketLengthL = 0; 123 | rxDataBuffer = NULL; //packet data buffer 124 | rxDataBufferLength = 0; 125 | rxPacketChecksum[0] = 0; 126 | rxPacketChecksum[1] = 0; 127 | rxPacketChecksumL = 0; 128 | 129 | fingerId = 0; //initialize them 130 | matchScore = 0; 131 | templateCount = 0; 132 | } 133 | 134 | //=========================================================================// 135 | //send a data packet to the FPS (fingerprint scanner) 136 | 137 | uint8_t R30X_FPS::sendPacket (uint8_t type, uint8_t command, uint8_t* data, uint16_t dataLength) { 138 | if(data != NULL) { //sometimes there's no additional data except the command 139 | txDataBuffer = data; 140 | txDataBufferLength = dataLength; 141 | } 142 | else { 143 | txDataBuffer = NULL; 144 | txDataBufferLength = 0; 145 | } 146 | 147 | txPacketType = type; //type of packet - 1 byte 148 | txInstructionCode = command; //instruction code - 1 byte 149 | txPacketLengthL = txDataBufferLength + 3; //1 byte for command, 2 bytes for checksum 150 | txPacketLength[0] = txPacketLengthL & 0xFFU; //get lower byte 151 | txPacketLength[1] = (txPacketLengthL >> 8) & 0xFFU; //get high byte 152 | 153 | txPacketChecksumL = txPacketType + txPacketLength[0] + txPacketLength[1] + txInstructionCode; //sum of packet ID and packet length bytes 154 | 155 | for(int i=0; i> 8) & 0xFFU; //get high byte 161 | 162 | mySerial->write(startCode[1]); //high byte is sent first 163 | mySerial->write(startCode[0]); 164 | mySerial->write(deviceAddress[3]); //high byte is sent first 165 | mySerial->write(deviceAddress[2]); 166 | mySerial->write(deviceAddress[1]); 167 | mySerial->write(deviceAddress[0]); 168 | mySerial->write(txPacketType); 169 | mySerial->write(txPacketLength[1]); //high byte is sent first 170 | mySerial->write(txPacketLength[0]); 171 | mySerial->write(txInstructionCode); 172 | 173 | for(int i=(txDataBufferLength-1); i>=0; i--) { 174 | mySerial->write(txDataBuffer[i]); //send high byte first 175 | } 176 | 177 | mySerial->write(txPacketChecksum[1]); 178 | mySerial->write(txPacketChecksum[0]); 179 | 180 | #ifdef FPS_DEBUG 181 | debugPort.print(F("Sent packet = ")); 182 | debugPort.print(startCode[1], HEX); //high byte is sent first 183 | debugPort.print(F("-")); 184 | debugPort.print(startCode[0], HEX); 185 | debugPort.print(F("-")); 186 | debugPort.print(deviceAddress[3], HEX); //high byte is sent first 187 | debugPort.print(F("-")); 188 | debugPort.print(deviceAddress[2], HEX); 189 | debugPort.print(F("-")); 190 | debugPort.print(deviceAddress[1], HEX); 191 | debugPort.print(F("-")); 192 | debugPort.print(deviceAddress[0], HEX); 193 | debugPort.print(F("-")); 194 | debugPort.print(txPacketType, HEX); 195 | debugPort.print(F("-")); 196 | debugPort.print(txPacketLength[1], HEX); //high byte is sent first 197 | debugPort.print(F("-")); 198 | debugPort.print(txPacketLength[0], HEX); 199 | debugPort.print(F("-")); 200 | debugPort.print(txInstructionCode, HEX); 201 | debugPort.print(F("-")); 202 | 203 | for(int i=(txDataBufferLength-1); i>=0; i--) { 204 | debugPort.print(txDataBuffer[i], HEX); //send high byte first 205 | debugPort.print(F("-")); 206 | } 207 | 208 | debugPort.print(txPacketChecksum[1], HEX); 209 | debugPort.print(F("-")); 210 | debugPort.print(txPacketChecksum[0], HEX); 211 | debugPort.println(); 212 | debugPort.print(F("txInstructionCode = ")); 213 | debugPort.println(txInstructionCode, HEX); 214 | debugPort.print(F("txDataBufferLength = ")); 215 | debugPort.println(txDataBufferLength, HEX); 216 | debugPort.print(F("txPacketLengthL = ")); 217 | debugPort.println(txPacketLengthL); 218 | // debugPort.print(F("rxPacketLength[] = ")); 219 | // debugPort.print(rxPacketLength[1], HEX); 220 | // debugPort.print(F("-")); 221 | // debugPort.println(rxPacketLength[0], HEX); 222 | #endif 223 | 224 | return FPS_RX_OK; 225 | } 226 | 227 | //=========================================================================// 228 | //receive a data packet from the FPS and extract values 229 | 230 | uint8_t R30X_FPS::receivePacket (uint32_t timeout) { 231 | uint8_t* dataBuffer; 232 | if(dataPacketLength < 64) { //data buffer length should be at least 64 bytes 233 | dataBuffer = new uint8_t[64](); //this contains only the data 234 | } 235 | else { 236 | dataBuffer = new uint8_t[FPS_DEFAULT_RX_DATA_LENGTH](); 237 | } 238 | 239 | rxDataBuffer = dataBuffer; 240 | uint8_t serialBuffer[FPS_DEFAULT_SERIAL_BUFFER_LENGTH] = {0}; //serialBuffer will store high byte at the start of the array 241 | uint16_t serialBufferLength = 0; 242 | uint8_t byteBuffer = 0; 243 | 244 | #ifdef FPS_DEBUG 245 | debugPort.println(); 246 | debugPort.println(F("Reading response.")); 247 | #endif 248 | 249 | //wait for message for a specific period 250 | while (timeout > 0) { 251 | if(mySerial->available()) { 252 | byteBuffer = mySerial->read(); 253 | #ifdef FPS_DEBUG 254 | // debugPort.print(F("Response byte found = ")); 255 | // debugPort.println(byteBuffer, HEX); 256 | #endif 257 | serialBuffer[serialBufferLength] = byteBuffer; 258 | serialBufferLength++; 259 | } 260 | 261 | timeout--; 262 | delay(1); 263 | } 264 | 265 | if(serialBufferLength == 0) { 266 | #ifdef FPS_DEBUG 267 | debugPort.println(F("Serial timed out.")); 268 | debugPort.println(F("This usually means the baud rate is not correct or the scanner has no power.")); 269 | #endif 270 | return FPS_RX_TIMEOUT; 271 | } 272 | 273 | if(serialBufferLength < 10) { 274 | #ifdef FPS_DEBUG 275 | debugPort.println(F("Received bad packet with length < 10")); 276 | #endif 277 | return FPS_RX_BADPACKET; 278 | } 279 | 280 | uint16_t token = 0; //a position counter/indicator 281 | 282 | //the following loop checks each segments of the data packet for errors, and retrieve the correct ones 283 | while(true) { 284 | switch (token) { 285 | case 0: //test packet start codes 286 | if(serialBuffer[token] == startCode[1]) 287 | break; 288 | else { 289 | #ifdef FPS_DEBUG //enable it to get debug info 290 | debugPort.println(F("Error at 0 : Start Code")); 291 | debugPort.print(F("Received packet = ")); 292 | for(int i=0; i < serialBufferLength; i++) { 293 | debugPort.print(serialBuffer[i], HEX); 294 | if(i != (serialBufferLength - 1)) { 295 | debugPort.print(F("-")); 296 | } 297 | } 298 | debugPort.println(); 299 | #endif 300 | 301 | return FPS_RX_BADPACKET; 302 | } 303 | 304 | case 1: 305 | if(serialBuffer[token] == startCode[0]) 306 | break; 307 | else { 308 | #ifdef FPS_DEBUG 309 | debugPort.println(F("Error at 1 : Start Code")); 310 | debugPort.print(F("Received packet = ")); 311 | for(int i=0; i < serialBufferLength; i++) { 312 | debugPort.print(serialBuffer[i], HEX); 313 | if(i != (serialBufferLength - 1)) { 314 | debugPort.print(F("-")); 315 | } 316 | } 317 | debugPort.println(); 318 | #endif 319 | 320 | return FPS_RX_BADPACKET; 321 | } 322 | 323 | case 2: //test device address 324 | if(serialBuffer[token] == deviceAddress[3]) 325 | break; 326 | else { 327 | #ifdef FPS_DEBUG 328 | debugPort.println(F("Error at 2 : Device Address")); 329 | debugPort.print(F("Received packet = ")); 330 | for(int i=0; i < serialBufferLength; i++) { 331 | debugPort.print(serialBuffer[i], HEX); 332 | if(i != (serialBufferLength - 1)) { 333 | debugPort.print(F("-")); 334 | } 335 | } 336 | debugPort.println(); 337 | #endif 338 | 339 | return FPS_RX_BADPACKET; 340 | } 341 | 342 | case 3: 343 | if(serialBuffer[token] == deviceAddress[2]) 344 | break; 345 | else { 346 | #ifdef FPS_DEBUG 347 | debugPort.println(F("Error at 3 : Device Address")); 348 | debugPort.print(F("Received packet = ")); 349 | for(int i=0; i < serialBufferLength; i++) { 350 | debugPort.print(serialBuffer[i], HEX); 351 | if(i != (serialBufferLength - 1)) { 352 | debugPort.print(F("-")); 353 | } 354 | } 355 | debugPort.println(); 356 | #endif 357 | 358 | return FPS_RX_BADPACKET; 359 | } 360 | 361 | case 4: 362 | if(serialBuffer[token] == deviceAddress[1]) 363 | break; 364 | else { 365 | #ifdef FPS_DEBUG 366 | debugPort.println(F("Error at 4 : Device Address")); 367 | debugPort.print(F("Received packet = ")); 368 | for(int i=0; i < serialBufferLength; i++) { 369 | debugPort.print(serialBuffer[i], HEX); 370 | if(i != (serialBufferLength - 1)) { 371 | debugPort.print(F("-")); 372 | } 373 | } 374 | debugPort.println(); 375 | #endif 376 | 377 | return FPS_RX_BADPACKET; 378 | } 379 | 380 | case 5: 381 | if(serialBuffer[token] == deviceAddress[0]) 382 | break; 383 | else { 384 | #ifdef FPS_DEBUG 385 | debugPort.println(F("Error at 5 : Device Address")); 386 | debugPort.print(F("Received packet = ")); 387 | for(int i=0; i < serialBufferLength; i++) { 388 | debugPort.print(serialBuffer[i], HEX); 389 | if(i != (serialBufferLength - 1)) { 390 | debugPort.print(F("-")); 391 | } 392 | } 393 | debugPort.println(); 394 | #endif 395 | 396 | return FPS_RX_BADPACKET; 397 | } 398 | 399 | case 6: //test for valid packet type 400 | if((serialBuffer[token] == FPS_ID_COMMANDPACKET) || (serialBuffer[token] == FPS_ID_DATAPACKET) || (serialBuffer[token] == FPS_ID_ACKPACKET) || (serialBuffer[token] == FPS_ID_ENDDATAPACKET)) { 401 | rxPacketType = serialBuffer[token]; //store the packet ID to class variable 402 | break; 403 | } 404 | else { 405 | #ifdef FPS_DEBUG 406 | debugPort.println(F("Error at 6 : Unknown Response")); 407 | debugPort.print(F("Received packet = ")); 408 | for(int i=0; i < serialBufferLength; i++) { 409 | debugPort.print(serialBuffer[i], HEX); 410 | if(i != (serialBufferLength - 1)) { 411 | debugPort.print(F("-")); 412 | } 413 | } 414 | debugPort.println(); 415 | #endif 416 | 417 | return FPS_RX_WRONG_RESPONSE; 418 | } 419 | 420 | case 7: //read packet data length 421 | if((serialBuffer[token] > 0) || (serialBuffer[token + 1] > 0)) { 422 | rxPacketLength[0] = serialBuffer[token + 1]; //lower byte 423 | rxPacketLength[1] = serialBuffer[token]; //higher byte 424 | rxPacketLengthL = uint16_t(rxPacketLength[1] << 8) + rxPacketLength[0]; //calculate the full length value 425 | rxDataBufferLength = rxPacketLengthL - 3; //subtract 2 for checksum and 1 for command 426 | token++; //because we read one additional bytes here 427 | break; 428 | } 429 | 430 | else { 431 | #ifdef FPS_DEBUG 432 | debugPort.println(F("Error at 7 : Unknown Response")); 433 | debugPort.print(F("Received packet = ")); 434 | for(int i=0; i < serialBufferLength; i++) { 435 | debugPort.print(serialBuffer[i], HEX); 436 | if(i != (serialBufferLength - 1)) { 437 | debugPort.print(F("-")); 438 | } 439 | } 440 | debugPort.println(); 441 | #endif 442 | 443 | return FPS_RX_WRONG_RESPONSE; 444 | } 445 | 446 | case 9: //read confirmation or instruction code 447 | rxConfirmationCode = serialBuffer[token]; //the first byte of data will be either instruction or confirmation code 448 | break; 449 | 450 | case 10: //read data 451 | for(int i=0; i < rxDataBufferLength; i++) { 452 | rxDataBuffer[(rxDataBufferLength - 1) - i] = serialBuffer[token + i]; //store low values at start of the rxDataBuffer array 453 | } 454 | break; 455 | 456 | case 11: //read checksum 457 | if(rxDataBufferLength == 0) { //sometimes there's no data other than the confirmation code 458 | rxPacketChecksum[0] = serialBuffer[token]; //lower byte 459 | rxPacketChecksum[1] = serialBuffer[token - 1]; //high byte 460 | rxPacketChecksumL = uint16_t(rxPacketChecksum[1] << 8) + rxPacketChecksum[0]; //calculate L value 461 | 462 | uint16_t tempSum = 0; //temp checksum 463 | 464 | tempSum = rxPacketType + rxPacketLength[0] + rxPacketLength[1] + rxConfirmationCode; 465 | 466 | if(rxPacketChecksumL == tempSum) { //check if the calculated checksum matches the received one 467 | #ifdef FPS_DEBUG 468 | debugPort.println(F("Checksum matching successful.")); 469 | debugPort.print(F("Received = ")); 470 | debugPort.print(rxPacketChecksum[1], HEX); 471 | debugPort.print(F("-")); 472 | debugPort.println(rxPacketChecksum[0], HEX); 473 | debugPort.print(F("Received L = ")); 474 | debugPort.println(rxPacketChecksumL, HEX); 475 | debugPort.print(F("Calculated = ")); 476 | debugPort.print(byte(tempSum >> 8), HEX); 477 | debugPort.print(F("-")); 478 | debugPort.println(byte(tempSum & 0xFFU), HEX); 479 | debugPort.print(F("Calculated L = ")); 480 | debugPort.println(tempSum, HEX); 481 | debugPort.print(F("Received packet = ")); 482 | 483 | for(int i=0; i < serialBufferLength; i++) { 484 | debugPort.print(serialBuffer[i], HEX); 485 | if(i != (serialBufferLength - 1)) { 486 | debugPort.print(F("-")); 487 | } 488 | } 489 | debugPort.println(); 490 | debugPort.print(F("Data stream = none")); 491 | 492 | debugPort.println(); 493 | debugPort.print(F("rxConfirmationCode = ")); 494 | debugPort.println(rxConfirmationCode, HEX); 495 | debugPort.print(F("rxDataBufferLength = ")); 496 | debugPort.println(rxDataBufferLength, HEX); 497 | debugPort.print(F("rxPacketLengthL = ")); 498 | debugPort.println(rxPacketLengthL); 499 | debugPort.print(F("rxPacketLength[] = ")); 500 | debugPort.print(rxPacketLength[1], HEX); 501 | debugPort.print(F("-")); 502 | debugPort.println(rxPacketLength[0], HEX); 503 | debugPort.println(); 504 | #endif 505 | 506 | return FPS_RX_OK; //packet read success 507 | } 508 | 509 | else { //if the checksums do not match 510 | #ifdef FPS_DEBUG 511 | debugPort.println(F("Checksum matching failed.")); 512 | debugPort.print(F("Received = ")); 513 | debugPort.print(rxPacketChecksum[1], HEX); 514 | debugPort.print(F("-")); 515 | debugPort.println(rxPacketChecksum[0], HEX); 516 | debugPort.print(F("Received L = ")); 517 | debugPort.println(rxPacketChecksumL, HEX); 518 | debugPort.print(F("Calculated = ")); 519 | debugPort.print(byte(tempSum >> 8), HEX); 520 | debugPort.print(F("-")); 521 | debugPort.println(byte(tempSum & 0xFFU), HEX); 522 | debugPort.print(F("Calculated L = ")); 523 | debugPort.println(tempSum, HEX); 524 | debugPort.print(F("Received packet = ")); 525 | 526 | for(int i=0; i < serialBufferLength; i++) { 527 | debugPort.print(serialBuffer[i], HEX); 528 | if(i != (serialBufferLength - 1)) { 529 | debugPort.print(F("-")); 530 | } 531 | } 532 | debugPort.println(); 533 | debugPort.print(F("Data stream = none")); 534 | 535 | debugPort.println(); 536 | debugPort.print(F("rxConfirmationCode = ")); 537 | debugPort.println(rxConfirmationCode, HEX); 538 | debugPort.print(F("rxDataBufferLength = ")); 539 | debugPort.println(rxDataBufferLength, HEX); 540 | debugPort.print(F("rxPacketLengthL = ")); 541 | debugPort.println(rxPacketLengthL, HEX); 542 | debugPort.print(F("rxPacketLength[] = ")); 543 | debugPort.print(rxPacketLength[1], HEX); 544 | debugPort.print(F("-")); 545 | debugPort.println(rxPacketLength[0], HEX); 546 | debugPort.println(); 547 | #endif 548 | 549 | return FPS_RX_BADPACKET; //then that's an error 550 | } 551 | break; 552 | } 553 | 554 | //-------------------------------------------------------------------------// 555 | 556 | else if((serialBuffer[token + (rxDataBufferLength-1)] > 0) || ((serialBuffer[token + 1 + (rxDataBufferLength-1)] > 0))) { 557 | rxPacketChecksum[0] = serialBuffer[token + 1 + (rxDataBufferLength-1)]; //lower byte 558 | rxPacketChecksum[1] = serialBuffer[token + (rxDataBufferLength-1)]; //high byte 559 | rxPacketChecksumL = uint16_t(rxPacketChecksum[1] << 8) + rxPacketChecksum[0]; //calculate L value 560 | 561 | uint16_t tempSum = 0; //temp checksum 562 | 563 | tempSum = rxPacketType + rxPacketLength[0] + rxPacketLength[1] + rxConfirmationCode; 564 | 565 | for(int i=0; i < rxDataBufferLength; i++) { 566 | tempSum += rxDataBuffer[i]; //calculate data checksum 567 | } 568 | 569 | if(rxPacketChecksumL == tempSum) { //check if the calculated checksum matches the received one 570 | #ifdef FPS_DEBUG 571 | debugPort.println(F("Checksum matching successful.")); 572 | debugPort.print(F("Received = ")); 573 | debugPort.print(rxPacketChecksum[1], HEX); 574 | debugPort.print(F("-")); 575 | debugPort.println(rxPacketChecksum[0], HEX); 576 | debugPort.print(F("Received L = ")); 577 | debugPort.println(rxPacketChecksumL, HEX); 578 | debugPort.print(F("Calculated = ")); 579 | debugPort.print(byte(tempSum >> 8), HEX); 580 | debugPort.print(F("-")); 581 | debugPort.println(byte(tempSum & 0xFFU), HEX); 582 | debugPort.print(F("Calculated L = ")); 583 | debugPort.println(tempSum, HEX); 584 | debugPort.print(F("Received packet = ")); 585 | 586 | for(int i=0; i < serialBufferLength; i++) { 587 | debugPort.print(serialBuffer[i], HEX); 588 | if(i != (serialBufferLength - 1)) { 589 | debugPort.print(F("-")); 590 | } 591 | } 592 | debugPort.println(); 593 | debugPort.print(F("Data stream = ")); 594 | 595 | for(int i=0; i < rxDataBufferLength; i++) { 596 | debugPort.print(rxDataBuffer[(rxDataBufferLength-1) - i], HEX); 597 | if(i != (rxDataBufferLength - 1)) { 598 | debugPort.print(F("-")); 599 | } 600 | } 601 | 602 | debugPort.println(); 603 | debugPort.print(F("rxConfirmationCode = ")); 604 | debugPort.println(rxConfirmationCode, HEX); 605 | debugPort.print(F("rxDataBufferLength = ")); 606 | debugPort.println(rxDataBufferLength, HEX); 607 | debugPort.print(F("rxPacketLengthL = ")); 608 | debugPort.println(rxPacketLengthL, HEX); 609 | debugPort.print(F("rxPacketLength[] = ")); 610 | debugPort.print(rxPacketLength[1], HEX); 611 | debugPort.print(F("-")); 612 | debugPort.println(rxPacketLength[0], HEX); 613 | debugPort.println(); 614 | #endif 615 | 616 | return FPS_RX_OK; //packet read success 617 | } 618 | 619 | else { //if the checksums do not match 620 | #ifdef FPS_DEBUG 621 | debugPort.println(F("Checksum matching failed.")); 622 | debugPort.print(F("Received = ")); 623 | debugPort.print(rxPacketChecksum[1], HEX); 624 | debugPort.print(F("-")); 625 | debugPort.println(rxPacketChecksum[0], HEX); 626 | debugPort.print(F("Received L = ")); 627 | debugPort.println(rxPacketChecksumL, HEX); 628 | debugPort.print(F("Calculated = ")); 629 | debugPort.print(byte(tempSum >> 8), HEX); 630 | debugPort.print(F("-")); 631 | debugPort.println(byte(tempSum & 0xFFU), HEX); 632 | debugPort.print(F("Calculated L = ")); 633 | debugPort.println(tempSum, HEX); 634 | debugPort.print(F("Received packet = ")); 635 | 636 | for(int i=0; i < serialBufferLength; i++) { 637 | debugPort.print(serialBuffer[i], HEX); 638 | if(i != (serialBufferLength - 1)) { 639 | debugPort.print(F("-")); 640 | } 641 | } 642 | debugPort.println(); 643 | debugPort.print(F("Data stream = ")); 644 | 645 | for(int i=0; i < rxDataBufferLength; i++) { 646 | debugPort.print(rxDataBuffer[(rxDataBufferLength-1) - i], HEX); 647 | if(i != (rxDataBufferLength - 1)) { 648 | debugPort.print(F("-")); 649 | } 650 | } 651 | 652 | debugPort.println(); 653 | debugPort.print(F("rxConfirmationCode = ")); 654 | debugPort.println(rxConfirmationCode, HEX); 655 | debugPort.print(F("rxDataBufferLength = ")); 656 | debugPort.println(rxDataBufferLength, HEX); 657 | debugPort.print(F("rxPacketLengthL = ")); 658 | debugPort.println(rxPacketLengthL, HEX); 659 | debugPort.print(F("rxPacketLength[] = ")); 660 | debugPort.print(rxPacketLength[1], HEX); 661 | debugPort.print(F("-")); 662 | debugPort.println(rxPacketLength[0], HEX); 663 | debugPort.println(); 664 | #endif 665 | 666 | return FPS_RX_BADPACKET; //then that's an error 667 | } 668 | break; 669 | } 670 | 671 | //-------------------------------------------------------------------------// 672 | 673 | else { //if the checksum received is 0 674 | #ifdef FPS_DEBUG 675 | debugPort.println(F("Error at 12 : Checksum")); 676 | debugPort.print(F("Received packet = ")); 677 | for(int i=0; i < serialBufferLength; i++) { 678 | debugPort.print(serialBuffer[i], HEX); 679 | if(i != (serialBufferLength - 1)) { 680 | debugPort.print(F("-")); 681 | } 682 | } 683 | debugPort.println(); 684 | #endif 685 | 686 | return FPS_RX_BADPACKET; //that too an error 687 | } 688 | break; 689 | 690 | default: 691 | break; 692 | } 693 | token++; //increment to progressively scan the packet 694 | } 695 | } 696 | 697 | //=========================================================================// 698 | //verify if the password set by user is correct 699 | 700 | uint8_t R30X_FPS::verifyPassword (uint32_t inputPassword) { 701 | uint8_t inputPasswordBytes[4] = {0}; //to store the split password 702 | inputPasswordBytes[0] = inputPassword & 0xFFU; //save each bytes 703 | inputPasswordBytes[1] = (inputPassword >> 8) & 0xFFU; 704 | inputPasswordBytes[2] = (inputPassword >> 16) & 0xFFU; 705 | inputPasswordBytes[3] = (inputPassword >> 24) & 0xFFU; 706 | 707 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_VERIFYPASSWORD, inputPasswordBytes, 4); //send the command and data 708 | 709 | uint8_t response = receivePacket(); //read response 710 | if(response == FPS_RX_OK) { //if the response packet is valid 711 | if(rxConfirmationCode == FPS_RESP_OK) { 712 | //save the input password if it is correct 713 | //this is actually redundant, but can make sure the right password is available to execute further commands 714 | devicePasswordL = inputPassword; 715 | devicePassword[0] = inputPasswordBytes[0]; //save the new password as array 716 | devicePassword[1] = inputPasswordBytes[1]; 717 | devicePassword[2] = inputPasswordBytes[2]; 718 | devicePassword[3] = inputPasswordBytes[3]; 719 | 720 | #ifdef FPS_DEBUG 721 | debugPort.println(F("Password is correct.")); 722 | debugPort.print(F("Current Password = ")); 723 | debugPort.println(devicePasswordL, HEX); 724 | #endif 725 | 726 | return FPS_RESP_OK; //password is correct 727 | } 728 | else { 729 | #ifdef FPS_DEBUG 730 | debugPort.println(F("Password is not correct.")); 731 | debugPort.print(F("Tested Password = ")); 732 | debugPort.println(inputPassword, HEX); 733 | debugPort.print(F("rxConfirmationCode = ")); 734 | debugPort.println(rxConfirmationCode, HEX); 735 | #endif 736 | 737 | return rxConfirmationCode; //password is not correct and so send confirmation code 738 | } 739 | } 740 | else { 741 | return response; //return packet receive error code 742 | } 743 | } 744 | 745 | //=========================================================================// 746 | //set a new 4 byte password 747 | 748 | uint8_t R30X_FPS::setPassword (uint32_t inputPassword) { 749 | uint8_t inputPasswordBytes[4] = {0}; 750 | inputPasswordBytes[0] = inputPassword & 0xFFU; 751 | inputPasswordBytes[1] = (inputPassword >> 8) & 0xFFU; 752 | inputPasswordBytes[2] = (inputPassword >> 16) & 0xFFU; 753 | inputPasswordBytes[3] = (inputPassword >> 24) & 0xFFU; 754 | 755 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SETPASSWORD, inputPasswordBytes, 4); //send the command and data 756 | uint8_t response = receivePacket(); //read response 757 | 758 | if(response == FPS_RX_OK) { //if the response packet is valid 759 | if(rxConfirmationCode == FPS_RESP_OK) { //the confrim code will be saved when the response is received 760 | devicePasswordL = inputPassword; //save the new password (Long) 761 | devicePassword[0] = inputPasswordBytes[0]; //save the new password as array 762 | devicePassword[1] = inputPasswordBytes[1]; 763 | devicePassword[2] = inputPasswordBytes[2]; 764 | devicePassword[3] = inputPasswordBytes[3]; 765 | 766 | #ifdef FPS_DEBUG 767 | debugPort.println(F("Setting password successful.")); 768 | debugPort.print(F("New password = ")); 769 | debugPort.println(devicePasswordL, HEX); 770 | #endif 771 | 772 | return FPS_RESP_OK; //password setting complete 773 | } 774 | else { 775 | #ifdef FPS_DEBUG 776 | debugPort.println(F("Setting password failed.")); 777 | debugPort.print(F("Input Password = ")); 778 | debugPort.println(inputPassword, HEX); 779 | debugPort.print(F("rxConfirmationCode = ")); 780 | debugPort.println(rxConfirmationCode, HEX); 781 | #endif 782 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 783 | } 784 | } 785 | else { 786 | return response; //return packet receive error code 787 | } 788 | } 789 | 790 | //=========================================================================// 791 | //set a new 4 byte device address. if the operation is successful, the new 792 | //address will be saved 793 | 794 | uint8_t R30X_FPS::setAddress (uint32_t address) { 795 | uint8_t addressArray[4] = {0}; //just so that we do not need to alter the existing address before successfully changing it 796 | addressArray[0] = address & 0xFF; 797 | addressArray[1] = (address >> 8) & 0xFF; 798 | addressArray[2] = (address >> 16) & 0xFF; 799 | addressArray[3] = (address >> 24) & 0xFF; 800 | 801 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SETDEVICEADDRESS, addressArray, 4); //send the command and data 802 | 803 | deviceAddressL = address; //save the new address (Long) 804 | deviceAddress[0] = addressArray[0]; //save the new address as array 805 | deviceAddress[1] = addressArray[1]; 806 | deviceAddress[2] = addressArray[2]; 807 | deviceAddress[3] = addressArray[3]; 808 | 809 | uint8_t response = receivePacket(); //read response 810 | 811 | if(response == FPS_RX_OK) { //if the response packet is valid 812 | if((rxConfirmationCode == FPS_RESP_OK) || (rxConfirmationCode == 0x20U)) { //the confrim code will be saved when the response is received 813 | #ifdef FPS_DEBUG 814 | debugPort.println(F("Setting address successful.")); 815 | debugPort.print(F("New address = ")); 816 | debugPort.println(deviceAddressL, HEX); 817 | #endif 818 | 819 | return FPS_RESP_OK; //address setting complete 820 | } 821 | else { 822 | #ifdef FPS_DEBUG 823 | debugPort.println(F("Setting address failed.")); 824 | debugPort.print(F("rxConfirmationCode = ")); 825 | debugPort.println(rxConfirmationCode, HEX); 826 | #endif 827 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 828 | } 829 | } 830 | else { 831 | return response; //return packet receive error code 832 | } 833 | } 834 | 835 | //=========================================================================// 836 | //change the baudrate and reinitialize the port. the new baudrate will be 837 | //saved after successful execution 838 | 839 | uint8_t R30X_FPS::setBaudrate (uint32_t baud) { 840 | uint8_t baudNumber = baud / 9600; //check if the baudrate is a multiple of 9600 841 | uint8_t dataArray[2] = {0}; 842 | 843 | #ifdef FPS_DEBUG 844 | debugPort.print(F("Input baudrate = ")); 845 | debugPort.println(baud); 846 | debugPort.print(F("Baud number = ")); 847 | debugPort.println(baudNumber); 848 | #endif 849 | 850 | if((baudNumber > 0) && (baudNumber < 13)) { //should be between 1 (9600bps) and 12 (115200bps) 851 | dataArray[0] = baudNumber; //low byte 852 | dataArray[1] = 4; //the code for the system parameter number, 4 means baudrate 853 | 854 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SETSYSPARA, dataArray, 2); //send the command and data 855 | uint8_t response = receivePacket(); //read response 856 | 857 | if(response == FPS_RX_OK) { //if the response packet is valid 858 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 859 | deviceBaudrate = baud; 860 | 861 | reinitializePort(deviceBaudrate); 862 | 863 | #ifdef FPS_DEBUG 864 | debugPort.println(F("Setting baudrate successful.")); 865 | #endif 866 | return FPS_RESP_OK; //baudrate setting complete 867 | } 868 | else { 869 | #ifdef FPS_DEBUG 870 | debugPort.println(F("Setting baudrate failed.")); 871 | debugPort.print(F("rxConfirmationCode = ")); 872 | debugPort.println(rxConfirmationCode, HEX); 873 | #endif 874 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 875 | } 876 | } 877 | else { 878 | return response; //return packet receive error code 879 | } 880 | } 881 | else { 882 | #ifdef FPS_DEBUG 883 | debugPort.println(F("Bad baudrate value.")); 884 | debugPort.println(F("Setting baudrate failed.")); 885 | #endif 886 | return FPS_BAD_VALUE; 887 | } 888 | } 889 | 890 | //=========================================================================// 891 | //reinitializes the serial port with a new baud rate, without changing the 892 | //device configuration. this is useful when you don't already know the 893 | //device's configured baud rate 894 | 895 | uint8_t R30X_FPS::reinitializePort(uint32_t baud) { 896 | if(hwSerial) { //if using hardware serial 897 | hwSerial->end(); //end the existing serial port 898 | hwSerial->begin(baud); //restart the port with new baudrate 899 | } 900 | 901 | #if defined(__AVR__) || defined(ESP8266) 902 | if (swSerial) { //if using software serial 903 | swSerial->end(); //stop existing serial port 904 | swSerial->begin(baud); //restart the port with new baudrate 905 | } 906 | #endif 907 | 908 | #ifdef FPS_DEBUG 909 | debugPort.println(F("Reinitialized port.")); 910 | #endif 911 | } 912 | 913 | //=========================================================================// 914 | //change the security level - or the threshold for matching two fingerprint 915 | //templates 916 | 917 | uint8_t R30X_FPS::setSecurityLevel (uint8_t level) { 918 | uint8_t dataArray[2] = {0}; 919 | 920 | if((level > 0) && (level < 6)) { //should be between 1 and 5 921 | dataArray[0] = level; //low byte 922 | dataArray[1] = 5; //the code for the system parameter number, 5 means the security level 923 | 924 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SETSYSPARA, dataArray, 2); //send the command and data 925 | uint8_t response = receivePacket(); //read response 926 | 927 | if(response == FPS_RX_OK) { //if the response packet is valid 928 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 929 | #ifdef FPS_DEBUG 930 | debugPort.println(F("Setting new security level successful.")); 931 | debugPort.print(F("Old value = ")); 932 | debugPort.println(securityLevel, HEX); 933 | debugPort.print(F("New value = ")); 934 | debugPort.println(level, HEX); 935 | #endif 936 | securityLevel = level; //save new value 937 | return FPS_RESP_OK; //security level setting complete 938 | } 939 | else { 940 | #ifdef FPS_DEBUG 941 | debugPort.println(F("Setting security level failed.")); 942 | debugPort.print(F("Current value = ")); 943 | debugPort.println(securityLevel, HEX); 944 | debugPort.print(F("rxConfirmationCode = ")); 945 | debugPort.println(rxConfirmationCode, HEX); 946 | #endif 947 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 948 | } 949 | } 950 | else { 951 | return response; //return packet receive error code 952 | } 953 | } 954 | else { 955 | #ifdef FPS_DEBUG 956 | debugPort.println(F("Bad security level value.")); 957 | debugPort.println(F("Setting security level failed.")); 958 | #endif 959 | return FPS_BAD_VALUE; //the received parameter is invalid 960 | } 961 | } 962 | 963 | //=========================================================================// 964 | //set the max length of data bytes that can be received from the module 965 | 966 | uint8_t R30X_FPS::setDataLength (uint16_t length) { 967 | #ifdef FPS_DEBUG 968 | debugPort.println(F("Setting new data length..")); 969 | #endif 970 | 971 | uint8_t dataArray[2] = {0}; 972 | 973 | if((length == 32) || (length == 64) || (length == 128) || (length == 256)) { //should be 32, 64, 128 or 256 bytes 974 | if(length == 32) 975 | dataArray[0] = 0; //low byte 976 | else if(length == 64) 977 | dataArray[0] = 1; //low byte 978 | else if(length == 128) 979 | dataArray[0] = 2; //low byte 980 | else if(length == 256) 981 | dataArray[0] = 3; //low byte 982 | 983 | dataArray[1] = 6; //the code for the system parameter number 984 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SETSYSPARA, dataArray, 2); //send the command and data 985 | uint8_t response = receivePacket(); //read response 986 | 987 | if(response == FPS_RX_OK) { //if the response packet is valid 988 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 989 | dataPacketLength = length; //save the new data length 990 | 991 | #ifdef FPS_DEBUG 992 | debugPort.println(F("Setting data length successful.")); 993 | debugPort.print(F("dataPacketLength = ")); 994 | debugPort.println(dataPacketLength); 995 | #endif 996 | 997 | return FPS_RESP_OK; //length setting complete 998 | } 999 | else { 1000 | #ifdef FPS_DEBUG 1001 | debugPort.println(F("Setting data length failed.")); 1002 | debugPort.print(F("rxConfirmationCode = ")); 1003 | debugPort.println(rxConfirmationCode, HEX); 1004 | #endif 1005 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1006 | } 1007 | } 1008 | else { 1009 | return response; //return packet receive error code 1010 | } 1011 | } 1012 | else { 1013 | #ifdef FPS_DEBUG 1014 | debugPort.println(F("Bad data length value.")); 1015 | debugPort.println(F("Setting data length failed.")); 1016 | #endif 1017 | return FPS_BAD_VALUE; //the received parameter is invalid 1018 | } 1019 | } 1020 | 1021 | //=========================================================================// 1022 | //turns the communication port on/off 1023 | 1024 | uint8_t R30X_FPS::portControl (uint8_t value) { 1025 | #ifdef FPS_DEBUG 1026 | if(value == 1) 1027 | debugPort.println(F("Turning on port..")); 1028 | else 1029 | debugPort.println(F("Turning off port..")); 1030 | #endif 1031 | 1032 | uint8_t dataArray[1] = {0}; 1033 | 1034 | if((value == 0) || (value == 1)) { //should be either 1 or 0 1035 | dataArray[0] = value; 1036 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_PORTCONTROL, dataArray, 1); //send the command and data 1037 | uint8_t response = receivePacket(); //read response 1038 | 1039 | if(response == FPS_RX_OK) { //if the response packet is valid 1040 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1041 | #ifdef FPS_DEBUG 1042 | if(value == 1) 1043 | debugPort.println(F("Turning on port successful.")); 1044 | else 1045 | debugPort.println(F("Turning off port successful.")); 1046 | #endif 1047 | return FPS_RESP_OK; //port setting complete 1048 | } 1049 | else { 1050 | #ifdef FPS_DEBUG 1051 | debugPort.println(F("Turning on/off port failed.")); 1052 | debugPort.print(F("rxConfirmationCode = ")); 1053 | debugPort.println(rxConfirmationCode, HEX); 1054 | #endif 1055 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1056 | } 1057 | } 1058 | else { 1059 | return response; //return packet receive error code 1060 | } 1061 | } 1062 | else { 1063 | return FPS_BAD_VALUE; //the received parameter is invalid 1064 | } 1065 | } 1066 | 1067 | //=========================================================================// 1068 | //read system configuration 1069 | 1070 | uint8_t R30X_FPS::readSysPara() { 1071 | #ifdef FPS_DEBUG 1072 | debugPort.println(F("Reading system parameters..")); 1073 | #endif 1074 | 1075 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_READSYSPARA); //send the command, there's no additional data 1076 | uint8_t response = receivePacket(); //read response 1077 | 1078 | if(response == FPS_RX_OK) { //if the response packet is valid 1079 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1080 | statusRegister = (uint16_t(rxDataBuffer[15]) << 8) + rxDataBuffer[14]; //high byte + low byte 1081 | systemID = (uint16_t(rxDataBuffer[13]) << 8) + rxDataBuffer[12]; 1082 | librarySize = (uint16_t(rxDataBuffer[11]) << 8) + rxDataBuffer[10]; 1083 | securityLevel = (uint16_t(rxDataBuffer[9]) << 8) + rxDataBuffer[8]; 1084 | 1085 | deviceAddressL = (uint32_t(rxDataBuffer[7]) << 24) + (uint32_t(rxDataBuffer[6]) << 16) + (uint32_t(rxDataBuffer[5]) << 8) + uint32_t(rxDataBuffer[4]); 1086 | 1087 | dataPacketLengthCode = (uint16_t(rxDataBuffer[3]) << 8) + rxDataBuffer[2]; 1088 | baudMultiplier = (uint16_t(rxDataBuffer[1]) << 8) + rxDataBuffer[0]; 1089 | 1090 | if(dataPacketLengthCode == 0) 1091 | dataPacketLength = 32; 1092 | else if(dataPacketLengthCode == 1) 1093 | dataPacketLength = 64; 1094 | else if(dataPacketLengthCode == 2) 1095 | dataPacketLength = 128; 1096 | else if(dataPacketLengthCode == 3) 1097 | dataPacketLength = 256; 1098 | 1099 | deviceBaudrate = uint32_t(baudMultiplier * 9600); //baudrate is retrieved as a multiplier 1100 | 1101 | #ifdef FPS_DEBUG 1102 | debugPort.println(F("Reading system parameters successful.")); 1103 | debugPort.print(F("statusRegister = 0x")); 1104 | debugPort.println(statusRegister, HEX); 1105 | debugPort.print(F("systemID = 0x")); 1106 | debugPort.println(systemID, HEX); 1107 | debugPort.print(F("librarySize = ")); 1108 | debugPort.println(librarySize); 1109 | debugPort.print(F("securityLevel = 0x")); 1110 | debugPort.println(securityLevel, HEX); 1111 | debugPort.print(F("deviceAddressL = 0x")); 1112 | debugPort.println(deviceAddressL, HEX); 1113 | debugPort.print(F("dataPacketLengthCode = 0x")); 1114 | debugPort.println(dataPacketLengthCode, HEX); 1115 | debugPort.print(F("baudMultiplier = 0x")); 1116 | debugPort.println(baudMultiplier, HEX); 1117 | debugPort.print(F("deviceBaudrate = ")); 1118 | debugPort.print(deviceBaudrate); 1119 | debugPort.println(F(" bps")); 1120 | #endif 1121 | 1122 | return FPS_RESP_OK; 1123 | } 1124 | else { 1125 | #ifdef FPS_DEBUG 1126 | debugPort.println(F("Reading system parameters failed.")); 1127 | debugPort.print(F("rxConfirmationCode = ")); 1128 | debugPort.println(rxConfirmationCode, HEX); 1129 | #endif 1130 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1131 | } 1132 | } 1133 | else { 1134 | return response; //return packet receive error code 1135 | } 1136 | } 1137 | 1138 | //=========================================================================// 1139 | //returns the total template count in the flash memory 1140 | 1141 | uint8_t R30X_FPS::getTemplateCount() { 1142 | #ifdef FPS_DEBUG 1143 | debugPort.println(F("Reading template count..")); 1144 | #endif 1145 | 1146 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_TEMPLATECOUNT); //send the command, there's no additional data 1147 | uint8_t response = receivePacket(); //read response 1148 | 1149 | if(response == FPS_RX_OK) { //if the response packet is valid 1150 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1151 | templateCount = (uint16_t(rxDataBuffer[1]) << 8) + rxDataBuffer[0]; //high byte + low byte 1152 | 1153 | #ifdef FPS_DEBUG 1154 | debugPort.println(F("Reading template count successful.")); 1155 | debugPort.print(F("templateCount = ")); 1156 | debugPort.println(templateCount); 1157 | #endif 1158 | 1159 | return FPS_RESP_OK; 1160 | } 1161 | else { 1162 | #ifdef FPS_DEBUG 1163 | debugPort.println(F("Reading template count failed.")); 1164 | debugPort.print(F("rxConfirmationCode = ")); 1165 | debugPort.println(rxConfirmationCode, HEX); 1166 | #endif 1167 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1168 | } 1169 | } 1170 | else { 1171 | return response; //return packet receive error code 1172 | } 1173 | } 1174 | 1175 | //=========================================================================// 1176 | //scans the fingerprint and finds a match within specified range 1177 | //timeout = 100-25500 milliseconds 1178 | //startId = #1-#1000 1179 | //range = 1-1000 1180 | 1181 | uint8_t R30X_FPS::captureAndRangeSearch (uint16_t captureTimeout, uint16_t startLocation, uint16_t count) { 1182 | if(captureTimeout > 25500) { //25500 is the max timeout the device supports 1183 | #ifdef FPS_DEBUG 1184 | debugPort.println(F("Capture and range search failed.")); 1185 | debugPort.println(F("Bad capture timeout.")); 1186 | debugPort.print(F("captureTimeout = ")); 1187 | debugPort.println(captureTimeout); 1188 | #endif 1189 | return FPS_BAD_VALUE; 1190 | } 1191 | 1192 | if((startLocation > 1000) || (startLocation < 1)) { //if not in range (0-999) 1193 | #ifdef FPS_DEBUG 1194 | debugPort.println(F("Capture and range search failed.")); 1195 | debugPort.println(F("Bad start ID")); 1196 | debugPort.print(F("startId = #")); 1197 | debugPort.println(startLocation); 1198 | #endif 1199 | 1200 | return FPS_BAD_VALUE; 1201 | } 1202 | 1203 | if((startLocation + count) > 1001) { //if range overflows 1204 | #ifdef FPS_DEBUG 1205 | debugPort.println(F("Capture and range search failed.")); 1206 | debugPort.println(F("startLocation + count can't be greater than 1001.")); 1207 | debugPort.print(F("startLocation = #")); 1208 | debugPort.println(startLocation); 1209 | debugPort.print(F("count = ")); 1210 | debugPort.println(count); 1211 | debugPort.print(F("startLocation + count = ")); 1212 | debugPort.println(startLocation + count); 1213 | #endif 1214 | return FPS_BAD_VALUE; 1215 | } 1216 | 1217 | uint8_t dataArray[5] = {0}; //need 5 bytes here 1218 | 1219 | //generate the data array 1220 | dataArray[4] = uint8_t(captureTimeout / 140); //this byte is sent first 1221 | dataArray[3] = ((startLocation-1) >> 8) & 0xFFU; //high byte 1222 | dataArray[2] = uint8_t((startLocation-1) & 0xFFU); //low byte 1223 | dataArray[1] = (count >> 8) & 0xFFU; //high byte 1224 | dataArray[0] = uint8_t(count & 0xFFU); //low byte 1225 | 1226 | #ifdef FPS_DEBUG 1227 | debugPort.println(F("Starting capture and range search.")); 1228 | debugPort.print(F("captureTimeout = ")); 1229 | debugPort.println(captureTimeout); 1230 | debugPort.print(F("startLocation = #")); 1231 | debugPort.println(startLocation); 1232 | debugPort.print(F("count = ")); 1233 | debugPort.println(count); 1234 | debugPort.print(F("startLocation + count = ")); 1235 | debugPort.println(startLocation + count); 1236 | #endif 1237 | 1238 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SCANANDRANGESEARCH, dataArray, 5); //send the command, there's no additional data 1239 | uint8_t response = receivePacket(captureTimeout + 100); //read response 1240 | 1241 | if(response == FPS_RX_OK) { //if the response packet is valid 1242 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1243 | fingerId = (uint16_t(rxDataBuffer[3]) << 8) + rxDataBuffer[2]; //high byte + low byte 1244 | fingerId += 1; //because IDs start from #1 1245 | matchScore = (uint16_t(rxDataBuffer[1]) << 8) + rxDataBuffer[0]; //data length will be 4 here 1246 | 1247 | #ifdef FPS_DEBUG 1248 | debugPort.println(F("Capture and range search successful.")); 1249 | debugPort.print(F("fingerId = #")); 1250 | debugPort.println(fingerId); 1251 | debugPort.print(F("matchScore = ")); 1252 | debugPort.println(matchScore); 1253 | #endif 1254 | 1255 | return FPS_RESP_OK; 1256 | } 1257 | else { 1258 | fingerId = 0; 1259 | matchScore = 0; 1260 | 1261 | #ifdef FPS_DEBUG 1262 | debugPort.println(F("Fingerprint not found.")); 1263 | debugPort.print(F("rxConfirmationCode = ")); 1264 | debugPort.println(rxConfirmationCode, HEX); 1265 | #endif 1266 | 1267 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1268 | } 1269 | } 1270 | else { 1271 | return response; //return packet receive error code 1272 | } 1273 | } 1274 | 1275 | //=========================================================================// 1276 | //scans the fingerprint and finds a match within the full range of library 1277 | //a timeout can not be specified here 1278 | 1279 | uint8_t R30X_FPS::captureAndFullSearch () { 1280 | #ifdef FPS_DEBUG 1281 | debugPort.println(F("Starting capture and full search.")); 1282 | #endif 1283 | 1284 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SCANANDFULLSEARCH); //send the command, there's no additional data 1285 | uint8_t response = receivePacket(3000); //read response 1286 | 1287 | if(response == FPS_RX_OK) { //if the response packet is valid 1288 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1289 | fingerId = (uint16_t(rxDataBuffer[3]) << 8) + rxDataBuffer[2]; //high byte + low byte 1290 | fingerId += 1; //because IDs start from #1 1291 | matchScore = (uint16_t(rxDataBuffer[1]) << 8) + rxDataBuffer[0]; //data length will be 4 here 1292 | 1293 | #ifdef FPS_DEBUG 1294 | debugPort.println(F("Capture and full search successful.")); 1295 | debugPort.print(F("fingerId = #")); 1296 | debugPort.println(fingerId); 1297 | debugPort.print(F("matchScore = ")); 1298 | debugPort.println(matchScore); 1299 | #endif 1300 | 1301 | return FPS_RESP_OK; 1302 | } 1303 | else { 1304 | fingerId = 0; 1305 | matchScore = 0; 1306 | 1307 | #ifdef FPS_DEBUG 1308 | debugPort.println(F("Fingerprint not found.")); 1309 | debugPort.print(F("rxConfirmationCode = ")); 1310 | debugPort.println(rxConfirmationCode, HEX); 1311 | #endif 1312 | 1313 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1314 | } 1315 | } 1316 | else { 1317 | return response; //return packet receive error code 1318 | } 1319 | } 1320 | 1321 | //=========================================================================// 1322 | //scan the fingerprint, generate an image and store it in the image buffer 1323 | 1324 | uint8_t R30X_FPS::generateImage () { 1325 | #ifdef FPS_DEBUG 1326 | debugPort.println(F("Generating fingerprint image..")); 1327 | #endif 1328 | 1329 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SCANFINGER); //send the command, there's no additional data 1330 | uint8_t response = receivePacket(); //read response 1331 | 1332 | if(response == FPS_RX_OK) { //if the response packet is valid 1333 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1334 | #ifdef FPS_DEBUG 1335 | debugPort.println(F("Image saved to buffer successfully.")); 1336 | #endif 1337 | return FPS_RESP_OK; //just the confirmation code only 1338 | } 1339 | else { 1340 | #ifdef FPS_DEBUG 1341 | debugPort.println(F("Generating fingerprint failed.")); 1342 | debugPort.print(F("rxConfirmationCode = ")); 1343 | debugPort.println(rxConfirmationCode, HEX); 1344 | #endif 1345 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1346 | } 1347 | } 1348 | else { 1349 | return response; //return packet receive error code 1350 | } 1351 | } 1352 | 1353 | //=========================================================================// 1354 | //export the image stored in one of the buffers to the computer 1355 | //this is not fully implemented. please do not use it 1356 | 1357 | uint8_t R30X_FPS::exportImage () { 1358 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_EXPORTIMAGE); //send the command, there's no additional data 1359 | uint8_t response = receivePacket(); //read response 1360 | 1361 | if(response == FPS_RX_OK) { //if the response packet is valid 1362 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1363 | return FPS_RESP_OK; //just the confirmation code only 1364 | } 1365 | else { 1366 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1367 | } 1368 | } 1369 | else { 1370 | return response; //return packet receive error code 1371 | } 1372 | } 1373 | 1374 | //=========================================================================// 1375 | //import an image file from computer to one of the buffers. 1376 | //this is not fully implemented. please do not use it 1377 | 1378 | uint8_t R30X_FPS::importImage (uint8_t* dataBuffer) { 1379 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_IMPORTIMAGE, dataBuffer, 64); //send the command, there's no additional data 1380 | uint8_t response = receivePacket(); //read response 1381 | 1382 | if(response == FPS_RX_OK) { //if the response packet is valid 1383 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1384 | return FPS_RESP_OK; //just the confirmation code only 1385 | } 1386 | else { 1387 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1388 | } 1389 | } 1390 | else { 1391 | return response; //return packet receive error code 1392 | } 1393 | } 1394 | 1395 | //=========================================================================// 1396 | //generate a character file from image stored in image buffer and store it in 1397 | //one of the two character buffers 1398 | 1399 | uint8_t R30X_FPS::generateCharacter (uint8_t bufferId) { 1400 | if(!((bufferId > 0) && (bufferId < 3))) { //if the value is not 1 or 2 1401 | #ifdef FPS_DEBUG 1402 | debugPort.println(F("Generating character file failed.")); 1403 | debugPort.println(F("Bad value. bufferId can only be 1 or 2.")); 1404 | debugPort.print(F("bufferId = ")); 1405 | debugPort.println(bufferId); 1406 | #endif 1407 | 1408 | return FPS_BAD_VALUE; 1409 | } 1410 | uint8_t dataBuffer[1] = {bufferId}; //create data array 1411 | 1412 | #ifdef FPS_DEBUG 1413 | debugPort.println(F("Generating character file..")); 1414 | debugPort.print(F("Character bufferId = ")); 1415 | debugPort.println(bufferId); 1416 | #endif 1417 | 1418 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_IMAGETOCHARACTER, dataBuffer, 1); 1419 | uint8_t response = receivePacket(); //read response 1420 | 1421 | if(response == FPS_RX_OK) { //if the response packet is valid 1422 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1423 | #ifdef FPS_DEBUG 1424 | debugPort.println(F("Generating character file successful.")); 1425 | #endif 1426 | return FPS_RESP_OK; //just the confirmation code only 1427 | } 1428 | else { 1429 | #ifdef FPS_DEBUG 1430 | debugPort.println(F("Generating character file failed.")); 1431 | debugPort.print(F("rxConfirmationCode = ")); 1432 | debugPort.println(rxConfirmationCode, HEX); 1433 | 1434 | if(rxConfirmationCode == FPS_RESP_OVERDISORDERFAIL2) { 1435 | debugPort.println(F("Character file overly disordered.")); 1436 | } 1437 | 1438 | if(rxConfirmationCode == FPS_RESP_FEATUREFAIL) { 1439 | debugPort.println(F("Character file feature fail.")); 1440 | } 1441 | 1442 | if(rxConfirmationCode == FPS_RESP_IMAGEGENERATEFAIL) { 1443 | debugPort.println(F("Valid image not available.")); 1444 | } 1445 | 1446 | #endif 1447 | 1448 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1449 | } 1450 | } 1451 | else { 1452 | return response; //return packet receive error code 1453 | } 1454 | } 1455 | 1456 | //=========================================================================// 1457 | //combine the two character files from buffers and generate a template 1458 | //the template will be saved to the both the buffers 1459 | 1460 | uint8_t R30X_FPS::generateTemplate () { 1461 | #ifdef FPS_DEBUG 1462 | debugPort.println(F("Generating template from char buffers..")); 1463 | #endif 1464 | 1465 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_GENERATETEMPLATE); //send the command, there's no additional data 1466 | uint8_t response = receivePacket(); //read response 1467 | 1468 | if(response == FPS_RX_OK) { //if the response packet is valid 1469 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1470 | #ifdef FPS_DEBUG 1471 | debugPort.println(F("Generating template successful.")); 1472 | #endif 1473 | return FPS_RESP_OK; //just the confirmation code only 1474 | } 1475 | else { 1476 | #ifdef FPS_DEBUG 1477 | debugPort.println(F("Generating template failed.")); 1478 | debugPort.print(F("rxConfirmationCode = ")); 1479 | debugPort.println(rxConfirmationCode, HEX); 1480 | #endif 1481 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1482 | } 1483 | } 1484 | else { 1485 | return response; //return packet receive error code 1486 | } 1487 | } 1488 | 1489 | //=========================================================================// 1490 | //export a character file from one of the buffers to the computer 1491 | //this is not completely implemented. please do not use it 1492 | 1493 | uint8_t R30X_FPS::exportCharacter (uint8_t bufferId) { 1494 | uint8_t dataBuffer[1] = {bufferId}; //create data array 1495 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_IMPORTIMAGE); 1496 | uint8_t response = receivePacket(); //read response 1497 | 1498 | if(response == FPS_RX_OK) { //if the response packet is valid 1499 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1500 | return FPS_RESP_OK; //just the confirmation code only 1501 | } 1502 | else { 1503 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1504 | } 1505 | } 1506 | else { 1507 | return response; //return packet receive error code 1508 | } 1509 | } 1510 | 1511 | //=========================================================================// 1512 | //import a character file from computer to one of the buffers 1513 | //this is not completely implemented. please do not use it 1514 | 1515 | uint8_t R30X_FPS::importCharacter (uint8_t bufferId, uint8_t* dataBuffer) { 1516 | uint8_t dataArray[sizeof(dataBuffer)+1] = {0}; //create data array 1517 | dataArray[sizeof(dataBuffer)]; 1518 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_IMPORTIMAGE); 1519 | uint8_t response = receivePacket(); //read response 1520 | 1521 | if(response == FPS_RX_OK) { //if the response packet is valid 1522 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1523 | return FPS_RESP_OK; //just the confirmation code only 1524 | } 1525 | else { 1526 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1527 | } 1528 | } 1529 | else { 1530 | return response; //return packet receive error code 1531 | } 1532 | } 1533 | 1534 | //=========================================================================// 1535 | //store the contents of one of the two template (character) buffers to a 1536 | //location on the fingerprint library 1537 | 1538 | uint8_t R30X_FPS::saveTemplate (uint8_t bufferId, uint16_t location) { 1539 | if(!((bufferId > 0) && (bufferId < 3))) { //if the value is not 1 or 2 1540 | #ifdef FPS_DEBUG 1541 | debugPort.println(F("Storing template failed.")); 1542 | debugPort.println(F("Bad value. bufferId can only be 1 or 2.")); 1543 | debugPort.print(F("bufferId = ")); 1544 | debugPort.println(bufferId); 1545 | #endif 1546 | 1547 | return FPS_BAD_VALUE; 1548 | } 1549 | 1550 | if((location > 1000) || (location < 1)) { //if the value is not in range 1551 | #ifdef FPS_DEBUG 1552 | debugPort.println(F("Generating template failed.")); 1553 | debugPort.println(F("Bad value. location must be #1 to #1000.")); 1554 | debugPort.print(F("location = ")); 1555 | debugPort.println(location); 1556 | #endif 1557 | 1558 | return FPS_BAD_VALUE; 1559 | } 1560 | 1561 | #ifdef FPS_DEBUG 1562 | debugPort.println(F("Saving template..")); 1563 | #endif 1564 | 1565 | uint8_t dataArray[3] = {0}; //create data array 1566 | dataArray[2] = bufferId; //highest byte 1567 | dataArray[1] = ((location-1) >> 8) & 0xFFU; //high byte of location 1568 | dataArray[0] = ((location-1) & 0xFFU); //low byte of location 1569 | 1570 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_STORETEMPLATE, dataArray, 3); //send the command and data 1571 | uint8_t response = receivePacket(); //read response 1572 | 1573 | if(response == FPS_RX_OK) { //if the response packet is valid 1574 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1575 | #ifdef FPS_DEBUG 1576 | debugPort.println(F("Storing template successful.")); 1577 | debugPort.print(F("Saved to #")); 1578 | debugPort.println(location); 1579 | #endif 1580 | return FPS_RESP_OK; //just the confirmation code only 1581 | } 1582 | else { 1583 | #ifdef FPS_DEBUG 1584 | debugPort.println(F("Storing template failed.")); 1585 | debugPort.print(F("rxConfirmationCode = ")); 1586 | debugPort.println(rxConfirmationCode, HEX); 1587 | #endif 1588 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1589 | } 1590 | } 1591 | else { 1592 | return response; //return packet receive error code 1593 | } 1594 | } 1595 | 1596 | //=========================================================================// 1597 | //load the contents from a location on the library to one of the two 1598 | //template/character buffers 1599 | 1600 | uint8_t R30X_FPS::loadTemplate (uint8_t bufferId, uint16_t location) { 1601 | if(!((bufferId > 0) && (bufferId < 3))) { //if the value is not 1 or 2 1602 | #ifdef FPS_DEBUG 1603 | debugPort.println(F("Loading template failed.")); 1604 | debugPort.println(F("Bad value. bufferId can only be 1 or 2.")); 1605 | debugPort.print(F("bufferId = ")); 1606 | debugPort.println(bufferId); 1607 | #endif 1608 | 1609 | return FPS_BAD_VALUE; 1610 | } 1611 | 1612 | if((location > 1000) || (location < 1)) { //if the value is not in range 1613 | #ifdef FPS_DEBUG 1614 | debugPort.println(F("Loading template failed.")); 1615 | debugPort.println(F("Bad value. location must be #1 to #1000.")); 1616 | debugPort.print(F("location = ")); 1617 | debugPort.println(location); 1618 | #endif 1619 | 1620 | return FPS_BAD_VALUE; 1621 | } 1622 | 1623 | uint8_t dataArray[3] = {0}; //create data array 1624 | dataArray[2] = bufferId; //highest byte 1625 | dataArray[1] = ((location-1) >> 8) & 0xFFU; //high byte of location 1626 | dataArray[0] = ((location-1) & 0xFFU); //low byte of location 1627 | 1628 | #ifdef FPS_DEBUG 1629 | debugPort.println(F("Loading template..")); 1630 | #endif 1631 | 1632 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_LOADTEMPLATE, dataArray, 3); //send the command and data 1633 | uint8_t response = receivePacket(); //read response 1634 | 1635 | if(response == FPS_RX_OK) { //if the response packet is valid 1636 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1637 | #ifdef FPS_DEBUG 1638 | debugPort.println(F("Loading template successful.")); 1639 | debugPort.print(F("Loaded #")); 1640 | debugPort.print(location); 1641 | debugPort.print(F(" to buffer ")); 1642 | debugPort.println(bufferId); 1643 | #endif 1644 | 1645 | return FPS_RESP_OK; //just the confirmation code only 1646 | } 1647 | else { 1648 | #ifdef FPS_DEBUG 1649 | debugPort.println(F("Loading template failed.")); 1650 | debugPort.print(F("rxConfirmationCode = ")); 1651 | debugPort.println(rxConfirmationCode, HEX); 1652 | #endif 1653 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1654 | } 1655 | } 1656 | else { 1657 | return response; //return packet receive error code 1658 | } 1659 | } 1660 | 1661 | //=========================================================================// 1662 | //delete a set of templates saved in the flash memory 1663 | 1664 | uint8_t R30X_FPS::deleteTemplate (uint16_t startLocation, uint16_t count) { 1665 | if((startLocation > 1000) || (startLocation < 1)) { //if the value is not 1 or 2 1666 | #ifdef FPS_DEBUG 1667 | debugPort.println(F("Deleting template failed.")); 1668 | debugPort.println(F("Bad value. Start location must be #1 to #1000.")); 1669 | debugPort.print(F("startLocation = ")); 1670 | debugPort.println(startLocation); 1671 | #endif 1672 | 1673 | return FPS_BAD_VALUE; 1674 | } 1675 | 1676 | if((count + startLocation) > 1001) { //if the value is not in range 1677 | #ifdef FPS_DEBUG 1678 | debugPort.println(F("Deleting template failed.")); 1679 | debugPort.println(F("Bad value. Sum of startLocation and count can't be greater than 1001.")); 1680 | debugPort.print(F("startLocation + count = ")); 1681 | debugPort.println(startLocation + count); 1682 | #endif 1683 | 1684 | return FPS_BAD_VALUE; 1685 | } 1686 | 1687 | uint8_t dataArray[4] = {0}; //create data array 1688 | dataArray[3] = ((startLocation-1) >> 8) & 0xFFU; //high byte of location 1689 | dataArray[2] = ((startLocation-1) & 0xFFU); //low byte of location 1690 | dataArray[1] = (count >> 8) & 0xFFU; //high byte of total no. of templates to delete 1691 | dataArray[0] = (count & 0xFFU); //low byte of count 1692 | 1693 | #ifdef FPS_DEBUG 1694 | debugPort.println(F("Deleting template..")); 1695 | #endif 1696 | 1697 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_DELETETEMPLATE, dataArray, 4); //send the command and data 1698 | uint8_t response = receivePacket(); //read response 1699 | 1700 | if(response == FPS_RX_OK) { //if the response packet is valid 1701 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1702 | #ifdef FPS_DEBUG 1703 | debugPort.println(F("Deleting template successful.")); 1704 | debugPort.print(F("From #")); 1705 | debugPort.print(startLocation); 1706 | debugPort.print(F(" to #")); 1707 | debugPort.println(startLocation + count - 1); 1708 | #endif 1709 | return FPS_RESP_OK; //just the confirmation code only 1710 | } 1711 | else { 1712 | #ifdef FPS_DEBUG 1713 | debugPort.println(F("Deleting template failed.")); 1714 | debugPort.print(F("rxConfirmationCode = ")); 1715 | debugPort.println(rxConfirmationCode, HEX); 1716 | #endif 1717 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1718 | } 1719 | } 1720 | else { 1721 | return response; //return packet receive error code 1722 | } 1723 | } 1724 | 1725 | //=========================================================================// 1726 | //deletes all the templates stored in the library 1727 | 1728 | uint8_t R30X_FPS::clearLibrary () { 1729 | #ifdef FPS_DEBUG 1730 | debugPort.println(F("Clearing library..")); 1731 | #endif 1732 | 1733 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_CLEARLIBRARY); //send the command 1734 | uint8_t response = receivePacket(); //read response 1735 | 1736 | if(response == FPS_RX_OK) { //if the response packet is valid 1737 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1738 | #ifdef FPS_DEBUG 1739 | debugPort.println(F("Clearing library successful.")); 1740 | #endif 1741 | return FPS_RESP_OK; //just the confirmation code only 1742 | } 1743 | else { 1744 | #ifdef FPS_DEBUG 1745 | debugPort.println(F("Clearing library failed.")); 1746 | debugPort.print(F("rxConfirmationCode = ")); 1747 | debugPort.println(rxConfirmationCode, HEX); 1748 | #endif 1749 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1750 | } 1751 | } 1752 | else { 1753 | return response; //return packet receive error code 1754 | } 1755 | } 1756 | 1757 | //=========================================================================// 1758 | //match the templates stored in the buffers and calculate a match score 1759 | 1760 | uint8_t R30X_FPS::matchTemplates () { 1761 | #ifdef FPS_DEBUG 1762 | debugPort.println(F("Matching templates..")); 1763 | #endif 1764 | 1765 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_MATCHTEMPLATES); //send the command 1766 | uint8_t response = receivePacket(); //read response 1767 | 1768 | if(response == FPS_RX_OK) { //if the response packet is valid 1769 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1770 | #ifdef FPS_DEBUG 1771 | debugPort.println(F("Matching templates successful.")); 1772 | #endif 1773 | 1774 | matchScore = uint16_t(rxDataBuffer[1] << 8) + rxDataBuffer[0]; 1775 | return FPS_RESP_OK; //just the confirmation code only 1776 | } 1777 | else { 1778 | #ifdef FPS_DEBUG 1779 | debugPort.println(F("The templates do no match.")); 1780 | debugPort.print(F("rxConfirmationCode = ")); 1781 | debugPort.println(rxConfirmationCode, HEX); 1782 | #endif 1783 | return rxConfirmationCode; //setting was unsuccessful and so send confirmation code 1784 | } 1785 | } 1786 | else { 1787 | return response; //return packet receive error code 1788 | } 1789 | } 1790 | 1791 | //=========================================================================// 1792 | //searches the contents of one of the two char buffers for a match on the 1793 | //fingerprint library throughout a range 1794 | 1795 | uint8_t R30X_FPS::searchLibrary (uint8_t bufferId, uint16_t startLocation, uint16_t count) { 1796 | if(!((bufferId > 0) && (bufferId < 3))) { //if the value is not 1 or 2 1797 | #ifdef FPS_DEBUG 1798 | debugPort.println(F("Searching library failed.")); 1799 | debugPort.println(F("Bad value. bufferId can only be 1 or 2.")); 1800 | debugPort.print(F("bufferId = ")); 1801 | debugPort.println(bufferId); 1802 | #endif 1803 | return FPS_BAD_VALUE; 1804 | } 1805 | 1806 | if((startLocation > 1000) || (startLocation < 1)) { //if not in range (0-999) 1807 | #ifdef FPS_DEBUG 1808 | debugPort.println(F("Searching library failed.")); 1809 | debugPort.println(F("Bad start ID")); 1810 | debugPort.print(F("startId = #")); 1811 | debugPort.println(startLocation); 1812 | #endif 1813 | return FPS_BAD_VALUE; 1814 | } 1815 | 1816 | if((startLocation + count) > 1001) { //if range overflows 1817 | #ifdef FPS_DEBUG 1818 | debugPort.println(F("Searching library failed.")); 1819 | debugPort.println(F("startLocation + count can't be greater than 1001.")); 1820 | debugPort.print(F("startLocation = #")); 1821 | debugPort.println(startLocation); 1822 | debugPort.print(F("count = ")); 1823 | debugPort.println(count); 1824 | debugPort.print(F("startLocation + count = ")); 1825 | debugPort.println(startLocation + count); 1826 | #endif 1827 | return FPS_BAD_VALUE; 1828 | } 1829 | 1830 | uint8_t dataArray[5] = {0}; 1831 | dataArray[4] = bufferId; 1832 | dataArray[3] = (startLocation >> 8) & 0xFFU; //high byte 1833 | dataArray[2] = (startLocation & 0xFFU); //low byte 1834 | dataArray[1] = (count >> 8) & 0xFFU; //high byte 1835 | dataArray[0] = (count & 0xFFU); //low byte 1836 | 1837 | #ifdef FPS_DEBUG 1838 | debugPort.println(F("Starting searching library for buffer content.")); 1839 | debugPort.print(F("bufferId = ")); 1840 | debugPort.println(bufferId); 1841 | debugPort.print(F("startLocation = #")); 1842 | debugPort.println(startLocation); 1843 | debugPort.print(F("count = ")); 1844 | debugPort.println(count); 1845 | debugPort.print(F("startLocation + count = ")); 1846 | debugPort.println(startLocation + count); 1847 | #endif 1848 | 1849 | sendPacket(FPS_ID_COMMANDPACKET, FPS_CMD_SEARCHLIBRARY, dataArray, 5); //send the command 1850 | uint8_t response = receivePacket(); //read response 1851 | 1852 | if(response == FPS_RX_OK) { //if the response packet is valid 1853 | if(rxConfirmationCode == FPS_RESP_OK) { //the confirm code will be saved when the response is received 1854 | fingerId = (uint16_t(rxDataBuffer[3]) << 8) + rxDataBuffer[2]; //add high byte and low byte 1855 | fingerId += 1; //because IDs start from #1 1856 | matchScore = (uint16_t(rxDataBuffer[1]) << 8) + rxDataBuffer[0]; //add high byte and low byte 1857 | 1858 | #ifdef FPS_DEBUG 1859 | debugPort.println(F("Buffer content found in library.")); 1860 | debugPort.print(F("fingerId = #")); 1861 | debugPort.println(fingerId); 1862 | debugPort.print(F("matchScore = ")); 1863 | debugPort.println(matchScore); 1864 | #endif 1865 | 1866 | return FPS_RESP_OK; //just the confirmation code only 1867 | } 1868 | else { 1869 | //fingerId = 0 doesn't mean the match was found at location 0 1870 | //instead it means an error. check the confirmation code to determine the problem 1871 | fingerId = 0; 1872 | matchScore = 0; 1873 | 1874 | #ifdef FPS_DEBUG 1875 | debugPort.println(F("Fingerprint not found.")); 1876 | debugPort.print(F("rxConfirmationCode = ")); 1877 | debugPort.println(rxConfirmationCode, HEX); 1878 | #endif 1879 | 1880 | return rxConfirmationCode; 1881 | } 1882 | } 1883 | else { 1884 | return response; //return packet receive error code 1885 | } 1886 | } 1887 | 1888 | //=========================================================================// 1889 | 1890 | //written by human, for humans. 1891 | --------------------------------------------------------------------------------