# HG changeset patch # User drewp@bigasterisk.com # Date 1598257653 25200 # Node ID 6c42c1f64f00e288f9a76577884cfa3eb9d70361 # Parent 729ab70c62124dc5eebe14427ca49df9134f31f5 new driver for esp32 and R503 fingerprint sensor diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/platformio.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/platformio.ini Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,52 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:ttgo-t1] +platform = espressif32 +board = ttgo-t1 +framework = arduino +upload_port = /dev/ttyUSB0 +upload_protocol = esptool +upload_speed = 921600 +monitor_port = /dev/ttyUSB0 +monitor_speed = 115200 + +build_flags = + -Os + -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + -DUSER_SETUP_LOADED=1 + -DST7789_DRIVER=1 + -DTFT_WIDTH=135 + -DTFT_HEIGHT=240 + -DCGRAM_OFFSET=1 + -DTFT_MISO=-1 + -DTFT_MOSI=19 + -DTFT_SCLK=18 + -DTFT_CS=5 + -DTFT_DC=16 + -DTFT_RST=23 + -DTFT_BL=4 + -DTFT_BACKLIGHT_ON=1 + -DLOAD_GLCD=1 + -DLOAD_FONT2=1 + -DLOAD_FONT4=1 + -DLOAD_FONT6=1 + -DLOAD_FONT7=1 + -DLOAD_FONT8=1 + -DLOAD_GFXFF=1 + -DSMOOTH_FONT=1 + -DSPI_FREQUENCY=40000000 + -DSPI_READ_FREQUENCY=6000000 + +lib_deps = + TFT_eSPI@1.4.21 + Button2@1.0.0 + https://github.com/brianrho/FPM + AsyncMqttClient@0.8.2 diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/display.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/display.cpp Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,24 @@ +#include "display.h" + +#include +#include + +// see https://github.com/JakubAndrysek/TTGO_T_Display + +namespace display { + +TFT_eSPI tft(135, 240); + +void Setup() { + tft.init(); + tft.fontHeight(2); + tft.setRotation(1); + tft.fillScreen(TFT_BLACK); +} + +void Message(std::string msg) { + tft.drawString(msg.c_str(), tft.width() / 4, tft.height() / 2, + 4); // string,start x,start y, font weight {1;2;4;6;7;8} +} + +} \ No newline at end of file diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/display.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/display.h Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,17 @@ +#ifndef INCLUDED_DISPLAY +#define INCLUDED_DISPLAY +#include + +#ifndef TFT_DISPOFF +#define TFT_DISPOFF 0x28 +#endif + +#ifndef TFT_SLPIN +#define TFT_SLPIN 0x10 +#endif + +namespace display { +void Setup(); +void Message(std::string msg); +} // namespace display +#endif \ No newline at end of file diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/fingerprint.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/fingerprint.cpp Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,314 @@ +#include "fingerprint.h" + +#include + +#include "mqtt.h" + +namespace fingerprint { + +HardwareSerial fserial(1); +FPM finger(&fserial); + +constexpr uint8_t led_red = 0x01, led_blue = 0x02, led_purple = 0x03; +constexpr uint8_t led_breathe = 0x01, led_flash = 0x02, led_on = 0x03, + led_off = 0x04, led_gradual_on = 0x05, led_gradual_off = 0x06; +constexpr uint8_t led_fast = 0x30, led_medium = 0x60, led_slow = 0x80; +constexpr uint8_t led_forever = 0; + +FPM_System_Params params; + +void BlinkNotConnected() { + finger.led_control(led_flash, led_fast, led_red, led_forever); +} +void BlinkConnected() { + finger.led_control(led_flash, led_fast, led_red, /*times=*/1); +} +void BlinkProgress() { + finger.led_control(led_flash, led_fast, led_blue, /*times=*/1); +} +void BlinkSuccess() { + finger.led_control(led_breathe, led_medium, led_purple, led_forever); +} +void BlinkClearSuccess() { + finger.led_control(led_breathe, led_medium, led_purple, 1); +} +void BlinkError() { + finger.led_control(led_flash, led_medium, led_red, /*times=*/3); + delay(500); +} +void BlinkDoorUnlocked() {} +void BlinkStartEnroll() { + finger.led_control(led_flash, led_slow, led_blue, led_forever); +} +void BlinkStartEnrollRepeat() { + finger.led_control(led_flash, led_medium, led_blue, led_forever); +} +void BlinkClearEnroll() { + finger.led_control(led_flash, led_slow, led_blue, 1); +} + +void (*queued)() = nullptr; +void QueueBlinkConnected() { queued = BlinkConnected; } +void ExecuteAnyQueued() { + if (queued) { + Serial.println("executing queued function"); + queued(); + queued = nullptr; + } +} + +void PublishError(std::string caller, int16_t p) { + std::string errStr; + switch (p) { + case FPM_FEATUREFAIL: + errStr = "Could not find fingerprint features"; + break; + case FPM_IMAGEFAIL: + errStr = "Imaging error"; + break; + case FPM_IMAGEMESS: + errStr = "Image too messy"; + break; + case FPM_INVALIDIMAGE: + errStr = "Could not find fingerprint features"; + break; + case FPM_NOTFOUND: + errStr = "Did not find a match"; + break; + case FPM_PACKETRECIEVEERR: + errStr = "Communication error"; + break; + case FPM_READ_ERROR: + errStr = "Got wrong PID or length"; + break; + case FPM_BADLOCATION: + errStr = "Could not store/delete in that location"; + break; + case FPM_FLASHERR: + errStr = "Error writing to flash"; + break; + case FPM_TIMEOUT: + errStr = "Timeout"; + break; + case FPM_ENROLLMISMATCH: + errStr = "Fingerprints did not match"; + break; + default: + char buf[100]; + snprintf(buf, sizeof(buf), "Unknown error (%d)", p); + errStr = buf; + break; + } + mqtt::Publish("messages", caller + ": " + errStr); +} + +bool GetImage() { + int16_t p = -1; + mqtt::Publish("messages", "Waiting for valid finger"); + + while (p != FPM_OK) { + p = finger.getImage(); + + if (p == FPM_OK) { + mqtt::Publish("messages", "getImage: Image taken"); + } else if (p == FPM_NOFINGER) { + if (mqtt::HasPendingCommand() || queued) { + return false; + } + } else { + PublishError("getImage", p); + return false; + } + yield(); + } + mqtt::Publish("messages", "getImage: got image"); + + BlinkProgress(); + return true; +} + +bool ConvertImage(uint8_t slot = 1) { + int16_t p = -1; + p = finger.image2Tz(); + if (p == FPM_OK) { + mqtt::Publish("messages", "image2Tz: Image converted"); + } else { + PublishError("image2Tz", p); + return false; + } + return true; +} + +bool SearchDatabase(uint16_t* fid, uint16_t* score) { + int16_t p = -1; + p = finger.searchDatabase(fid, score); + + /* now wait to remove the finger, though not necessary; + this was moved here after the search because of the R503 sensor, + which seems to wipe its buffers after each scan */ + mqtt::Publish("messages", "Waiting for finger removal"); + while (finger.getImage() != FPM_NOFINGER) { + delay(500); + } + + if (p != FPM_OK) { + PublishError("searchDatabase", p); + + if (p == FPM_NOTFOUND) { + BlinkError(); + } + return false; + } + return true; +} + +void ReportFoundMatch(uint16_t fid, uint16_t score) { + char msg[100]; + snprintf(msg, sizeof(msg), "found id %d confidence %d", fid, score); + mqtt::Publish("match", msg); +} + +void ScanLoop() { + if (!GetImage()) { + return; + } + + if (!ConvertImage()) { + return; + } + + uint16_t fid, score; + if (!SearchDatabase(&fid, &score)) { + return; + } + + ReportFoundMatch(fid, score); +} + +bool get_free_id(int16_t* fid) { + int16_t p = -1; + for (int page = 0; page < (params.capacity / FPM_TEMPLATES_PER_PAGE) + 1; + page++) { + p = finger.getFreeIndex(page, fid); + if (p != FPM_OK) { + PublishError("getFreeIndex", p); + return false; + } + if (*fid != FPM_NOFREEINDEX) { + char buf[100]; + snprintf(buf, sizeof(buf), "getFreeIndex: Free slot at id %d", *fid); + mqtt::Publish("messages", buf); + return true; + } + yield(); + } + mqtt::Publish("messages", "getFreeIndex: No free slots"); + return false; +} + +void WaitForRemove() { + int16_t p = -1; + mqtt::Publish("messages", "Remove finger"); + delay(2000); + p = 0; + while (p != FPM_NOFINGER) { + p = finger.getImage(); + yield(); + } +} + +void EnrollFailed() { + mqtt::Publish("messages", "exiting enroll"); + BlinkError(); + WaitForRemove(); +} + +void enroll_finger(int16_t fid) { + int16_t p = -1; + mqtt::Publish("messages", "Waiting for valid finger to enroll"); + BlinkStartEnroll(); + if (!GetImage()) { + return EnrollFailed(); + } + + if (!ConvertImage(1)) { + return EnrollFailed(); + } + + WaitForRemove(); + + BlinkStartEnrollRepeat(); + mqtt::Publish("messages", "Place same finger again"); + if (!GetImage()) { + return EnrollFailed(); + } + if (!ConvertImage(2)) { + return EnrollFailed(); + } + + p = finger.createModel(); + if (p == FPM_OK) { + mqtt::Publish("messages", "createModel: Prints matched"); + } else { + PublishError("createModel", p); + return EnrollFailed(); + } + + p = finger.storeModel(fid); + if (p == FPM_OK) { + mqtt::Publish("messages", "Stored!"); + BlinkSuccess(); + WaitForRemove(); + BlinkClearSuccess(); + return; + } else { + PublishError("storeModel", p); + return EnrollFailed(); + } +} + +void DeleteFingerprint(uint16_t fid) { + int p = -1; + + p = finger.deleteModel(fid); + + if (p == FPM_OK) { + Serial.println("Deleted!"); + } else { + PublishError("deleteModel", p); + } +} + +void Enroll() { + BlinkStartEnroll(); + mqtt::Publish("messages", + "Searching for a free slot to store the template..."); + int16_t fid; + if (get_free_id(&fid)) { + enroll_finger(fid); + } else { + mqtt::Publish("messages", "No free slot in flash library!"); + BlinkError(); + } +} + +void DownloadPrintImage(uint16_t fid) {} +void DeleteAll() {} + +void Setup() { + fserial.begin(57600, SERIAL_8N1, 26 /*rx*/, 27 /*tx*/); + + if (finger.begin()) { + finger.readParams(¶ms); + Serial.println("Found fingerprint sensor!"); + Serial.print("Capacity: "); + Serial.println(params.capacity); + Serial.print("Packet length: "); + Serial.println(FPM::packet_lengths[params.packet_len]); + } else { + Serial.println("Did not find fingerprint sensor :("); + while (1) yield(); + } + BlinkNotConnected(); +} +} // namespace fingerprint \ No newline at end of file diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/fingerprint.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/fingerprint.h Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,20 @@ +#ifndef INCLUDED_FINGERPRINT +#define INCLUDED_FINGERPRINT +#include +#include + +namespace fingerprint { +void Setup(); +void ExecuteAnyQueued(); +void BlinkProgress(); +void BlinkNotConnected(); +void BlinkConnected(); +void QueueBlinkConnected(); // for inside an ISR +void BlinkSuccess(); +void BlinkClearSuccess(); +void ScanLoop(); +void Enroll(); +void DownloadPrintImage(uint16_t fid); +void DeleteAll(); +} +#endif \ No newline at end of file diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/main.cpp Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,42 @@ +#include + +#include "display.h" +#include "fingerprint.h" +#include "mqtt.h" +#include "wifi.h" + +#define ADC_EN 14 +#define ADC_PIN 34 + +// #include +// #define BUTTON_1 35 +// #define BUTTON_2 0 + +void setup() { + Serial.begin(115200); + Serial.println("Serial.begin"); + + fingerprint::Setup(); // go early since the others display status on our LED + display::Setup(); + display::Message("Hello world"); + wifi::Setup(); + mqtt::Setup(); +} + +void loop() { + Serial.println("--loop--"); + fingerprint::ExecuteAnyQueued(); + fingerprint::ScanLoop(); + if (mqtt::HasPendingCommand()) { + std::string cmd = mqtt::PopPendingCommand(); + if (cmd == "enroll") { + fingerprint::Enroll(); + } else if (cmd == "show_success") { + fingerprint::BlinkSuccess(); + while (!mqtt::HasPendingCommand()) yield(); + cmd = mqtt::PopPendingCommand(); + // hope it's "clear_success", but who cares + fingerprint::BlinkClearSuccess(); + } + } +} diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/mqtt.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/mqtt.cpp Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,86 @@ +#include "mqtt.h" + +#include "config.h" +#include "fingerprint.h" +#include "wifi.h" + +namespace mqtt { +AsyncMqttClient mqttClient; +TimerHandle_t mqttReconnectTimer; +std::string pendingCmd = ""; + +void StopTimer() { + xTimerStop(mqttReconnectTimer, + 0); // ensure we don't reconnect to MQTT while reconnecting + // to Wi-Fi +} + +void Publish(std::string subtopic, std::string msg) { + std::string topic = "fingerprint/" + subtopic; + mqttClient.publish(topic.c_str(), 1, /*retain=*/false, msg.c_str()); +} + +void ConnectToMqtt() { + Serial.println("Connecting to MQTT..."); + mqttClient.connect(); +} + +void SendTemperature() { + float temp_c = temperatureRead(); + char buf[20]; + snprintf(buf, sizeof(buf), "%.3fC", temp_c); + mqttClient.publish("fingerprint/temperature", 1, /*retain=*/true, buf); +} +void onMqttConnect(bool sessionPresent) { + Serial.println("Connected to MQTT."); + Serial.print("Session present: "); + Serial.println(sessionPresent); + + mqttClient.subscribe("fingerprint/command", 1); + + SendTemperature(); + + mqttClient.setWill("fingerprint/status", 1, /*retain=*/true, "offline"); + mqttClient.publish("fingerprint/status", 1, /*retain=*/true, "online"); + + Serial.println("queuing a blink change"); + fingerprint::QueueBlinkConnected(); +} + +void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { + Serial.println("Disconnected from MQTT."); + fingerprint::BlinkNotConnected(); + + if (wifi::IsConnected()) { + xTimerStart(mqttReconnectTimer, 0); + } +} + +void onMqttMessage(char* topic, char* payload, + AsyncMqttClientMessageProperties properties, size_t len, + size_t index, size_t total) { + std::string cmd(payload, len); + pendingCmd = cmd; +} + +bool HasPendingCommand() { + return pendingCmd != ""; +} +std::string PopPendingCommand() { + std::string cmd = pendingCmd; + pendingCmd = ""; + return cmd; +} + +void Setup() { + mqttReconnectTimer = + xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, + reinterpret_cast(ConnectToMqtt)); + + mqttClient.onConnect(onMqttConnect); + mqttClient.onDisconnect(onMqttDisconnect); + mqttClient.onMessage(onMqttMessage); + mqttClient.setServer(MQTT_HOST, MQTT_PORT); +} + +} // namespace mqtt diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/mqtt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/mqtt.h Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,24 @@ +#ifndef INCLUDED_MQTT +#define INCLUDED_MQTT +#include + +#include + +// #include "esp_adc_cal.h" + +extern "C" { +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" +} + +namespace mqtt { + +void Setup(); +void Publish(std::string subtopic, std::string msg); +void StopTimer(); +void ConnectToMqtt(); +bool HasPendingCommand(); +std::string PopPendingCommand(); + +} // namespace mqtt +#endif \ No newline at end of file diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/wifi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/wifi.cpp Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,45 @@ +#include "wifi.h" + +#include "config.h" +#include "mqtt.h" +#include "fingerprint.h" + +namespace wifi { + +TimerHandle_t wifiReconnectTimer; +namespace { +void connectToWifi() { + Serial.println("Connecting to Wi-Fi..."); + fingerprint::BlinkNotConnected(); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +} +void WiFiEvent(WiFiEvent_t event) { + Serial.printf("[WiFi-event] event: %d\n", event); + switch (event) { + case SYSTEM_EVENT_STA_GOT_IP: + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + mqtt::ConnectToMqtt(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Serial.println("WiFi lost connection"); + mqtt::StopTimer(); + xTimerStart(wifiReconnectTimer, 0); + break; + default: + // ?? + break; + } +} +} // namespace +void Setup() { + wifiReconnectTimer = + xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, + reinterpret_cast(connectToWifi)); + + WiFi.onEvent(WiFiEvent); + connectToWifi(); +} +bool IsConnected() { return WiFi.isConnected(); } +} // namespace wifi \ No newline at end of file diff -r 729ab70c6212 -r 6c42c1f64f00 espNode/desk/src/wifi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/espNode/desk/src/wifi.h Mon Aug 24 01:27:33 2020 -0700 @@ -0,0 +1,14 @@ +#ifndef INCLUDED_WIFI +#define INCLUDED_WIFI + +#include "WiFi.h" +extern "C" { +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" +} + +namespace wifi { +void Setup(); +bool IsConnected(); +} // namespace wifi +#endif \ No newline at end of file