diff --git a/examples/Module/Fingerprint/Fingerprint.ino b/examples/Module/Fingerprint/Fingerprint.ino new file mode 100644 index 0000000..eb33032 --- /dev/null +++ b/examples/Module/Fingerprint/Fingerprint.ino @@ -0,0 +1,157 @@ + + +#include +#include "fingerprint.h" + +#define MODULE_TX 33 +#define MODULE_RX 34 +#define UART_BAUD 57600 +#define VTOUCH_PIN 26 +#define BUZZER_PIN 25 +#define BUZZER_CHANNEL 2 + +#define ModuleSerial Serial1 + +TTGOClass *watch = nullptr; +TFT_eSPI *tft = nullptr; + +Fingerprint eic(&Serial1); +SysParams_t params; +bool flag = false; + +char buff[512]; + +void touchPadAttach(void) +{ + Serial.println("TouchPad Attach"); + flag = true; +} + +void playSound() +{ + ledcWriteTone(BUZZER_CHANNEL, 1000); + delay(200); + ledcWriteTone(BUZZER_CHANNEL, 0); +} + +void setup() +{ + Serial.begin(115200); + + delay(500); + + watch = TTGOClass::getWatch(); + + watch->begin(); + + tft = watch->eTFT; + + tft->setTextFont(2); + + tft->fillScreen(TFT_BLACK); + + tft->setCursor(0, 0); + + watch->sdcard_begin(); + + if (watch->sdcard_begin()) { + tft->println("SD Begin OK"); + } else { + tft->println("SD Begin Failed"); + } + + tft->println("Begin Fingerprint module ..."); + + // enable module power + watch->enableLDO3(); + + // open blacklight + watch->openBL(); + + ModuleSerial.begin(UART_BAUD, SERIAL_8N1, MODULE_RX, MODULE_TX); + + // buzzer init + ledcSetup(BUZZER_CHANNEL, 1000, 8); + ledcAttachPin(BUZZER_PIN, BUZZER_CHANNEL); + + // module interrupt pin init + pinMode(VTOUCH_PIN, INPUT_PULLDOWN); + attachInterrupt(VTOUCH_PIN, touchPadAttach, CHANGE); + + // Wait for module ack + do { + eic.readSysParams(¶ms); + + Serial.printf("address: 0x%x --packSize : %u -- %d bps -- level:%d -- statusReg:0x%x -- code:0x%x\n", + params.address, + params.packSize, + 9600 * params.bps, + params.level, + params.statusReg, + params.code + ); + delay(1000); + } while (params.address != 0xFFFFFFFF); + + tft->setTextColor(TFT_GREEN, TFT_BLACK); + + tft->print("Address:"); tft->println(params.address, HEX); + tft->print("Pack Size:"); tft->println(params.packSize); + tft->print("Speed:"); tft->println(9600 * params.bps); + tft->print("Level:"); tft->println(params.level); + tft->print("StatusReg:"); tft->println(params.statusReg, HEX); + tft->print("Code:"); tft->println(params.code); + + playSound(); + playSound(); + playSound(); + playSound(); + +} + + +bool loop1(GR_BufID_t id) +{ + // while (!flag) { + // delay(500); + // } + flag = false; + if (eic.entryFinger()) { + Serial.println("entery PASS"); + delay(200); + if (eic.generateFeature(id)) { + Serial.println("generater PASS"); + return true; + } else { + Serial.println("generater FAIL"); + } + } + return false; +} + +void loop() +{ + while (!loop1(GR_CHAR_BUFFER_1)); + while (!loop1(GR_CHAR_BUFFER_2)); + if (eic.mergeFeature()) { + Serial.println("merge PASS"); + if (eic.storeFeature(GR_CHAR_BUFFER_1, 0)) { + Serial.println("storeFeature PASS"); + } else { + Serial.println("storeFeature FAIL"); + } + } else { + Serial.println("merge FAIL"); + } + while (1) { + if (loop1(GR_CHAR_BUFFER_1)) { + if (eic.searchFingerprint(GR_CHAR_BUFFER_1, 0, 10)) { + Serial.println("Fingerprint valid PASS"); + playSound(); + + } else { + // Serial.println("Fingerprint valid FAIL"); + } + } + } +} \ No newline at end of file diff --git a/examples/Module/Fingerprint/fingerprint.cpp b/examples/Module/Fingerprint/fingerprint.cpp new file mode 100644 index 0000000..08e5f3c --- /dev/null +++ b/examples/Module/Fingerprint/fingerprint.cpp @@ -0,0 +1,515 @@ +#include "fingerprint.h" + +/*起始帧*/ +#define GR_PACK_HEAD 0XEF01 +/* 包标识*/ +#define GR_PACK_COMMAND_FLAG 0X01 +//当为2时,表示后续还有包 +#define GR_PACK_DATA_FALG 0X02 +#define GR_PACK_ACK_FALG 0X07 +#define GR_PACK_END_FALG 0X08 +// 包长度 = 数据到校验和之间的长度 +// 校验和 = 包标识 ~ 校验和之间的和 ,超两个字节对高位进行忽略 + +Fingerprint::Fingerprint(Stream *UART, uint32_t ADDRRESS) +{ + _uart = UART; + _addr = ADDRRESS; + _headBuffer[0] = 0xEF; + _headBuffer[1] = 0x01; + memcpy(&_headBuffer[2], &_addr, sizeof(_addr)); +}; + +Fingerprint::~Fingerprint(void) +{ + +}; + +/********************* + * 0 1 2 3 4 5 6 7 8 9 10 11 + * ef 01 ff ff ff ff flag len_h len_l code sum_h sum_l + * *******************/ +bool Fingerprint::validSum(uint8_t *resp, uint8_t len) +{ + uint16_t sum = 0; + for (int i = 6; i < len - 2; i++) { + sum += resp[i]; + } + // Serial.printf("sum:%x -2:%x -1:%x \n", sum, resp[len - 2], resp[len - 1]); + // Serial.printf("merge: %x \n", (resp[len - 2] << 8 | resp[len - 1])); + return sum == (resp[len - 2] << 8 | resp[len - 1]); +} + +bool Fingerprint::waitForAck(uint8_t *reqs, uint8_t len) +{ + uint32_t i = 0, timerStart = millis(); + while (1) { + if (_uart->available()) { + reqs[i++] = _uart->read(); + Serial.print(reqs[i - 1], HEX); + Serial.print(" "); + if (i >= len) { + Serial.println(); + break; + } + } + if (millis() - timerStart > 1000) { + Serial.printf("time out\n"); + return false; + } + } + return true; +} + +int Fingerprint::waitForResp(uint8_t respSize, uint32_t timeout) +{ + int i = 0; + uint32_t timerStart = millis(); + uint8_t response[respSize]; + while (1) { + if (_uart->available()) { + response[i++] = _uart->read(); + if (i >= sizeof(response)) + break; + } + if (millis() - timerStart > 1000 * timeout) { + return -1; + } + } + if (validSum(response, sizeof(response))) { + return response[9]; + } + return -1; +} + +void Fingerprint::__sendCom(uint8_t command, uint16_t len) +{ + uint16_t sum = 0; + uint8_t commandBuffer[6]; + commandBuffer[0] = GR_PACK_COMMAND_FLAG; + commandBuffer[1] = (len & 0xFF00) >> 8; + commandBuffer[2] = len & 0xFF; + commandBuffer[3] = command; + + for (int i = 0; i < sizeof(commandBuffer) - 2; i++) { + sum += commandBuffer[i]; + } + commandBuffer[4] = (sum & 0xFF00) >> 8; + commandBuffer[5] = sum & 0xFF; + _uart->write(_headBuffer, sizeof(_headBuffer)); + _uart->write(commandBuffer, sizeof(commandBuffer)); +} + +/** + * @brief 录入指纹到ImageBuffer + * @note 标准应答格式 12Bytes + * @retval 0H ~ 03H + */ +bool Fingerprint::entryFinger(void) +{ + int ret = GR_OK; + + __sendCom(GR_GET_IMAGE, 0x03); + + ret = waitForResp(12, 15); + if (ret != GR_OK) { + getErrorReason(ret); + } + return ret == GR_OK; +} + +void Fingerprint::getErrorReason(int err) +{ + // Serial.printf("Error :[%d]\n", err); + switch (err) { + case 0: + break; + } +} + +/** + * @brief 生成特征标识 + * @note 标准应答格式 12Bytes + * @param id: 01H ~ 02H + * @retval + */ +bool Fingerprint::generateFeature(GR_BufID_t id) +{ + int ret = GR_OK; + uint8_t commandBuffer[7]; + _uart->write(_headBuffer, 6); + commandBuffer[0] = GR_PACK_COMMAND_FLAG; + commandBuffer[1] = 0x00; + commandBuffer[2] = 0x04; + commandBuffer[3] = GR_GET_CHAR; + commandBuffer[4] = id; + commandBuffer[5] = 0x00; + commandBuffer[6] = 0x07 + id; + _uart->write(commandBuffer, sizeof(commandBuffer)); + ret = waitForResp(12, 1); + if (ret != GR_OK) { + getErrorReason(ret); + } + return ret == GR_OK; +} + +/** + * @brief 精确比对两枚指纹特征 + * @note //! 非标准应答格式 14Bytes + * @retval 0x00 0x01 0x08 + */ +bool Fingerprint::matchFingerprint(void) +{ + int ret = GR_OK; + + __sendCom(GR_MATCH, 0x03); + ret = waitForResp(14, 1); + if (ret != GR_OK) { + getErrorReason(ret); + } + return ret == GR_OK; +} + +/** + * @brief 搜索指纹 + * @note //! 非标准应答格式 16Bytes + * @retval 确认字,页码(相配指纹模板) + */ +bool Fingerprint::searchFingerprint(GR_BufID_t id, uint16_t sPage, uint16_t pNum) +{ + int ret = GR_OK; + uint32_t sum = 0; + uint8_t commandBuffer[11]; + _uart->write(_headBuffer, 6); + commandBuffer[0] = GR_PACK_COMMAND_FLAG; + commandBuffer[1] = 0x00; + commandBuffer[2] = 0x08; + commandBuffer[3] = GR_SEARCH; + commandBuffer[4] = id; + commandBuffer[5] = (sPage & 0xFF00) >> 8; + commandBuffer[6] = sPage & 0xFF; + commandBuffer[7] = (pNum & 0xFF00) >> 8; + commandBuffer[8] = pNum & 0xFF; + + for (int i = 0; i < sizeof(commandBuffer) - 2; i++) { + sum += commandBuffer[i]; + } + commandBuffer[9] = (sum & 0x00FF00) >> 8; + commandBuffer[10] = sum & 0xFF; + + _uart->write(commandBuffer, sizeof(commandBuffer)); + ret = waitForResp(16, 1); + if (ret != GR_OK) { + getErrorReason(ret); + } + return ret == GR_OK; +} + +/** + * @brief 合并特征(生成模板) + * @note 标准应答格式 12Bytes + * @retval 0x00 0x01 0x0A + */ +bool Fingerprint::mergeFeature(void) +{ + int ret = GR_OK; + uint8_t commandBuffer[6]; + _uart->write(_headBuffer, 6); + commandBuffer[0] = GR_PACK_COMMAND_FLAG; + commandBuffer[1] = 0x00; + commandBuffer[2] = 0x03; + commandBuffer[3] = GR_REG_MODEL; + commandBuffer[4] = 0x00; + commandBuffer[5] = 0x09; + _uart->write(commandBuffer, sizeof(commandBuffer)); + ret = waitForResp(12, 1); + if (ret != GR_OK) { + getErrorReason(ret); + } + return ret == GR_OK; +} + +/** + * @brief 储存模板 + * @note 标准应答格式 12Bytes + * @retval + */ +bool Fingerprint::storeFeature(GR_BufID_t id, uint16_t posNum) +{ + int ret = GR_OK; + uint32_t sum = 0; + uint8_t commandBuffer[9]; + _uart->write(_headBuffer, 6); + commandBuffer[0] = GR_PACK_COMMAND_FLAG; + commandBuffer[1] = 0x00; + commandBuffer[2] = 0x06; + commandBuffer[3] = GR_STORE_CHAR; + commandBuffer[4] = id; + commandBuffer[5] = (posNum & 0xFF00) >> 8; + commandBuffer[6] = posNum & 0xFF; + for (int i = 0; i < sizeof(commandBuffer) - 2; i++) { + sum += commandBuffer[i]; + } + commandBuffer[7] = (sum & 0x00FF00) >> 8; + commandBuffer[8] = sum & 0xFF; + + _uart->write(commandBuffer, sizeof(commandBuffer)); + ret = waitForResp(12, 1); + if (ret != GR_OK) { + getErrorReason(ret); + } + return ret == GR_OK; +} + +/** + * @brief 读出模板 + * @note 标准应答格式 12Bytes,将flash数据库中指定ID号的指纹模板读入到模板缓冲区CharBuffer1或CharBuffer2 + * @retval + */ +bool Fingerprint::loadFeature(GR_BufID_t id, uint16_t pNum) +{ + int ret = GR_OK; + uint32_t sum = 0; + uint8_t commandBuffer[9]; + _uart->write(_headBuffer, 6); + commandBuffer[0] = GR_PACK_COMMAND_FLAG; + commandBuffer[1] = 0x00; + commandBuffer[2] = 0x06; + commandBuffer[3] = GR_LOAD_CHAR; + commandBuffer[4] = id; + commandBuffer[5] = (pNum & 0xFF00) >> 8; + commandBuffer[6] = pNum & 0xFF; + for (int i = 0; i < sizeof(commandBuffer) - 2; i++) { + sum += commandBuffer[i]; + } + commandBuffer[7] = (sum & 0x00FF00) >> 8; + commandBuffer[8] = sum & 0xFF; + + _uart->write(commandBuffer, sizeof(commandBuffer)); + ret = waitForResp(12, 1); + if (ret != GR_OK) { + getErrorReason(ret); + } + return ret == GR_OK; +} + +/** + * @brief 上传特征或模板 + * @note 标准应答格式 12Bytes + * @retval + */ +bool Fingerprint::uplaodFeature(GR_BufID_t id) +{ + int ret = GR_OK; + uint32_t sum = 0; + uint8_t commandBuffer[7]; + _uart->write(_headBuffer, 6); + commandBuffer[0] = GR_PACK_COMMAND_FLAG; + commandBuffer[1] = 0x00; + commandBuffer[2] = 0x04; + commandBuffer[3] = GR_UP_CHAR; + commandBuffer[4] = id; + for (int i = 0; i < sizeof(commandBuffer) - 2; i++) { + sum += commandBuffer[i]; + } + commandBuffer[5] = (sum & 0x00FF00) >> 8; + commandBuffer[6] = sum & 0xFF; + + _uart->write(commandBuffer, sizeof(commandBuffer)); + ret = waitForResp(12, 1); + if (ret != GR_OK) { + getErrorReason(ret); + } + return ret == GR_OK; +} + +/** + * @brief 下载特征或模板 + * @note 标准应答格式 12Bytes + * @retval + */ +bool Fingerprint::downloadFeature(GR_BufID_t id) +{ + return true; +} + +// /** +// * @brief 上传原始图像 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::uploadImage(void) +// { +// } + +// /** +// * @brief 下载原始图像 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::downloadImage(void) +// { +// } + +// /** +// * @brief 删除模板 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::uploadImage(void) +// { +// } + +// /** +// * @brief 清空指纹库 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::deleteLibarry(void) +// { +// } + +// /** +// * @brief 写系统寄存器 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::writeSysReg(void) +// { +// } + +/** + * @brief 读系统基本参数 + * @note //! 非标准应答格式 28Bytes + * @retval + */ +bool Fingerprint::readSysParams(SysParams_t *params) +{ + uint8_t response[28]; + const uint8_t order[] = {0x01, 0x00, 0x03, 0x0F, 0x00, 0x13}; + _uart->write(_headBuffer, sizeof(_headBuffer)); + _uart->write(order, sizeof(order)); + if (waitForAck(response, sizeof(response))) { + if (validSum(response, sizeof(response)) && response[9] == GR_OK) { + Serial.printf("\nvalid pass\n\n"); + params->statusReg = (response[10] << 8) | response[11]; + params->code = response[12] << 8 | response[13]; + params->libSize = response[14] << 8 | response[15]; + params->level = response[16] << 8 | response[17]; + params->address = response[18] << 24 | response[19] << 16 | response[20] << 8 | response[21]; + params->packSize = response[22] << 8 | response[23]; + params->bps = response[24] << 8 | response[25]; + return true; + } + } + return false; +} + + +bool Fingerprint::readINFpage() +{ + uint8_t response[255]; + const uint8_t order[] = {0x01, 0x00, 0x03, 0x16, 0x00, 0x19}; + _uart->write(_headBuffer, sizeof(_headBuffer)); + _uart->write(order, sizeof(order)); + if (waitForAck(response, sizeof(response))) { + if (validSum(response, sizeof(response)) && response[9] == GR_OK) { + Serial.printf("\nvalid pass\n\n"); + return true; + } + } + return false; + +} + + + +// /** +// * @brief 设置口令 +// * @note //! 非标准应答格式 11Bytes +// * @retval +// */ +// bool Fingerprint::setPassWord(void) +// { +// } + +// /** +// * @brief 验证口令 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::setPassWord(void) +// { +// } + +// /** +// * @brief 采样随机数 +// * @note //! 非标准应答格式 16Bytes +// * @retval +// */ +// bool Fingerprint::getRandom(void) +// { +// } + +// /** +// * @brief 设置模块地址 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::setAddress(void) +// { +// } + +// /** +// * @brief 端口控制 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::setAddress(void) +// { +// } + +// /** +// * @brief 写记事本 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::writeNotepad(void) +// { +// } + +// /** +// * @brief 读记事本 +// * @note //! 非标准应答格式 44Bytes +// * @retval +// */ +// bool Fingerprint::readNotepad(void) +// { +// } + +// /** +// * @brief 生成细化指纹图像 +// * @note 标准应答格式 12Bytes +// * @retval +// */ +// bool Fingerprint::generateBinImage(void) +// { +// } + +// /** +// * @brief 读有效模板个数 +// * @note //! 标准应答格式 14Bytes +// * @retval +// */ +// bool Fingerprint::generateBinImage(void) +// { +// } + +// /** +// * @brief 读索引表 +// * @note //! 非标准应答格式 44Bytes +// * @retval +// */ +// bool Fingerprint::readNotepad(void) +// { +// } \ No newline at end of file diff --git a/examples/Module/Fingerprint/fingerprint.h b/examples/Module/Fingerprint/fingerprint.h new file mode 100644 index 0000000..2baf4b1 --- /dev/null +++ b/examples/Module/Fingerprint/fingerprint.h @@ -0,0 +1,135 @@ +#pragma once + +#include + +typedef enum { + GR_GET_IMAGE = 0X01, + GR_GET_CHAR = 0X02, + GR_MATCH = 0X03, + GR_SEARCH = 0X04, + GR_REG_MODEL = 0X05, + GR_STORE_CHAR = 0X06, + GR_LOAD_CHAR = 0X07, + GR_UP_CHAR = 0X08, + GR_DOWN_CHAR = 0X09, + GR_UP_IMAGE = 0X0A, + GR_DOWN_IMAGE = 0X0B, + GR_DEL_CHAR = 0X0C, + GR_EMPTY = 0X0D, + GR_WRITE_REG = 0X0E, + GR_READ_STATE = 0X0F, + GR_SET_PASSWORD = 0X12, + GR_VALID_PASSWORD = 0X13, + GR_GET_RANDOM = 0X14, + GR_SET_ADDRESS = 0X15, + GR_PORT_CONTROL = 0X17, + GR_WRITE_NOTEPAD = 0X18, + GR_READ_NOTEPAD = 0X19, + GR_GEN_BIN_IMAGE = 0X1C, + GR_VALID_TEMPLETE_NUM = 0X1D, + GR_READ_INDEX_TABLE = 0X1F +} GR_ORDER; + +typedef enum { + GR_CHAR_BUFFER_1 = 0x01, + GR_CHAR_BUFFER_2 = 0x02 +} GR_BufID_t; + +enum { + GR_OK = 0X00, + PACK_ERROR = 0X01, + GR_NO_FINGERPRINT = 0X02, + GR_ENTERY_FAIL = 0X03, + GR_IMAGE_FAIL_1 = 0X04, + GR_IMAGE_FAIL_2 = 0X05, + GR_IMAGE_FAIL_3 = 0X06, + GR_IMAGE_FAIL_4 = 0X07, + GR_IMAGE_NO_MATCH = 0X08, + GR_IMAGE_SEARCH_FAIL = 0X09, + GR_MERGE_FAIL = 0X0A, + + GR_REFUSE_PACK = 0X0E, + GR_IMAGE_UP_FAIL = 0X0F, + GR_IMAGE_DEL_FAIL = 0X10, + GR_DATABASE_DEL_FAIL = 0X11, + GR_ORDER_NO_MATCH = 0X12, + GR_BUFFER_EMPTY = 0X13, + + GR_RW_FLASH_FAIL = 0X18, + GR_ERROR_OTHER, + GR_INVALID_REG, + GR_REG_NUM_ERROR, + GR_NOTEBOOK_ERROR, + GR_PORT_FAIL, + GR_REGISTER_FAIL, + GR_DATABASE_FULL, +}; + +//数据包大小 1word +//波特率 1word N * 9600 +//模块口令 2word default<0> +// 默 认 波 特 率 为 57600bps +#define MODLUES_ADDRESS 0xffffffff //2WORD +#define STATUS_REG 0 //1WORD +#define SECURITY_LEVEL //1WORD + +/*设备地址*/ +#define GR_MD_ADDRESS 0XFFFFFFFF + +typedef struct { + uint16_t statusReg; + uint16_t code; + uint16_t libSize; + uint16_t level; + uint32_t address; + uint16_t packSize; + uint16_t bps; +} SysParams_t; + +class Fingerprint +{ +public: + Fingerprint(Stream *UART, uint32_t ADDRRESS = GR_MD_ADDRESS); + ~Fingerprint(void); + bool entryFinger(void); + bool readSysParams(SysParams_t *params); + bool generateFeature(GR_BufID_t id); + bool mergeFeature(void); + bool storeFeature(GR_BufID_t id, uint16_t posNum); + bool searchFingerprint(GR_BufID_t id, uint16_t sPage, uint16_t pNum); + bool readINFpage(); +private: + bool waitForAck(uint8_t *reqs, uint8_t len); + int waitForResp(uint32_t timeout); + bool validSum(uint8_t *resp, uint8_t len); + int waitForResp(uint8_t respSize, uint32_t timeout); + void __sendCom(uint8_t command, uint16_t len); + void getErrorReason(int err); + + bool matchFingerprint(void); + bool loadFeature(GR_BufID_t id, uint16_t pNum); + bool uplaodFeature(GR_BufID_t id); + bool downloadFeature(GR_BufID_t id); + // bool uploadImage(void); + // bool downloadImage(void); + // bool uploadImage(void); + // bool deleteLibarry(void); + // bool writeSysReg(void); + // bool setPassWord(void); + // bool setPassWord(void); + // bool getRandom(void); + // bool setAddress(void); + // bool setAddress(void); + // bool writeNotepad(void); + // bool readNotepad(void); + // bool generateBinImage(void); + // bool generateBinImage(void); + // bool readNotepad(void); + + bool isPowerUp; + Stream *_uart; + uint32_t _addr; + uint8_t _headBuffer[6]; + +protected: +}; \ No newline at end of file