From 32493833fbfc67b079a85e41811051dd44a7e5d4 Mon Sep 17 00:00:00 2001
From: dorababu <dorababu@subcom.tech>
Date: Sat, 23 Jul 2022 10:57:32 +0530
Subject: [PATCH] Moved to here from key repo

---
 FingerPrintMatching/include/DFRobot_ID809.h   |  494 ++++++++
 FingerPrintMatching/platformio.ini            |   12 +
 FingerPrintMatching/src/DFRobot_ID809.cpp     |  748 +++++++++++
 FingerPrintMatching/src/src.cpp               |  107 ++
 FingerPrintRegister/include/DFRobot_ID809.h   |  494 ++++++++
 FingerPrintRegister/platformio.ini            |   11 +
 FingerPrintRegister/src/DFRobot_ID809.cpp     |  748 +++++++++++
 FingerPrintRegister/src/src.cpp               |  132 ++
 FingerPrintUnregister/include/DFRobot_ID809.h |  494 ++++++++
 FingerPrintUnregister/platformio.ini          |    9 +
 FingerPrintUnregister/src/DFRobot_ID809.cpp   |  748 +++++++++++
 FingerPrintUnregister/src/platformio.ini      |    0
 FingerPrintUnregister/src/src.cpp             |  110 ++
 .../lib/DFRobot_ID809/DFRobot_ID809.cpp       | 1089 +++++++++++++++++
 .../lib/DFRobot_ID809/DFRobot_ID809.h         |  504 ++++++++
 RegFPwithHash/platformio.ini                  |   12 +
 RegFPwithHash/src/src.cpp                     |  216 ++++
 .../lib/DFRobot_ID809/DFRobot_ID809.cpp       | 1089 +++++++++++++++++
 .../lib/DFRobot_ID809/DFRobot_ID809.h         |  504 ++++++++
 matchFPandHash/platformio.ini                 |   13 +
 matchFPandHash/src/src.cpp                    |  178 +++
 .../lib/DFRobot_ID809/DFRobot_ID809.cpp       | 1089 +++++++++++++++++
 .../lib/DFRobot_ID809/DFRobot_ID809.h         |  504 ++++++++
 readTemplate/platformio.ini                   |   13 +
 readTemplate/src/src.cpp                      |  192 +++
 25 files changed, 9510 insertions(+)
 create mode 100644 FingerPrintMatching/include/DFRobot_ID809.h
 create mode 100644 FingerPrintMatching/platformio.ini
 create mode 100644 FingerPrintMatching/src/DFRobot_ID809.cpp
 create mode 100644 FingerPrintMatching/src/src.cpp
 create mode 100644 FingerPrintRegister/include/DFRobot_ID809.h
 create mode 100644 FingerPrintRegister/platformio.ini
 create mode 100644 FingerPrintRegister/src/DFRobot_ID809.cpp
 create mode 100644 FingerPrintRegister/src/src.cpp
 create mode 100644 FingerPrintUnregister/include/DFRobot_ID809.h
 create mode 100644 FingerPrintUnregister/platformio.ini
 create mode 100644 FingerPrintUnregister/src/DFRobot_ID809.cpp
 create mode 100644 FingerPrintUnregister/src/platformio.ini
 create mode 100644 FingerPrintUnregister/src/src.cpp
 create mode 100644 RegFPwithHash/lib/DFRobot_ID809/DFRobot_ID809.cpp
 create mode 100644 RegFPwithHash/lib/DFRobot_ID809/DFRobot_ID809.h
 create mode 100644 RegFPwithHash/platformio.ini
 create mode 100644 RegFPwithHash/src/src.cpp
 create mode 100644 matchFPandHash/lib/DFRobot_ID809/DFRobot_ID809.cpp
 create mode 100644 matchFPandHash/lib/DFRobot_ID809/DFRobot_ID809.h
 create mode 100644 matchFPandHash/platformio.ini
 create mode 100644 matchFPandHash/src/src.cpp
 create mode 100644 readTemplate/lib/DFRobot_ID809/DFRobot_ID809.cpp
 create mode 100644 readTemplate/lib/DFRobot_ID809/DFRobot_ID809.h
 create mode 100644 readTemplate/platformio.ini
 create mode 100644 readTemplate/src/src.cpp

diff --git a/FingerPrintMatching/include/DFRobot_ID809.h b/FingerPrintMatching/include/DFRobot_ID809.h
new file mode 100644
index 0000000..4cb90d9
--- /dev/null
+++ b/FingerPrintMatching/include/DFRobot_ID809.h
@@ -0,0 +1,494 @@
+/*!
+ * @file DFRobot_ID809.h
+ * @brief Define basic structure of DFRobot_ID809 class
+ * @n This is an library for capacitive fingerprint module
+ * @n Main functions: fingerprint image capturing, fingerprint comparison, fingerprint deletion
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#ifndef _DFRobot_ID809_H
+#define _DFRobot_ID809_H
+
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+#include "WProgram.h"
+#endif
+#include <Wire.h>
+
+#include <stdint.h>
+
+//Open this macro to see the detailed running process of the program 
+
+//#define ENABLE_DBG
+#ifdef ENABLE_DBG
+#define LDBG(...) if(dbg) {dbg->print("["); dbg->print(__FUNCTION__); dbg->print("(): "); dbg->print(__LINE__); dbg->print(" ] "); dbg->println(__VA_ARGS__);}
+#else
+#define LDBG(...)
+#endif
+
+extern Stream *dbg;
+
+  /*
+   Frame struct of command packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  CMD;
+  uint16_t  LEN;
+  uint8_t payload[0];
+}__attribute__ ((packed)) sCmdPacketHeader_t, *pCmdPacketHeader_t;
+
+  /*
+   Frame struct of response packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  RCM;
+  uint16_t  LEN;
+  uint16_t  RET;
+  uint8_t   payload[0];
+}__attribute__ ((packed)) sRcmPacketHeader_t, *pRcmPacketHeader_t;
+
+  
+
+
+class DFRobot_ID809{
+public: 
+
+#define FINGERPRINT_CAPACITY     80      //Fingerprint module capacity
+#define MODULE_SN_SIZE           16      //Module SN length 
+
+
+#define DELALL                   0xFF    //Delete all fingerprints 
+
+#define CMD_PREFIX_CODE          0xAA55  //Command packet prefix code 
+#define RCM_PREFIX_CODE          0x55AA  //Response packet prefix code 
+#define CMD_DATA_PREFIX_CODE     0xA55A  //Command data packet prefix code 
+#define RCM_DATA_PREFIX_CODE     0x5AA5  //Response data packet prefix code 
+
+#define CMD_TYPE                 0xF0    //Command packet type 
+#define RCM_TYPE                 0xF0    //Response packet type 
+#define DATA_TYPE                0x0F    //Data packet type 
+
+#define CMD_TEST_CONNECTION      0X0001  //Test connection 
+#define CMD_SET_PARAM            0X0002  //Set parameter
+#define CMD_GET_PARAM            0X0003  //Read parameter 
+#define CMD_DEVICE_INFO          0X0004  //Read device information 
+#define CMD_SET_MODULE_SN        0X0008  //Set module serial number 
+#define CMD_GET_MODULE_SN        0X0009  //Read module serial number
+#define CMD_ENTER_STANDBY_STATE  0X000C  //Enter sleep mode 
+#define CMD_GET_IMAGE            0X0020  //Capture fingerprint image 
+#define CMD_FINGER_DETECT        0X0021  //Detect fingerprint 
+    #define CMD_UP_IMAGE_CODE        0X0022  //Upload fingerprint image to host 
+    #define CMD_DOWN_IMAGE           0X0023  //Download fingerprint image to module 
+#define CMD_SLED_CTRL            0X0024  //Control collector backlight 
+#define CMD_STORE_CHAR           0X0040  //Save fingerprint template data into fingerprint library 
+#define CMD_LOAD_CHAR            0X0041  //Read fingerprint in module and save it in RAMBUFFER temporarily  
+    #define CMD_UP_CHAR              0X0042  //Upload the fingerprint template saved in RAMBUFFER to host 
+    #define CMD_DOWN_CHAR            0X0043  //Download fingerprint template to module designated RAMBUFFER
+#define CMD_DEL_CHAR             0X0044  //Delete fingerprint in specific ID range 
+#define CMD_GET_EMPTY_ID         0X0045  //Get the first registerable ID in specific ID range 
+#define CMD_GET_STATUS           0X0046  //Check if the designated ID has been registered 
+#define CMD_GET_BROKEN_ID        0X0047  //Check whether there is damaged data in fingerprint library of specific range
+#define CMD_GET_ENROLL_COUNT     0X0048  //Get the number of registered fingerprints in specific ID range 
+#define CMD_GET_ENROLLED_ID_LIST 0X0049  //Get registered ID list
+#define CMD_GENERATE             0X0060  //Generate template from the fingerprint images saved in IMAGEBUFFER temporarily 
+#define CMD_MERGE                0X0061  //Synthesize fingerprint template data 
+#define CMD_MATCH                0X0062  //Compare templates in 2 designated RAMBUFFER 
+#define CMD_SEARCH               0X0063  //1:N Recognition in specific ID range 
+#define CMD_VERIFY               0X0064  //Compare specific RAMBUFFER template with specific ID template in fingerprint library 
+
+#define ERR_SUCCESS              0x00    //Command processed successfully 
+#define ERR_ID809                0xFF    //error 
+
+
+public:
+  
+  typedef enum{
+    eBreathing = 1,  //Breathing 
+    eFastBlink,      //Quick blink
+    eKeepsOn,        //On
+    eNormalClose,    //Off
+    eFadeIn,         //Fade in 
+    eFadeOut,        //Fade out
+    eSlowBlink       //Slow blink
+  }eLEDMode_t;
+  
+  typedef enum{
+    eLEDGreen = 1,   //green 
+    eLEDRed,         //red 
+    eLEDYellow,      //yellow
+    eLEDBlue,        //blue
+    eLEDCyan,        //cyan
+    eLEDMagenta,     //magenta
+    eLEDWhite        //white
+  }eLEDColor_t;
+   
+  typedef enum{
+    e9600bps = 1,
+    e19200bps,
+    e38400bps,
+    e57600bps,
+    e115200bps
+  }eDeviceBaudrate_t;
+  
+  typedef enum{
+    eErrorSuccess            = 0x00,    //Command processed successfully
+    eErrorFail               = 0x01,    //Command processing failed 
+    eErrorVerify             = 0x10,    //1:1 Templates comparison in specific ID failed 
+    eErrorIdentify           = 0x11,    //1:N comparison has been made, no same templates here 
+    eErrorTmplEmpty          = 0x12,    //No registered template in the designated ID 
+    eErrorTmplNotEmpty       = 0x13,    //Template already exists in the specified ID 
+    eErrorAllTmplEmpty       = 0x14,    //No registered Template 
+    eErrorEmptyIDNoexist     = 0x15,    //No registerable Template ID 
+    eErrorBrokenIDNoexist    = 0x16,    //No damaged Template 
+    eErrorInvalidTmplData    = 0x17,    //The designated Template Data is invalid 
+    eErrorDuplicationID      = 0x18,    //The fingerprint has been registered 
+    eErrorBadQuality         = 0x19,    //Poor quality fingerprint image 
+    eErrorMergeFail          = 0x1A,    //Template synthesis failed 
+    eErrorNotAuthorized      = 0x1B,    //Communication password not authorized 
+    eErrorMemory             = 0x1C,    //Error in exernal Flash burning 
+    eErrorInvalidTmplNo      = 0x1D,    //The designated template ID is invalid 
+    eErrorInvalidParam       = 0x22,    //Incorrect parameter has been used 
+    eErrorTimeOut            = 0x23,    //Acquisition timeout 
+    eErrorGenCount           = 0x25,    //Invalid number of fingerprint synthesis 
+    eErrorInvalidBufferID    = 0x26,    //Wrong Buffer ID value 
+    eErrorFPNotDetected      = 0x28,    //No fingerprint input into fingerprint reader 
+    eErrorFPCancel           = 0x41,    //Command cancelled 
+    eErrorRecvLength         = 0x42,    //Wrong length of recieved data 
+    eErrorRecvCks            = 0x43,    //Wrong check code 
+    eErrorGatherOut          = 0x45,    //Exceed upper limit of acquisition times 
+    eErrorRecvTimeout        = 0x46     //Communication timeout 
+  }eError_t;
+  
+  typedef struct{
+    /**< Gesture enumeration variable X */
+    eError_t error;
+    /**< Description about the gesture enumeration variable X */
+    const char * description;
+  }sErrorDescription_t;
+
+public:
+  DFRobot_ID809();
+  ~DFRobot_ID809();
+  
+  /**
+   * @brief Init communication port
+   * @param Software serial or hardware serial 
+   * @return true or false
+   */
+  bool begin(Stream &s_);
+  
+  /**
+   * @brief Test whether the module connection is ok
+   * @return true or false
+   */
+  bool isConnected();
+  
+  /**
+   * @brief Set module ID
+   * @param ID:1-255
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDeviceID(uint8_t deviceID);
+  
+  /**
+   * @brief Set module security level 
+   * @param security level:1-5
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSecurityLevel(uint8_t securityLevel);
+  
+  /**
+   * @brief Set module fingerprint replication check (Check whether the fingperint has been registered when saving it)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDuplicationCheck(uint8_t duplicationCheck);
+  
+  /**
+   * @brief Set module baud rate 
+   * @param Baudrate:in typedef enum eDeviceBaudrate_t
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setBaudrate(eDeviceBaudrate_t baudrate);
+  
+  /**
+   * @brief Set module self-learning function (Update fingeprint when fingerprint comparison succeeds)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSelfLearn(uint8_t selfLearn);
+  
+  /**
+   * @brief Read module ID
+   * @return ID号:1-255 or ERR_ID809
+   */
+  uint8_t getDeviceID();
+  
+  /**
+   * @brief Read module security level 
+   * @return Security level:1-5 or ERR_ID809
+   */
+  uint8_t getSecurityLevel();
+  
+  /**
+   * @brief Read module fingerprint replication check status
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getDuplicationCheck();
+  
+  /**
+   * @brief Read module baud rate 
+   * @return Baudrate:in typedef enum eDEVICE_BAUDRATE_t or ERR_ID809
+   */
+  uint8_t getBaudrate();
+  
+  /**
+   * @brief Read module self-learning function status 
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getSelfLearn();
+   
+  /**
+   * @brief Read device number 
+   * @return Device number
+   */
+  String getDeviceInfo();
+  
+  /**
+   * @brief Set serial number
+   * @param String pointer 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setModuleSN(const char* SN);
+  /**
+   * @brief Read serial number 
+   * @return Serial number
+   */
+  String getModuleSN();
+  
+  /**
+   * @brief Set LED
+   * @param mode:in typedef enum eLEDMode_t
+   * @param color:in typedef enum eLEDColor_t
+   * @param blink Count: 00 represents blinking all the time
+   * @This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount);
+  
+  /**
+   * @brief Detect if there is finger touched 
+   * @return 1(Touched) or 0(No touch)
+   */
+  uint8_t detectFinger();
+  
+  /**
+   * @brief Get the first registerable ID 
+   * @return Registerable ID or ERR_ID809
+   */
+  uint8_t getEmptyID();
+  
+  /**
+   * @brief Check if the ID has been registered 
+   * @return 0(Registered), 1(Unregistered) or ERR_ID809
+   */
+  uint8_t getStatusID(uint8_t ID);
+  
+  /**
+   * @brief Get the number of registered users 
+   * @return Number of registered users or ERR_ID809
+   */
+  uint8_t getEnrollCount();
+  
+  /**
+   * @brief Get registered user list 
+   * @return 0(succeed) or ERR_ID809
+   */
+   uint8_t getEnrolledIDList(uint8_t* list);
+  
+  /**
+   * @brief Fingerprint acquisition 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t collectionFingerprint(uint16_t timeout);
+  
+  /**
+   * @brief Save fingerprint 
+   * @param Fingerprint ID
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t storeFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Delete fingerprint 
+   * @param Delete ID or DELALL(delete all)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t delFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Match the fingerprint with all fingeprints 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t search();
+
+  /**
+   * @brief Match the fingerprint with specific fingerprint 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t verify(uint8_t ID);
+
+  /**
+   * @brief Compare templates in two specific RamBuffers
+   * @param RamBuffer number 
+   * @param RamBuffer number 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t match(uint8_t RamBufferID0, uint8_t RamBufferID1);
+  
+  /**
+   * @brief Get the number of damaged fingerprints 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenQuantity();
+
+  /**
+   * @brief Get the first damaged fingerprint ID 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenID();
+  
+  /**
+   * @brief Take out fingerprint template, temporarily save into RamBuffer
+   * @param Fingerprint ID 
+   * @param RamBuffer number 0-2
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t loadFingerprint(uint8_t ID, uint8_t RamBufferID);
+  
+  /**
+   * @brief Enter sleep mode
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t enterSleepState();
+  
+  /**
+   * @brief Get error information
+   * @return Text description of error information
+   */
+  String getErrorDescription();
+  
+  bool setDbgSerial(Stream &s_){dbg = &s_; return true;}
+protected:
+   /**
+   * @brief Set parameter 
+   * @param Data type+ data
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setParam(uint8_t* data);
+  
+   /**
+   * @brief Read parameter 
+   * @param Data type 
+   * @return data or ERR_ID809
+   */
+  uint8_t getParam(uint8_t* data);
+  
+  /**
+   * @brief Capture fingerprint image 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t getImage();
+   
+   /**
+   * @brief Take image as template 
+   * @param Ram Buffer number
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t generate(uint8_t RamBufferID);
+  
+ /**
+   * @brief Fingerprint synthesis 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t merge();
+  
+ /**
+   * @brief Packing data frame 
+   * @param Data type:CMD_TYPE or DATA_TYPE
+   * @param Command
+   * @param Data 
+   * @param Length
+   * @return Data frame 
+   */
+  pCmdPacketHeader_t pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len);
+  
+ /**
+   * @brief Send data 
+   * @param Data frame
+   */
+  void sendPacket(pCmdPacketHeader_t header);
+  
+ /**
+   * @brief Read byte 
+   * @param Pointer for saving data 
+   * @param Length of data to be received 
+   * @return Actual received data length 
+   */
+  size_t readN(void* buf_, size_t len);
+  
+ /**
+   * @brief Read frame header 
+   * @param Frame header struct of response packet
+   * @return Response packet type:RCM_TYPE,DATA_TYPE or 1(reading timeout)
+   */
+  uint16_t readPrefix( pRcmPacketHeader_t header );
+  
+ /**
+   * @brief Read data
+   * @param Pointer for saving data 
+   * @return 0(success) or ERR_ID809
+   */
+  uint8_t responsePayload(void* buf);
+  
+ /**
+   * @brief Get command packet CKS
+   * @param Command packet frame 
+   * @return CKS
+   */
+  uint16_t getCmdCKS(pCmdPacketHeader_t packet);
+  
+ /**
+   * @brief Get response packet CKS
+   * @param Response packet frame 
+   * @return CKS
+   */
+  uint16_t getRcmCKS(pRcmPacketHeader_t packet);
+  
+private:
+  Stream *s;
+  uint8_t buf[20];     //For saving response packet data 
+  pCmdPacketHeader_t  sendHeader;
+  pRcmPacketHeader_t  recHeader;
+  
+  static const sErrorDescription_t /*PROGMEM*/ errorDescriptionsTable[26];   //Error information list 
+  
+  uint8_t _number = 0;       //Fingerprint acquisistion times 
+  eError_t _error;           //Error code 
+  uint16_t _PacketSize = 0;  //Data packet length to be sent 
+};
+
+#endif
diff --git a/FingerPrintMatching/platformio.ini b/FingerPrintMatching/platformio.ini
new file mode 100644
index 0000000..3f073b4
--- /dev/null
+++ b/FingerPrintMatching/platformio.ini
@@ -0,0 +1,12 @@
+[env:teensy_u2f]
+
+platform = teensy
+framework = arduino
+board = teensy31
+build_flags = 
+	-D USB_SERIAL 
+	-D TEENSY_OPT_SMALLEST_CODE
+
+lib_deps = 
+	Wire 
+
diff --git a/FingerPrintMatching/src/DFRobot_ID809.cpp b/FingerPrintMatching/src/DFRobot_ID809.cpp
new file mode 100644
index 0000000..4561698
--- /dev/null
+++ b/FingerPrintMatching/src/DFRobot_ID809.cpp
@@ -0,0 +1,748 @@
+/*!
+ * @file DFRobot_ID809.cpp
+ * @brief Define the basic structure of DFRobot_ID809 class and the implementation of underlying methods 
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#include "DFRobot_ID809.h"
+#include <Arduino.h>
+#include <string.h>
+#include <stdio.h>
+Stream *dbg=NULL;
+
+DFRobot_ID809::DFRobot_ID809()
+  :s(NULL){
+        
+}
+
+DFRobot_ID809::~DFRobot_ID809(){
+        
+}
+
+bool DFRobot_ID809::begin(Stream &s_){
+    s = &s_;
+    if(s == NULL){
+        return false;
+    }
+    return true;
+}
+
+bool DFRobot_ID809::isConnected(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_TEST_CONNECTION, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        return true;
+    }else{
+        return false;
+    }
+}
+
+uint8_t DFRobot_ID809::setDeviceID(uint8_t deviceID){
+    uint8_t data[5] = {0};    //data:1bytes Parameter Type+4bytes Parameter Value
+    data[1] = deviceID;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSecurityLevel(uint8_t securityLevel){
+    uint8_t data[5] = {0};
+    data[0] = 1;
+    data[1] = securityLevel;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setDuplicationCheck(uint8_t duplicationCheck){
+    uint8_t data[5] = {0};
+    data[0] = 2;
+    data[1] = duplicationCheck;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setBaudrate(eDeviceBaudrate_t baudrate){
+    uint8_t data[5] = {0};
+    data[0] = 3;
+    data[1] = baudrate;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSelfLearn(uint8_t selfLearn){
+    uint8_t data[5] = {0};
+    data[0] = 4;
+    data[1] = selfLearn;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDeviceID(){
+    uint8_t data[1];  //data:1byte Parameter Type
+    data[0] = 0;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSecurityLevel(){
+    uint8_t data[1];
+    data[0] = 1;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDuplicationCheck(){
+    uint8_t data[1];
+    data[0] = 2;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBaudrate(){
+    uint8_t data[1];
+    data[0] = 3;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSelfLearn(){
+    uint8_t data[1];
+    data[0] = 4;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+String DFRobot_ID809::getDeviceInfo(){
+    char *data;
+    uint8_t result;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEVICE_INFO, NULL, 0);
+    sendPacket(header);
+    free(header);
+    result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setModuleSN(const char* SN){
+    char data[2];
+    data[0] = MODULE_SN_SIZE;
+    if(strlen(SN) > MODULE_SN_SIZE){
+        LDBG("The serial number exceeds 15 characters");
+        return ERR_ID809;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_MODULE_SN, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    header = pack(DATA_TYPE, CMD_SET_MODULE_SN, SN, MODULE_SN_SIZE);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+String DFRobot_ID809::getModuleSN(){
+    char *data;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_MODULE_SN, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount){
+    char data[4] = {0};
+    data[0] = mode;
+    data[2] = data[1] = color;
+    data[3] = blinkCount;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SLED_CTRL, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::detectFinger(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_FINGER_DETECT, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEmptyID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;     //80 fingerprints at most, default to full range 
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_EMPTY_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getStatusID(uint8_t ID){
+    char data[2] = {0};
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_STATUS, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEnrollCount(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLL_COUNT, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+#define  getID(A, V)  (A[0 + V/8] & (0x01 << (V & 0x07)))
+uint8_t DFRobot_ID809::getEnrolledIDList(uint8_t* list)
+{
+    char *data;
+    uint8_t i = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLLED_ID_LIST, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    uint16_t dataLen = buf[0]+(buf[1]<<8);
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    ret = responsePayload(data);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else{
+        for(uint16_t j = 0; j < (dataLen*8); j++){
+            if(getID(data, j) != 0){
+                list[i] = j;
+                i++;
+            }
+        }
+    }
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::storeFingerprint(uint8_t ID){
+    char data[4] = {0};
+    uint8_t ret;
+    ret = merge();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number = 0;
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+    
+}
+
+uint8_t DFRobot_ID809::delFingerprint(uint8_t ID){
+    char data[4] = {0};
+    if(ID == DELALL){
+        data[0] = 1;
+        data[2] = FINGERPRINT_CAPACITY;
+    }else{
+        data[0] = data[2] = ID;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEL_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::search(){
+    char data[6] = {0};
+    data[2] = 1;
+    data[4] = FINGERPRINT_CAPACITY;
+    _number = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SEARCH, data, 6);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::verify(uint8_t ID){
+    char data[4] = {0};
+    data[0] = ID;
+    _number = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_VERIFY, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::match(uint8_t RamBufferID0, uint8_t RamBufferID1){
+    char data[4] = {0};
+    data[0] = RamBufferID0;
+    data[2] = RamBufferID1;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenQuantity(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[2];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::loadFingerprint(uint8_t ID, uint8_t RamBufferID){
+    char data[4] = {0};
+    data[0] = ID;
+    data[2] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::enterSleepState(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_ENTER_STANDBY_STATE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_PARAM, (const char *)data, 5);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_PARAM, (const char *)data, 1);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getImage(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::collectionFingerprint(uint16_t timeout){  //Collect fingerprint 
+    uint16_t i = 0;
+    uint8_t ret;
+    if(_number > 2){
+        _error = eErrorGatherOut;
+        LDBG("Exceed upper limit of acquisition times ");
+        return ERR_ID809;
+    }
+    while(!detectFinger()){
+        if(timeout != 0){
+            delay(10);
+            if(++i > timeout*1){
+                _error = eErrorTimeOut;
+                LDBG("Acquisition timeout ");
+                LDBG("ret=");LDBG(ret);
+                return ERR_ID809;
+            }
+       }
+    }
+    ret = getImage();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    ret = generate(_number);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number++;
+    return ret;
+}
+
+uint8_t DFRobot_ID809::generate(uint8_t RamBufferID){
+    char data[2] = {0};
+    data[0] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GENERATE, (const char *)data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::merge(){
+    char data[3] = {0};
+    data[2] = _number;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MERGE, data, 3);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+pCmdPacketHeader_t DFRobot_ID809::pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len){
+    pCmdPacketHeader_t header;
+    uint16_t cks=0;
+    uint16_t dataLen;
+    if(type == CMD_TYPE){    //Structure of command packet, fixed 26 bytes:10(frame header)+14(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+16+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_PREFIX_CODE;
+        for(int i=0;i<16;i++){
+            header->payload[i] = 0;
+        }
+        dataLen = 16;   //Length of data to be replicated 
+    }else{                   //Structure of command data packet, unfixed length:10(frame header)+LEN(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+len+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_DATA_PREFIX_CODE;
+        dataLen = len;   //Length of data to be replicated 
+    }
+    header->SID = 0;
+    header->DID = 0;
+    header->CMD = cmd;
+    header->LEN = len;
+    if(len){
+        memcpy(header->payload, payload, len);
+    }
+    cks = getCmdCKS(header);
+    memcpy(&header->payload[dataLen],&cks,2);
+    _PacketSize = sizeof(sCmdPacketHeader_t) + dataLen +2;
+    return header;
+}
+
+
+void DFRobot_ID809::sendPacket(pCmdPacketHeader_t header){
+    s->write((uint8_t *)header,_PacketSize);
+}
+
+uint8_t DFRobot_ID809::responsePayload(void* buf){
+    sRcmPacketHeader_t header;
+    uint16_t dataLen,dataCount,cks;
+    uint8_t ch,ret;
+    int16_t type;
+    type = readPrefix(&header);
+    if(type == 1){
+        LDBG("--recv timeout---");
+        _error = eErrorRecvTimeout;
+        return ERR_ID809;
+    }
+    pRcmPacketHeader_t packet;
+    if(type == RCM_TYPE){    //Structure of response packet, fixed 26 bytes: 10(frame header)+14(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+14+2);
+        dataLen = 14+2;      //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }else{                   //Structure of response data packet, unfixed length: 10(frame header)+(LEN-2)(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+header.LEN);
+        dataLen = header.LEN;  //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }
+    memcpy(packet, &header, 10);
+    dataCount = readN(packet->payload, dataLen);
+    cks = packet->payload[dataLen-2]+(packet->payload[dataLen-1]<<8);
+    ret = (header.RET&0xFF);
+    _error = (eError_t)ret;
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else if(dataLen != dataCount){
+        LDBG("--recvRspPacket length error---");
+        _error = eErrorRecvLength;
+        ret = ERR_ID809;
+    }else if(getRcmCKS(packet) != cks){
+        LDBG("--recvRspPacket cks error---");
+        _error = eErrorRecvCks;
+        ret = ERR_ID809;
+    }else{
+        LDBG("--recvRspPacket OK---");
+        memcpy(buf, packet->payload, dataLen);
+    }
+    free(packet);
+    packet = NULL;
+    return ret;
+}
+
+uint16_t DFRobot_ID809::readPrefix( pRcmPacketHeader_t header ){
+    uint8_t ch,ret;
+    typedef enum{
+        RECV_HEADER_INIT,
+        RECV_HEADER_AA,
+        RECV_HEADER_A5,
+        RECV_HEADER_OK
+    }eRecvHeaderState;
+    eRecvHeaderState state = RECV_HEADER_INIT;
+    while(state != RECV_HEADER_OK){   //Can judge the received command packet and command data packet prefix at the same time 
+        if(readN(&ch, 1) != 1){
+            ret = 1;
+            return ret;
+        }
+        if((ch == 0xAA) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_AA;
+            continue;
+        }else if((ch == 0xA5) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_A5;
+            continue;
+        }else if((ch == 0x55) && (state == RECV_HEADER_AA)){
+            state = RECV_HEADER_OK;
+            ret = RCM_TYPE;
+            continue;
+        }else if((ch == 0x5A) && (state == RECV_HEADER_A5)){
+            state = RECV_HEADER_OK;
+            ret = DATA_TYPE;
+            continue;
+        }else{
+            state = RECV_HEADER_INIT;
+            if(ch == 0xAA){
+                state = RECV_HEADER_AA;
+            }else if(ch == 0xA5){
+                state = RECV_HEADER_A5;
+            }
+        }
+    }
+    if(ret == RCM_TYPE){
+        header->PREFIX = RCM_PREFIX_CODE;
+    }else if(ret == DATA_TYPE){
+        header->PREFIX = RCM_DATA_PREFIX_CODE;
+    }
+    readN(&header->SID, 1);
+    readN(&header->DID, 1);
+    readN(&header->RCM, 2);
+    readN(&header->LEN, 2);
+    readN(&header->RET, 2);
+    return ret;
+}
+
+size_t DFRobot_ID809::readN(void* buffer, size_t len){
+    size_t offset = 0,left = len;
+    uint8_t *buf = (uint8_t*)buffer;
+    long long curr = millis();
+    while(left){
+        if(s->available()){
+            buf[offset++] = s->read();
+            left--;
+        }
+        if(millis() - curr > 5000){
+            LDBG("----------!!!!!!!!!recv timeout----------");
+            break;
+        }
+    }
+    return offset;
+}
+
+uint16_t DFRobot_ID809::getCmdCKS(pCmdPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->CMD&0xFF;
+    cks += packet->CMD>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint8_t i = 0; i < packet->LEN; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+uint16_t DFRobot_ID809::getRcmCKS(pRcmPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->RCM&0xFF;
+    cks += packet->RCM>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    cks += packet->RET&0xFF;
+    cks += packet->RET>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint8_t i = 0; i < packet->LEN-2; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+const DFRobot_ID809::sErrorDescription_t DFRobot_ID809::errorDescriptionsTable[]={
+  {eErrorSuccess, "Command processed successfully"},
+  {eErrorFail, "Command processing failed"},
+  {eErrorVerify, "1:1 comparison failed"},
+  {eErrorIdentify, "Comparison with all fingerprints failed"},
+  {eErrorTmplEmpty, "No fingerprint in designated ID"},
+  {eErrorTmplNotEmpty, "Designated ID has fingerprint"},
+  {eErrorAllTmplEmpty, "Module unregistered fingerprint"},
+  {eErrorEmptyIDNoexist, "No registerable ID here"},
+  {eErrorBrokenIDNoexist, "No broken fingerprint"},
+  {eErrorInvalidTmplData, "Invalid desingated fingerprint data"},
+  {eErrorDuplicationID, "The fingerprint has been registered"},
+  {eErrorBadQuality, "Poor quality fingerprint image"},
+  {eErrorMergeFail, "Fingerprint synthesis failed"},
+  {eErrorNotAuthorized, "Communication password not authorized"},
+  {eErrorMemory, "External Flash burning error"},
+  {eErrorInvalidTmplNo, "Invalid designated ID"},
+  {eErrorInvalidParam, "Incorrect parameter"},
+  {eErrorTimeOut, "Acquisition timeout"},
+  {eErrorGenCount, "Invalid number of fingerprint synthesis"},
+  {eErrorInvalidBufferID, "Incorrect Buffer ID value"},
+  {eErrorFPNotDetected, "No fingerprint input into fingerprint reader"},
+  {eErrorFPCancel, "Command cancelled"},
+  {eErrorRecvLength, "Wrong data length"},
+  {eErrorRecvCks, "Wrong data check code"},
+  {eErrorGatherOut, "Exceed upper limit of acquisition times"},
+  {eErrorRecvTimeout,"Data reading timeout"}
+};
+
+String DFRobot_ID809::getErrorDescription()
+{
+    for(int i=0;i<sizeof(errorDescriptionsTable)/sizeof(errorDescriptionsTable[0]);i++){
+        if(_error == errorDescriptionsTable[i].error){
+          return errorDescriptionsTable[i].description;
+        }
+    }
+    return "";
+}
diff --git a/FingerPrintMatching/src/src.cpp b/FingerPrintMatching/src/src.cpp
new file mode 100644
index 0000000..d82aba8
--- /dev/null
+++ b/FingerPrintMatching/src/src.cpp
@@ -0,0 +1,107 @@
+/*!
+ * @file fingerprintMatching.ino
+ * @brief Gather fingerprint and compare it with fingerprints in fingerprint library
+ * @n Experiment Phenomenon:capture fingerprint image and compare it with all fingerprints in the fingerprint library
+                If matched successfully, light up green LED and print ID number. Return 0 when failed.
+ * @copyright  Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](Eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+*/
+#include <Arduino.h>
+#include "DFRobot_ID809.h"
+
+/*Use software serial when using UNO or NANO*/
+//#if ((defined ARDUINO_AVR_UNO) || (defined ARDUINO_AVR_NANO))
+//    #include <SoftwareSerial.h>
+//    SoftwareSerial Serial1(2, 3);  //RX, TX
+//    #define FPSerial Serial1
+//#else
+//    #define FPSerial Serial1
+//#endif
+
+#define FPSerial Serial3
+
+DFRobot_ID809 fingerprint;
+//String desc;
+
+void setup(){
+  /*Init print serial port*/
+  Serial.begin(9600);
+  /*Init FPSerial*/
+  FPSerial.begin(115200);
+  /*Take FPSerial as communication serial port of the fingerprint module*/
+  fingerprint.begin(FPSerial);
+  /*Wait for Serial to open*/
+  //while(!Serial);
+  /*Test whether the device can properly communicate with mainboard
+   Return true or false
+    */
+  while(fingerprint.isConnected() == false){
+    Serial.println("Communication with device failed, please check connection");
+    /*Get error code information*/
+    //desc = fingerprint.getErrorDescription();
+    //Serial.println(desc);
+    delay(1000);
+  }
+}
+
+uint8_t ret;
+
+void loop(){
+  /*Set fingerprint LED ring mode, color, and number of blinks
+    Can be set as follows:
+    Parameter 1:<LEDMode>
+    eBreathing   eFastBlink   eKeepsOn    eNormalClose
+    eFadeIn      eFadeOut     eSlowBlink   
+    Parameter 2:<LEDColor>
+    eLEDGreen  eLEDRed      eLEDYellow   eLEDBlue
+    eLEDCyan   eLEDMagenta  eLEDWhite
+    Parameter 3:<number of blinks> 0 represents blinking all the time
+    This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+   */
+  fingerprint.ctrlLED(/*LEDMode = */fingerprint.eBreathing, /*LEDColor = */fingerprint.eLEDBlue, /*blinkCount = */0);
+  Serial.println("Please press down your finger");
+  /*Capture fingerprint image, Disable the collection timeout function 
+    If succeed return 0, otherwise return ERR_ID809
+   */
+  if((fingerprint.collectionFingerprint(/*timeout=*/0)) != ERR_ID809){
+    /*Set fingerprint LED ring to quick blink in yellow 3 times*/
+    fingerprint.ctrlLED(/*LEDMode = */fingerprint.eFastBlink, /*LEDColor = */fingerprint.eLEDYellow, /*blinkCount = */3);
+    Serial.println("Capturing succeeds");
+      Serial.println("Please release your finger");
+    /*Wait for finger to release
+      Return 1 when finger is detected, otherwise return 0 
+     */
+    while(fingerprint.detectFinger());
+    
+    /*Compare the captured fingerprint with all the fingerprints in the fingerprint library 
+      Return fingerprint ID(1-80) if succeed, return 0 when failed 
+     */
+    ret = fingerprint.search();
+    /*Compare the captured fingerprint with a fingerprint of specific ID 
+      Return fingerprint ID(1-80) if succeed, return 0 when failed 
+     */
+    //ret = fingerprint.verify(/*Fingerprint ID = */1);  
+    if(ret != 0){
+      /*Set fingerprint LED ring to always ON in green */
+      fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDGreen, /*blinkCount = */0);
+      Serial.print("Matching succeeds,ID=");
+      Serial.println(ret);
+    }else{
+      /*Set fingerprint LED ring to always ON in red*/
+      fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDRed, /*blinkCount = */0);
+      Serial.println("Matching fails");
+    }
+  }else{
+    Serial.println("Capturing fails");
+    /*Get error code information*/
+    //desc = fingerprint.getErrorDescription();
+    //Serial.println(desc);
+  }
+  Serial.println("-----------------------------");
+  delay(1000);
+}
diff --git a/FingerPrintRegister/include/DFRobot_ID809.h b/FingerPrintRegister/include/DFRobot_ID809.h
new file mode 100644
index 0000000..4cb90d9
--- /dev/null
+++ b/FingerPrintRegister/include/DFRobot_ID809.h
@@ -0,0 +1,494 @@
+/*!
+ * @file DFRobot_ID809.h
+ * @brief Define basic structure of DFRobot_ID809 class
+ * @n This is an library for capacitive fingerprint module
+ * @n Main functions: fingerprint image capturing, fingerprint comparison, fingerprint deletion
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#ifndef _DFRobot_ID809_H
+#define _DFRobot_ID809_H
+
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+#include "WProgram.h"
+#endif
+#include <Wire.h>
+
+#include <stdint.h>
+
+//Open this macro to see the detailed running process of the program 
+
+//#define ENABLE_DBG
+#ifdef ENABLE_DBG
+#define LDBG(...) if(dbg) {dbg->print("["); dbg->print(__FUNCTION__); dbg->print("(): "); dbg->print(__LINE__); dbg->print(" ] "); dbg->println(__VA_ARGS__);}
+#else
+#define LDBG(...)
+#endif
+
+extern Stream *dbg;
+
+  /*
+   Frame struct of command packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  CMD;
+  uint16_t  LEN;
+  uint8_t payload[0];
+}__attribute__ ((packed)) sCmdPacketHeader_t, *pCmdPacketHeader_t;
+
+  /*
+   Frame struct of response packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  RCM;
+  uint16_t  LEN;
+  uint16_t  RET;
+  uint8_t   payload[0];
+}__attribute__ ((packed)) sRcmPacketHeader_t, *pRcmPacketHeader_t;
+
+  
+
+
+class DFRobot_ID809{
+public: 
+
+#define FINGERPRINT_CAPACITY     80      //Fingerprint module capacity
+#define MODULE_SN_SIZE           16      //Module SN length 
+
+
+#define DELALL                   0xFF    //Delete all fingerprints 
+
+#define CMD_PREFIX_CODE          0xAA55  //Command packet prefix code 
+#define RCM_PREFIX_CODE          0x55AA  //Response packet prefix code 
+#define CMD_DATA_PREFIX_CODE     0xA55A  //Command data packet prefix code 
+#define RCM_DATA_PREFIX_CODE     0x5AA5  //Response data packet prefix code 
+
+#define CMD_TYPE                 0xF0    //Command packet type 
+#define RCM_TYPE                 0xF0    //Response packet type 
+#define DATA_TYPE                0x0F    //Data packet type 
+
+#define CMD_TEST_CONNECTION      0X0001  //Test connection 
+#define CMD_SET_PARAM            0X0002  //Set parameter
+#define CMD_GET_PARAM            0X0003  //Read parameter 
+#define CMD_DEVICE_INFO          0X0004  //Read device information 
+#define CMD_SET_MODULE_SN        0X0008  //Set module serial number 
+#define CMD_GET_MODULE_SN        0X0009  //Read module serial number
+#define CMD_ENTER_STANDBY_STATE  0X000C  //Enter sleep mode 
+#define CMD_GET_IMAGE            0X0020  //Capture fingerprint image 
+#define CMD_FINGER_DETECT        0X0021  //Detect fingerprint 
+    #define CMD_UP_IMAGE_CODE        0X0022  //Upload fingerprint image to host 
+    #define CMD_DOWN_IMAGE           0X0023  //Download fingerprint image to module 
+#define CMD_SLED_CTRL            0X0024  //Control collector backlight 
+#define CMD_STORE_CHAR           0X0040  //Save fingerprint template data into fingerprint library 
+#define CMD_LOAD_CHAR            0X0041  //Read fingerprint in module and save it in RAMBUFFER temporarily  
+    #define CMD_UP_CHAR              0X0042  //Upload the fingerprint template saved in RAMBUFFER to host 
+    #define CMD_DOWN_CHAR            0X0043  //Download fingerprint template to module designated RAMBUFFER
+#define CMD_DEL_CHAR             0X0044  //Delete fingerprint in specific ID range 
+#define CMD_GET_EMPTY_ID         0X0045  //Get the first registerable ID in specific ID range 
+#define CMD_GET_STATUS           0X0046  //Check if the designated ID has been registered 
+#define CMD_GET_BROKEN_ID        0X0047  //Check whether there is damaged data in fingerprint library of specific range
+#define CMD_GET_ENROLL_COUNT     0X0048  //Get the number of registered fingerprints in specific ID range 
+#define CMD_GET_ENROLLED_ID_LIST 0X0049  //Get registered ID list
+#define CMD_GENERATE             0X0060  //Generate template from the fingerprint images saved in IMAGEBUFFER temporarily 
+#define CMD_MERGE                0X0061  //Synthesize fingerprint template data 
+#define CMD_MATCH                0X0062  //Compare templates in 2 designated RAMBUFFER 
+#define CMD_SEARCH               0X0063  //1:N Recognition in specific ID range 
+#define CMD_VERIFY               0X0064  //Compare specific RAMBUFFER template with specific ID template in fingerprint library 
+
+#define ERR_SUCCESS              0x00    //Command processed successfully 
+#define ERR_ID809                0xFF    //error 
+
+
+public:
+  
+  typedef enum{
+    eBreathing = 1,  //Breathing 
+    eFastBlink,      //Quick blink
+    eKeepsOn,        //On
+    eNormalClose,    //Off
+    eFadeIn,         //Fade in 
+    eFadeOut,        //Fade out
+    eSlowBlink       //Slow blink
+  }eLEDMode_t;
+  
+  typedef enum{
+    eLEDGreen = 1,   //green 
+    eLEDRed,         //red 
+    eLEDYellow,      //yellow
+    eLEDBlue,        //blue
+    eLEDCyan,        //cyan
+    eLEDMagenta,     //magenta
+    eLEDWhite        //white
+  }eLEDColor_t;
+   
+  typedef enum{
+    e9600bps = 1,
+    e19200bps,
+    e38400bps,
+    e57600bps,
+    e115200bps
+  }eDeviceBaudrate_t;
+  
+  typedef enum{
+    eErrorSuccess            = 0x00,    //Command processed successfully
+    eErrorFail               = 0x01,    //Command processing failed 
+    eErrorVerify             = 0x10,    //1:1 Templates comparison in specific ID failed 
+    eErrorIdentify           = 0x11,    //1:N comparison has been made, no same templates here 
+    eErrorTmplEmpty          = 0x12,    //No registered template in the designated ID 
+    eErrorTmplNotEmpty       = 0x13,    //Template already exists in the specified ID 
+    eErrorAllTmplEmpty       = 0x14,    //No registered Template 
+    eErrorEmptyIDNoexist     = 0x15,    //No registerable Template ID 
+    eErrorBrokenIDNoexist    = 0x16,    //No damaged Template 
+    eErrorInvalidTmplData    = 0x17,    //The designated Template Data is invalid 
+    eErrorDuplicationID      = 0x18,    //The fingerprint has been registered 
+    eErrorBadQuality         = 0x19,    //Poor quality fingerprint image 
+    eErrorMergeFail          = 0x1A,    //Template synthesis failed 
+    eErrorNotAuthorized      = 0x1B,    //Communication password not authorized 
+    eErrorMemory             = 0x1C,    //Error in exernal Flash burning 
+    eErrorInvalidTmplNo      = 0x1D,    //The designated template ID is invalid 
+    eErrorInvalidParam       = 0x22,    //Incorrect parameter has been used 
+    eErrorTimeOut            = 0x23,    //Acquisition timeout 
+    eErrorGenCount           = 0x25,    //Invalid number of fingerprint synthesis 
+    eErrorInvalidBufferID    = 0x26,    //Wrong Buffer ID value 
+    eErrorFPNotDetected      = 0x28,    //No fingerprint input into fingerprint reader 
+    eErrorFPCancel           = 0x41,    //Command cancelled 
+    eErrorRecvLength         = 0x42,    //Wrong length of recieved data 
+    eErrorRecvCks            = 0x43,    //Wrong check code 
+    eErrorGatherOut          = 0x45,    //Exceed upper limit of acquisition times 
+    eErrorRecvTimeout        = 0x46     //Communication timeout 
+  }eError_t;
+  
+  typedef struct{
+    /**< Gesture enumeration variable X */
+    eError_t error;
+    /**< Description about the gesture enumeration variable X */
+    const char * description;
+  }sErrorDescription_t;
+
+public:
+  DFRobot_ID809();
+  ~DFRobot_ID809();
+  
+  /**
+   * @brief Init communication port
+   * @param Software serial or hardware serial 
+   * @return true or false
+   */
+  bool begin(Stream &s_);
+  
+  /**
+   * @brief Test whether the module connection is ok
+   * @return true or false
+   */
+  bool isConnected();
+  
+  /**
+   * @brief Set module ID
+   * @param ID:1-255
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDeviceID(uint8_t deviceID);
+  
+  /**
+   * @brief Set module security level 
+   * @param security level:1-5
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSecurityLevel(uint8_t securityLevel);
+  
+  /**
+   * @brief Set module fingerprint replication check (Check whether the fingperint has been registered when saving it)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDuplicationCheck(uint8_t duplicationCheck);
+  
+  /**
+   * @brief Set module baud rate 
+   * @param Baudrate:in typedef enum eDeviceBaudrate_t
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setBaudrate(eDeviceBaudrate_t baudrate);
+  
+  /**
+   * @brief Set module self-learning function (Update fingeprint when fingerprint comparison succeeds)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSelfLearn(uint8_t selfLearn);
+  
+  /**
+   * @brief Read module ID
+   * @return ID号:1-255 or ERR_ID809
+   */
+  uint8_t getDeviceID();
+  
+  /**
+   * @brief Read module security level 
+   * @return Security level:1-5 or ERR_ID809
+   */
+  uint8_t getSecurityLevel();
+  
+  /**
+   * @brief Read module fingerprint replication check status
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getDuplicationCheck();
+  
+  /**
+   * @brief Read module baud rate 
+   * @return Baudrate:in typedef enum eDEVICE_BAUDRATE_t or ERR_ID809
+   */
+  uint8_t getBaudrate();
+  
+  /**
+   * @brief Read module self-learning function status 
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getSelfLearn();
+   
+  /**
+   * @brief Read device number 
+   * @return Device number
+   */
+  String getDeviceInfo();
+  
+  /**
+   * @brief Set serial number
+   * @param String pointer 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setModuleSN(const char* SN);
+  /**
+   * @brief Read serial number 
+   * @return Serial number
+   */
+  String getModuleSN();
+  
+  /**
+   * @brief Set LED
+   * @param mode:in typedef enum eLEDMode_t
+   * @param color:in typedef enum eLEDColor_t
+   * @param blink Count: 00 represents blinking all the time
+   * @This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount);
+  
+  /**
+   * @brief Detect if there is finger touched 
+   * @return 1(Touched) or 0(No touch)
+   */
+  uint8_t detectFinger();
+  
+  /**
+   * @brief Get the first registerable ID 
+   * @return Registerable ID or ERR_ID809
+   */
+  uint8_t getEmptyID();
+  
+  /**
+   * @brief Check if the ID has been registered 
+   * @return 0(Registered), 1(Unregistered) or ERR_ID809
+   */
+  uint8_t getStatusID(uint8_t ID);
+  
+  /**
+   * @brief Get the number of registered users 
+   * @return Number of registered users or ERR_ID809
+   */
+  uint8_t getEnrollCount();
+  
+  /**
+   * @brief Get registered user list 
+   * @return 0(succeed) or ERR_ID809
+   */
+   uint8_t getEnrolledIDList(uint8_t* list);
+  
+  /**
+   * @brief Fingerprint acquisition 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t collectionFingerprint(uint16_t timeout);
+  
+  /**
+   * @brief Save fingerprint 
+   * @param Fingerprint ID
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t storeFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Delete fingerprint 
+   * @param Delete ID or DELALL(delete all)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t delFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Match the fingerprint with all fingeprints 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t search();
+
+  /**
+   * @brief Match the fingerprint with specific fingerprint 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t verify(uint8_t ID);
+
+  /**
+   * @brief Compare templates in two specific RamBuffers
+   * @param RamBuffer number 
+   * @param RamBuffer number 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t match(uint8_t RamBufferID0, uint8_t RamBufferID1);
+  
+  /**
+   * @brief Get the number of damaged fingerprints 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenQuantity();
+
+  /**
+   * @brief Get the first damaged fingerprint ID 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenID();
+  
+  /**
+   * @brief Take out fingerprint template, temporarily save into RamBuffer
+   * @param Fingerprint ID 
+   * @param RamBuffer number 0-2
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t loadFingerprint(uint8_t ID, uint8_t RamBufferID);
+  
+  /**
+   * @brief Enter sleep mode
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t enterSleepState();
+  
+  /**
+   * @brief Get error information
+   * @return Text description of error information
+   */
+  String getErrorDescription();
+  
+  bool setDbgSerial(Stream &s_){dbg = &s_; return true;}
+protected:
+   /**
+   * @brief Set parameter 
+   * @param Data type+ data
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setParam(uint8_t* data);
+  
+   /**
+   * @brief Read parameter 
+   * @param Data type 
+   * @return data or ERR_ID809
+   */
+  uint8_t getParam(uint8_t* data);
+  
+  /**
+   * @brief Capture fingerprint image 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t getImage();
+   
+   /**
+   * @brief Take image as template 
+   * @param Ram Buffer number
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t generate(uint8_t RamBufferID);
+  
+ /**
+   * @brief Fingerprint synthesis 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t merge();
+  
+ /**
+   * @brief Packing data frame 
+   * @param Data type:CMD_TYPE or DATA_TYPE
+   * @param Command
+   * @param Data 
+   * @param Length
+   * @return Data frame 
+   */
+  pCmdPacketHeader_t pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len);
+  
+ /**
+   * @brief Send data 
+   * @param Data frame
+   */
+  void sendPacket(pCmdPacketHeader_t header);
+  
+ /**
+   * @brief Read byte 
+   * @param Pointer for saving data 
+   * @param Length of data to be received 
+   * @return Actual received data length 
+   */
+  size_t readN(void* buf_, size_t len);
+  
+ /**
+   * @brief Read frame header 
+   * @param Frame header struct of response packet
+   * @return Response packet type:RCM_TYPE,DATA_TYPE or 1(reading timeout)
+   */
+  uint16_t readPrefix( pRcmPacketHeader_t header );
+  
+ /**
+   * @brief Read data
+   * @param Pointer for saving data 
+   * @return 0(success) or ERR_ID809
+   */
+  uint8_t responsePayload(void* buf);
+  
+ /**
+   * @brief Get command packet CKS
+   * @param Command packet frame 
+   * @return CKS
+   */
+  uint16_t getCmdCKS(pCmdPacketHeader_t packet);
+  
+ /**
+   * @brief Get response packet CKS
+   * @param Response packet frame 
+   * @return CKS
+   */
+  uint16_t getRcmCKS(pRcmPacketHeader_t packet);
+  
+private:
+  Stream *s;
+  uint8_t buf[20];     //For saving response packet data 
+  pCmdPacketHeader_t  sendHeader;
+  pRcmPacketHeader_t  recHeader;
+  
+  static const sErrorDescription_t /*PROGMEM*/ errorDescriptionsTable[26];   //Error information list 
+  
+  uint8_t _number = 0;       //Fingerprint acquisistion times 
+  eError_t _error;           //Error code 
+  uint16_t _PacketSize = 0;  //Data packet length to be sent 
+};
+
+#endif
diff --git a/FingerPrintRegister/platformio.ini b/FingerPrintRegister/platformio.ini
new file mode 100644
index 0000000..f539a67
--- /dev/null
+++ b/FingerPrintRegister/platformio.ini
@@ -0,0 +1,11 @@
+[env:teensy_u2f]
+
+platform = teensy
+framework = arduino
+board = teensy31
+build_flags = 
+	-D USB_SERIAL 
+	-D TEENSY_OPT_SMALLEST_CODE
+
+lib_deps = 
+	Wire
diff --git a/FingerPrintRegister/src/DFRobot_ID809.cpp b/FingerPrintRegister/src/DFRobot_ID809.cpp
new file mode 100644
index 0000000..f2aa3a2
--- /dev/null
+++ b/FingerPrintRegister/src/DFRobot_ID809.cpp
@@ -0,0 +1,748 @@
+/*!
+ * @file DFRobot_ID809.cpp
+ * @brief Define the basic structure of DFRobot_ID809 class and the implementation of underlying methods 
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#include "DFRobot_ID809.h"
+#include <Arduino.h>
+#include <string.h>
+#include <stdio.h>
+Stream *dbg=NULL;
+
+DFRobot_ID809::DFRobot_ID809()
+  :s(NULL){
+        
+}
+
+DFRobot_ID809::~DFRobot_ID809(){
+        
+}
+
+bool DFRobot_ID809::begin(Stream &s_){
+    s = &s_;
+    if(s == NULL){
+        return false;
+    }
+    return true;
+}
+
+bool DFRobot_ID809::isConnected(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_TEST_CONNECTION, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        return true;
+    }else{
+        return false;
+    }
+}
+
+uint8_t DFRobot_ID809::setDeviceID(uint8_t deviceID){
+    uint8_t data[5] = {0};    //data:1bytes Parameter Type+4bytes Parameter Value
+    data[1] = deviceID;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSecurityLevel(uint8_t securityLevel){
+    uint8_t data[5] = {0};
+    data[0] = 1;
+    data[1] = securityLevel;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setDuplicationCheck(uint8_t duplicationCheck){
+    uint8_t data[5] = {0};
+    data[0] = 2;
+    data[1] = duplicationCheck;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setBaudrate(eDeviceBaudrate_t baudrate){
+    uint8_t data[5] = {0};
+    data[0] = 3;
+    data[1] = baudrate;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSelfLearn(uint8_t selfLearn){
+    uint8_t data[5] = {0};
+    data[0] = 4;
+    data[1] = selfLearn;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDeviceID(){
+    uint8_t data[1];  //data:1byte Parameter Type
+    data[0] = 0;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSecurityLevel(){
+    uint8_t data[1];
+    data[0] = 1;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDuplicationCheck(){
+    uint8_t data[1];
+    data[0] = 2;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBaudrate(){
+    uint8_t data[1];
+    data[0] = 3;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSelfLearn(){
+    uint8_t data[1];
+    data[0] = 4;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+String DFRobot_ID809::getDeviceInfo(){
+    char *data;
+    uint8_t result;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEVICE_INFO, NULL, 0);
+    sendPacket(header);
+    free(header);
+    result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setModuleSN(const char* SN){
+    char data[2];
+    data[0] = MODULE_SN_SIZE;
+    if(strlen(SN) > MODULE_SN_SIZE){
+        LDBG("The serial number exceeds 15 characters");
+        return ERR_ID809;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_MODULE_SN, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    header = pack(DATA_TYPE, CMD_SET_MODULE_SN, SN, MODULE_SN_SIZE);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+String DFRobot_ID809::getModuleSN(){
+    char *data;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_MODULE_SN, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount){
+    char data[4] = {0};
+    data[0] = mode;
+    data[2] = data[1] = color;
+    data[3] = blinkCount;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SLED_CTRL, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::detectFinger(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_FINGER_DETECT, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEmptyID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;     //80 fingerprints at most, default to full range 
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_EMPTY_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getStatusID(uint8_t ID){
+    char data[2] = {0};
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_STATUS, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEnrollCount(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLL_COUNT, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+#define  getID(A, V)  (A[0 + V/8] & (0x01 << (V & 0x07)))
+uint8_t DFRobot_ID809::getEnrolledIDList(uint8_t* list)
+{
+    char *data;
+    uint8_t i = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLLED_ID_LIST, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    uint16_t dataLen = buf[0]+(buf[1]<<8);
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    ret = responsePayload(data);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else{
+        for(uint16_t j = 0; j < (dataLen*8); j++){
+            if(getID(data, j) != 0){
+                list[i] = j;
+                i++;
+            }
+        }
+    }
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::storeFingerprint(uint8_t ID){
+    char data[4] = {0};
+    uint8_t ret;
+    ret = merge();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number = 0;
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+    
+}
+
+uint8_t DFRobot_ID809::delFingerprint(uint8_t ID){
+    char data[4] = {0};
+    if(ID == DELALL){
+        data[0] = 1;
+        data[2] = FINGERPRINT_CAPACITY;
+    }else{
+        data[0] = data[2] = ID;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEL_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::search(){
+    char data[6] = {0};
+    data[2] = 1;
+    data[4] = FINGERPRINT_CAPACITY;
+    _number = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SEARCH, data, 6);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::verify(uint8_t ID){
+    char data[4] = {0};
+    data[0] = ID;
+    _number = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_VERIFY, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::match(uint8_t RamBufferID0, uint8_t RamBufferID1){
+    char data[4] = {0};
+    data[0] = RamBufferID0;
+    data[2] = RamBufferID1;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenQuantity(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[2];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::loadFingerprint(uint8_t ID, uint8_t RamBufferID){
+    char data[4] = {0};
+    data[0] = ID;
+    data[2] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::enterSleepState(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_ENTER_STANDBY_STATE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_PARAM, (const char *)data, 5);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_PARAM, (const char *)data, 1);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getImage(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::collectionFingerprint(uint16_t timeout){  //Collect fingerprint 
+    uint16_t i = 0;
+    uint8_t ret;
+    if(_number > 2){
+        _error = eErrorGatherOut;
+        LDBG("Exceed upper limit of acquisition times ");
+        return ERR_ID809;
+    }
+    while(!detectFinger()){
+        if(timeout != 0){
+            delay(10);
+            if(++i > timeout*10){
+                _error = eErrorTimeOut;
+                LDBG("Acquisition timeout ");
+                LDBG("ret=");LDBG(ret);
+                return ERR_ID809;
+            }
+       }
+    }
+    ret = getImage();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    ret = generate(_number);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number++;
+    return ret;
+}
+
+uint8_t DFRobot_ID809::generate(uint8_t RamBufferID){
+    char data[2] = {0};
+    data[0] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GENERATE, (const char *)data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::merge(){
+    char data[3] = {0};
+    data[2] = _number;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MERGE, data, 3);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+pCmdPacketHeader_t DFRobot_ID809::pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len){
+    pCmdPacketHeader_t header;
+    uint16_t cks=0;
+    uint16_t dataLen;
+    if(type == CMD_TYPE){    //Structure of command packet, fixed 26 bytes:10(frame header)+14(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+16+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_PREFIX_CODE;
+        for(int i=0;i<16;i++){
+            header->payload[i] = 0;
+        }
+        dataLen = 16;   //Length of data to be replicated 
+    }else{                   //Structure of command data packet, unfixed length:10(frame header)+LEN(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+len+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_DATA_PREFIX_CODE;
+        dataLen = len;   //Length of data to be replicated 
+    }
+    header->SID = 0;
+    header->DID = 0;
+    header->CMD = cmd;
+    header->LEN = len;
+    if(len){
+        memcpy(header->payload, payload, len);
+    }
+    cks = getCmdCKS(header);
+    memcpy(&header->payload[dataLen],&cks,2);
+    _PacketSize = sizeof(sCmdPacketHeader_t) + dataLen +2;
+    return header;
+}
+
+
+void DFRobot_ID809::sendPacket(pCmdPacketHeader_t header){
+    s->write((uint8_t *)header,_PacketSize);
+}
+
+uint8_t DFRobot_ID809::responsePayload(void* buf){
+    sRcmPacketHeader_t header;
+    uint16_t dataLen,dataCount,cks;
+    uint8_t ch,ret;
+    int16_t type;
+    type = readPrefix(&header);
+    if(type == 1){
+        LDBG("--recv timeout---");
+        _error = eErrorRecvTimeout;
+        return ERR_ID809;
+    }
+    pRcmPacketHeader_t packet;
+    if(type == RCM_TYPE){    //Structure of response packet, fixed 26 bytes: 10(frame header)+14(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+14+2);
+        dataLen = 14+2;      //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }else{                   //Structure of response data packet, unfixed length: 10(frame header)+(LEN-2)(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+header.LEN);
+        dataLen = header.LEN;  //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }
+    memcpy(packet, &header, 10);
+    dataCount = readN(packet->payload, dataLen);
+    cks = packet->payload[dataLen-2]+(packet->payload[dataLen-1]<<8);
+    ret = (header.RET&0xFF);
+    _error = (eError_t)ret;
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else if(dataLen != dataCount){
+        LDBG("--recvRspPacket length error---");
+        _error = eErrorRecvLength;
+        ret = ERR_ID809;
+    }else if(getRcmCKS(packet) != cks){
+        LDBG("--recvRspPacket cks error---");
+        _error = eErrorRecvCks;
+        ret = ERR_ID809;
+    }else{
+        LDBG("--recvRspPacket OK---");
+        memcpy(buf, packet->payload, dataLen);
+    }
+    free(packet);
+    packet = NULL;
+    return ret;
+}
+
+uint16_t DFRobot_ID809::readPrefix( pRcmPacketHeader_t header ){
+    uint8_t ch,ret;
+    typedef enum{
+        RECV_HEADER_INIT,
+        RECV_HEADER_AA,
+        RECV_HEADER_A5,
+        RECV_HEADER_OK
+    }eRecvHeaderState;
+    eRecvHeaderState state = RECV_HEADER_INIT;
+    while(state != RECV_HEADER_OK){   //Can judge the received command packet and command data packet prefix at the same time 
+        if(readN(&ch, 1) != 1){
+            ret = 1;
+            return ret;
+        }
+        if((ch == 0xAA) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_AA;
+            continue;
+        }else if((ch == 0xA5) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_A5;
+            continue;
+        }else if((ch == 0x55) && (state == RECV_HEADER_AA)){
+            state = RECV_HEADER_OK;
+            ret = RCM_TYPE;
+            continue;
+        }else if((ch == 0x5A) && (state == RECV_HEADER_A5)){
+            state = RECV_HEADER_OK;
+            ret = DATA_TYPE;
+            continue;
+        }else{
+            state = RECV_HEADER_INIT;
+            if(ch == 0xAA){
+                state = RECV_HEADER_AA;
+            }else if(ch == 0xA5){
+                state = RECV_HEADER_A5;
+            }
+        }
+    }
+    if(ret == RCM_TYPE){
+        header->PREFIX = RCM_PREFIX_CODE;
+    }else if(ret == DATA_TYPE){
+        header->PREFIX = RCM_DATA_PREFIX_CODE;
+    }
+    readN(&header->SID, 1);
+    readN(&header->DID, 1);
+    readN(&header->RCM, 2);
+    readN(&header->LEN, 2);
+    readN(&header->RET, 2);
+    return ret;
+}
+
+size_t DFRobot_ID809::readN(void* buffer, size_t len){
+    size_t offset = 0,left = len;
+    uint8_t *buf = (uint8_t*)buffer;
+    long long curr = millis();
+    while(left){
+        if(s->available()){
+            buf[offset++] = s->read();
+            left--;
+        }
+        if(millis() - curr > 5000){
+            LDBG("----------!!!!!!!!!recv timeout----------");
+            break;
+        }
+    }
+    return offset;
+}
+
+uint16_t DFRobot_ID809::getCmdCKS(pCmdPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->CMD&0xFF;
+    cks += packet->CMD>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint8_t i = 0; i < packet->LEN; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+uint16_t DFRobot_ID809::getRcmCKS(pRcmPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->RCM&0xFF;
+    cks += packet->RCM>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    cks += packet->RET&0xFF;
+    cks += packet->RET>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint8_t i = 0; i < packet->LEN-2; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+const DFRobot_ID809::sErrorDescription_t DFRobot_ID809::errorDescriptionsTable[]={
+  {eErrorSuccess, "Command processed successfully"},
+  {eErrorFail, "Command processing failed"},
+  {eErrorVerify, "1:1 comparison failed"},
+  {eErrorIdentify, "Comparison with all fingerprints failed"},
+  {eErrorTmplEmpty, "No fingerprint in designated ID"},
+  {eErrorTmplNotEmpty, "Designated ID has fingerprint"},
+  {eErrorAllTmplEmpty, "Module unregistered fingerprint"},
+  {eErrorEmptyIDNoexist, "No registerable ID here"},
+  {eErrorBrokenIDNoexist, "No broken fingerprint"},
+  {eErrorInvalidTmplData, "Invalid desingated fingerprint data"},
+  {eErrorDuplicationID, "The fingerprint has been registered"},
+  {eErrorBadQuality, "Poor quality fingerprint image"},
+  {eErrorMergeFail, "Fingerprint synthesis failed"},
+  {eErrorNotAuthorized, "Communication password not authorized"},
+  {eErrorMemory, "External Flash burning error"},
+  {eErrorInvalidTmplNo, "Invalid designated ID"},
+  {eErrorInvalidParam, "Incorrect parameter"},
+  {eErrorTimeOut, "Acquisition timeout"},
+  {eErrorGenCount, "Invalid number of fingerprint synthesis"},
+  {eErrorInvalidBufferID, "Incorrect Buffer ID value"},
+  {eErrorFPNotDetected, "No fingerprint input into fingerprint reader"},
+  {eErrorFPCancel, "Command cancelled"},
+  {eErrorRecvLength, "Wrong data length"},
+  {eErrorRecvCks, "Wrong data check code"},
+  {eErrorGatherOut, "Exceed upper limit of acquisition times"},
+  {eErrorRecvTimeout,"Data reading timeout"}
+};
+
+String DFRobot_ID809::getErrorDescription()
+{
+    for(int i=0;i<sizeof(errorDescriptionsTable)/sizeof(errorDescriptionsTable[0]);i++){
+        if(_error == errorDescriptionsTable[i].error){
+          return errorDescriptionsTable[i].description;
+        }
+    }
+    return "";
+}
diff --git a/FingerPrintRegister/src/src.cpp b/FingerPrintRegister/src/src.cpp
new file mode 100644
index 0000000..0efe98a
--- /dev/null
+++ b/FingerPrintRegister/src/src.cpp
@@ -0,0 +1,132 @@
+
+/*!
+ * @file fingerprintRegistration.ino
+ * @brief Fingerprint Acquisition and Saving 
+ * @n This module can be controlled by hardware serial or software serial 
+ * @n Experiment Phenomenon:auto retrieve unregistered ID, collect fingerprint 3 times.  
+ * @n           In collecting, set LED ring to breathing lighting in blue, and then to quick blink in yellow 3 times when completed 
+ * @n           At last, save the fingerprint in an unregistered ID, the green LED lights up for 1s and turns off. 
+ * @copyright  Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](Eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+*/
+#include <Arduino.h>
+#include "DFRobot_ID809.h"
+
+#define COLLECT_NUMBER 3  //Fingerprint sampling times, can be set to 2-3
+
+///*Use software serial when using UNO or NANO */
+//#if ((defined ARDUINO_AVR_UNO) || (defined ARDUINO_AVR_NANO))
+//    #include <SoftwareSerial.h>
+//    SoftwareSerial Serial1(2, 3);  //RX, TX
+//    #define FPSerial Serial1
+//#else
+//    #define FPSerial Serial1
+//#endif
+#ifndef FPSerial
+  #define FPSerial Serial3
+#endif
+
+DFRobot_ID809 fingerprint;
+//String desc;
+
+void setup(){
+  /*Init print serial port */
+  Serial.begin(9600);
+  /*Init FPSerial*/
+  FPSerial.begin(115200);
+  /*Take FPSerial as communication port of the module*/
+  fingerprint.begin(FPSerial);
+  /*Wait for Serial to open*/
+ // while(!Serial);
+  /*Test whether the device can communicate properly with mainboard 
+    Return true or false
+    */
+  while(fingerprint.isConnected() == false){
+    Serial.println("Communication with device failed, please check connection");
+    /*Get error code information*/
+    //desc = fingerprint.getErrorDescription();
+    //Serial.println(desc);
+    delay(1000);
+  }
+}
+
+uint8_t ID,i,ret;
+
+void loop(){
+  /*Get an unregistered ID for saving fingerprint 
+    Return ID when succeeded 
+    Return ERR_ID809 if failed 
+   */
+  if((ID = fingerprint.getEmptyID()) == ERR_ID809){
+    while(1){
+      /*Get error code information*/
+      //desc = fingerprint.getErrorDescription();
+      //Serial.println(desc);
+      delay(1000);
+    }
+  }
+  Serial.print("unresistered ID,ID=");
+  Serial.println(ID);
+  i = 0;   //Clear sampling times 
+  /*Fingerprint sampling 3 times*/
+  while(i < COLLECT_NUMBER){
+    /*Set fingerprint LED ring mode, color, and number of blinks 
+      Can be set as follows: 
+      Parameter 1:<LEDMode>
+      eBreathing   eFastBlink   eKeepsOn    eNormalClose
+      eFadeIn      eFadeOut     eSlowBlink   
+      Parameter 2:<LEDColor>
+      eLEDGreen  eLEDRed      eLEDYellow   eLEDBlue
+      eLEDCyan   eLEDMagenta  eLEDWhite
+      Parameter 3:<Number of blinks> 0 represents blinking all the time 
+      This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+     */
+    fingerprint.ctrlLED(/*LEDMode = */fingerprint.eBreathing, /*LEDColor = */fingerprint.eLEDBlue, /*blinkCount = */0);
+    Serial.print("The fingerprint sampling of the");
+    Serial.print(i+1);
+    Serial.println("(th) is being taken");
+    Serial.println("Please press down your finger");
+    /*Capture fingerprint image, 10s idle timeout, if timeout=0,Disable  the collection timeout function
+      IF succeeded, return 0, otherwise, return ERR_ID809
+     */
+    if((fingerprint.collectionFingerprint(/*timeout = */10)) != ERR_ID809){
+      /*Set fingerprint LED ring to quick blink in yellow 3 times */
+      fingerprint.ctrlLED(/*LEDMode = */fingerprint.eFastBlink, /*LEDColor = */fingerprint.eLEDYellow, /*blinkCount = */3);
+      Serial.println("Sampling succeeds");
+      i++;   //Sampling times +1
+    }else{
+      Serial.println("Sampling failed");
+      /*Get error code information*/
+      //desc = fingerprint.getErrorDescription();
+      //Serial.println(desc);
+    }
+    Serial.println("Please release your finger");
+    /*Wait for finger to release 
+      Return 1 when finger is detected, otherwise return 0 
+     */
+    while(fingerprint.detectFinger());
+  }
+  
+  /*Save fingerprint in an unregistered ID */
+  if(fingerprint.storeFingerprint(/*Empty ID = */ID) != ERR_ID809){
+    Serial.print("Saving succeed,ID=");
+    Serial.println(ID);
+    Serial.println("-----------------------------");
+    /*Set fingerprint LED ring to always ON in green */
+    fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDGreen, /*blinkCount = */0);
+    delay(1000);
+    /*Turn off fingerprint LED ring */
+    fingerprint.ctrlLED(/*LEDMode = */fingerprint.eNormalClose, /*LEDColor = */fingerprint.eLEDBlue, /*blinkCount = */0);
+    delay(1000);
+  }else{
+    Serial.println("Saving failed");
+    /*Get error code information*/
+    //desc = fingerprint.getErrorDescription();
+    //Serial.println(desc);
+  }
+}
diff --git a/FingerPrintUnregister/include/DFRobot_ID809.h b/FingerPrintUnregister/include/DFRobot_ID809.h
new file mode 100644
index 0000000..4cb90d9
--- /dev/null
+++ b/FingerPrintUnregister/include/DFRobot_ID809.h
@@ -0,0 +1,494 @@
+/*!
+ * @file DFRobot_ID809.h
+ * @brief Define basic structure of DFRobot_ID809 class
+ * @n This is an library for capacitive fingerprint module
+ * @n Main functions: fingerprint image capturing, fingerprint comparison, fingerprint deletion
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#ifndef _DFRobot_ID809_H
+#define _DFRobot_ID809_H
+
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+#include "WProgram.h"
+#endif
+#include <Wire.h>
+
+#include <stdint.h>
+
+//Open this macro to see the detailed running process of the program 
+
+//#define ENABLE_DBG
+#ifdef ENABLE_DBG
+#define LDBG(...) if(dbg) {dbg->print("["); dbg->print(__FUNCTION__); dbg->print("(): "); dbg->print(__LINE__); dbg->print(" ] "); dbg->println(__VA_ARGS__);}
+#else
+#define LDBG(...)
+#endif
+
+extern Stream *dbg;
+
+  /*
+   Frame struct of command packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  CMD;
+  uint16_t  LEN;
+  uint8_t payload[0];
+}__attribute__ ((packed)) sCmdPacketHeader_t, *pCmdPacketHeader_t;
+
+  /*
+   Frame struct of response packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  RCM;
+  uint16_t  LEN;
+  uint16_t  RET;
+  uint8_t   payload[0];
+}__attribute__ ((packed)) sRcmPacketHeader_t, *pRcmPacketHeader_t;
+
+  
+
+
+class DFRobot_ID809{
+public: 
+
+#define FINGERPRINT_CAPACITY     80      //Fingerprint module capacity
+#define MODULE_SN_SIZE           16      //Module SN length 
+
+
+#define DELALL                   0xFF    //Delete all fingerprints 
+
+#define CMD_PREFIX_CODE          0xAA55  //Command packet prefix code 
+#define RCM_PREFIX_CODE          0x55AA  //Response packet prefix code 
+#define CMD_DATA_PREFIX_CODE     0xA55A  //Command data packet prefix code 
+#define RCM_DATA_PREFIX_CODE     0x5AA5  //Response data packet prefix code 
+
+#define CMD_TYPE                 0xF0    //Command packet type 
+#define RCM_TYPE                 0xF0    //Response packet type 
+#define DATA_TYPE                0x0F    //Data packet type 
+
+#define CMD_TEST_CONNECTION      0X0001  //Test connection 
+#define CMD_SET_PARAM            0X0002  //Set parameter
+#define CMD_GET_PARAM            0X0003  //Read parameter 
+#define CMD_DEVICE_INFO          0X0004  //Read device information 
+#define CMD_SET_MODULE_SN        0X0008  //Set module serial number 
+#define CMD_GET_MODULE_SN        0X0009  //Read module serial number
+#define CMD_ENTER_STANDBY_STATE  0X000C  //Enter sleep mode 
+#define CMD_GET_IMAGE            0X0020  //Capture fingerprint image 
+#define CMD_FINGER_DETECT        0X0021  //Detect fingerprint 
+    #define CMD_UP_IMAGE_CODE        0X0022  //Upload fingerprint image to host 
+    #define CMD_DOWN_IMAGE           0X0023  //Download fingerprint image to module 
+#define CMD_SLED_CTRL            0X0024  //Control collector backlight 
+#define CMD_STORE_CHAR           0X0040  //Save fingerprint template data into fingerprint library 
+#define CMD_LOAD_CHAR            0X0041  //Read fingerprint in module and save it in RAMBUFFER temporarily  
+    #define CMD_UP_CHAR              0X0042  //Upload the fingerprint template saved in RAMBUFFER to host 
+    #define CMD_DOWN_CHAR            0X0043  //Download fingerprint template to module designated RAMBUFFER
+#define CMD_DEL_CHAR             0X0044  //Delete fingerprint in specific ID range 
+#define CMD_GET_EMPTY_ID         0X0045  //Get the first registerable ID in specific ID range 
+#define CMD_GET_STATUS           0X0046  //Check if the designated ID has been registered 
+#define CMD_GET_BROKEN_ID        0X0047  //Check whether there is damaged data in fingerprint library of specific range
+#define CMD_GET_ENROLL_COUNT     0X0048  //Get the number of registered fingerprints in specific ID range 
+#define CMD_GET_ENROLLED_ID_LIST 0X0049  //Get registered ID list
+#define CMD_GENERATE             0X0060  //Generate template from the fingerprint images saved in IMAGEBUFFER temporarily 
+#define CMD_MERGE                0X0061  //Synthesize fingerprint template data 
+#define CMD_MATCH                0X0062  //Compare templates in 2 designated RAMBUFFER 
+#define CMD_SEARCH               0X0063  //1:N Recognition in specific ID range 
+#define CMD_VERIFY               0X0064  //Compare specific RAMBUFFER template with specific ID template in fingerprint library 
+
+#define ERR_SUCCESS              0x00    //Command processed successfully 
+#define ERR_ID809                0xFF    //error 
+
+
+public:
+  
+  typedef enum{
+    eBreathing = 1,  //Breathing 
+    eFastBlink,      //Quick blink
+    eKeepsOn,        //On
+    eNormalClose,    //Off
+    eFadeIn,         //Fade in 
+    eFadeOut,        //Fade out
+    eSlowBlink       //Slow blink
+  }eLEDMode_t;
+  
+  typedef enum{
+    eLEDGreen = 1,   //green 
+    eLEDRed,         //red 
+    eLEDYellow,      //yellow
+    eLEDBlue,        //blue
+    eLEDCyan,        //cyan
+    eLEDMagenta,     //magenta
+    eLEDWhite        //white
+  }eLEDColor_t;
+   
+  typedef enum{
+    e9600bps = 1,
+    e19200bps,
+    e38400bps,
+    e57600bps,
+    e115200bps
+  }eDeviceBaudrate_t;
+  
+  typedef enum{
+    eErrorSuccess            = 0x00,    //Command processed successfully
+    eErrorFail               = 0x01,    //Command processing failed 
+    eErrorVerify             = 0x10,    //1:1 Templates comparison in specific ID failed 
+    eErrorIdentify           = 0x11,    //1:N comparison has been made, no same templates here 
+    eErrorTmplEmpty          = 0x12,    //No registered template in the designated ID 
+    eErrorTmplNotEmpty       = 0x13,    //Template already exists in the specified ID 
+    eErrorAllTmplEmpty       = 0x14,    //No registered Template 
+    eErrorEmptyIDNoexist     = 0x15,    //No registerable Template ID 
+    eErrorBrokenIDNoexist    = 0x16,    //No damaged Template 
+    eErrorInvalidTmplData    = 0x17,    //The designated Template Data is invalid 
+    eErrorDuplicationID      = 0x18,    //The fingerprint has been registered 
+    eErrorBadQuality         = 0x19,    //Poor quality fingerprint image 
+    eErrorMergeFail          = 0x1A,    //Template synthesis failed 
+    eErrorNotAuthorized      = 0x1B,    //Communication password not authorized 
+    eErrorMemory             = 0x1C,    //Error in exernal Flash burning 
+    eErrorInvalidTmplNo      = 0x1D,    //The designated template ID is invalid 
+    eErrorInvalidParam       = 0x22,    //Incorrect parameter has been used 
+    eErrorTimeOut            = 0x23,    //Acquisition timeout 
+    eErrorGenCount           = 0x25,    //Invalid number of fingerprint synthesis 
+    eErrorInvalidBufferID    = 0x26,    //Wrong Buffer ID value 
+    eErrorFPNotDetected      = 0x28,    //No fingerprint input into fingerprint reader 
+    eErrorFPCancel           = 0x41,    //Command cancelled 
+    eErrorRecvLength         = 0x42,    //Wrong length of recieved data 
+    eErrorRecvCks            = 0x43,    //Wrong check code 
+    eErrorGatherOut          = 0x45,    //Exceed upper limit of acquisition times 
+    eErrorRecvTimeout        = 0x46     //Communication timeout 
+  }eError_t;
+  
+  typedef struct{
+    /**< Gesture enumeration variable X */
+    eError_t error;
+    /**< Description about the gesture enumeration variable X */
+    const char * description;
+  }sErrorDescription_t;
+
+public:
+  DFRobot_ID809();
+  ~DFRobot_ID809();
+  
+  /**
+   * @brief Init communication port
+   * @param Software serial or hardware serial 
+   * @return true or false
+   */
+  bool begin(Stream &s_);
+  
+  /**
+   * @brief Test whether the module connection is ok
+   * @return true or false
+   */
+  bool isConnected();
+  
+  /**
+   * @brief Set module ID
+   * @param ID:1-255
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDeviceID(uint8_t deviceID);
+  
+  /**
+   * @brief Set module security level 
+   * @param security level:1-5
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSecurityLevel(uint8_t securityLevel);
+  
+  /**
+   * @brief Set module fingerprint replication check (Check whether the fingperint has been registered when saving it)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDuplicationCheck(uint8_t duplicationCheck);
+  
+  /**
+   * @brief Set module baud rate 
+   * @param Baudrate:in typedef enum eDeviceBaudrate_t
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setBaudrate(eDeviceBaudrate_t baudrate);
+  
+  /**
+   * @brief Set module self-learning function (Update fingeprint when fingerprint comparison succeeds)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSelfLearn(uint8_t selfLearn);
+  
+  /**
+   * @brief Read module ID
+   * @return ID号:1-255 or ERR_ID809
+   */
+  uint8_t getDeviceID();
+  
+  /**
+   * @brief Read module security level 
+   * @return Security level:1-5 or ERR_ID809
+   */
+  uint8_t getSecurityLevel();
+  
+  /**
+   * @brief Read module fingerprint replication check status
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getDuplicationCheck();
+  
+  /**
+   * @brief Read module baud rate 
+   * @return Baudrate:in typedef enum eDEVICE_BAUDRATE_t or ERR_ID809
+   */
+  uint8_t getBaudrate();
+  
+  /**
+   * @brief Read module self-learning function status 
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getSelfLearn();
+   
+  /**
+   * @brief Read device number 
+   * @return Device number
+   */
+  String getDeviceInfo();
+  
+  /**
+   * @brief Set serial number
+   * @param String pointer 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setModuleSN(const char* SN);
+  /**
+   * @brief Read serial number 
+   * @return Serial number
+   */
+  String getModuleSN();
+  
+  /**
+   * @brief Set LED
+   * @param mode:in typedef enum eLEDMode_t
+   * @param color:in typedef enum eLEDColor_t
+   * @param blink Count: 00 represents blinking all the time
+   * @This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount);
+  
+  /**
+   * @brief Detect if there is finger touched 
+   * @return 1(Touched) or 0(No touch)
+   */
+  uint8_t detectFinger();
+  
+  /**
+   * @brief Get the first registerable ID 
+   * @return Registerable ID or ERR_ID809
+   */
+  uint8_t getEmptyID();
+  
+  /**
+   * @brief Check if the ID has been registered 
+   * @return 0(Registered), 1(Unregistered) or ERR_ID809
+   */
+  uint8_t getStatusID(uint8_t ID);
+  
+  /**
+   * @brief Get the number of registered users 
+   * @return Number of registered users or ERR_ID809
+   */
+  uint8_t getEnrollCount();
+  
+  /**
+   * @brief Get registered user list 
+   * @return 0(succeed) or ERR_ID809
+   */
+   uint8_t getEnrolledIDList(uint8_t* list);
+  
+  /**
+   * @brief Fingerprint acquisition 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t collectionFingerprint(uint16_t timeout);
+  
+  /**
+   * @brief Save fingerprint 
+   * @param Fingerprint ID
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t storeFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Delete fingerprint 
+   * @param Delete ID or DELALL(delete all)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t delFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Match the fingerprint with all fingeprints 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t search();
+
+  /**
+   * @brief Match the fingerprint with specific fingerprint 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t verify(uint8_t ID);
+
+  /**
+   * @brief Compare templates in two specific RamBuffers
+   * @param RamBuffer number 
+   * @param RamBuffer number 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t match(uint8_t RamBufferID0, uint8_t RamBufferID1);
+  
+  /**
+   * @brief Get the number of damaged fingerprints 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenQuantity();
+
+  /**
+   * @brief Get the first damaged fingerprint ID 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenID();
+  
+  /**
+   * @brief Take out fingerprint template, temporarily save into RamBuffer
+   * @param Fingerprint ID 
+   * @param RamBuffer number 0-2
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t loadFingerprint(uint8_t ID, uint8_t RamBufferID);
+  
+  /**
+   * @brief Enter sleep mode
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t enterSleepState();
+  
+  /**
+   * @brief Get error information
+   * @return Text description of error information
+   */
+  String getErrorDescription();
+  
+  bool setDbgSerial(Stream &s_){dbg = &s_; return true;}
+protected:
+   /**
+   * @brief Set parameter 
+   * @param Data type+ data
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setParam(uint8_t* data);
+  
+   /**
+   * @brief Read parameter 
+   * @param Data type 
+   * @return data or ERR_ID809
+   */
+  uint8_t getParam(uint8_t* data);
+  
+  /**
+   * @brief Capture fingerprint image 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t getImage();
+   
+   /**
+   * @brief Take image as template 
+   * @param Ram Buffer number
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t generate(uint8_t RamBufferID);
+  
+ /**
+   * @brief Fingerprint synthesis 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t merge();
+  
+ /**
+   * @brief Packing data frame 
+   * @param Data type:CMD_TYPE or DATA_TYPE
+   * @param Command
+   * @param Data 
+   * @param Length
+   * @return Data frame 
+   */
+  pCmdPacketHeader_t pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len);
+  
+ /**
+   * @brief Send data 
+   * @param Data frame
+   */
+  void sendPacket(pCmdPacketHeader_t header);
+  
+ /**
+   * @brief Read byte 
+   * @param Pointer for saving data 
+   * @param Length of data to be received 
+   * @return Actual received data length 
+   */
+  size_t readN(void* buf_, size_t len);
+  
+ /**
+   * @brief Read frame header 
+   * @param Frame header struct of response packet
+   * @return Response packet type:RCM_TYPE,DATA_TYPE or 1(reading timeout)
+   */
+  uint16_t readPrefix( pRcmPacketHeader_t header );
+  
+ /**
+   * @brief Read data
+   * @param Pointer for saving data 
+   * @return 0(success) or ERR_ID809
+   */
+  uint8_t responsePayload(void* buf);
+  
+ /**
+   * @brief Get command packet CKS
+   * @param Command packet frame 
+   * @return CKS
+   */
+  uint16_t getCmdCKS(pCmdPacketHeader_t packet);
+  
+ /**
+   * @brief Get response packet CKS
+   * @param Response packet frame 
+   * @return CKS
+   */
+  uint16_t getRcmCKS(pRcmPacketHeader_t packet);
+  
+private:
+  Stream *s;
+  uint8_t buf[20];     //For saving response packet data 
+  pCmdPacketHeader_t  sendHeader;
+  pRcmPacketHeader_t  recHeader;
+  
+  static const sErrorDescription_t /*PROGMEM*/ errorDescriptionsTable[26];   //Error information list 
+  
+  uint8_t _number = 0;       //Fingerprint acquisistion times 
+  eError_t _error;           //Error code 
+  uint16_t _PacketSize = 0;  //Data packet length to be sent 
+};
+
+#endif
diff --git a/FingerPrintUnregister/platformio.ini b/FingerPrintUnregister/platformio.ini
new file mode 100644
index 0000000..97cb9cb
--- /dev/null
+++ b/FingerPrintUnregister/platformio.ini
@@ -0,0 +1,9 @@
+[env:teensy_u2f]
+
+platform = teensy
+framework = arduino
+board = teensy31
+build_flags = 
+	-D USB_SERIAL 
+	-D TEENSY_OPT_SMALLEST_CODE
+
diff --git a/FingerPrintUnregister/src/DFRobot_ID809.cpp b/FingerPrintUnregister/src/DFRobot_ID809.cpp
new file mode 100644
index 0000000..f2aa3a2
--- /dev/null
+++ b/FingerPrintUnregister/src/DFRobot_ID809.cpp
@@ -0,0 +1,748 @@
+/*!
+ * @file DFRobot_ID809.cpp
+ * @brief Define the basic structure of DFRobot_ID809 class and the implementation of underlying methods 
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#include "DFRobot_ID809.h"
+#include <Arduino.h>
+#include <string.h>
+#include <stdio.h>
+Stream *dbg=NULL;
+
+DFRobot_ID809::DFRobot_ID809()
+  :s(NULL){
+        
+}
+
+DFRobot_ID809::~DFRobot_ID809(){
+        
+}
+
+bool DFRobot_ID809::begin(Stream &s_){
+    s = &s_;
+    if(s == NULL){
+        return false;
+    }
+    return true;
+}
+
+bool DFRobot_ID809::isConnected(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_TEST_CONNECTION, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        return true;
+    }else{
+        return false;
+    }
+}
+
+uint8_t DFRobot_ID809::setDeviceID(uint8_t deviceID){
+    uint8_t data[5] = {0};    //data:1bytes Parameter Type+4bytes Parameter Value
+    data[1] = deviceID;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSecurityLevel(uint8_t securityLevel){
+    uint8_t data[5] = {0};
+    data[0] = 1;
+    data[1] = securityLevel;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setDuplicationCheck(uint8_t duplicationCheck){
+    uint8_t data[5] = {0};
+    data[0] = 2;
+    data[1] = duplicationCheck;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setBaudrate(eDeviceBaudrate_t baudrate){
+    uint8_t data[5] = {0};
+    data[0] = 3;
+    data[1] = baudrate;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSelfLearn(uint8_t selfLearn){
+    uint8_t data[5] = {0};
+    data[0] = 4;
+    data[1] = selfLearn;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDeviceID(){
+    uint8_t data[1];  //data:1byte Parameter Type
+    data[0] = 0;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSecurityLevel(){
+    uint8_t data[1];
+    data[0] = 1;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDuplicationCheck(){
+    uint8_t data[1];
+    data[0] = 2;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBaudrate(){
+    uint8_t data[1];
+    data[0] = 3;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSelfLearn(){
+    uint8_t data[1];
+    data[0] = 4;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+String DFRobot_ID809::getDeviceInfo(){
+    char *data;
+    uint8_t result;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEVICE_INFO, NULL, 0);
+    sendPacket(header);
+    free(header);
+    result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setModuleSN(const char* SN){
+    char data[2];
+    data[0] = MODULE_SN_SIZE;
+    if(strlen(SN) > MODULE_SN_SIZE){
+        LDBG("The serial number exceeds 15 characters");
+        return ERR_ID809;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_MODULE_SN, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    header = pack(DATA_TYPE, CMD_SET_MODULE_SN, SN, MODULE_SN_SIZE);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+String DFRobot_ID809::getModuleSN(){
+    char *data;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_MODULE_SN, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount){
+    char data[4] = {0};
+    data[0] = mode;
+    data[2] = data[1] = color;
+    data[3] = blinkCount;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SLED_CTRL, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::detectFinger(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_FINGER_DETECT, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEmptyID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;     //80 fingerprints at most, default to full range 
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_EMPTY_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getStatusID(uint8_t ID){
+    char data[2] = {0};
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_STATUS, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEnrollCount(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLL_COUNT, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+#define  getID(A, V)  (A[0 + V/8] & (0x01 << (V & 0x07)))
+uint8_t DFRobot_ID809::getEnrolledIDList(uint8_t* list)
+{
+    char *data;
+    uint8_t i = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLLED_ID_LIST, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    uint16_t dataLen = buf[0]+(buf[1]<<8);
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    ret = responsePayload(data);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else{
+        for(uint16_t j = 0; j < (dataLen*8); j++){
+            if(getID(data, j) != 0){
+                list[i] = j;
+                i++;
+            }
+        }
+    }
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::storeFingerprint(uint8_t ID){
+    char data[4] = {0};
+    uint8_t ret;
+    ret = merge();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number = 0;
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+    
+}
+
+uint8_t DFRobot_ID809::delFingerprint(uint8_t ID){
+    char data[4] = {0};
+    if(ID == DELALL){
+        data[0] = 1;
+        data[2] = FINGERPRINT_CAPACITY;
+    }else{
+        data[0] = data[2] = ID;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEL_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::search(){
+    char data[6] = {0};
+    data[2] = 1;
+    data[4] = FINGERPRINT_CAPACITY;
+    _number = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SEARCH, data, 6);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::verify(uint8_t ID){
+    char data[4] = {0};
+    data[0] = ID;
+    _number = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_VERIFY, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::match(uint8_t RamBufferID0, uint8_t RamBufferID1){
+    char data[4] = {0};
+    data[0] = RamBufferID0;
+    data[2] = RamBufferID1;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenQuantity(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[2];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::loadFingerprint(uint8_t ID, uint8_t RamBufferID){
+    char data[4] = {0};
+    data[0] = ID;
+    data[2] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::enterSleepState(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_ENTER_STANDBY_STATE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_PARAM, (const char *)data, 5);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_PARAM, (const char *)data, 1);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getImage(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::collectionFingerprint(uint16_t timeout){  //Collect fingerprint 
+    uint16_t i = 0;
+    uint8_t ret;
+    if(_number > 2){
+        _error = eErrorGatherOut;
+        LDBG("Exceed upper limit of acquisition times ");
+        return ERR_ID809;
+    }
+    while(!detectFinger()){
+        if(timeout != 0){
+            delay(10);
+            if(++i > timeout*10){
+                _error = eErrorTimeOut;
+                LDBG("Acquisition timeout ");
+                LDBG("ret=");LDBG(ret);
+                return ERR_ID809;
+            }
+       }
+    }
+    ret = getImage();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    ret = generate(_number);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number++;
+    return ret;
+}
+
+uint8_t DFRobot_ID809::generate(uint8_t RamBufferID){
+    char data[2] = {0};
+    data[0] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GENERATE, (const char *)data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::merge(){
+    char data[3] = {0};
+    data[2] = _number;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MERGE, data, 3);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+pCmdPacketHeader_t DFRobot_ID809::pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len){
+    pCmdPacketHeader_t header;
+    uint16_t cks=0;
+    uint16_t dataLen;
+    if(type == CMD_TYPE){    //Structure of command packet, fixed 26 bytes:10(frame header)+14(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+16+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_PREFIX_CODE;
+        for(int i=0;i<16;i++){
+            header->payload[i] = 0;
+        }
+        dataLen = 16;   //Length of data to be replicated 
+    }else{                   //Structure of command data packet, unfixed length:10(frame header)+LEN(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+len+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_DATA_PREFIX_CODE;
+        dataLen = len;   //Length of data to be replicated 
+    }
+    header->SID = 0;
+    header->DID = 0;
+    header->CMD = cmd;
+    header->LEN = len;
+    if(len){
+        memcpy(header->payload, payload, len);
+    }
+    cks = getCmdCKS(header);
+    memcpy(&header->payload[dataLen],&cks,2);
+    _PacketSize = sizeof(sCmdPacketHeader_t) + dataLen +2;
+    return header;
+}
+
+
+void DFRobot_ID809::sendPacket(pCmdPacketHeader_t header){
+    s->write((uint8_t *)header,_PacketSize);
+}
+
+uint8_t DFRobot_ID809::responsePayload(void* buf){
+    sRcmPacketHeader_t header;
+    uint16_t dataLen,dataCount,cks;
+    uint8_t ch,ret;
+    int16_t type;
+    type = readPrefix(&header);
+    if(type == 1){
+        LDBG("--recv timeout---");
+        _error = eErrorRecvTimeout;
+        return ERR_ID809;
+    }
+    pRcmPacketHeader_t packet;
+    if(type == RCM_TYPE){    //Structure of response packet, fixed 26 bytes: 10(frame header)+14(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+14+2);
+        dataLen = 14+2;      //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }else{                   //Structure of response data packet, unfixed length: 10(frame header)+(LEN-2)(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+header.LEN);
+        dataLen = header.LEN;  //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }
+    memcpy(packet, &header, 10);
+    dataCount = readN(packet->payload, dataLen);
+    cks = packet->payload[dataLen-2]+(packet->payload[dataLen-1]<<8);
+    ret = (header.RET&0xFF);
+    _error = (eError_t)ret;
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else if(dataLen != dataCount){
+        LDBG("--recvRspPacket length error---");
+        _error = eErrorRecvLength;
+        ret = ERR_ID809;
+    }else if(getRcmCKS(packet) != cks){
+        LDBG("--recvRspPacket cks error---");
+        _error = eErrorRecvCks;
+        ret = ERR_ID809;
+    }else{
+        LDBG("--recvRspPacket OK---");
+        memcpy(buf, packet->payload, dataLen);
+    }
+    free(packet);
+    packet = NULL;
+    return ret;
+}
+
+uint16_t DFRobot_ID809::readPrefix( pRcmPacketHeader_t header ){
+    uint8_t ch,ret;
+    typedef enum{
+        RECV_HEADER_INIT,
+        RECV_HEADER_AA,
+        RECV_HEADER_A5,
+        RECV_HEADER_OK
+    }eRecvHeaderState;
+    eRecvHeaderState state = RECV_HEADER_INIT;
+    while(state != RECV_HEADER_OK){   //Can judge the received command packet and command data packet prefix at the same time 
+        if(readN(&ch, 1) != 1){
+            ret = 1;
+            return ret;
+        }
+        if((ch == 0xAA) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_AA;
+            continue;
+        }else if((ch == 0xA5) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_A5;
+            continue;
+        }else if((ch == 0x55) && (state == RECV_HEADER_AA)){
+            state = RECV_HEADER_OK;
+            ret = RCM_TYPE;
+            continue;
+        }else if((ch == 0x5A) && (state == RECV_HEADER_A5)){
+            state = RECV_HEADER_OK;
+            ret = DATA_TYPE;
+            continue;
+        }else{
+            state = RECV_HEADER_INIT;
+            if(ch == 0xAA){
+                state = RECV_HEADER_AA;
+            }else if(ch == 0xA5){
+                state = RECV_HEADER_A5;
+            }
+        }
+    }
+    if(ret == RCM_TYPE){
+        header->PREFIX = RCM_PREFIX_CODE;
+    }else if(ret == DATA_TYPE){
+        header->PREFIX = RCM_DATA_PREFIX_CODE;
+    }
+    readN(&header->SID, 1);
+    readN(&header->DID, 1);
+    readN(&header->RCM, 2);
+    readN(&header->LEN, 2);
+    readN(&header->RET, 2);
+    return ret;
+}
+
+size_t DFRobot_ID809::readN(void* buffer, size_t len){
+    size_t offset = 0,left = len;
+    uint8_t *buf = (uint8_t*)buffer;
+    long long curr = millis();
+    while(left){
+        if(s->available()){
+            buf[offset++] = s->read();
+            left--;
+        }
+        if(millis() - curr > 5000){
+            LDBG("----------!!!!!!!!!recv timeout----------");
+            break;
+        }
+    }
+    return offset;
+}
+
+uint16_t DFRobot_ID809::getCmdCKS(pCmdPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->CMD&0xFF;
+    cks += packet->CMD>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint8_t i = 0; i < packet->LEN; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+uint16_t DFRobot_ID809::getRcmCKS(pRcmPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->RCM&0xFF;
+    cks += packet->RCM>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    cks += packet->RET&0xFF;
+    cks += packet->RET>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint8_t i = 0; i < packet->LEN-2; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+const DFRobot_ID809::sErrorDescription_t DFRobot_ID809::errorDescriptionsTable[]={
+  {eErrorSuccess, "Command processed successfully"},
+  {eErrorFail, "Command processing failed"},
+  {eErrorVerify, "1:1 comparison failed"},
+  {eErrorIdentify, "Comparison with all fingerprints failed"},
+  {eErrorTmplEmpty, "No fingerprint in designated ID"},
+  {eErrorTmplNotEmpty, "Designated ID has fingerprint"},
+  {eErrorAllTmplEmpty, "Module unregistered fingerprint"},
+  {eErrorEmptyIDNoexist, "No registerable ID here"},
+  {eErrorBrokenIDNoexist, "No broken fingerprint"},
+  {eErrorInvalidTmplData, "Invalid desingated fingerprint data"},
+  {eErrorDuplicationID, "The fingerprint has been registered"},
+  {eErrorBadQuality, "Poor quality fingerprint image"},
+  {eErrorMergeFail, "Fingerprint synthesis failed"},
+  {eErrorNotAuthorized, "Communication password not authorized"},
+  {eErrorMemory, "External Flash burning error"},
+  {eErrorInvalidTmplNo, "Invalid designated ID"},
+  {eErrorInvalidParam, "Incorrect parameter"},
+  {eErrorTimeOut, "Acquisition timeout"},
+  {eErrorGenCount, "Invalid number of fingerprint synthesis"},
+  {eErrorInvalidBufferID, "Incorrect Buffer ID value"},
+  {eErrorFPNotDetected, "No fingerprint input into fingerprint reader"},
+  {eErrorFPCancel, "Command cancelled"},
+  {eErrorRecvLength, "Wrong data length"},
+  {eErrorRecvCks, "Wrong data check code"},
+  {eErrorGatherOut, "Exceed upper limit of acquisition times"},
+  {eErrorRecvTimeout,"Data reading timeout"}
+};
+
+String DFRobot_ID809::getErrorDescription()
+{
+    for(int i=0;i<sizeof(errorDescriptionsTable)/sizeof(errorDescriptionsTable[0]);i++){
+        if(_error == errorDescriptionsTable[i].error){
+          return errorDescriptionsTable[i].description;
+        }
+    }
+    return "";
+}
diff --git a/FingerPrintUnregister/src/platformio.ini b/FingerPrintUnregister/src/platformio.ini
new file mode 100644
index 0000000..e69de29
diff --git a/FingerPrintUnregister/src/src.cpp b/FingerPrintUnregister/src/src.cpp
new file mode 100644
index 0000000..a1de0fb
--- /dev/null
+++ b/FingerPrintUnregister/src/src.cpp
@@ -0,0 +1,110 @@
+/*!
+ * @file fingerprintDeletion.ino
+ * @brief Delete a specific fingerprint 
+ * @n Experiment phenomenon:press your finger on the sensor, if this fingerprint is registered, delete it and LED turns on in green. 
+      If it is unregistered or fingerprint collection fails, LED light turns on in red.
+ * @copyright  Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](Eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/DFRobot/DFRobot_ID809
+*/
+#include "DFRobot_ID809.h"
+
+///*Use software serial when using UNO or NANO */
+//#if ((defined ARDUINO_AVR_UNO) || (defined ARDUINO_AVR_NANO))
+//    #include <SoftwareSerial.h>
+//    SoftwareSerial Serial1(2, 3);  //RX, TX
+//    #define FPSerial Serial1
+//#else
+//    #define FPSerial Serial1
+//#endif
+
+#define FPSerial Serial3
+
+DFRobot_ID809 fingerprint;
+//String desc;
+
+void setup(){
+  /*Init print serial port*/
+  Serial.begin(9600);
+  /*Init FPSerial*/
+  FPSerial.begin(115200);
+  /*Take FPSerial as communication serial port of the fingerprint module */
+  fingerprint.begin(FPSerial);
+  /*Wait for Serial to open*/
+  while(!Serial);
+  /*Test whether the device can properly communicate with mainboard
+    Return true or false
+    */
+  while(fingerprint.isConnected() == false){
+    Serial.println("Communication with device failed, please check connection");
+    /*Get error code information*/
+    //desc = fingerprint.getErrorDescription();
+    //Serial.println(desc);
+    delay(1000);
+  }
+}
+
+void loop(){
+  uint8_t ret = 0;
+  Serial.println("Press your finger on the sensor to delete the fingerprint");
+  /*Set fingerprint LED ring mode, color, and number of blinks 
+    Can be set as follows: 
+    Parameter 1:<LEDMode>
+    eBreathing   eFastBlink   eKeepsOn    eNormalClose
+    eFadeIn      eFadeOut     eSlowBlink   
+    Parameter 2:<LEDColor>
+    eLEDGreen  eLEDRed      eLEDYellow   eLEDBlue
+    eLEDCyan   eLEDMagenta  eLEDWhite
+    Parameter 3:<Number of blinks> 0 represents blinking all the time 
+    This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+   */
+  fingerprint.ctrlLED(/*LEDMode = */fingerprint.eBreathing, /*LEDColor = */fingerprint.eLEDBlue, /*blinkCount = */0);
+  /*Capture fingerprint image, 10s idle timeout, if timeout=0,Disable  the collection timeout function
+    If succeed return 0, otherwise return ERR_ID809
+   */
+  if((fingerprint.collectionFingerprint(/*timeout=*/10)) != ERR_ID809){
+    /*Compare the captured fingerprint with all the fingerprints in the fingerprint library 
+      Return fingerprint ID(1-80) if succeed, return 0 when failed 
+     */
+    ret = fingerprint.search();
+    if(ret != 0){
+      /*Delete the fingerprint of this ID*/
+      fingerprint.delFingerprint(/*Fingerprint ID = */ret);
+      //fingerprint.delFingerprint(DELALL);  //Delete all fingerprints 
+      Serial.print("delete succeeds,ID=");
+      Serial.println(ret);
+      /*Set fingerprint LED ring to always ON in green */
+      fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDGreen, /*blinkCount = */0);
+    }else{
+      Serial.println("Fingerprint is unregistered");
+      /*Set fingerprint LED ring to always ON in red*/
+      fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDRed, /*blinkCount = */0);
+    }
+  }else{
+    Serial.println("Capturing fails");
+    /*Get error code information*/
+    //desc = fingerprint.getErrorDescription();
+    //Serial.println(desc);
+    /*Set fingerprint LED ring to always ON in red*/
+    fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDRed, /*blinkCount = */0);
+  }
+  Serial.println("Please release your finger");
+  /*Wait for finger to release
+    Return 1 when finger is detected, otherwise return 0 
+   */
+  while(fingerprint.detectFinger());
+    /*Check whether the fingerprint ID has been registered 
+    Return 1 if registered, otherwise return 0 
+   */
+//  if(fingerprint.getStatusID(/*Fingerprint ID = */ret)){
+//    Serial.println("ID has been registered");
+//  }else{
+//    Serial.println("ID is unregistered");
+//  }
+  Serial.println("-----------------------------");
+  delay(1000);
+}
diff --git a/RegFPwithHash/lib/DFRobot_ID809/DFRobot_ID809.cpp b/RegFPwithHash/lib/DFRobot_ID809/DFRobot_ID809.cpp
new file mode 100644
index 0000000..d49f6f4
--- /dev/null
+++ b/RegFPwithHash/lib/DFRobot_ID809/DFRobot_ID809.cpp
@@ -0,0 +1,1089 @@
+/*!
+ * @file DFRobot_ID809.cpp
+ * @brief Define the basic structure of DFRobot_ID809 class and the implementation of underlying methods 
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#include <DFRobot_ID809.h>
+#include <Arduino.h>
+#include <string.h>
+#include <stdio.h>
+Stream *dbg=NULL;
+
+DFRobot_ID809::DFRobot_ID809()
+  :s(NULL){
+        
+}
+
+DFRobot_ID809::~DFRobot_ID809(){
+        
+}
+
+bool DFRobot_ID809::begin(Stream &s_){
+    s = &s_;
+	String str = getDeviceInfo();
+  //Serial.println(str[str.length()-1]);
+  if(str[str.length()-1] == '4'){
+	    
+	   FINGERPRINT_CAPACITY   =    80 ;
+	  
+	  //Serial.println(str[str.length()-1]);
+  }else if(str[str.length()-1] == '3'){
+	  //Serial.println(str[str.length()-1]);
+	   FINGERPRINT_CAPACITY  =   200 ;
+	  
+  }
+	
+    if(s == NULL){
+        return false;
+    }
+    return true;
+}
+
+bool DFRobot_ID809::isConnected(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_TEST_CONNECTION, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        return true;
+    }else{
+        return false;
+    }
+}
+
+uint8_t DFRobot_ID809::setDeviceID(uint8_t deviceID){
+    uint8_t data[5] = {0};    //data:1bytes Parameter Type+4bytes Parameter Value
+    data[1] = deviceID;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSecurityLevel(uint8_t securityLevel){
+    uint8_t data[5] = {0};
+    data[0] = 1;
+    data[1] = securityLevel;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setDuplicationCheck(uint8_t duplicationCheck){
+    uint8_t data[5] = {0};
+    data[0] = 2;
+    data[1] = duplicationCheck;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setBaudrate(eDeviceBaudrate_t baudrate){
+    uint8_t data[5] = {0};
+    data[0] = 3;
+    data[1] = baudrate;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSelfLearn(uint8_t selfLearn){
+    uint8_t data[5] = {0};
+    data[0] = 4;
+    data[1] = selfLearn;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDeviceID(){
+    uint8_t data[1];  //data:1byte Parameter Type
+    data[0] = 0;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSecurityLevel(){
+    uint8_t data[1];
+    data[0] = 1;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDuplicationCheck(){
+    uint8_t data[1];
+    data[0] = 2;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBaudrate(){
+    uint8_t data[1];
+    data[0] = 3;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSelfLearn(){
+    uint8_t data[1];
+    data[0] = 4;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+String DFRobot_ID809::getDeviceInfo(){
+    char *data;
+    uint8_t result;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEVICE_INFO, NULL, 0);
+    sendPacket(header);
+    free(header);
+    result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setModuleSN(const char* SN){
+    char data[2];
+    data[0] = MODULE_SN_SIZE;
+    if(strlen(SN) > MODULE_SN_SIZE){
+        LDBG("The serial number exceeds 15 characters");
+        return ERR_ID809;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_MODULE_SN, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    header = pack(DATA_TYPE, CMD_SET_MODULE_SN, SN, MODULE_SN_SIZE);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getTemplate(uint16_t id,uint8_t * temp){
+  char data[4];
+  data[0] = id;
+  data[1] = 0;
+  data[2] = 0;
+  data[3] = 0;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  data[0] = 0;
+  data[1] = 0;
+  header = pack(CMD_TYPE, CMD_UP_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  ret = responsePayload(temp);
+
+  return ret;
+}
+
+uint8_t DFRobot_ID809::downLoadTemplate(uint16_t id,uint8_t * temp){
+
+  char data[4];
+  data[0] = 0xf2;
+  data[1] = 3;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(0x3f2 +1);
+  tempData[0] = 0;
+  tempData[1] = 0;
+  memcpy(tempData+2,temp,0x3f0);
+  
+
+  header = pack(DATA_TYPE, CMD_DOWN_CHAR, tempData, 0x3f2);
+
+  sendPacket(header);
+
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  free(tempData);
+  
+
+  return store(id);
+}
+
+uint8_t DFRobot_ID809::contrastTemplate(uint8_t *temp){
+
+  char data[4];
+  data[0] = 0xf2;
+  data[1] = 3;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(0x3f2 +1);
+  tempData[0] = 2;
+  tempData[1] = 0;
+  memcpy(tempData+2,temp,0x3f0);
+  
+
+  header = pack(DATA_TYPE, CMD_DOWN_CHAR, tempData, 0x3f2);
+
+  sendPacket(header);
+
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  free(tempData);
+  data[0] = 0;
+  data[1] = 0;
+  data[2] = 2;
+  data[3] = 0;
+  header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ret;
+  }
+  return ret;
+
+}
+uint8_t DFRobot_ID809::getFingerImage(uint8_t *image)
+{
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  
+  char data[1];
+  data[0] = 0;
+  header = pack(CMD_TYPE, CMD_UP_IMAGE_CODE, data, 1);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500 +1);
+  for(uint8_t i=0;i<52;i++){
+
+     ret = responsePayload(tempData);
+     if(i == 51)
+       memcpy(image+i*496,tempData+2,304);
+     else
+       memcpy(image+i*496,tempData+2,496);
+  }
+  free(tempData);
+}
+uint8_t DFRobot_ID809::getQuarterFingerImage(uint8_t *image){
+
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  
+  char data[1];
+  data[0] = 1;
+  header = pack(CMD_TYPE, CMD_UP_IMAGE_CODE, data, 1);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500 +1);
+  for(uint8_t i=0;i<13;i++){
+
+     ret = responsePayload(tempData);
+     if(i == 12)
+       memcpy(image+i*496,tempData+2,448);
+     else
+       memcpy(image+i*496,tempData+2,496);
+  }
+  free(tempData);
+
+}
+uint8_t DFRobot_ID809::downLoadImage(uint16_t id,uint8_t * temp)
+{
+  char data[4];
+  data[0] = 0xa0;
+  data[1] = 0;
+  data[2] = 0xa0;
+  data[3] = 0;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_IMAGE, data, 4);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500);
+  for(uint8_t i =0 ;i<52;i++){
+     tempData[0] = i;
+	 tempData[1] = 0;
+     if(i == 51){
+       memcpy(tempData+2,temp+i*496,304);
+       header = pack(DATA_TYPE, CMD_DOWN_IMAGE, tempData, 306);
+	 }else{
+       memcpy(tempData+2,temp+i*496,496);
+       header = pack(DATA_TYPE, CMD_DOWN_IMAGE, tempData, 498);
+     }
+     sendPacket(header);
+     
+     free(header);
+     
+     ret = responsePayload(buf);
+     LDBG("ret=");
+     LDBG(ret);
+     if(ret != ERR_SUCCESS) {
+       return ERR_ID809;
+     }
+     
+  }  
+  free(tempData);
+  
+  data[0] = 0;
+  data[1] = 0;
+  header = pack(CMD_TYPE, CMD_GENERATE, data, 2);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+   // return ERR_ID809;
+  }
+  return store(id);
+
+}
+
+uint8_t DFRobot_ID809::receiveImageData(uint8_t * image){
+
+
+
+  uint8_t ret = responsePayload(image);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+
+}
+String DFRobot_ID809::getModuleSN(){
+    char *data;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_MODULE_SN, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount){
+    char data[4] = {0};
+  if(FINGERPRINT_CAPACITY == 80){
+    data[0] = mode;
+    data[2] = data[1] = color;
+    data[3] = blinkCount;
+  }else{
+	if(mode == 1){
+	  data[0] = 2;
+	} else if(mode == 2){
+		data[0] = 4;
+	} else if(mode == 3){
+	    data[0] = 1;
+	} else if(mode == 4){
+		data[0] = 0;
+	} else if(mode == 5){
+		data[0] = 3;
+	}
+	if(color == eLEDGreen){
+          data[2] = data[1] =  0x84;
+        }else if(color == eLEDRed){
+	  data[2] = data[1] = 0x82;
+	}else if(color == eLEDYellow){
+	  data[2] = data[1] = 0x86;
+	}else if(color == eLEDBlue){
+	  data[2] = data[1] = 0x81;
+	}else if(color == eLEDCyan){
+	  data[2] = data[1] = 0x85;
+	}else if(color == eLEDMagenta){
+	  data[2] = data[1] = 0x83;
+	}else {
+	  data[2] = data[1] = 0x87;
+	}
+  }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SLED_CTRL, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::detectFinger(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_FINGER_DETECT, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEmptyID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;     //80 fingerprints at most, default to full range 
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_EMPTY_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getStatusID(uint8_t ID){
+    char data[2] = {0};
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_STATUS, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEnrollCount(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLL_COUNT, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+#define  getID(A, V)  (A[0 + V/8] & (0x01 << (V & 0x07)))
+uint8_t DFRobot_ID809::getEnrolledIDList(uint8_t* list)
+{
+    char *data;
+    uint8_t i = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLLED_ID_LIST, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    uint16_t dataLen = buf[0]+(buf[1]<<8);
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    ret = responsePayload(data);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else{
+        for(uint16_t j = 0; j < (dataLen*8); j++){
+            if(getID(data, j) != 0){
+                list[i] = j;
+                i++;
+            }
+        }
+    }
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::storeFingerprint(uint8_t ID){
+    char data[4] = {0};
+    uint8_t ret;
+    ret = merge();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number = 0;
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+    
+}
+uint8_t DFRobot_ID809::store(uint8_t ID){
+
+
+  char data[4] = {0};
+  uint8_t ret;
+  LDBG("ret=");
+  LDBG(ret);
+  data[0] = ID;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  return ret;
+}
+uint8_t DFRobot_ID809::delFingerprint(uint8_t ID)
+{
+  char data[4] = {0};
+  if(ID == DELALL) {
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+  } else {
+    data[0] = data[2] = ID;
+  }
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEL_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  return ret;
+}
+
+uint8_t DFRobot_ID809::search(){
+    if(_state == 1){
+        char data[6] = {0};
+        data[2] = 1;
+        data[4] = FINGERPRINT_CAPACITY;
+        _number = 0;
+        pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SEARCH, data, 6);
+        sendPacket(header);
+        free(header);
+        uint8_t ret = responsePayload(buf);
+        LDBG("ret=");LDBG(ret);
+        if(ret == ERR_SUCCESS){
+            ret = buf[0];
+        }else{
+            ret = 0;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+uint8_t DFRobot_ID809::verify(uint8_t ID){
+    if(_state == 1){
+        char data[4] = {0};
+        data[0] = ID;
+        _number = 0;
+        pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_VERIFY, data, 4);
+        sendPacket(header);
+        free(header);
+        uint8_t ret = responsePayload(buf);
+        LDBG("ret=");LDBG(ret);
+        if(ret == ERR_SUCCESS){
+            ret = buf[0];
+        }else{
+            ret = 0;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+uint8_t DFRobot_ID809::match(uint8_t RamBufferID0, uint8_t RamBufferID1){
+    char data[4] = {0};
+    data[0] = RamBufferID0;
+    data[2] = RamBufferID1;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenQuantity(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[2];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::loadFingerprint(uint8_t ID, uint8_t RamBufferID){
+    char data[4] = {0};
+    data[0] = ID;
+    data[2] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::enterStandbyState(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_ENTER_STANDBY_STATE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_PARAM, (const char *)data, 5);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_PARAM, (const char *)data, 1);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getImage(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::collectionFingerprint(uint16_t timeout,int ramNumber){  //Collect fingerprint 
+    uint16_t i = 0;
+    uint8_t ret;
+   if(ramNumber == -1){
+     if(_number > 2){
+         _error = eErrorGatherOut;
+         LDBG("Exceed upper limit of acquisition times ");
+         return ERR_ID809;
+     }
+   }
+    while(!detectFinger()){
+        if(timeout != 0){
+            delay(10);
+            if(++i > timeout*10){
+                _error = eErrorTimeOut;
+                LDBG("Acquisition timeout ");
+                LDBG("ret=");LDBG(ret);
+                _state = 0;
+                return ERR_ID809;
+            }
+       }
+    }
+    ret = getImage();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        _state = 0;
+        return ERR_ID809;
+    }
+   if(ramNumber != -1){
+     ret = generate(ramNumber);
+   } else{
+     ret = generate(_number);
+   }
+	LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        _state = 0;
+        return ERR_ID809;
+    }
+    _number++;
+    _state = 1;
+    return ret;
+}
+
+uint8_t DFRobot_ID809::generate(uint8_t RamBufferID){
+    char data[2] = {0};
+    data[0] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GENERATE, (const char *)data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::merge(){
+    char data[3] = {0};
+    data[2] = _number;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MERGE, data, 3);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+pCmdPacketHeader_t DFRobot_ID809::pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len){
+    pCmdPacketHeader_t header;
+    uint16_t cks=0;
+    uint16_t dataLen;
+    if(type == CMD_TYPE){    //Structure of command packet, fixed 26 bytes:10(frame header)+14(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+16+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_PREFIX_CODE;
+        for(int i=0;i<16;i++){
+            header->payload[i] = 0;
+        }
+        dataLen = 16;   //Length of data to be replicated 
+    }else{                   //Structure of command data packet, unfixed length:10(frame header)+LEN(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+len+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_DATA_PREFIX_CODE;
+        dataLen = len;   //Length of data to be replicated 
+    }
+    header->SID = 0;
+    header->DID = 0;
+    header->CMD = cmd;
+    header->LEN = len;
+    if(len){
+        memcpy(header->payload, payload, len);
+    }
+    cks = getCmdCKS(header);
+    memcpy(&header->payload[dataLen],&cks,2);
+    _PacketSize = sizeof(sCmdPacketHeader_t) + dataLen +2;
+    return header;
+}
+
+
+void DFRobot_ID809::sendPacket(pCmdPacketHeader_t header){
+    s->write((uint8_t *)header,_PacketSize);
+}
+
+uint8_t DFRobot_ID809::responsePayload(void* buf){
+    sRcmPacketHeader_t header;
+    uint16_t dataLen,dataCount,cks;
+    uint8_t ch,ret;
+    int16_t type;
+    type = readPrefix(&header);
+    if(type == 1){
+        LDBG("--recv timeout---");
+        _error = eErrorRecvTimeout;
+        return ERR_ID809;
+    }
+    pRcmPacketHeader_t packet;
+    if(type == RCM_TYPE){    //Structure of response packet, fixed 26 bytes: 10(frame header)+14(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+14+2);
+        dataLen = 14+2;      //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }else{                   //Structure of response data packet, unfixed length: 10(frame header)+(LEN-2)(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+header.LEN);
+        dataLen = header.LEN;  //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }
+    memcpy(packet, &header, 10);
+    dataCount = readN(packet->payload, dataLen);
+    cks = packet->payload[dataLen-2]+(packet->payload[dataLen-1]<<8);
+    ret = (header.RET&0xFF);
+    _error = (eError_t)ret;
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else if(dataLen != dataCount){
+        LDBG("--recvRspPacket length error---");
+        _error = eErrorRecvLength;
+        ret = ERR_ID809;
+    }else if(getRcmCKS(packet) != cks){
+        LDBG("--recvRspPacket cks error---");
+        _error = eErrorRecvCks;
+        ret = ERR_ID809;
+    }else{
+        LDBG("--recvRspPacket OK---");
+        memcpy(buf, packet->payload, dataLen);
+    }
+    free(packet);
+    packet = NULL;
+    return ret;
+}
+
+uint16_t DFRobot_ID809::readPrefix( pRcmPacketHeader_t header ){
+    uint8_t ch,ret;
+    typedef enum{
+        RECV_HEADER_INIT,
+        RECV_HEADER_AA,
+        RECV_HEADER_A5,
+        RECV_HEADER_OK
+    }eRecvHeaderState;
+    eRecvHeaderState state = RECV_HEADER_INIT;
+    while(state != RECV_HEADER_OK){   //Can judge the received command packet and command data packet prefix at the same time 
+        if(readN(&ch, 1) != 1){
+            ret = 1;
+            return ret;
+        }
+        if((ch == 0xAA) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_AA;
+            continue;
+        }else if((ch == 0xA5) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_A5;
+            continue;
+        }else if((ch == 0x55) && (state == RECV_HEADER_AA)){
+            state = RECV_HEADER_OK;
+            ret = RCM_TYPE;
+            continue;
+        }else if((ch == 0x5A) && (state == RECV_HEADER_A5)){
+            state = RECV_HEADER_OK;
+            ret = DATA_TYPE;
+            continue;
+        }else{
+            state = RECV_HEADER_INIT;
+            if(ch == 0xAA){
+                state = RECV_HEADER_AA;
+            }else if(ch == 0xA5){
+                state = RECV_HEADER_A5;
+            }
+        }
+    }
+    if(ret == RCM_TYPE){
+        header->PREFIX = RCM_PREFIX_CODE;
+    }else if(ret == DATA_TYPE){
+        header->PREFIX = RCM_DATA_PREFIX_CODE;
+    }
+    readN(&header->SID, 1);
+    readN(&header->DID, 1);
+    readN(&header->RCM, 2);
+    readN(&header->LEN, 2);
+    readN(&header->RET, 2);
+    return ret;
+}
+
+size_t DFRobot_ID809::readN(void* buffer, size_t len){
+    size_t offset = 0,left = len;
+    uint8_t *buf = (uint8_t*)buffer;
+    long long curr = millis();
+    while(left){
+        if(s->available()){
+            buf[offset++] = s->read();
+            left--;
+        }
+        if(millis() - curr > 5000){
+            LDBG("----------!!!!!!!!!recv timeout----------");
+            break;
+        }
+    }
+    return offset;
+}
+
+uint16_t DFRobot_ID809::getCmdCKS(pCmdPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->CMD&0xFF;
+    cks += packet->CMD>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint16_t i = 0; i < packet->LEN; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+uint16_t DFRobot_ID809::getRcmCKS(pRcmPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->RCM&0xFF;
+    cks += packet->RCM>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    cks += packet->RET&0xFF;
+    cks += packet->RET>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint16_t i = 0; i < packet->LEN-2; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+const DFRobot_ID809::sErrorDescription_t DFRobot_ID809::errorDescriptionsTable[]={
+  {eErrorSuccess, "Command processed successfully"},
+  {eErrorFail, "Command processing failed"},
+  {eErrorVerify, "1:1 comparison failed"},
+  {eErrorIdentify, "Comparison with all fingerprints failed"},
+  {eErrorTmplEmpty, "No fingerprint in designated ID"},
+  {eErrorTmplNotEmpty, "Designated ID has fingerprint"},
+  {eErrorAllTmplEmpty, "Module unregistered fingerprint"},
+  {eErrorEmptyIDNoexist, "No registerable ID here"},
+  {eErrorBrokenIDNoexist, "No broken fingerprint"},
+  {eErrorInvalidTmplData, "Invalid desingated fingerprint data"},
+  {eErrorDuplicationID, "The fingerprint has been registered"},
+  {eErrorBadQuality, "Poor quality fingerprint image"},
+  {eErrorMergeFail, "Fingerprint synthesis failed"},
+  {eErrorNotAuthorized, "Communication password not authorized"},
+  {eErrorMemory, "External Flash burning error"},
+  {eErrorInvalidTmplNo, "Invalid designated ID"},
+  {eErrorInvalidParam, "Incorrect parameter"},
+  {eErrorTimeOut, "Acquisition timeout"},
+  {eErrorGenCount, "Invalid number of fingerprint synthesis"},
+  {eErrorInvalidBufferID, "Incorrect Buffer ID value"},
+  {eErrorFPNotDetected, "No fingerprint input into fingerprint reader"},
+  {eErrorFPCancel, "Command cancelled"},
+  {eErrorRecvLength, "Wrong data length"},
+  {eErrorRecvCks, "Wrong data check code"},
+  {eErrorGatherOut, "Exceed upper limit of acquisition times"},
+  {eErrorRecvTimeout,"Data reading timeout"}
+};
+
+String DFRobot_ID809::getErrorDescription()
+{
+    for(int i=0;i<sizeof(errorDescriptionsTable)/sizeof(errorDescriptionsTable[0]);i++){
+        if(_error == errorDescriptionsTable[i].error){
+          return errorDescriptionsTable[i].description;
+        }
+    }
+    return "";
+}
+
+
diff --git a/RegFPwithHash/lib/DFRobot_ID809/DFRobot_ID809.h b/RegFPwithHash/lib/DFRobot_ID809/DFRobot_ID809.h
new file mode 100644
index 0000000..83ca50d
--- /dev/null
+++ b/RegFPwithHash/lib/DFRobot_ID809/DFRobot_ID809.h
@@ -0,0 +1,504 @@
+/*!
+ * @file DFRobot_ID809.h
+ * @brief Define basic structure of DFRobot_ID809 class
+ * @n This is an library for capacitive fingerprint module
+ * @n Main functions: fingerprint image capturing, fingerprint comparison, fingerprint deletion
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#ifndef _DFRobot_ID809_H
+#define _DFRobot_ID809_H
+
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+#include "WProgram.h"
+#endif
+#include <Wire.h>
+
+#include <stdint.h>
+
+//Open this macro to see the detailed running process of the program 
+
+//#define ENABLE_DBG
+#ifdef ENABLE_DBG
+#define LDBG(...) if(dbg) {dbg->print("["); dbg->print(__FUNCTION__); dbg->print("(): "); dbg->print(__LINE__); dbg->print(" ] "); dbg->println(__VA_ARGS__);}
+#else
+#define LDBG(...)
+#endif
+
+extern Stream *dbg;
+
+  /*
+   Frame struct of command packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  CMD;
+  uint16_t  LEN;
+  uint8_t payload[0];
+}__attribute__ ((packed)) sCmdPacketHeader_t, *pCmdPacketHeader_t;
+
+  /*
+   Frame struct of response packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  RCM;
+  uint16_t  LEN;
+  uint16_t  RET;
+  uint8_t   payload[0];
+}__attribute__ ((packed)) sRcmPacketHeader_t, *pRcmPacketHeader_t;
+
+  
+
+
+class DFRobot_ID809{
+public: 
+
+//#define FINGERPRINT_CAPACITY     80      //Fingerprint module capacity
+#define MODULE_SN_SIZE           16      //Module SN length 
+
+
+#define DELALL                   0xFF    //Delete all fingerprints 
+
+#define CMD_PREFIX_CODE          0xAA55  //Command packet prefix code 
+#define RCM_PREFIX_CODE          0x55AA  //Response packet prefix code 
+#define CMD_DATA_PREFIX_CODE     0xA55A  //Command data packet prefix code 
+#define RCM_DATA_PREFIX_CODE     0x5AA5  //Response data packet prefix code 
+
+#define CMD_TYPE                 0xF0    //Command packet type 
+#define RCM_TYPE                 0xF0    //Response packet type 
+#define DATA_TYPE                0x0F    //Data packet type 
+
+#define CMD_TEST_CONNECTION      0X0001  //Test connection 
+#define CMD_SET_PARAM            0X0002  //Set parameter
+#define CMD_GET_PARAM            0X0003  //Read parameter 
+#define CMD_DEVICE_INFO          0X0004  //Read device information 
+#define CMD_SET_MODULE_SN        0X0008  //Set module serial number 
+#define CMD_GET_MODULE_SN        0X0009  //Read module serial number
+#define CMD_ENTER_STANDBY_STATE  0X000C  //Enter sleep mode 
+#define CMD_GET_IMAGE            0X0020  //Capture fingerprint image 
+#define CMD_FINGER_DETECT        0X0021  //Detect fingerprint 
+    #define CMD_UP_IMAGE_CODE        0X0022  //Upload fingerprint image to host 
+    #define CMD_DOWN_IMAGE           0X0023  //Download fingerprint image to module 
+#define CMD_SLED_CTRL            0X0024  //Control collector backlight 
+#define CMD_STORE_CHAR           0X0040  //Save fingerprint template data into fingerprint library 
+#define CMD_LOAD_CHAR            0X0041  //Read fingerprint in module and save it in RAMBUFFER temporarily  
+    #define CMD_UP_CHAR              0X0042  //Upload the fingerprint template saved in RAMBUFFER to host 
+    #define CMD_DOWN_CHAR            0X0043  //Download fingerprint template to module designated RAMBUFFER
+#define CMD_DEL_CHAR             0X0044  //Delete fingerprint in specific ID range 
+#define CMD_GET_EMPTY_ID         0X0045  //Get the first registerable ID in specific ID range 
+#define CMD_GET_STATUS           0X0046  //Check if the designated ID has been registered 
+#define CMD_GET_BROKEN_ID        0X0047  //Check whether there is damaged data in fingerprint library of specific range
+#define CMD_GET_ENROLL_COUNT     0X0048  //Get the number of registered fingerprints in specific ID range 
+#define CMD_GET_ENROLLED_ID_LIST 0X0049  //Get registered ID list
+#define CMD_GENERATE             0X0060  //Generate template from the fingerprint images saved in IMAGEBUFFER temporarily 
+#define CMD_MERGE                0X0061  //Synthesize fingerprint template data 
+#define CMD_MATCH                0X0062  //Compare templates in 2 designated RAMBUFFER 
+#define CMD_SEARCH               0X0063  //1:N Recognition in specific ID range 
+#define CMD_VERIFY               0X0064  //Compare specific RAMBUFFER template with specific ID template in fingerprint library 
+
+#define ERR_SUCCESS              0x00    //Command processed successfully 
+#define ERR_ID809                0xFF    //error 
+
+
+public:
+  
+  typedef enum{
+    eBreathing = 1,  //Breathing 
+    eFastBlink,      //Quick blink
+    eKeepsOn,        //On
+    eNormalClose,    //Off
+    eFadeIn,         //Fade in 
+    eFadeOut,        //Fade out
+    eSlowBlink       //Slow blink
+  }eLEDMode_t;
+  
+  typedef enum{
+    eLEDGreen = 1,   //green 
+    eLEDRed,         //red 
+    eLEDYellow,      //yellow
+    eLEDBlue,        //blue
+    eLEDCyan,        //cyan
+    eLEDMagenta,     //magenta
+    eLEDWhite        //white
+  }eLEDColor_t;
+   
+  typedef enum{
+    e9600bps = 1,
+    e19200bps,
+    e38400bps,
+    e57600bps,
+    e115200bps
+  }eDeviceBaudrate_t;
+  
+  typedef enum{
+    eErrorSuccess            = 0x00,    //Command processed successfully
+    eErrorFail               = 0x01,    //Command processing failed 
+    eErrorVerify             = 0x10,    //1:1 Templates comparison in specific ID failed 
+    eErrorIdentify           = 0x11,    //1:N comparison has been made, no same templates here 
+    eErrorTmplEmpty          = 0x12,    //No registered template in the designated ID 
+    eErrorTmplNotEmpty       = 0x13,    //Template already exists in the specified ID 
+    eErrorAllTmplEmpty       = 0x14,    //No registered Template 
+    eErrorEmptyIDNoexist     = 0x15,    //No registerable Template ID 
+    eErrorBrokenIDNoexist    = 0x16,    //No damaged Template 
+    eErrorInvalidTmplData    = 0x17,    //The designated Template Data is invalid 
+    eErrorDuplicationID      = 0x18,    //The fingerprint has been registered 
+    eErrorBadQuality         = 0x19,    //Poor quality fingerprint image 
+    eErrorMergeFail          = 0x1A,    //Template synthesis failed 
+    eErrorNotAuthorized      = 0x1B,    //Communication password not authorized 
+    eErrorMemory             = 0x1C,    //Error in exernal Flash burning 
+    eErrorInvalidTmplNo      = 0x1D,    //The designated template ID is invalid 
+    eErrorInvalidParam       = 0x22,    //Incorrect parameter has been used 
+    eErrorTimeOut            = 0x23,    //Acquisition timeout 
+    eErrorGenCount           = 0x25,    //Invalid number of fingerprint synthesis 
+    eErrorInvalidBufferID    = 0x26,    //Wrong Buffer ID value 
+    eErrorFPNotDetected      = 0x28,    //No fingerprint input into fingerprint reader 
+    eErrorFPCancel           = 0x41,    //Command cancelled 
+    eErrorRecvLength         = 0x42,    //Wrong length of recieved data 
+    eErrorRecvCks            = 0x43,    //Wrong check code 
+    eErrorGatherOut          = 0x45,    //Exceed upper limit of acquisition times 
+    eErrorRecvTimeout        = 0x46     //Communication timeout 
+  }eError_t;
+  
+  typedef struct{
+    /**< Gesture enumeration variable X */
+    eError_t error;
+    /**< Description about the gesture enumeration variable X */
+    const char * description;
+  }sErrorDescription_t;
+
+public:
+  DFRobot_ID809();
+  ~DFRobot_ID809();
+  
+  /**
+   * @brief Init communication port
+   * @param Software serial or hardware serial 
+   * @return true or false
+   */
+  bool begin(Stream &s_);
+  
+  /**
+   * @brief Test whether the module connection is ok
+   * @return true or false
+   */
+  bool isConnected();
+  
+  /**
+   * @brief Set module ID
+   * @param ID:1-255
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDeviceID(uint8_t deviceID);
+  
+  /**
+   * @brief Set module security level 
+   * @param security level:1-5
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSecurityLevel(uint8_t securityLevel);
+  
+  /**
+   * @brief Set module fingerprint replication check (Check whether the fingperint has been registered when saving it)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDuplicationCheck(uint8_t duplicationCheck);
+  
+  /**
+   * @brief Set module baud rate 
+   * @param Baudrate:in typedef enum eDeviceBaudrate_t
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setBaudrate(eDeviceBaudrate_t baudrate);
+  
+  /**
+   * @brief Set module self-learning function (Update fingeprint when fingerprint comparison succeeds)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSelfLearn(uint8_t selfLearn);
+  
+  /**
+   * @brief Read module ID
+   * @return ID号:1-255 or ERR_ID809
+   */
+  uint8_t getDeviceID();
+  
+  /**
+   * @brief Read module security level 
+   * @return Security level:1-5 or ERR_ID809
+   */
+  uint8_t getSecurityLevel();
+  
+  /**
+   * @brief Read module fingerprint replication check status
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getDuplicationCheck();
+  
+  /**
+   * @brief Read module baud rate 
+   * @return Baudrate:in typedef enum eDEVICE_BAUDRATE_t or ERR_ID809
+   */
+  uint8_t getBaudrate();
+  
+  /**
+   * @brief Read module self-learning function status 
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getSelfLearn();
+  uint8_t getTemplate(uint16_t id,uint8_t * temp);
+  uint8_t downLoadTemplate(uint16_t id,uint8_t * temp);
+  uint8_t getFingerImage(uint8_t *image);
+  uint8_t downLoadImage(uint16_t id,uint8_t * temp);
+  uint8_t receiveImageData(uint8_t *image);
+  uint8_t getQuarterFingerImage(uint8_t *image);
+  uint8_t contrastTemplate(uint8_t *temp);
+  /**
+   * @brief Read device number 
+   * @return Device number
+   */
+  String getDeviceInfo();
+  
+  /**
+   * @brief Set serial number
+   * @param String pointer 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setModuleSN(const char* SN);
+  /**
+   * @brief Read serial number 
+   * @return Serial number
+   */
+  String getModuleSN();
+  
+  /**
+   * @brief Set LED
+   * @param mode:in typedef enum eLEDMode_t
+   * @param color:in typedef enum eLEDColor_t
+   * @param blink Count: 00 represents blinking all the time
+   * @This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount);
+  
+  /**
+   * @brief Detect if there is finger touched 
+   * @return 1(Touched) or 0(No touch)
+   */
+  uint8_t detectFinger();
+  
+  /**
+   * @brief Get the first registerable ID 
+   * @return Registerable ID or ERR_ID809
+   */
+  uint8_t getEmptyID();
+  
+  /**
+   * @brief Check if the ID has been registered 
+   * @return 0(Registered), 1(Unregistered) or ERR_ID809
+   */
+  uint8_t getStatusID(uint8_t ID);
+  
+  /**
+   * @brief Get the number of registered users 
+   * @return Number of registered users or ERR_ID809
+   */
+  uint8_t getEnrollCount();
+  
+  /**
+   * @brief Get registered user list 
+   * @return 0(succeed) or ERR_ID809
+   */
+   uint8_t getEnrolledIDList(uint8_t* list);
+  
+  /**
+   * @brief Fingerprint acquisition 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t collectionFingerprint(uint16_t timeout,int ramNumber = -1);
+  
+  /**
+   * @brief Save fingerprint 
+   * @param Fingerprint ID
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t storeFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Delete fingerprint 
+   * @param Delete ID or DELALL(delete all)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t delFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Match the fingerprint with all fingeprints 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t search();
+
+  /**
+   * @brief Match the fingerprint with specific fingerprint 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t verify(uint8_t ID);
+
+  /**
+   * @brief Compare templates in two specific RamBuffers
+   * @param RamBuffer number 
+   * @param RamBuffer number 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t match(uint8_t RamBufferID0, uint8_t RamBufferID1);
+  
+  /**
+   * @brief Get the number of damaged fingerprints 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenQuantity();
+
+  /**
+   * @brief Get the first damaged fingerprint ID 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenID();
+  
+  /**
+   * @brief Take out fingerprint template, temporarily save into RamBuffer
+   * @param Fingerprint ID 
+   * @param RamBuffer number 0-2
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t loadFingerprint(uint8_t ID, uint8_t RamBufferID);
+  
+  /**
+   * @brief Enter Standby mode
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t enterStandbyState();
+  
+  /**
+   * @brief Get error information
+   * @return Text description of error information
+   */
+  String getErrorDescription();
+  
+  bool setDbgSerial(Stream &s_){dbg = &s_; return true;}
+    uint16_t FINGERPRINT_CAPACITY = 80;
+protected:
+   /**
+   * @brief Set parameter 
+   * @param Data type+ data
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setParam(uint8_t* data);
+  
+   /**
+   * @brief Read parameter 
+   * @param Data type 
+   * @return data or ERR_ID809
+   */
+  uint8_t getParam(uint8_t* data);
+  
+  /**
+   * @brief Capture fingerprint image 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t getImage();
+   
+   /**
+   * @brief Take image as template 
+   * @param Ram Buffer number
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t generate(uint8_t RamBufferID);
+  
+ /**
+   * @brief Fingerprint synthesis 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t merge();
+  
+ /**
+   * @brief Packing data frame 
+   * @param Data type:CMD_TYPE or DATA_TYPE
+   * @param Command
+   * @param Data 
+   * @param Length
+   * @return Data frame 
+   */
+  pCmdPacketHeader_t pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len);
+  
+ /**
+   * @brief Send data 
+   * @param Data frame
+   */
+  void sendPacket(pCmdPacketHeader_t header);
+  
+ /**
+   * @brief Read byte 
+   * @param Pointer for saving data 
+   * @param Length of data to be received 
+   * @return Actual received data length 
+   */
+  size_t readN(void* buf_, size_t len);
+  
+ /**
+   * @brief Read frame header 
+   * @param Frame header struct of response packet
+   * @return Response packet type:RCM_TYPE,DATA_TYPE or 1(reading timeout)
+   */
+  uint16_t readPrefix( pRcmPacketHeader_t header );
+  
+ /**
+   * @brief Read data
+   * @param Pointer for saving data 
+   * @return 0(success) or ERR_ID809
+   */
+  uint8_t responsePayload(void* buf);
+  
+ /**
+   * @brief Get command packet CKS
+   * @param Command packet frame 
+   * @return CKS
+   */
+  uint16_t getCmdCKS(pCmdPacketHeader_t packet);
+  
+ /**
+   * @brief Get response packet CKS
+   * @param Response packet frame 
+   * @return CKS
+   */
+  uint16_t getRcmCKS(pRcmPacketHeader_t packet);
+  uint8_t store(uint8_t ID);
+  
+private:
+  Stream *s;
+  uint8_t buf[20];     //For saving response packet data 
+  pCmdPacketHeader_t  sendHeader;
+  pRcmPacketHeader_t  recHeader;
+  
+  static const sErrorDescription_t /*PROGMEM*/ errorDescriptionsTable[26];   //Error information list 
+  
+  uint8_t _number = 0;       //Fingerprint acquisistion times 
+  uint8_t _state = 0;        //Collect fingerprint state
+  eError_t _error;           //Error code 
+  uint16_t _PacketSize = 0;  //Data packet length to be sent 
+};
+
+#endif
+
diff --git a/RegFPwithHash/platformio.ini b/RegFPwithHash/platformio.ini
new file mode 100644
index 0000000..f0c71a5
--- /dev/null
+++ b/RegFPwithHash/platformio.ini
@@ -0,0 +1,12 @@
+[env:Teensy_FP]
+
+board = teensy31
+framework = arduino
+platform = teensy
+
+build_flags = 
+	-I lib/DFRobot_ID809
+
+lib_deps = 
+	intrbiz/crypto
+
diff --git a/RegFPwithHash/src/src.cpp b/RegFPwithHash/src/src.cpp
new file mode 100644
index 0000000..1547c0a
--- /dev/null
+++ b/RegFPwithHash/src/src.cpp
@@ -0,0 +1,216 @@
+#include <Arduino.h>
+#include <Crypto.h>
+#include <DFRobot_ID809.h>
+#include <EEPROM.h>
+
+// use serial3 as interface with fingerprint
+// sensor.
+
+#define FPSerial Serial3
+
+// define buillt_in led
+
+#define BUILTIN_LED 13
+
+// Collect the fingerprint 3 times
+
+#define COLLECT_NUMBER  3 
+
+// EEPROM OFFSET to store
+
+/*------Global variables--------------*/
+
+DFRobot_ID809 fingerprint;
+uint8_t ID = 0, ret;
+byte hash[SHA256_SIZE];
+uint8_t temp[1008];
+const uint16_t EEPROM_FP_HASH = 1696;
+
+/*---------Compute hash----------------*/
+
+void compute_hash() {
+
+  SHA256 hasher;
+  hasher.doUpdate(temp, sizeof(temp));
+  hasher.doFinal(hash);
+
+  for (uint8_t i = 0; i < SHA256_SIZE; i++) {
+
+    if (hash[i] < 0x10) {
+
+      Serial.print('0');
+    }
+
+    Serial.print(hash[i], HEX);
+    Serial.print(" ");
+  }
+  Serial.println("\n");
+  Serial.println("-----------------");
+}
+
+/*-----Blink on board led -------------- */
+
+void blink_led() {
+  digitalWrite(BUILTIN_LED, HIGH);
+  delay(500);
+  digitalWrite(BUILTIN_LED, LOW);
+  delay(500);
+}
+
+/*-------- Save FingerPrint hash in EEPROM ------*/
+
+void saveHash() {
+  uint16_t memoryAddress;
+
+  memoryAddress = EEPROM_FP_HASH + ((ID - 1) * 32);
+
+  for (uint8_t i = 0; i < SHA256_SIZE; i++) {
+
+    EEPROM.write(memoryAddress, hash[i]);
+    memoryAddress++;
+  }
+}
+
+/*---------Arduino setup function------*/
+
+void setup() {
+  // config led_pin as output
+  pinMode(BUILTIN_LED, OUTPUT);
+  // use serial port to print the baud rate
+  Serial.begin(9600);
+  // config fingerprint sensor
+  FPSerial.begin(115200);
+  fingerprint.begin(FPSerial);
+
+  while (fingerprint.isConnected() == false) {
+    Serial.println("Communication with the device failed");
+    delay(1000);
+  }
+  // Disable self-learn feature 
+  fingerprint.setSelfLearn(0);
+}
+
+/*------Read stored EEPROM data--------- */
+
+void readHash() {
+
+  uint16_t memoryAddress;
+  byte eeprom_data;
+
+  memoryAddress = EEPROM_FP_HASH + ((ID - 1) * 32);
+
+  for (uint16_t i = memoryAddress; i < (memoryAddress + SHA256_SIZE); i++) {
+
+    eeprom_data = EEPROM.read(i);
+    Serial.print(eeprom_data, HEX);
+    Serial.print(" ");
+  }
+  Serial.println("\n");
+  Serial.println("--------------------");
+}
+
+/*---------Register Finger print ------------*/
+
+void regFingerprint() {
+  uint8_t i = 0;
+  /*Get an unregistered ID for saving fingerprint
+Return ID when succeeded
+Return ERR_ID809 if failed
+*/
+  if ((ID = fingerprint.getEmptyID()) == ERR_ID809) {
+    while (1) {
+      /*Get error code information*/
+      // desc = fingerprint.getErrorDescription();
+      // Serial.println(desc);
+      delay(1000);
+    }
+  }
+  Serial.print("unresistered ID,ID=");
+  Serial.println(ID);
+  i = 0; // Clear sampling times
+  /*Fingerprint sampling 3 times*/
+  while (i < COLLECT_NUMBER) {
+    /*Set fingerprint LED ring mode, color, and number of blinks
+      Can be set as follows:
+      Parameter 1:<LEDMode>
+      eBreathing   eFastBlink   eKeepsOn    eNormalClose
+      eFadeIn      eFadeOut     eSlowBlink
+      Parameter 2:<LEDColor>
+      eLEDGreen  eLEDRed      eLEDYellow   eLEDBlue
+      eLEDCyan   eLEDMagenta  eLEDWhite
+      Parameter 3:<Number of blinks> 0 represents blinking all the time
+      This parameter will only be valid in mode eBreathing, eFastBlink,
+      eSlowBlink
+     */
+    fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eBreathing,
+                        /*LEDColor = */ fingerprint.eLEDBlue,
+                        /*blinkCount = */ 0);
+    Serial.print("The fingerprint sampling of the");
+    Serial.print(i + 1);
+    Serial.println("(th) is being taken");
+    Serial.println("Please press down your finger");
+    /*Capture fingerprint image, 10s idle timeout, if timeout=0,Disable  the
+      collection timeout function IF succeeded, return 0, otherwise, return
+      ERR_ID809
+     */
+    if ((fingerprint.collectionFingerprint(/*timeout = */ 10)) != ERR_ID809) {
+      /*Set fingerprint LED ring to quick blink in yellow 3 times */
+      fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eFastBlink,
+                          /*LEDColor = */ fingerprint.eLEDYellow,
+                          /*blinkCount = */ 3);
+      Serial.println("Sampling succeeds");
+      i++; // Sampling times +1
+    } else {
+      Serial.println("Sampling failed");
+      /*Get error code information*/
+      // desc = fingerprint.getErrorDescription();
+      // Serial.println(desc);
+    }
+    Serial.println("Please release your finger");
+    /*Wait for finger to release
+      Return 1 when finger is detected, otherwise return 0
+     */
+    while (fingerprint.detectFinger())
+      ;
+  }
+
+  if (ID < 1) {
+    Serial.println("Fingerprint registration failed");
+    return;
+  }
+
+  /*Save fingerprint in an unregistered ID */
+  if (fingerprint.storeFingerprint(/*Empty ID = */ ID) != ERR_ID809) {
+    Serial.print("Saving succeed,ID=");
+    Serial.println(ID);
+    Serial.println("-----------------------------");
+    /*Set fingerprint LED ring to always ON in green */
+    fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eKeepsOn,
+                        /*LEDColor = */ fingerprint.eLEDGreen,
+                        /*blinkCount = */ 0);
+    delay(1000);
+    /*Turn off fingerprint LED ring */
+    fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eNormalClose,
+                        /*LEDColor = */ fingerprint.eLEDBlue,
+                        /*blinkCount = */ 0);
+    delay(1000);
+
+    fingerprint.getTemplate(ID, temp);
+    compute_hash();
+    saveHash();
+    readHash();
+
+  } else {
+    Serial.println("Saving failed");
+    /*Get error code information*/
+    // desc = fingerprint.getErrorDescription();
+    // Serial.println(desc);
+  }
+}
+
+/*-----------Arduino loop function--------- */
+
+void loop() {
+  blink_led();
+  regFingerprint();
+}
diff --git a/matchFPandHash/lib/DFRobot_ID809/DFRobot_ID809.cpp b/matchFPandHash/lib/DFRobot_ID809/DFRobot_ID809.cpp
new file mode 100644
index 0000000..d49f6f4
--- /dev/null
+++ b/matchFPandHash/lib/DFRobot_ID809/DFRobot_ID809.cpp
@@ -0,0 +1,1089 @@
+/*!
+ * @file DFRobot_ID809.cpp
+ * @brief Define the basic structure of DFRobot_ID809 class and the implementation of underlying methods 
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#include <DFRobot_ID809.h>
+#include <Arduino.h>
+#include <string.h>
+#include <stdio.h>
+Stream *dbg=NULL;
+
+DFRobot_ID809::DFRobot_ID809()
+  :s(NULL){
+        
+}
+
+DFRobot_ID809::~DFRobot_ID809(){
+        
+}
+
+bool DFRobot_ID809::begin(Stream &s_){
+    s = &s_;
+	String str = getDeviceInfo();
+  //Serial.println(str[str.length()-1]);
+  if(str[str.length()-1] == '4'){
+	    
+	   FINGERPRINT_CAPACITY   =    80 ;
+	  
+	  //Serial.println(str[str.length()-1]);
+  }else if(str[str.length()-1] == '3'){
+	  //Serial.println(str[str.length()-1]);
+	   FINGERPRINT_CAPACITY  =   200 ;
+	  
+  }
+	
+    if(s == NULL){
+        return false;
+    }
+    return true;
+}
+
+bool DFRobot_ID809::isConnected(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_TEST_CONNECTION, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        return true;
+    }else{
+        return false;
+    }
+}
+
+uint8_t DFRobot_ID809::setDeviceID(uint8_t deviceID){
+    uint8_t data[5] = {0};    //data:1bytes Parameter Type+4bytes Parameter Value
+    data[1] = deviceID;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSecurityLevel(uint8_t securityLevel){
+    uint8_t data[5] = {0};
+    data[0] = 1;
+    data[1] = securityLevel;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setDuplicationCheck(uint8_t duplicationCheck){
+    uint8_t data[5] = {0};
+    data[0] = 2;
+    data[1] = duplicationCheck;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setBaudrate(eDeviceBaudrate_t baudrate){
+    uint8_t data[5] = {0};
+    data[0] = 3;
+    data[1] = baudrate;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSelfLearn(uint8_t selfLearn){
+    uint8_t data[5] = {0};
+    data[0] = 4;
+    data[1] = selfLearn;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDeviceID(){
+    uint8_t data[1];  //data:1byte Parameter Type
+    data[0] = 0;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSecurityLevel(){
+    uint8_t data[1];
+    data[0] = 1;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDuplicationCheck(){
+    uint8_t data[1];
+    data[0] = 2;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBaudrate(){
+    uint8_t data[1];
+    data[0] = 3;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSelfLearn(){
+    uint8_t data[1];
+    data[0] = 4;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+String DFRobot_ID809::getDeviceInfo(){
+    char *data;
+    uint8_t result;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEVICE_INFO, NULL, 0);
+    sendPacket(header);
+    free(header);
+    result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setModuleSN(const char* SN){
+    char data[2];
+    data[0] = MODULE_SN_SIZE;
+    if(strlen(SN) > MODULE_SN_SIZE){
+        LDBG("The serial number exceeds 15 characters");
+        return ERR_ID809;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_MODULE_SN, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    header = pack(DATA_TYPE, CMD_SET_MODULE_SN, SN, MODULE_SN_SIZE);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getTemplate(uint16_t id,uint8_t * temp){
+  char data[4];
+  data[0] = id;
+  data[1] = 0;
+  data[2] = 0;
+  data[3] = 0;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  data[0] = 0;
+  data[1] = 0;
+  header = pack(CMD_TYPE, CMD_UP_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  ret = responsePayload(temp);
+
+  return ret;
+}
+
+uint8_t DFRobot_ID809::downLoadTemplate(uint16_t id,uint8_t * temp){
+
+  char data[4];
+  data[0] = 0xf2;
+  data[1] = 3;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(0x3f2 +1);
+  tempData[0] = 0;
+  tempData[1] = 0;
+  memcpy(tempData+2,temp,0x3f0);
+  
+
+  header = pack(DATA_TYPE, CMD_DOWN_CHAR, tempData, 0x3f2);
+
+  sendPacket(header);
+
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  free(tempData);
+  
+
+  return store(id);
+}
+
+uint8_t DFRobot_ID809::contrastTemplate(uint8_t *temp){
+
+  char data[4];
+  data[0] = 0xf2;
+  data[1] = 3;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(0x3f2 +1);
+  tempData[0] = 2;
+  tempData[1] = 0;
+  memcpy(tempData+2,temp,0x3f0);
+  
+
+  header = pack(DATA_TYPE, CMD_DOWN_CHAR, tempData, 0x3f2);
+
+  sendPacket(header);
+
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  free(tempData);
+  data[0] = 0;
+  data[1] = 0;
+  data[2] = 2;
+  data[3] = 0;
+  header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ret;
+  }
+  return ret;
+
+}
+uint8_t DFRobot_ID809::getFingerImage(uint8_t *image)
+{
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  
+  char data[1];
+  data[0] = 0;
+  header = pack(CMD_TYPE, CMD_UP_IMAGE_CODE, data, 1);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500 +1);
+  for(uint8_t i=0;i<52;i++){
+
+     ret = responsePayload(tempData);
+     if(i == 51)
+       memcpy(image+i*496,tempData+2,304);
+     else
+       memcpy(image+i*496,tempData+2,496);
+  }
+  free(tempData);
+}
+uint8_t DFRobot_ID809::getQuarterFingerImage(uint8_t *image){
+
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  
+  char data[1];
+  data[0] = 1;
+  header = pack(CMD_TYPE, CMD_UP_IMAGE_CODE, data, 1);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500 +1);
+  for(uint8_t i=0;i<13;i++){
+
+     ret = responsePayload(tempData);
+     if(i == 12)
+       memcpy(image+i*496,tempData+2,448);
+     else
+       memcpy(image+i*496,tempData+2,496);
+  }
+  free(tempData);
+
+}
+uint8_t DFRobot_ID809::downLoadImage(uint16_t id,uint8_t * temp)
+{
+  char data[4];
+  data[0] = 0xa0;
+  data[1] = 0;
+  data[2] = 0xa0;
+  data[3] = 0;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_IMAGE, data, 4);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500);
+  for(uint8_t i =0 ;i<52;i++){
+     tempData[0] = i;
+	 tempData[1] = 0;
+     if(i == 51){
+       memcpy(tempData+2,temp+i*496,304);
+       header = pack(DATA_TYPE, CMD_DOWN_IMAGE, tempData, 306);
+	 }else{
+       memcpy(tempData+2,temp+i*496,496);
+       header = pack(DATA_TYPE, CMD_DOWN_IMAGE, tempData, 498);
+     }
+     sendPacket(header);
+     
+     free(header);
+     
+     ret = responsePayload(buf);
+     LDBG("ret=");
+     LDBG(ret);
+     if(ret != ERR_SUCCESS) {
+       return ERR_ID809;
+     }
+     
+  }  
+  free(tempData);
+  
+  data[0] = 0;
+  data[1] = 0;
+  header = pack(CMD_TYPE, CMD_GENERATE, data, 2);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+   // return ERR_ID809;
+  }
+  return store(id);
+
+}
+
+uint8_t DFRobot_ID809::receiveImageData(uint8_t * image){
+
+
+
+  uint8_t ret = responsePayload(image);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+
+}
+String DFRobot_ID809::getModuleSN(){
+    char *data;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_MODULE_SN, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount){
+    char data[4] = {0};
+  if(FINGERPRINT_CAPACITY == 80){
+    data[0] = mode;
+    data[2] = data[1] = color;
+    data[3] = blinkCount;
+  }else{
+	if(mode == 1){
+	  data[0] = 2;
+	} else if(mode == 2){
+		data[0] = 4;
+	} else if(mode == 3){
+	    data[0] = 1;
+	} else if(mode == 4){
+		data[0] = 0;
+	} else if(mode == 5){
+		data[0] = 3;
+	}
+	if(color == eLEDGreen){
+          data[2] = data[1] =  0x84;
+        }else if(color == eLEDRed){
+	  data[2] = data[1] = 0x82;
+	}else if(color == eLEDYellow){
+	  data[2] = data[1] = 0x86;
+	}else if(color == eLEDBlue){
+	  data[2] = data[1] = 0x81;
+	}else if(color == eLEDCyan){
+	  data[2] = data[1] = 0x85;
+	}else if(color == eLEDMagenta){
+	  data[2] = data[1] = 0x83;
+	}else {
+	  data[2] = data[1] = 0x87;
+	}
+  }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SLED_CTRL, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::detectFinger(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_FINGER_DETECT, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEmptyID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;     //80 fingerprints at most, default to full range 
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_EMPTY_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getStatusID(uint8_t ID){
+    char data[2] = {0};
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_STATUS, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEnrollCount(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLL_COUNT, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+#define  getID(A, V)  (A[0 + V/8] & (0x01 << (V & 0x07)))
+uint8_t DFRobot_ID809::getEnrolledIDList(uint8_t* list)
+{
+    char *data;
+    uint8_t i = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLLED_ID_LIST, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    uint16_t dataLen = buf[0]+(buf[1]<<8);
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    ret = responsePayload(data);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else{
+        for(uint16_t j = 0; j < (dataLen*8); j++){
+            if(getID(data, j) != 0){
+                list[i] = j;
+                i++;
+            }
+        }
+    }
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::storeFingerprint(uint8_t ID){
+    char data[4] = {0};
+    uint8_t ret;
+    ret = merge();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number = 0;
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+    
+}
+uint8_t DFRobot_ID809::store(uint8_t ID){
+
+
+  char data[4] = {0};
+  uint8_t ret;
+  LDBG("ret=");
+  LDBG(ret);
+  data[0] = ID;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  return ret;
+}
+uint8_t DFRobot_ID809::delFingerprint(uint8_t ID)
+{
+  char data[4] = {0};
+  if(ID == DELALL) {
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+  } else {
+    data[0] = data[2] = ID;
+  }
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEL_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  return ret;
+}
+
+uint8_t DFRobot_ID809::search(){
+    if(_state == 1){
+        char data[6] = {0};
+        data[2] = 1;
+        data[4] = FINGERPRINT_CAPACITY;
+        _number = 0;
+        pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SEARCH, data, 6);
+        sendPacket(header);
+        free(header);
+        uint8_t ret = responsePayload(buf);
+        LDBG("ret=");LDBG(ret);
+        if(ret == ERR_SUCCESS){
+            ret = buf[0];
+        }else{
+            ret = 0;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+uint8_t DFRobot_ID809::verify(uint8_t ID){
+    if(_state == 1){
+        char data[4] = {0};
+        data[0] = ID;
+        _number = 0;
+        pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_VERIFY, data, 4);
+        sendPacket(header);
+        free(header);
+        uint8_t ret = responsePayload(buf);
+        LDBG("ret=");LDBG(ret);
+        if(ret == ERR_SUCCESS){
+            ret = buf[0];
+        }else{
+            ret = 0;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+uint8_t DFRobot_ID809::match(uint8_t RamBufferID0, uint8_t RamBufferID1){
+    char data[4] = {0};
+    data[0] = RamBufferID0;
+    data[2] = RamBufferID1;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenQuantity(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[2];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::loadFingerprint(uint8_t ID, uint8_t RamBufferID){
+    char data[4] = {0};
+    data[0] = ID;
+    data[2] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::enterStandbyState(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_ENTER_STANDBY_STATE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_PARAM, (const char *)data, 5);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_PARAM, (const char *)data, 1);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getImage(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::collectionFingerprint(uint16_t timeout,int ramNumber){  //Collect fingerprint 
+    uint16_t i = 0;
+    uint8_t ret;
+   if(ramNumber == -1){
+     if(_number > 2){
+         _error = eErrorGatherOut;
+         LDBG("Exceed upper limit of acquisition times ");
+         return ERR_ID809;
+     }
+   }
+    while(!detectFinger()){
+        if(timeout != 0){
+            delay(10);
+            if(++i > timeout*10){
+                _error = eErrorTimeOut;
+                LDBG("Acquisition timeout ");
+                LDBG("ret=");LDBG(ret);
+                _state = 0;
+                return ERR_ID809;
+            }
+       }
+    }
+    ret = getImage();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        _state = 0;
+        return ERR_ID809;
+    }
+   if(ramNumber != -1){
+     ret = generate(ramNumber);
+   } else{
+     ret = generate(_number);
+   }
+	LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        _state = 0;
+        return ERR_ID809;
+    }
+    _number++;
+    _state = 1;
+    return ret;
+}
+
+uint8_t DFRobot_ID809::generate(uint8_t RamBufferID){
+    char data[2] = {0};
+    data[0] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GENERATE, (const char *)data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::merge(){
+    char data[3] = {0};
+    data[2] = _number;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MERGE, data, 3);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+pCmdPacketHeader_t DFRobot_ID809::pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len){
+    pCmdPacketHeader_t header;
+    uint16_t cks=0;
+    uint16_t dataLen;
+    if(type == CMD_TYPE){    //Structure of command packet, fixed 26 bytes:10(frame header)+14(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+16+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_PREFIX_CODE;
+        for(int i=0;i<16;i++){
+            header->payload[i] = 0;
+        }
+        dataLen = 16;   //Length of data to be replicated 
+    }else{                   //Structure of command data packet, unfixed length:10(frame header)+LEN(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+len+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_DATA_PREFIX_CODE;
+        dataLen = len;   //Length of data to be replicated 
+    }
+    header->SID = 0;
+    header->DID = 0;
+    header->CMD = cmd;
+    header->LEN = len;
+    if(len){
+        memcpy(header->payload, payload, len);
+    }
+    cks = getCmdCKS(header);
+    memcpy(&header->payload[dataLen],&cks,2);
+    _PacketSize = sizeof(sCmdPacketHeader_t) + dataLen +2;
+    return header;
+}
+
+
+void DFRobot_ID809::sendPacket(pCmdPacketHeader_t header){
+    s->write((uint8_t *)header,_PacketSize);
+}
+
+uint8_t DFRobot_ID809::responsePayload(void* buf){
+    sRcmPacketHeader_t header;
+    uint16_t dataLen,dataCount,cks;
+    uint8_t ch,ret;
+    int16_t type;
+    type = readPrefix(&header);
+    if(type == 1){
+        LDBG("--recv timeout---");
+        _error = eErrorRecvTimeout;
+        return ERR_ID809;
+    }
+    pRcmPacketHeader_t packet;
+    if(type == RCM_TYPE){    //Structure of response packet, fixed 26 bytes: 10(frame header)+14(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+14+2);
+        dataLen = 14+2;      //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }else{                   //Structure of response data packet, unfixed length: 10(frame header)+(LEN-2)(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+header.LEN);
+        dataLen = header.LEN;  //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }
+    memcpy(packet, &header, 10);
+    dataCount = readN(packet->payload, dataLen);
+    cks = packet->payload[dataLen-2]+(packet->payload[dataLen-1]<<8);
+    ret = (header.RET&0xFF);
+    _error = (eError_t)ret;
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else if(dataLen != dataCount){
+        LDBG("--recvRspPacket length error---");
+        _error = eErrorRecvLength;
+        ret = ERR_ID809;
+    }else if(getRcmCKS(packet) != cks){
+        LDBG("--recvRspPacket cks error---");
+        _error = eErrorRecvCks;
+        ret = ERR_ID809;
+    }else{
+        LDBG("--recvRspPacket OK---");
+        memcpy(buf, packet->payload, dataLen);
+    }
+    free(packet);
+    packet = NULL;
+    return ret;
+}
+
+uint16_t DFRobot_ID809::readPrefix( pRcmPacketHeader_t header ){
+    uint8_t ch,ret;
+    typedef enum{
+        RECV_HEADER_INIT,
+        RECV_HEADER_AA,
+        RECV_HEADER_A5,
+        RECV_HEADER_OK
+    }eRecvHeaderState;
+    eRecvHeaderState state = RECV_HEADER_INIT;
+    while(state != RECV_HEADER_OK){   //Can judge the received command packet and command data packet prefix at the same time 
+        if(readN(&ch, 1) != 1){
+            ret = 1;
+            return ret;
+        }
+        if((ch == 0xAA) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_AA;
+            continue;
+        }else if((ch == 0xA5) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_A5;
+            continue;
+        }else if((ch == 0x55) && (state == RECV_HEADER_AA)){
+            state = RECV_HEADER_OK;
+            ret = RCM_TYPE;
+            continue;
+        }else if((ch == 0x5A) && (state == RECV_HEADER_A5)){
+            state = RECV_HEADER_OK;
+            ret = DATA_TYPE;
+            continue;
+        }else{
+            state = RECV_HEADER_INIT;
+            if(ch == 0xAA){
+                state = RECV_HEADER_AA;
+            }else if(ch == 0xA5){
+                state = RECV_HEADER_A5;
+            }
+        }
+    }
+    if(ret == RCM_TYPE){
+        header->PREFIX = RCM_PREFIX_CODE;
+    }else if(ret == DATA_TYPE){
+        header->PREFIX = RCM_DATA_PREFIX_CODE;
+    }
+    readN(&header->SID, 1);
+    readN(&header->DID, 1);
+    readN(&header->RCM, 2);
+    readN(&header->LEN, 2);
+    readN(&header->RET, 2);
+    return ret;
+}
+
+size_t DFRobot_ID809::readN(void* buffer, size_t len){
+    size_t offset = 0,left = len;
+    uint8_t *buf = (uint8_t*)buffer;
+    long long curr = millis();
+    while(left){
+        if(s->available()){
+            buf[offset++] = s->read();
+            left--;
+        }
+        if(millis() - curr > 5000){
+            LDBG("----------!!!!!!!!!recv timeout----------");
+            break;
+        }
+    }
+    return offset;
+}
+
+uint16_t DFRobot_ID809::getCmdCKS(pCmdPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->CMD&0xFF;
+    cks += packet->CMD>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint16_t i = 0; i < packet->LEN; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+uint16_t DFRobot_ID809::getRcmCKS(pRcmPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->RCM&0xFF;
+    cks += packet->RCM>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    cks += packet->RET&0xFF;
+    cks += packet->RET>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint16_t i = 0; i < packet->LEN-2; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+const DFRobot_ID809::sErrorDescription_t DFRobot_ID809::errorDescriptionsTable[]={
+  {eErrorSuccess, "Command processed successfully"},
+  {eErrorFail, "Command processing failed"},
+  {eErrorVerify, "1:1 comparison failed"},
+  {eErrorIdentify, "Comparison with all fingerprints failed"},
+  {eErrorTmplEmpty, "No fingerprint in designated ID"},
+  {eErrorTmplNotEmpty, "Designated ID has fingerprint"},
+  {eErrorAllTmplEmpty, "Module unregistered fingerprint"},
+  {eErrorEmptyIDNoexist, "No registerable ID here"},
+  {eErrorBrokenIDNoexist, "No broken fingerprint"},
+  {eErrorInvalidTmplData, "Invalid desingated fingerprint data"},
+  {eErrorDuplicationID, "The fingerprint has been registered"},
+  {eErrorBadQuality, "Poor quality fingerprint image"},
+  {eErrorMergeFail, "Fingerprint synthesis failed"},
+  {eErrorNotAuthorized, "Communication password not authorized"},
+  {eErrorMemory, "External Flash burning error"},
+  {eErrorInvalidTmplNo, "Invalid designated ID"},
+  {eErrorInvalidParam, "Incorrect parameter"},
+  {eErrorTimeOut, "Acquisition timeout"},
+  {eErrorGenCount, "Invalid number of fingerprint synthesis"},
+  {eErrorInvalidBufferID, "Incorrect Buffer ID value"},
+  {eErrorFPNotDetected, "No fingerprint input into fingerprint reader"},
+  {eErrorFPCancel, "Command cancelled"},
+  {eErrorRecvLength, "Wrong data length"},
+  {eErrorRecvCks, "Wrong data check code"},
+  {eErrorGatherOut, "Exceed upper limit of acquisition times"},
+  {eErrorRecvTimeout,"Data reading timeout"}
+};
+
+String DFRobot_ID809::getErrorDescription()
+{
+    for(int i=0;i<sizeof(errorDescriptionsTable)/sizeof(errorDescriptionsTable[0]);i++){
+        if(_error == errorDescriptionsTable[i].error){
+          return errorDescriptionsTable[i].description;
+        }
+    }
+    return "";
+}
+
+
diff --git a/matchFPandHash/lib/DFRobot_ID809/DFRobot_ID809.h b/matchFPandHash/lib/DFRobot_ID809/DFRobot_ID809.h
new file mode 100644
index 0000000..83ca50d
--- /dev/null
+++ b/matchFPandHash/lib/DFRobot_ID809/DFRobot_ID809.h
@@ -0,0 +1,504 @@
+/*!
+ * @file DFRobot_ID809.h
+ * @brief Define basic structure of DFRobot_ID809 class
+ * @n This is an library for capacitive fingerprint module
+ * @n Main functions: fingerprint image capturing, fingerprint comparison, fingerprint deletion
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#ifndef _DFRobot_ID809_H
+#define _DFRobot_ID809_H
+
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+#include "WProgram.h"
+#endif
+#include <Wire.h>
+
+#include <stdint.h>
+
+//Open this macro to see the detailed running process of the program 
+
+//#define ENABLE_DBG
+#ifdef ENABLE_DBG
+#define LDBG(...) if(dbg) {dbg->print("["); dbg->print(__FUNCTION__); dbg->print("(): "); dbg->print(__LINE__); dbg->print(" ] "); dbg->println(__VA_ARGS__);}
+#else
+#define LDBG(...)
+#endif
+
+extern Stream *dbg;
+
+  /*
+   Frame struct of command packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  CMD;
+  uint16_t  LEN;
+  uint8_t payload[0];
+}__attribute__ ((packed)) sCmdPacketHeader_t, *pCmdPacketHeader_t;
+
+  /*
+   Frame struct of response packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  RCM;
+  uint16_t  LEN;
+  uint16_t  RET;
+  uint8_t   payload[0];
+}__attribute__ ((packed)) sRcmPacketHeader_t, *pRcmPacketHeader_t;
+
+  
+
+
+class DFRobot_ID809{
+public: 
+
+//#define FINGERPRINT_CAPACITY     80      //Fingerprint module capacity
+#define MODULE_SN_SIZE           16      //Module SN length 
+
+
+#define DELALL                   0xFF    //Delete all fingerprints 
+
+#define CMD_PREFIX_CODE          0xAA55  //Command packet prefix code 
+#define RCM_PREFIX_CODE          0x55AA  //Response packet prefix code 
+#define CMD_DATA_PREFIX_CODE     0xA55A  //Command data packet prefix code 
+#define RCM_DATA_PREFIX_CODE     0x5AA5  //Response data packet prefix code 
+
+#define CMD_TYPE                 0xF0    //Command packet type 
+#define RCM_TYPE                 0xF0    //Response packet type 
+#define DATA_TYPE                0x0F    //Data packet type 
+
+#define CMD_TEST_CONNECTION      0X0001  //Test connection 
+#define CMD_SET_PARAM            0X0002  //Set parameter
+#define CMD_GET_PARAM            0X0003  //Read parameter 
+#define CMD_DEVICE_INFO          0X0004  //Read device information 
+#define CMD_SET_MODULE_SN        0X0008  //Set module serial number 
+#define CMD_GET_MODULE_SN        0X0009  //Read module serial number
+#define CMD_ENTER_STANDBY_STATE  0X000C  //Enter sleep mode 
+#define CMD_GET_IMAGE            0X0020  //Capture fingerprint image 
+#define CMD_FINGER_DETECT        0X0021  //Detect fingerprint 
+    #define CMD_UP_IMAGE_CODE        0X0022  //Upload fingerprint image to host 
+    #define CMD_DOWN_IMAGE           0X0023  //Download fingerprint image to module 
+#define CMD_SLED_CTRL            0X0024  //Control collector backlight 
+#define CMD_STORE_CHAR           0X0040  //Save fingerprint template data into fingerprint library 
+#define CMD_LOAD_CHAR            0X0041  //Read fingerprint in module and save it in RAMBUFFER temporarily  
+    #define CMD_UP_CHAR              0X0042  //Upload the fingerprint template saved in RAMBUFFER to host 
+    #define CMD_DOWN_CHAR            0X0043  //Download fingerprint template to module designated RAMBUFFER
+#define CMD_DEL_CHAR             0X0044  //Delete fingerprint in specific ID range 
+#define CMD_GET_EMPTY_ID         0X0045  //Get the first registerable ID in specific ID range 
+#define CMD_GET_STATUS           0X0046  //Check if the designated ID has been registered 
+#define CMD_GET_BROKEN_ID        0X0047  //Check whether there is damaged data in fingerprint library of specific range
+#define CMD_GET_ENROLL_COUNT     0X0048  //Get the number of registered fingerprints in specific ID range 
+#define CMD_GET_ENROLLED_ID_LIST 0X0049  //Get registered ID list
+#define CMD_GENERATE             0X0060  //Generate template from the fingerprint images saved in IMAGEBUFFER temporarily 
+#define CMD_MERGE                0X0061  //Synthesize fingerprint template data 
+#define CMD_MATCH                0X0062  //Compare templates in 2 designated RAMBUFFER 
+#define CMD_SEARCH               0X0063  //1:N Recognition in specific ID range 
+#define CMD_VERIFY               0X0064  //Compare specific RAMBUFFER template with specific ID template in fingerprint library 
+
+#define ERR_SUCCESS              0x00    //Command processed successfully 
+#define ERR_ID809                0xFF    //error 
+
+
+public:
+  
+  typedef enum{
+    eBreathing = 1,  //Breathing 
+    eFastBlink,      //Quick blink
+    eKeepsOn,        //On
+    eNormalClose,    //Off
+    eFadeIn,         //Fade in 
+    eFadeOut,        //Fade out
+    eSlowBlink       //Slow blink
+  }eLEDMode_t;
+  
+  typedef enum{
+    eLEDGreen = 1,   //green 
+    eLEDRed,         //red 
+    eLEDYellow,      //yellow
+    eLEDBlue,        //blue
+    eLEDCyan,        //cyan
+    eLEDMagenta,     //magenta
+    eLEDWhite        //white
+  }eLEDColor_t;
+   
+  typedef enum{
+    e9600bps = 1,
+    e19200bps,
+    e38400bps,
+    e57600bps,
+    e115200bps
+  }eDeviceBaudrate_t;
+  
+  typedef enum{
+    eErrorSuccess            = 0x00,    //Command processed successfully
+    eErrorFail               = 0x01,    //Command processing failed 
+    eErrorVerify             = 0x10,    //1:1 Templates comparison in specific ID failed 
+    eErrorIdentify           = 0x11,    //1:N comparison has been made, no same templates here 
+    eErrorTmplEmpty          = 0x12,    //No registered template in the designated ID 
+    eErrorTmplNotEmpty       = 0x13,    //Template already exists in the specified ID 
+    eErrorAllTmplEmpty       = 0x14,    //No registered Template 
+    eErrorEmptyIDNoexist     = 0x15,    //No registerable Template ID 
+    eErrorBrokenIDNoexist    = 0x16,    //No damaged Template 
+    eErrorInvalidTmplData    = 0x17,    //The designated Template Data is invalid 
+    eErrorDuplicationID      = 0x18,    //The fingerprint has been registered 
+    eErrorBadQuality         = 0x19,    //Poor quality fingerprint image 
+    eErrorMergeFail          = 0x1A,    //Template synthesis failed 
+    eErrorNotAuthorized      = 0x1B,    //Communication password not authorized 
+    eErrorMemory             = 0x1C,    //Error in exernal Flash burning 
+    eErrorInvalidTmplNo      = 0x1D,    //The designated template ID is invalid 
+    eErrorInvalidParam       = 0x22,    //Incorrect parameter has been used 
+    eErrorTimeOut            = 0x23,    //Acquisition timeout 
+    eErrorGenCount           = 0x25,    //Invalid number of fingerprint synthesis 
+    eErrorInvalidBufferID    = 0x26,    //Wrong Buffer ID value 
+    eErrorFPNotDetected      = 0x28,    //No fingerprint input into fingerprint reader 
+    eErrorFPCancel           = 0x41,    //Command cancelled 
+    eErrorRecvLength         = 0x42,    //Wrong length of recieved data 
+    eErrorRecvCks            = 0x43,    //Wrong check code 
+    eErrorGatherOut          = 0x45,    //Exceed upper limit of acquisition times 
+    eErrorRecvTimeout        = 0x46     //Communication timeout 
+  }eError_t;
+  
+  typedef struct{
+    /**< Gesture enumeration variable X */
+    eError_t error;
+    /**< Description about the gesture enumeration variable X */
+    const char * description;
+  }sErrorDescription_t;
+
+public:
+  DFRobot_ID809();
+  ~DFRobot_ID809();
+  
+  /**
+   * @brief Init communication port
+   * @param Software serial or hardware serial 
+   * @return true or false
+   */
+  bool begin(Stream &s_);
+  
+  /**
+   * @brief Test whether the module connection is ok
+   * @return true or false
+   */
+  bool isConnected();
+  
+  /**
+   * @brief Set module ID
+   * @param ID:1-255
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDeviceID(uint8_t deviceID);
+  
+  /**
+   * @brief Set module security level 
+   * @param security level:1-5
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSecurityLevel(uint8_t securityLevel);
+  
+  /**
+   * @brief Set module fingerprint replication check (Check whether the fingperint has been registered when saving it)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDuplicationCheck(uint8_t duplicationCheck);
+  
+  /**
+   * @brief Set module baud rate 
+   * @param Baudrate:in typedef enum eDeviceBaudrate_t
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setBaudrate(eDeviceBaudrate_t baudrate);
+  
+  /**
+   * @brief Set module self-learning function (Update fingeprint when fingerprint comparison succeeds)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSelfLearn(uint8_t selfLearn);
+  
+  /**
+   * @brief Read module ID
+   * @return ID号:1-255 or ERR_ID809
+   */
+  uint8_t getDeviceID();
+  
+  /**
+   * @brief Read module security level 
+   * @return Security level:1-5 or ERR_ID809
+   */
+  uint8_t getSecurityLevel();
+  
+  /**
+   * @brief Read module fingerprint replication check status
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getDuplicationCheck();
+  
+  /**
+   * @brief Read module baud rate 
+   * @return Baudrate:in typedef enum eDEVICE_BAUDRATE_t or ERR_ID809
+   */
+  uint8_t getBaudrate();
+  
+  /**
+   * @brief Read module self-learning function status 
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getSelfLearn();
+  uint8_t getTemplate(uint16_t id,uint8_t * temp);
+  uint8_t downLoadTemplate(uint16_t id,uint8_t * temp);
+  uint8_t getFingerImage(uint8_t *image);
+  uint8_t downLoadImage(uint16_t id,uint8_t * temp);
+  uint8_t receiveImageData(uint8_t *image);
+  uint8_t getQuarterFingerImage(uint8_t *image);
+  uint8_t contrastTemplate(uint8_t *temp);
+  /**
+   * @brief Read device number 
+   * @return Device number
+   */
+  String getDeviceInfo();
+  
+  /**
+   * @brief Set serial number
+   * @param String pointer 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setModuleSN(const char* SN);
+  /**
+   * @brief Read serial number 
+   * @return Serial number
+   */
+  String getModuleSN();
+  
+  /**
+   * @brief Set LED
+   * @param mode:in typedef enum eLEDMode_t
+   * @param color:in typedef enum eLEDColor_t
+   * @param blink Count: 00 represents blinking all the time
+   * @This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount);
+  
+  /**
+   * @brief Detect if there is finger touched 
+   * @return 1(Touched) or 0(No touch)
+   */
+  uint8_t detectFinger();
+  
+  /**
+   * @brief Get the first registerable ID 
+   * @return Registerable ID or ERR_ID809
+   */
+  uint8_t getEmptyID();
+  
+  /**
+   * @brief Check if the ID has been registered 
+   * @return 0(Registered), 1(Unregistered) or ERR_ID809
+   */
+  uint8_t getStatusID(uint8_t ID);
+  
+  /**
+   * @brief Get the number of registered users 
+   * @return Number of registered users or ERR_ID809
+   */
+  uint8_t getEnrollCount();
+  
+  /**
+   * @brief Get registered user list 
+   * @return 0(succeed) or ERR_ID809
+   */
+   uint8_t getEnrolledIDList(uint8_t* list);
+  
+  /**
+   * @brief Fingerprint acquisition 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t collectionFingerprint(uint16_t timeout,int ramNumber = -1);
+  
+  /**
+   * @brief Save fingerprint 
+   * @param Fingerprint ID
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t storeFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Delete fingerprint 
+   * @param Delete ID or DELALL(delete all)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t delFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Match the fingerprint with all fingeprints 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t search();
+
+  /**
+   * @brief Match the fingerprint with specific fingerprint 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t verify(uint8_t ID);
+
+  /**
+   * @brief Compare templates in two specific RamBuffers
+   * @param RamBuffer number 
+   * @param RamBuffer number 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t match(uint8_t RamBufferID0, uint8_t RamBufferID1);
+  
+  /**
+   * @brief Get the number of damaged fingerprints 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenQuantity();
+
+  /**
+   * @brief Get the first damaged fingerprint ID 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenID();
+  
+  /**
+   * @brief Take out fingerprint template, temporarily save into RamBuffer
+   * @param Fingerprint ID 
+   * @param RamBuffer number 0-2
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t loadFingerprint(uint8_t ID, uint8_t RamBufferID);
+  
+  /**
+   * @brief Enter Standby mode
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t enterStandbyState();
+  
+  /**
+   * @brief Get error information
+   * @return Text description of error information
+   */
+  String getErrorDescription();
+  
+  bool setDbgSerial(Stream &s_){dbg = &s_; return true;}
+    uint16_t FINGERPRINT_CAPACITY = 80;
+protected:
+   /**
+   * @brief Set parameter 
+   * @param Data type+ data
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setParam(uint8_t* data);
+  
+   /**
+   * @brief Read parameter 
+   * @param Data type 
+   * @return data or ERR_ID809
+   */
+  uint8_t getParam(uint8_t* data);
+  
+  /**
+   * @brief Capture fingerprint image 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t getImage();
+   
+   /**
+   * @brief Take image as template 
+   * @param Ram Buffer number
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t generate(uint8_t RamBufferID);
+  
+ /**
+   * @brief Fingerprint synthesis 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t merge();
+  
+ /**
+   * @brief Packing data frame 
+   * @param Data type:CMD_TYPE or DATA_TYPE
+   * @param Command
+   * @param Data 
+   * @param Length
+   * @return Data frame 
+   */
+  pCmdPacketHeader_t pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len);
+  
+ /**
+   * @brief Send data 
+   * @param Data frame
+   */
+  void sendPacket(pCmdPacketHeader_t header);
+  
+ /**
+   * @brief Read byte 
+   * @param Pointer for saving data 
+   * @param Length of data to be received 
+   * @return Actual received data length 
+   */
+  size_t readN(void* buf_, size_t len);
+  
+ /**
+   * @brief Read frame header 
+   * @param Frame header struct of response packet
+   * @return Response packet type:RCM_TYPE,DATA_TYPE or 1(reading timeout)
+   */
+  uint16_t readPrefix( pRcmPacketHeader_t header );
+  
+ /**
+   * @brief Read data
+   * @param Pointer for saving data 
+   * @return 0(success) or ERR_ID809
+   */
+  uint8_t responsePayload(void* buf);
+  
+ /**
+   * @brief Get command packet CKS
+   * @param Command packet frame 
+   * @return CKS
+   */
+  uint16_t getCmdCKS(pCmdPacketHeader_t packet);
+  
+ /**
+   * @brief Get response packet CKS
+   * @param Response packet frame 
+   * @return CKS
+   */
+  uint16_t getRcmCKS(pRcmPacketHeader_t packet);
+  uint8_t store(uint8_t ID);
+  
+private:
+  Stream *s;
+  uint8_t buf[20];     //For saving response packet data 
+  pCmdPacketHeader_t  sendHeader;
+  pRcmPacketHeader_t  recHeader;
+  
+  static const sErrorDescription_t /*PROGMEM*/ errorDescriptionsTable[26];   //Error information list 
+  
+  uint8_t _number = 0;       //Fingerprint acquisistion times 
+  uint8_t _state = 0;        //Collect fingerprint state
+  eError_t _error;           //Error code 
+  uint16_t _PacketSize = 0;  //Data packet length to be sent 
+};
+
+#endif
+
diff --git a/matchFPandHash/platformio.ini b/matchFPandHash/platformio.ini
new file mode 100644
index 0000000..7a3aa31
--- /dev/null
+++ b/matchFPandHash/platformio.ini
@@ -0,0 +1,13 @@
+[env:Teensy_FP]
+
+platform = teensy
+framework = arduino
+board = teensy31
+
+build_flags = 
+	-I lib/DFRobot_ID809
+
+lib_deps = 
+	intrbiz/crypto
+
+
diff --git a/matchFPandHash/src/src.cpp b/matchFPandHash/src/src.cpp
new file mode 100644
index 0000000..7afea72
--- /dev/null
+++ b/matchFPandHash/src/src.cpp
@@ -0,0 +1,178 @@
+#include <Arduino.h>
+#include <Crypto.h>
+#include <DFRobot_ID809.h>
+#include <EEPROM.h>
+
+// use serial3 as interface with fingerprint
+// sensor.
+
+#define FPSerial Serial3
+
+// define buillt_in led
+
+#define BUILTIN_LED 13
+
+// Collect the fingerprint 3 times
+
+#define COLLECT_NUMBER 3
+
+/*------Global variables--------------*/
+
+DFRobot_ID809 fingerprint;
+uint8_t ID, i, ret;
+byte hash[SHA256_SIZE];
+uint8_t temp[1008];
+// EEPROM OFFSET to store
+
+const uint16_t EEPROM_FP_HASH = 1696;
+
+/*---------Compute hash----------------*/
+
+void compute_hash() {
+
+  SHA256 hasher;
+  hasher.doUpdate(temp, sizeof(temp));
+  hasher.doFinal(hash);
+
+  Serial.println("-----------------------");
+  for (uint8_t i = 0; i < SHA256_SIZE; i++) {
+
+    if (hash[i] < 0x10) {
+
+      Serial.print('0');
+    }
+
+    Serial.print(hash[i], HEX);
+    Serial.print(" ");
+  }
+  Serial.println("-----------------------");
+}
+
+/*-----Blink on board led -------------- */
+
+void blink_led() {
+  digitalWrite(BUILTIN_LED, HIGH);
+  delay(500);
+  digitalWrite(BUILTIN_LED, LOW);
+  delay(500);
+}
+
+/*-------- Save FingerPrint hash in EEPROM ------*/
+
+void compareHash() {
+  uint16_t memoryAddress;
+  byte stored_hash[SHA256_SIZE];
+
+  memoryAddress = EEPROM_FP_HASH + ((ID - 1) * 32);
+
+  Serial.println("---------------------------");
+  for (uint8_t i = 0; i < SHA256_SIZE; i++) {
+
+    stored_hash[i] = EEPROM.read(memoryAddress);
+    Serial.print(stored_hash[i], HEX);
+    Serial.print(" ");
+    memoryAddress++;
+  }
+  Serial.println("--------------------------");
+
+  for (uint8_t i = 0; i < SHA256_SIZE; i++) {
+
+    if (stored_hash[i] != hash[i]) {
+      Serial.println("Hash not matched");
+      return;
+    }
+  }
+  Serial.println("Hash matched");
+}
+
+/*---------Arduino setup function------*/
+
+void setup() {
+  // config led_pin as output
+  pinMode(BUILTIN_LED, OUTPUT);
+  // use serial port to print the baud rate
+  Serial.begin(9600);
+  // config fingerprint sensor
+  FPSerial.begin(115200);
+  fingerprint.begin(FPSerial);
+
+  while (fingerprint.isConnected() == false) {
+    Serial.println("Communication with the device failed");
+    delay(1000);
+  }
+}
+
+/*---------Register Finger print ------------*/
+
+void matchFingerprint() {
+
+  /*Set fingerprint LED ring mode, color, and number of blinks
+    Can be set as follows:
+    Parameter 1:<LEDMode>
+    eBreathing   eFastBlink   eKeepsOn    eNormalClose
+    eFadeIn      eFadeOut     eSlowBlink
+    Parameter 2:<LEDColor>
+    eLEDGreen  eLEDRed      eLEDYellow   eLEDBlue
+    eLEDCyan   eLEDMagenta  eLEDWhite
+    Parameter 3:<Number of blinks> 0 represents blinking all the time
+    This parameter will only be valid in mode eBreathing, eFastBlink,
+    eSlowBlink
+   */
+  fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eBreathing,
+                      /*LEDColor = */ fingerprint.eLEDBlue,
+                      /*blinkCount = */ 0);
+
+  Serial.println("Plase press down your finger");
+
+  if ((fingerprint.collectionFingerprint(/*timeout = */ 0)) != ERR_ID809) {
+    /*Set fingerprint LED ring to quick blink in yellow 3 times */
+    fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eFastBlink,
+                        /*LEDColor = */ fingerprint.eLEDYellow,
+                        /*blinkCount = */ 3);
+    Serial.println("capturing succeeds");
+    Serial.println("Please release your finger");
+
+    while (fingerprint.detectFinger())
+      ;
+
+    /*Compare the captured fingerprint with all the fingerprints
+     * inthe fingerprint library return fingerprint ID if succeed,
+     * return 0 when failed
+     * */
+    ret = fingerprint.search();
+
+    if (ret != 0) {
+
+      /*Set fingerprint LED ring to always ON in green */
+      fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eKeepsOn,
+                          /*LEDColor = */ fingerprint.eLEDGreen,
+                          /*blinkCount = */ 0);
+      Serial.print("Matching succeeds,ID=");
+      ID = ret;
+      Serial.println(ret);
+      fingerprint.getTemplate(ID, temp);
+      delay(100);
+      compute_hash();
+      compareHash();
+
+    } else {
+      /*Set fingerprint LED ring to always ON in red*/
+      fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eKeepsOn,
+                          /*LEDColor = */ fingerprint.eLEDRed,
+                          /*blinkCount = */ 0);
+      Serial.println("Matching fails");
+    }
+  } else {
+    Serial.println("Capturing failes");
+    /*Get error code information*/
+    // desc = fingerprint.getErrorDescription();
+    // Serial.println(desc);
+  }
+}
+
+/*-----------Arduino loop function--------- */
+
+void loop() {
+  blink_led();
+  matchFingerprint();
+}
diff --git a/readTemplate/lib/DFRobot_ID809/DFRobot_ID809.cpp b/readTemplate/lib/DFRobot_ID809/DFRobot_ID809.cpp
new file mode 100644
index 0000000..d49f6f4
--- /dev/null
+++ b/readTemplate/lib/DFRobot_ID809/DFRobot_ID809.cpp
@@ -0,0 +1,1089 @@
+/*!
+ * @file DFRobot_ID809.cpp
+ * @brief Define the basic structure of DFRobot_ID809 class and the implementation of underlying methods 
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#include <DFRobot_ID809.h>
+#include <Arduino.h>
+#include <string.h>
+#include <stdio.h>
+Stream *dbg=NULL;
+
+DFRobot_ID809::DFRobot_ID809()
+  :s(NULL){
+        
+}
+
+DFRobot_ID809::~DFRobot_ID809(){
+        
+}
+
+bool DFRobot_ID809::begin(Stream &s_){
+    s = &s_;
+	String str = getDeviceInfo();
+  //Serial.println(str[str.length()-1]);
+  if(str[str.length()-1] == '4'){
+	    
+	   FINGERPRINT_CAPACITY   =    80 ;
+	  
+	  //Serial.println(str[str.length()-1]);
+  }else if(str[str.length()-1] == '3'){
+	  //Serial.println(str[str.length()-1]);
+	   FINGERPRINT_CAPACITY  =   200 ;
+	  
+  }
+	
+    if(s == NULL){
+        return false;
+    }
+    return true;
+}
+
+bool DFRobot_ID809::isConnected(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_TEST_CONNECTION, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        return true;
+    }else{
+        return false;
+    }
+}
+
+uint8_t DFRobot_ID809::setDeviceID(uint8_t deviceID){
+    uint8_t data[5] = {0};    //data:1bytes Parameter Type+4bytes Parameter Value
+    data[1] = deviceID;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSecurityLevel(uint8_t securityLevel){
+    uint8_t data[5] = {0};
+    data[0] = 1;
+    data[1] = securityLevel;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setDuplicationCheck(uint8_t duplicationCheck){
+    uint8_t data[5] = {0};
+    data[0] = 2;
+    data[1] = duplicationCheck;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setBaudrate(eDeviceBaudrate_t baudrate){
+    uint8_t data[5] = {0};
+    data[0] = 3;
+    data[1] = baudrate;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setSelfLearn(uint8_t selfLearn){
+    uint8_t data[5] = {0};
+    data[0] = 4;
+    data[1] = selfLearn;
+    uint8_t ret = setParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDeviceID(){
+    uint8_t data[1];  //data:1byte Parameter Type
+    data[0] = 0;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSecurityLevel(){
+    uint8_t data[1];
+    data[0] = 1;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getDuplicationCheck(){
+    uint8_t data[1];
+    data[0] = 2;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBaudrate(){
+    uint8_t data[1];
+    data[0] = 3;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getSelfLearn(){
+    uint8_t data[1];
+    data[0] = 4;
+    uint8_t ret = getParam(data);
+    return ret;
+}
+
+String DFRobot_ID809::getDeviceInfo(){
+    char *data;
+    uint8_t result;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEVICE_INFO, NULL, 0);
+    sendPacket(header);
+    free(header);
+    result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setModuleSN(const char* SN){
+    char data[2];
+    data[0] = MODULE_SN_SIZE;
+    if(strlen(SN) > MODULE_SN_SIZE){
+        LDBG("The serial number exceeds 15 characters");
+        return ERR_ID809;
+    }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_MODULE_SN, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    header = pack(DATA_TYPE, CMD_SET_MODULE_SN, SN, MODULE_SN_SIZE);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getTemplate(uint16_t id,uint8_t * temp){
+  char data[4];
+  data[0] = id;
+  data[1] = 0;
+  data[2] = 0;
+  data[3] = 0;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  data[0] = 0;
+  data[1] = 0;
+  header = pack(CMD_TYPE, CMD_UP_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  ret = responsePayload(temp);
+
+  return ret;
+}
+
+uint8_t DFRobot_ID809::downLoadTemplate(uint16_t id,uint8_t * temp){
+
+  char data[4];
+  data[0] = 0xf2;
+  data[1] = 3;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(0x3f2 +1);
+  tempData[0] = 0;
+  tempData[1] = 0;
+  memcpy(tempData+2,temp,0x3f0);
+  
+
+  header = pack(DATA_TYPE, CMD_DOWN_CHAR, tempData, 0x3f2);
+
+  sendPacket(header);
+
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  free(tempData);
+  
+
+  return store(id);
+}
+
+uint8_t DFRobot_ID809::contrastTemplate(uint8_t *temp){
+
+  char data[4];
+  data[0] = 0xf2;
+  data[1] = 3;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_CHAR, data, 2);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(0x3f2 +1);
+  tempData[0] = 2;
+  tempData[1] = 0;
+  memcpy(tempData+2,temp,0x3f0);
+  
+
+  header = pack(DATA_TYPE, CMD_DOWN_CHAR, tempData, 0x3f2);
+
+  sendPacket(header);
+
+  free(header);
+  
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret == ERR_SUCCESS) {
+    ret = buf[0];
+  }
+  free(tempData);
+  data[0] = 0;
+  data[1] = 0;
+  data[2] = 2;
+  data[3] = 0;
+  header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ret;
+  }
+  return ret;
+
+}
+uint8_t DFRobot_ID809::getFingerImage(uint8_t *image)
+{
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  
+  char data[1];
+  data[0] = 0;
+  header = pack(CMD_TYPE, CMD_UP_IMAGE_CODE, data, 1);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500 +1);
+  for(uint8_t i=0;i<52;i++){
+
+     ret = responsePayload(tempData);
+     if(i == 51)
+       memcpy(image+i*496,tempData+2,304);
+     else
+       memcpy(image+i*496,tempData+2,496);
+  }
+  free(tempData);
+}
+uint8_t DFRobot_ID809::getQuarterFingerImage(uint8_t *image){
+
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  
+  char data[1];
+  data[0] = 1;
+  header = pack(CMD_TYPE, CMD_UP_IMAGE_CODE, data, 1);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500 +1);
+  for(uint8_t i=0;i<13;i++){
+
+     ret = responsePayload(tempData);
+     if(i == 12)
+       memcpy(image+i*496,tempData+2,448);
+     else
+       memcpy(image+i*496,tempData+2,496);
+  }
+  free(tempData);
+
+}
+uint8_t DFRobot_ID809::downLoadImage(uint16_t id,uint8_t * temp)
+{
+  char data[4];
+  data[0] = 0xa0;
+  data[1] = 0;
+  data[2] = 0xa0;
+  data[3] = 0;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DOWN_IMAGE, data, 4);
+  sendPacket(header);
+  free(header);
+
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+  char *tempData= (char *)malloc(500);
+  for(uint8_t i =0 ;i<52;i++){
+     tempData[0] = i;
+	 tempData[1] = 0;
+     if(i == 51){
+       memcpy(tempData+2,temp+i*496,304);
+       header = pack(DATA_TYPE, CMD_DOWN_IMAGE, tempData, 306);
+	 }else{
+       memcpy(tempData+2,temp+i*496,496);
+       header = pack(DATA_TYPE, CMD_DOWN_IMAGE, tempData, 498);
+     }
+     sendPacket(header);
+     
+     free(header);
+     
+     ret = responsePayload(buf);
+     LDBG("ret=");
+     LDBG(ret);
+     if(ret != ERR_SUCCESS) {
+       return ERR_ID809;
+     }
+     
+  }  
+  free(tempData);
+  
+  data[0] = 0;
+  data[1] = 0;
+  header = pack(CMD_TYPE, CMD_GENERATE, data, 2);
+  sendPacket(header);
+  free(header);
+
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  if(ret != ERR_SUCCESS) {
+   // return ERR_ID809;
+  }
+  return store(id);
+
+}
+
+uint8_t DFRobot_ID809::receiveImageData(uint8_t * image){
+
+
+
+  uint8_t ret = responsePayload(image);
+  if(ret != ERR_SUCCESS) {
+    return ERR_ID809;
+  }
+
+}
+String DFRobot_ID809::getModuleSN(){
+    char *data;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_MODULE_SN, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t result = responsePayload(buf);
+    LDBG("result=");LDBG(result);
+    if(result != ERR_SUCCESS){
+        return "";
+    }
+    uint16_t dataLen = buf[0]+(buf[1]<<8)+1;
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    data[dataLen] = 0;
+    result = responsePayload(data);
+    LDBG("result=");LDBG(result);
+    String ret = String(data);
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount){
+    char data[4] = {0};
+  if(FINGERPRINT_CAPACITY == 80){
+    data[0] = mode;
+    data[2] = data[1] = color;
+    data[3] = blinkCount;
+  }else{
+	if(mode == 1){
+	  data[0] = 2;
+	} else if(mode == 2){
+		data[0] = 4;
+	} else if(mode == 3){
+	    data[0] = 1;
+	} else if(mode == 4){
+		data[0] = 0;
+	} else if(mode == 5){
+		data[0] = 3;
+	}
+	if(color == eLEDGreen){
+          data[2] = data[1] =  0x84;
+        }else if(color == eLEDRed){
+	  data[2] = data[1] = 0x82;
+	}else if(color == eLEDYellow){
+	  data[2] = data[1] = 0x86;
+	}else if(color == eLEDBlue){
+	  data[2] = data[1] = 0x81;
+	}else if(color == eLEDCyan){
+	  data[2] = data[1] = 0x85;
+	}else if(color == eLEDMagenta){
+	  data[2] = data[1] = 0x83;
+	}else {
+	  data[2] = data[1] = 0x87;
+	}
+  }
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SLED_CTRL, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::detectFinger(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_FINGER_DETECT, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEmptyID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;     //80 fingerprints at most, default to full range 
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_EMPTY_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getStatusID(uint8_t ID){
+    char data[2] = {0};
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_STATUS, data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getEnrollCount(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLL_COUNT, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+#define  getID(A, V)  (A[0 + V/8] & (0x01 << (V & 0x07)))
+uint8_t DFRobot_ID809::getEnrolledIDList(uint8_t* list)
+{
+    char *data;
+    uint8_t i = 0;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_ENROLLED_ID_LIST, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    uint16_t dataLen = buf[0]+(buf[1]<<8);
+    if((data = (char *)malloc(dataLen)) == NULL){
+        LDBG("no memory!!!\r\n");
+        while(1);
+    }
+    ret = responsePayload(data);
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else{
+        for(uint16_t j = 0; j < (dataLen*8); j++){
+            if(getID(data, j) != 0){
+                list[i] = j;
+                i++;
+            }
+        }
+    }
+    free(data);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::storeFingerprint(uint8_t ID){
+    char data[4] = {0};
+    uint8_t ret;
+    ret = merge();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        return ERR_ID809;
+    }
+    _number = 0;
+    data[0] = ID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+    
+}
+uint8_t DFRobot_ID809::store(uint8_t ID){
+
+
+  char data[4] = {0};
+  uint8_t ret;
+  LDBG("ret=");
+  LDBG(ret);
+  data[0] = ID;
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_STORE_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  return ret;
+}
+uint8_t DFRobot_ID809::delFingerprint(uint8_t ID)
+{
+  char data[4] = {0};
+  if(ID == DELALL) {
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+  } else {
+    data[0] = data[2] = ID;
+  }
+  pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_DEL_CHAR, data, 4);
+  sendPacket(header);
+  free(header);
+  uint8_t ret = responsePayload(buf);
+  LDBG("ret=");
+  LDBG(ret);
+  return ret;
+}
+
+uint8_t DFRobot_ID809::search(){
+    if(_state == 1){
+        char data[6] = {0};
+        data[2] = 1;
+        data[4] = FINGERPRINT_CAPACITY;
+        _number = 0;
+        pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SEARCH, data, 6);
+        sendPacket(header);
+        free(header);
+        uint8_t ret = responsePayload(buf);
+        LDBG("ret=");LDBG(ret);
+        if(ret == ERR_SUCCESS){
+            ret = buf[0];
+        }else{
+            ret = 0;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+uint8_t DFRobot_ID809::verify(uint8_t ID){
+    if(_state == 1){
+        char data[4] = {0};
+        data[0] = ID;
+        _number = 0;
+        pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_VERIFY, data, 4);
+        sendPacket(header);
+        free(header);
+        uint8_t ret = responsePayload(buf);
+        LDBG("ret=");LDBG(ret);
+        if(ret == ERR_SUCCESS){
+            ret = buf[0];
+        }else{
+            ret = 0;
+        }
+        return ret;
+    }
+    return 0;
+}
+
+uint8_t DFRobot_ID809::match(uint8_t RamBufferID0, uint8_t RamBufferID1){
+    char data[4] = {0};
+    data[0] = RamBufferID0;
+    data[2] = RamBufferID1;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MATCH, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }else{
+        ret = 0;
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenQuantity(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getBrokenID(){
+    char data[4] = {0};
+    data[0] = 1;
+    data[2] = FINGERPRINT_CAPACITY;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_BROKEN_ID, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[2];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::loadFingerprint(uint8_t ID, uint8_t RamBufferID){
+    char data[4] = {0};
+    data[0] = ID;
+    data[2] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_LOAD_CHAR, data, 4);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::enterStandbyState(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_ENTER_STANDBY_STATE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::setParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_SET_PARAM, (const char *)data, 5);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getParam(uint8_t* data){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_PARAM, (const char *)data, 1);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    if(ret == ERR_SUCCESS){
+        ret = buf[0];
+    }
+    return ret;
+}
+
+uint8_t DFRobot_ID809::getImage(){
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GET_IMAGE, NULL, 0);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::collectionFingerprint(uint16_t timeout,int ramNumber){  //Collect fingerprint 
+    uint16_t i = 0;
+    uint8_t ret;
+   if(ramNumber == -1){
+     if(_number > 2){
+         _error = eErrorGatherOut;
+         LDBG("Exceed upper limit of acquisition times ");
+         return ERR_ID809;
+     }
+   }
+    while(!detectFinger()){
+        if(timeout != 0){
+            delay(10);
+            if(++i > timeout*10){
+                _error = eErrorTimeOut;
+                LDBG("Acquisition timeout ");
+                LDBG("ret=");LDBG(ret);
+                _state = 0;
+                return ERR_ID809;
+            }
+       }
+    }
+    ret = getImage();
+    LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        _state = 0;
+        return ERR_ID809;
+    }
+   if(ramNumber != -1){
+     ret = generate(ramNumber);
+   } else{
+     ret = generate(_number);
+   }
+	LDBG("ret=");LDBG(ret);
+    if(ret != ERR_SUCCESS){
+        _state = 0;
+        return ERR_ID809;
+    }
+    _number++;
+    _state = 1;
+    return ret;
+}
+
+uint8_t DFRobot_ID809::generate(uint8_t RamBufferID){
+    char data[2] = {0};
+    data[0] = RamBufferID;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_GENERATE, (const char *)data, 2);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+uint8_t DFRobot_ID809::merge(){
+    char data[3] = {0};
+    data[2] = _number;
+    pCmdPacketHeader_t header = pack(CMD_TYPE, CMD_MERGE, data, 3);
+    sendPacket(header);
+    free(header);
+    uint8_t ret = responsePayload(buf);
+    LDBG("ret=");LDBG(ret);
+    return ret;
+}
+
+pCmdPacketHeader_t DFRobot_ID809::pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len){
+    pCmdPacketHeader_t header;
+    uint16_t cks=0;
+    uint16_t dataLen;
+    if(type == CMD_TYPE){    //Structure of command packet, fixed 26 bytes:10(frame header)+14(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+16+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_PREFIX_CODE;
+        for(int i=0;i<16;i++){
+            header->payload[i] = 0;
+        }
+        dataLen = 16;   //Length of data to be replicated 
+    }else{                   //Structure of command data packet, unfixed length:10(frame header)+LEN(data)+2(CKS)
+        if((header = (pCmdPacketHeader_t)malloc(sizeof(sCmdPacketHeader_t)+len+2)) == NULL){
+            return NULL;
+        }
+        header->PREFIX = CMD_DATA_PREFIX_CODE;
+        dataLen = len;   //Length of data to be replicated 
+    }
+    header->SID = 0;
+    header->DID = 0;
+    header->CMD = cmd;
+    header->LEN = len;
+    if(len){
+        memcpy(header->payload, payload, len);
+    }
+    cks = getCmdCKS(header);
+    memcpy(&header->payload[dataLen],&cks,2);
+    _PacketSize = sizeof(sCmdPacketHeader_t) + dataLen +2;
+    return header;
+}
+
+
+void DFRobot_ID809::sendPacket(pCmdPacketHeader_t header){
+    s->write((uint8_t *)header,_PacketSize);
+}
+
+uint8_t DFRobot_ID809::responsePayload(void* buf){
+    sRcmPacketHeader_t header;
+    uint16_t dataLen,dataCount,cks;
+    uint8_t ch,ret;
+    int16_t type;
+    type = readPrefix(&header);
+    if(type == 1){
+        LDBG("--recv timeout---");
+        _error = eErrorRecvTimeout;
+        return ERR_ID809;
+    }
+    pRcmPacketHeader_t packet;
+    if(type == RCM_TYPE){    //Structure of response packet, fixed 26 bytes: 10(frame header)+14(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+14+2);
+        dataLen = 14+2;      //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }else{                   //Structure of response data packet, unfixed length: 10(frame header)+(LEN-2)(data)+2(CKS)
+        packet = (pRcmPacketHeader_t)malloc(sizeof(sRcmPacketHeader_t)+header.LEN);
+        dataLen = header.LEN;  //Length of data+CKS
+        if(packet == NULL){
+            LDBG("");
+            while(1);
+        }
+    }
+    memcpy(packet, &header, 10);
+    dataCount = readN(packet->payload, dataLen);
+    cks = packet->payload[dataLen-2]+(packet->payload[dataLen-1]<<8);
+    ret = (header.RET&0xFF);
+    _error = (eError_t)ret;
+    if(ret != ERR_SUCCESS){
+        ret = ERR_ID809;
+    }else if(dataLen != dataCount){
+        LDBG("--recvRspPacket length error---");
+        _error = eErrorRecvLength;
+        ret = ERR_ID809;
+    }else if(getRcmCKS(packet) != cks){
+        LDBG("--recvRspPacket cks error---");
+        _error = eErrorRecvCks;
+        ret = ERR_ID809;
+    }else{
+        LDBG("--recvRspPacket OK---");
+        memcpy(buf, packet->payload, dataLen);
+    }
+    free(packet);
+    packet = NULL;
+    return ret;
+}
+
+uint16_t DFRobot_ID809::readPrefix( pRcmPacketHeader_t header ){
+    uint8_t ch,ret;
+    typedef enum{
+        RECV_HEADER_INIT,
+        RECV_HEADER_AA,
+        RECV_HEADER_A5,
+        RECV_HEADER_OK
+    }eRecvHeaderState;
+    eRecvHeaderState state = RECV_HEADER_INIT;
+    while(state != RECV_HEADER_OK){   //Can judge the received command packet and command data packet prefix at the same time 
+        if(readN(&ch, 1) != 1){
+            ret = 1;
+            return ret;
+        }
+        if((ch == 0xAA) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_AA;
+            continue;
+        }else if((ch == 0xA5) && (state == RECV_HEADER_INIT)){
+            state = RECV_HEADER_A5;
+            continue;
+        }else if((ch == 0x55) && (state == RECV_HEADER_AA)){
+            state = RECV_HEADER_OK;
+            ret = RCM_TYPE;
+            continue;
+        }else if((ch == 0x5A) && (state == RECV_HEADER_A5)){
+            state = RECV_HEADER_OK;
+            ret = DATA_TYPE;
+            continue;
+        }else{
+            state = RECV_HEADER_INIT;
+            if(ch == 0xAA){
+                state = RECV_HEADER_AA;
+            }else if(ch == 0xA5){
+                state = RECV_HEADER_A5;
+            }
+        }
+    }
+    if(ret == RCM_TYPE){
+        header->PREFIX = RCM_PREFIX_CODE;
+    }else if(ret == DATA_TYPE){
+        header->PREFIX = RCM_DATA_PREFIX_CODE;
+    }
+    readN(&header->SID, 1);
+    readN(&header->DID, 1);
+    readN(&header->RCM, 2);
+    readN(&header->LEN, 2);
+    readN(&header->RET, 2);
+    return ret;
+}
+
+size_t DFRobot_ID809::readN(void* buffer, size_t len){
+    size_t offset = 0,left = len;
+    uint8_t *buf = (uint8_t*)buffer;
+    long long curr = millis();
+    while(left){
+        if(s->available()){
+            buf[offset++] = s->read();
+            left--;
+        }
+        if(millis() - curr > 5000){
+            LDBG("----------!!!!!!!!!recv timeout----------");
+            break;
+        }
+    }
+    return offset;
+}
+
+uint16_t DFRobot_ID809::getCmdCKS(pCmdPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->CMD&0xFF;
+    cks += packet->CMD>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint16_t i = 0; i < packet->LEN; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+uint16_t DFRobot_ID809::getRcmCKS(pRcmPacketHeader_t packet){
+    uint16_t cks = 0xFF;
+    cks += packet->SID;
+    cks += packet->DID;
+    cks += packet->RCM&0xFF;
+    cks += packet->RCM>>8;
+    cks += packet->LEN&0xFF;
+    cks += packet->LEN>>8;
+    cks += packet->RET&0xFF;
+    cks += packet->RET>>8;
+    if(packet->LEN > 0){
+        uint8_t *p = packet->payload;
+        for(uint16_t i = 0; i < packet->LEN-2; i++){
+            cks += p[i];
+        }
+    }
+    return cks&0xFFFF;
+}
+
+const DFRobot_ID809::sErrorDescription_t DFRobot_ID809::errorDescriptionsTable[]={
+  {eErrorSuccess, "Command processed successfully"},
+  {eErrorFail, "Command processing failed"},
+  {eErrorVerify, "1:1 comparison failed"},
+  {eErrorIdentify, "Comparison with all fingerprints failed"},
+  {eErrorTmplEmpty, "No fingerprint in designated ID"},
+  {eErrorTmplNotEmpty, "Designated ID has fingerprint"},
+  {eErrorAllTmplEmpty, "Module unregistered fingerprint"},
+  {eErrorEmptyIDNoexist, "No registerable ID here"},
+  {eErrorBrokenIDNoexist, "No broken fingerprint"},
+  {eErrorInvalidTmplData, "Invalid desingated fingerprint data"},
+  {eErrorDuplicationID, "The fingerprint has been registered"},
+  {eErrorBadQuality, "Poor quality fingerprint image"},
+  {eErrorMergeFail, "Fingerprint synthesis failed"},
+  {eErrorNotAuthorized, "Communication password not authorized"},
+  {eErrorMemory, "External Flash burning error"},
+  {eErrorInvalidTmplNo, "Invalid designated ID"},
+  {eErrorInvalidParam, "Incorrect parameter"},
+  {eErrorTimeOut, "Acquisition timeout"},
+  {eErrorGenCount, "Invalid number of fingerprint synthesis"},
+  {eErrorInvalidBufferID, "Incorrect Buffer ID value"},
+  {eErrorFPNotDetected, "No fingerprint input into fingerprint reader"},
+  {eErrorFPCancel, "Command cancelled"},
+  {eErrorRecvLength, "Wrong data length"},
+  {eErrorRecvCks, "Wrong data check code"},
+  {eErrorGatherOut, "Exceed upper limit of acquisition times"},
+  {eErrorRecvTimeout,"Data reading timeout"}
+};
+
+String DFRobot_ID809::getErrorDescription()
+{
+    for(int i=0;i<sizeof(errorDescriptionsTable)/sizeof(errorDescriptionsTable[0]);i++){
+        if(_error == errorDescriptionsTable[i].error){
+          return errorDescriptionsTable[i].description;
+        }
+    }
+    return "";
+}
+
+
diff --git a/readTemplate/lib/DFRobot_ID809/DFRobot_ID809.h b/readTemplate/lib/DFRobot_ID809/DFRobot_ID809.h
new file mode 100644
index 0000000..83ca50d
--- /dev/null
+++ b/readTemplate/lib/DFRobot_ID809/DFRobot_ID809.h
@@ -0,0 +1,504 @@
+/*!
+ * @file DFRobot_ID809.h
+ * @brief Define basic structure of DFRobot_ID809 class
+ * @n This is an library for capacitive fingerprint module
+ * @n Main functions: fingerprint image capturing, fingerprint comparison, fingerprint deletion
+ * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
+ * @licence     The MIT License (MIT)
+ * @author [Eddard](eddard.liu@dfrobot.com)
+ * @version  V1.0
+ * @date  2020-03-19
+ * @get from https://www.dfrobot.com
+ * @url https://github.com/cdjq/DFRobot_ID809
+ */
+
+#ifndef _DFRobot_ID809_H
+#define _DFRobot_ID809_H
+
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+#include "WProgram.h"
+#endif
+#include <Wire.h>
+
+#include <stdint.h>
+
+//Open this macro to see the detailed running process of the program 
+
+//#define ENABLE_DBG
+#ifdef ENABLE_DBG
+#define LDBG(...) if(dbg) {dbg->print("["); dbg->print(__FUNCTION__); dbg->print("(): "); dbg->print(__LINE__); dbg->print(" ] "); dbg->println(__VA_ARGS__);}
+#else
+#define LDBG(...)
+#endif
+
+extern Stream *dbg;
+
+  /*
+   Frame struct of command packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  CMD;
+  uint16_t  LEN;
+  uint8_t payload[0];
+}__attribute__ ((packed)) sCmdPacketHeader_t, *pCmdPacketHeader_t;
+
+  /*
+   Frame struct of response packet 
+  */
+typedef struct{
+  uint16_t  PREFIX;
+  uint8_t   SID;
+  uint8_t   DID;
+  uint16_t  RCM;
+  uint16_t  LEN;
+  uint16_t  RET;
+  uint8_t   payload[0];
+}__attribute__ ((packed)) sRcmPacketHeader_t, *pRcmPacketHeader_t;
+
+  
+
+
+class DFRobot_ID809{
+public: 
+
+//#define FINGERPRINT_CAPACITY     80      //Fingerprint module capacity
+#define MODULE_SN_SIZE           16      //Module SN length 
+
+
+#define DELALL                   0xFF    //Delete all fingerprints 
+
+#define CMD_PREFIX_CODE          0xAA55  //Command packet prefix code 
+#define RCM_PREFIX_CODE          0x55AA  //Response packet prefix code 
+#define CMD_DATA_PREFIX_CODE     0xA55A  //Command data packet prefix code 
+#define RCM_DATA_PREFIX_CODE     0x5AA5  //Response data packet prefix code 
+
+#define CMD_TYPE                 0xF0    //Command packet type 
+#define RCM_TYPE                 0xF0    //Response packet type 
+#define DATA_TYPE                0x0F    //Data packet type 
+
+#define CMD_TEST_CONNECTION      0X0001  //Test connection 
+#define CMD_SET_PARAM            0X0002  //Set parameter
+#define CMD_GET_PARAM            0X0003  //Read parameter 
+#define CMD_DEVICE_INFO          0X0004  //Read device information 
+#define CMD_SET_MODULE_SN        0X0008  //Set module serial number 
+#define CMD_GET_MODULE_SN        0X0009  //Read module serial number
+#define CMD_ENTER_STANDBY_STATE  0X000C  //Enter sleep mode 
+#define CMD_GET_IMAGE            0X0020  //Capture fingerprint image 
+#define CMD_FINGER_DETECT        0X0021  //Detect fingerprint 
+    #define CMD_UP_IMAGE_CODE        0X0022  //Upload fingerprint image to host 
+    #define CMD_DOWN_IMAGE           0X0023  //Download fingerprint image to module 
+#define CMD_SLED_CTRL            0X0024  //Control collector backlight 
+#define CMD_STORE_CHAR           0X0040  //Save fingerprint template data into fingerprint library 
+#define CMD_LOAD_CHAR            0X0041  //Read fingerprint in module and save it in RAMBUFFER temporarily  
+    #define CMD_UP_CHAR              0X0042  //Upload the fingerprint template saved in RAMBUFFER to host 
+    #define CMD_DOWN_CHAR            0X0043  //Download fingerprint template to module designated RAMBUFFER
+#define CMD_DEL_CHAR             0X0044  //Delete fingerprint in specific ID range 
+#define CMD_GET_EMPTY_ID         0X0045  //Get the first registerable ID in specific ID range 
+#define CMD_GET_STATUS           0X0046  //Check if the designated ID has been registered 
+#define CMD_GET_BROKEN_ID        0X0047  //Check whether there is damaged data in fingerprint library of specific range
+#define CMD_GET_ENROLL_COUNT     0X0048  //Get the number of registered fingerprints in specific ID range 
+#define CMD_GET_ENROLLED_ID_LIST 0X0049  //Get registered ID list
+#define CMD_GENERATE             0X0060  //Generate template from the fingerprint images saved in IMAGEBUFFER temporarily 
+#define CMD_MERGE                0X0061  //Synthesize fingerprint template data 
+#define CMD_MATCH                0X0062  //Compare templates in 2 designated RAMBUFFER 
+#define CMD_SEARCH               0X0063  //1:N Recognition in specific ID range 
+#define CMD_VERIFY               0X0064  //Compare specific RAMBUFFER template with specific ID template in fingerprint library 
+
+#define ERR_SUCCESS              0x00    //Command processed successfully 
+#define ERR_ID809                0xFF    //error 
+
+
+public:
+  
+  typedef enum{
+    eBreathing = 1,  //Breathing 
+    eFastBlink,      //Quick blink
+    eKeepsOn,        //On
+    eNormalClose,    //Off
+    eFadeIn,         //Fade in 
+    eFadeOut,        //Fade out
+    eSlowBlink       //Slow blink
+  }eLEDMode_t;
+  
+  typedef enum{
+    eLEDGreen = 1,   //green 
+    eLEDRed,         //red 
+    eLEDYellow,      //yellow
+    eLEDBlue,        //blue
+    eLEDCyan,        //cyan
+    eLEDMagenta,     //magenta
+    eLEDWhite        //white
+  }eLEDColor_t;
+   
+  typedef enum{
+    e9600bps = 1,
+    e19200bps,
+    e38400bps,
+    e57600bps,
+    e115200bps
+  }eDeviceBaudrate_t;
+  
+  typedef enum{
+    eErrorSuccess            = 0x00,    //Command processed successfully
+    eErrorFail               = 0x01,    //Command processing failed 
+    eErrorVerify             = 0x10,    //1:1 Templates comparison in specific ID failed 
+    eErrorIdentify           = 0x11,    //1:N comparison has been made, no same templates here 
+    eErrorTmplEmpty          = 0x12,    //No registered template in the designated ID 
+    eErrorTmplNotEmpty       = 0x13,    //Template already exists in the specified ID 
+    eErrorAllTmplEmpty       = 0x14,    //No registered Template 
+    eErrorEmptyIDNoexist     = 0x15,    //No registerable Template ID 
+    eErrorBrokenIDNoexist    = 0x16,    //No damaged Template 
+    eErrorInvalidTmplData    = 0x17,    //The designated Template Data is invalid 
+    eErrorDuplicationID      = 0x18,    //The fingerprint has been registered 
+    eErrorBadQuality         = 0x19,    //Poor quality fingerprint image 
+    eErrorMergeFail          = 0x1A,    //Template synthesis failed 
+    eErrorNotAuthorized      = 0x1B,    //Communication password not authorized 
+    eErrorMemory             = 0x1C,    //Error in exernal Flash burning 
+    eErrorInvalidTmplNo      = 0x1D,    //The designated template ID is invalid 
+    eErrorInvalidParam       = 0x22,    //Incorrect parameter has been used 
+    eErrorTimeOut            = 0x23,    //Acquisition timeout 
+    eErrorGenCount           = 0x25,    //Invalid number of fingerprint synthesis 
+    eErrorInvalidBufferID    = 0x26,    //Wrong Buffer ID value 
+    eErrorFPNotDetected      = 0x28,    //No fingerprint input into fingerprint reader 
+    eErrorFPCancel           = 0x41,    //Command cancelled 
+    eErrorRecvLength         = 0x42,    //Wrong length of recieved data 
+    eErrorRecvCks            = 0x43,    //Wrong check code 
+    eErrorGatherOut          = 0x45,    //Exceed upper limit of acquisition times 
+    eErrorRecvTimeout        = 0x46     //Communication timeout 
+  }eError_t;
+  
+  typedef struct{
+    /**< Gesture enumeration variable X */
+    eError_t error;
+    /**< Description about the gesture enumeration variable X */
+    const char * description;
+  }sErrorDescription_t;
+
+public:
+  DFRobot_ID809();
+  ~DFRobot_ID809();
+  
+  /**
+   * @brief Init communication port
+   * @param Software serial or hardware serial 
+   * @return true or false
+   */
+  bool begin(Stream &s_);
+  
+  /**
+   * @brief Test whether the module connection is ok
+   * @return true or false
+   */
+  bool isConnected();
+  
+  /**
+   * @brief Set module ID
+   * @param ID:1-255
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDeviceID(uint8_t deviceID);
+  
+  /**
+   * @brief Set module security level 
+   * @param security level:1-5
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSecurityLevel(uint8_t securityLevel);
+  
+  /**
+   * @brief Set module fingerprint replication check (Check whether the fingperint has been registered when saving it)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setDuplicationCheck(uint8_t duplicationCheck);
+  
+  /**
+   * @brief Set module baud rate 
+   * @param Baudrate:in typedef enum eDeviceBaudrate_t
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setBaudrate(eDeviceBaudrate_t baudrate);
+  
+  /**
+   * @brief Set module self-learning function (Update fingeprint when fingerprint comparison succeeds)
+   * @param 1(ON) or 0(OFF)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setSelfLearn(uint8_t selfLearn);
+  
+  /**
+   * @brief Read module ID
+   * @return ID号:1-255 or ERR_ID809
+   */
+  uint8_t getDeviceID();
+  
+  /**
+   * @brief Read module security level 
+   * @return Security level:1-5 or ERR_ID809
+   */
+  uint8_t getSecurityLevel();
+  
+  /**
+   * @brief Read module fingerprint replication check status
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getDuplicationCheck();
+  
+  /**
+   * @brief Read module baud rate 
+   * @return Baudrate:in typedef enum eDEVICE_BAUDRATE_t or ERR_ID809
+   */
+  uint8_t getBaudrate();
+  
+  /**
+   * @brief Read module self-learning function status 
+   * @return Status:1(ON), 0(OFF) or ERR_ID809
+   */
+  uint8_t getSelfLearn();
+  uint8_t getTemplate(uint16_t id,uint8_t * temp);
+  uint8_t downLoadTemplate(uint16_t id,uint8_t * temp);
+  uint8_t getFingerImage(uint8_t *image);
+  uint8_t downLoadImage(uint16_t id,uint8_t * temp);
+  uint8_t receiveImageData(uint8_t *image);
+  uint8_t getQuarterFingerImage(uint8_t *image);
+  uint8_t contrastTemplate(uint8_t *temp);
+  /**
+   * @brief Read device number 
+   * @return Device number
+   */
+  String getDeviceInfo();
+  
+  /**
+   * @brief Set serial number
+   * @param String pointer 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setModuleSN(const char* SN);
+  /**
+   * @brief Read serial number 
+   * @return Serial number
+   */
+  String getModuleSN();
+  
+  /**
+   * @brief Set LED
+   * @param mode:in typedef enum eLEDMode_t
+   * @param color:in typedef enum eLEDColor_t
+   * @param blink Count: 00 represents blinking all the time
+   * @This parameter will only be valid in mode eBreathing, eFastBlink, eSlowBlink
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t ctrlLED(eLEDMode_t mode,eLEDColor_t color,uint8_t blinkCount);
+  
+  /**
+   * @brief Detect if there is finger touched 
+   * @return 1(Touched) or 0(No touch)
+   */
+  uint8_t detectFinger();
+  
+  /**
+   * @brief Get the first registerable ID 
+   * @return Registerable ID or ERR_ID809
+   */
+  uint8_t getEmptyID();
+  
+  /**
+   * @brief Check if the ID has been registered 
+   * @return 0(Registered), 1(Unregistered) or ERR_ID809
+   */
+  uint8_t getStatusID(uint8_t ID);
+  
+  /**
+   * @brief Get the number of registered users 
+   * @return Number of registered users or ERR_ID809
+   */
+  uint8_t getEnrollCount();
+  
+  /**
+   * @brief Get registered user list 
+   * @return 0(succeed) or ERR_ID809
+   */
+   uint8_t getEnrolledIDList(uint8_t* list);
+  
+  /**
+   * @brief Fingerprint acquisition 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t collectionFingerprint(uint16_t timeout,int ramNumber = -1);
+  
+  /**
+   * @brief Save fingerprint 
+   * @param Fingerprint ID
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t storeFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Delete fingerprint 
+   * @param Delete ID or DELALL(delete all)
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t delFingerprint(uint8_t ID);
+  
+  /**
+   * @brief Match the fingerprint with all fingeprints 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t search();
+
+  /**
+   * @brief Match the fingerprint with specific fingerprint 
+   * @return Successfully matched fingerprint ID, 0(Matching failed) or ERR_ID809
+   */
+  uint8_t verify(uint8_t ID);
+
+  /**
+   * @brief Compare templates in two specific RamBuffers
+   * @param RamBuffer number 
+   * @param RamBuffer number 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t match(uint8_t RamBufferID0, uint8_t RamBufferID1);
+  
+  /**
+   * @brief Get the number of damaged fingerprints 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenQuantity();
+
+  /**
+   * @brief Get the first damaged fingerprint ID 
+   * @return Damaged fingerprint ID or ERR_ID809
+   */
+  uint8_t getBrokenID();
+  
+  /**
+   * @brief Take out fingerprint template, temporarily save into RamBuffer
+   * @param Fingerprint ID 
+   * @param RamBuffer number 0-2
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t loadFingerprint(uint8_t ID, uint8_t RamBufferID);
+  
+  /**
+   * @brief Enter Standby mode
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t enterStandbyState();
+  
+  /**
+   * @brief Get error information
+   * @return Text description of error information
+   */
+  String getErrorDescription();
+  
+  bool setDbgSerial(Stream &s_){dbg = &s_; return true;}
+    uint16_t FINGERPRINT_CAPACITY = 80;
+protected:
+   /**
+   * @brief Set parameter 
+   * @param Data type+ data
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t setParam(uint8_t* data);
+  
+   /**
+   * @brief Read parameter 
+   * @param Data type 
+   * @return data or ERR_ID809
+   */
+  uint8_t getParam(uint8_t* data);
+  
+  /**
+   * @brief Capture fingerprint image 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t getImage();
+   
+   /**
+   * @brief Take image as template 
+   * @param Ram Buffer number
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t generate(uint8_t RamBufferID);
+  
+ /**
+   * @brief Fingerprint synthesis 
+   * @return 0(succeed) or ERR_ID809
+   */
+  uint8_t merge();
+  
+ /**
+   * @brief Packing data frame 
+   * @param Data type:CMD_TYPE or DATA_TYPE
+   * @param Command
+   * @param Data 
+   * @param Length
+   * @return Data frame 
+   */
+  pCmdPacketHeader_t pack(uint8_t type, uint16_t cmd, const char *payload, uint16_t len);
+  
+ /**
+   * @brief Send data 
+   * @param Data frame
+   */
+  void sendPacket(pCmdPacketHeader_t header);
+  
+ /**
+   * @brief Read byte 
+   * @param Pointer for saving data 
+   * @param Length of data to be received 
+   * @return Actual received data length 
+   */
+  size_t readN(void* buf_, size_t len);
+  
+ /**
+   * @brief Read frame header 
+   * @param Frame header struct of response packet
+   * @return Response packet type:RCM_TYPE,DATA_TYPE or 1(reading timeout)
+   */
+  uint16_t readPrefix( pRcmPacketHeader_t header );
+  
+ /**
+   * @brief Read data
+   * @param Pointer for saving data 
+   * @return 0(success) or ERR_ID809
+   */
+  uint8_t responsePayload(void* buf);
+  
+ /**
+   * @brief Get command packet CKS
+   * @param Command packet frame 
+   * @return CKS
+   */
+  uint16_t getCmdCKS(pCmdPacketHeader_t packet);
+  
+ /**
+   * @brief Get response packet CKS
+   * @param Response packet frame 
+   * @return CKS
+   */
+  uint16_t getRcmCKS(pRcmPacketHeader_t packet);
+  uint8_t store(uint8_t ID);
+  
+private:
+  Stream *s;
+  uint8_t buf[20];     //For saving response packet data 
+  pCmdPacketHeader_t  sendHeader;
+  pRcmPacketHeader_t  recHeader;
+  
+  static const sErrorDescription_t /*PROGMEM*/ errorDescriptionsTable[26];   //Error information list 
+  
+  uint8_t _number = 0;       //Fingerprint acquisistion times 
+  uint8_t _state = 0;        //Collect fingerprint state
+  eError_t _error;           //Error code 
+  uint16_t _PacketSize = 0;  //Data packet length to be sent 
+};
+
+#endif
+
diff --git a/readTemplate/platformio.ini b/readTemplate/platformio.ini
new file mode 100644
index 0000000..7a3aa31
--- /dev/null
+++ b/readTemplate/platformio.ini
@@ -0,0 +1,13 @@
+[env:Teensy_FP]
+
+platform = teensy
+framework = arduino
+board = teensy31
+
+build_flags = 
+	-I lib/DFRobot_ID809
+
+lib_deps = 
+	intrbiz/crypto
+
+
diff --git a/readTemplate/src/src.cpp b/readTemplate/src/src.cpp
new file mode 100644
index 0000000..d5adb90
--- /dev/null
+++ b/readTemplate/src/src.cpp
@@ -0,0 +1,192 @@
+#include <Arduino.h>
+#include <Crypto.h>
+#include <DFRobot_ID809.h>
+#include <EEPROM.h>
+
+// use serial3 as interface with fingerprint
+// sensor.
+
+#define FPSerial Serial3
+
+// define buillt_in led
+
+#define BUILTIN_LED 13
+
+// Collect the fingerprint 3 times
+
+#define COLLECT_NUMBER 3
+
+/*------Global variables--------------*/
+
+DFRobot_ID809 fingerprint;
+uint8_t ID, i, ret;
+byte hash[SHA256_SIZE];
+uint8_t temp[1008];
+// EEPROM OFFSET to store
+
+const uint16_t EEPROM_FP_HASH = 1696;
+
+/*---------Compute hash----------------*/
+
+void compute_hash() {
+
+  SHA256 hasher;
+  hasher.doUpdate(temp, sizeof(temp));
+  hasher.doFinal(hash);
+
+  Serial.println("-----------------------");
+  Serial.println();
+  for (uint8_t i = 0; i < SHA256_SIZE; i++) {
+
+    if (hash[i] < 0x10) {
+
+      Serial.print('0');
+    }
+
+    Serial.print(hash[i], HEX);
+    Serial.print(" ");
+  }
+  Serial.println();
+  Serial.println("-----------------------");
+}
+
+/*-----Blink on board led -------------- */
+
+void blink_led() {
+  digitalWrite(BUILTIN_LED, HIGH);
+  delay(500);
+  digitalWrite(BUILTIN_LED, LOW);
+  delay(500);
+}
+
+/*-------- Save FingerPrint hash in EEPROM ------*/
+
+void compareHash() {
+  uint16_t memoryAddress;
+  byte stored_hash[SHA256_SIZE];
+
+  memoryAddress = EEPROM_FP_HASH + ((ID - 1) * 32);
+
+  Serial.println("---------------------------");
+  for (uint8_t i = 0; i < SHA256_SIZE; i++) {
+
+    stored_hash[i] = EEPROM.read(memoryAddress);
+    Serial.print(stored_hash[i], HEX);
+    Serial.print(" ");
+    memoryAddress++;
+  }
+  Serial.println("--------------------------");
+
+  for (uint8_t i = 0; i < SHA256_SIZE; i++) {
+
+    if (stored_hash[i] != hash[i]) {
+      Serial.println("Hash not matched");
+      return;
+    }
+  }
+  Serial.println("Hash mathed");
+}
+
+/*---------Arduino setup function------*/
+
+void setup() {
+  // config led_pin as output
+  pinMode(BUILTIN_LED, OUTPUT);
+  // use serial port to print the baud rate
+  Serial.begin(9600);
+  // config fingerprint sensor
+  FPSerial.begin(115200);
+  fingerprint.begin(FPSerial);
+
+  while (fingerprint.isConnected() == false) {
+    Serial.println("Communication with the device failed");
+    delay(1000);
+  }
+}
+
+/*---------Register Finger print ------------*/
+
+void matchFingerprint() {
+
+  /*Set fingerprint LED ring mode, color, and number of blinks
+    Can be set as follows:
+    Parameter 1:<LEDMode>
+    eBreathing   eFastBlink   eKeepsOn    eNormalClose
+    eFadeIn      eFadeOut     eSlowBlink
+    Parameter 2:<LEDColor>
+    eLEDGreen  eLEDRed      eLEDYellow   eLEDBlue
+    eLEDCyan   eLEDMagenta  eLEDWhite
+    Parameter 3:<Number of blinks> 0 represents blinking all the time
+    This parameter will only be valid in mode eBreathing, eFastBlink,
+    eSlowBlink
+   */
+  fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eBreathing,
+                      /*LEDColor = */ fingerprint.eLEDBlue,
+                      /*blinkCount = */ 0);
+
+  Serial.println("Plase press down your finger");
+
+  if ((fingerprint.collectionFingerprint(/*timeout = */ 0)) != ERR_ID809) {
+    /*Set fingerprint LED ring to quick blink in yellow 3 times */
+    fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eFastBlink,
+                        /*LEDColor = */ fingerprint.eLEDYellow,
+                        /*blinkCount = */ 3);
+    Serial.println("capturing succeeds");
+    Serial.println("Please release your finger");
+
+    while (fingerprint.detectFinger())
+      ;
+
+    /*Compare the captured fingerprint with all the fingerprints
+     * inthe fingerprint library return fingerprint ID if succeed,
+     * return 0 when failed
+     * */
+    ret = fingerprint.search();
+
+    if (ret != 0) {
+
+      /*Set fingerprint LED ring to always ON in green */
+      fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eKeepsOn,
+                          /*LEDColor = */ fingerprint.eLEDGreen,
+                          /*blinkCount = */ 0);
+      Serial.print("Matching succeeds,ID=");
+      ID = ret;
+      Serial.println(ret);
+      fingerprint.getTemplate(ID, temp);
+      // delay(100);
+      // compute_hash();
+      // compareHash();
+
+      // print template data
+      Serial.println("---------------------------------");
+      Serial.println();
+      for (uint16_t i = 0; i < 1008; i++) {
+
+        Serial.print(temp[i], HEX);
+        Serial.print(" ");
+      }
+      Serial.println();
+      Serial.println("-------------------------------");
+
+      compute_hash();
+    } else {
+      /*Set fingerprint LED ring to always ON in red*/
+      fingerprint.ctrlLED(/*LEDMode = */ fingerprint.eKeepsOn,
+                          /*LEDColor = */ fingerprint.eLEDRed,
+                          /*blinkCount = */ 0);
+      Serial.println("Matching fails");
+    }
+  } else {
+    Serial.println("Capturing failes");
+    /*Get error code information*/
+    // desc = fingerprint.getErrorDescription();
+    // Serial.println(desc);
+  }
+}
+
+/*-----------Arduino loop function--------- */
+
+void loop() {
+  blink_led();
+  matchFingerprint();
+}
-- 
GitLab