Mercurial > code > home > repos > homeauto
view espNode/desk/src/fingerprint.cpp @ 783:e4cf795d3677
support download/set/delete, but somehow enroll has broken
author | drewp@bigasterisk.com |
---|---|
date | Wed, 26 Aug 2020 03:06:07 -0700 |
parents | 6c42c1f64f00 |
children | 415d7853ad45 |
line wrap: on
line source
#include "fingerprint.h" #include <string> #include <vector> #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) { 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; case FPM_UPLOADFAIL: errStr = "Cannot transfer the image"; break; case FPM_DBREADFAIL: errStr = "Invalid model"; 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::HasPendingMessage() || 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) { mqtt::Publish("messages", "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(); } } // a GetImage image must be in the buffer to get the real bitmap image void DownloadLastImage() { mqtt::Publish("messages", "Starting image stream"); finger.downImage(); std::vector<char> image(256 * 288 / 2); size_t image_pos = 0; bool read_complete = false; uint16_t read_len; while (true) { read_len = image.size() - image_pos; if (!finger.readRaw(FPM_OUTPUT_TO_BUFFER, image.data() + image_pos, &read_complete, &read_len)) { mqtt::Publish("messages", "readRaw: failed"); return; } image_pos += read_len; if (read_complete) { break; } } size_t image_len = image_pos; char buf[100]; snprintf(buf, sizeof(buf), "got %d bytes to download", image_len); mqtt::Publish("messages", buf); std::string msg(image.data(), image_len); char subtopic[50]; snprintf(subtopic, sizeof(subtopic), "image/%d", -1); mqtt::Publish(subtopic, msg); } void DownloadModel(uint16_t fid) { int p = -1; mqtt::Publish("messages", "retrieve model for download"); p = finger.loadModel(fid); if (p != FPM_OK) { PublishError("loadModel", p); return; } p = finger.downloadModel(fid); if (p != FPM_OK) { PublishError("downloadModel", p); return; } byte model[2048]; // expect 1536 bytes size_t model_pos = 0; bool read_complete = false; uint16_t read_len; while (true) { read_len = sizeof(model) - model_pos; if (!finger.readRaw(FPM_OUTPUT_TO_BUFFER, model + model_pos, &read_complete, &read_len)) { mqtt::Publish("messages", "readRaw: failed"); return; } model_pos += read_len; if (read_complete) { break; } } size_t model_len = model_pos; char buf[100]; snprintf(buf, sizeof(buf), "got %d bytes to download", model_len); mqtt::Publish("messages", buf); std::string msg(reinterpret_cast<char*>(model), model_len); char subtopic[50]; snprintf(subtopic, sizeof(subtopic), "model/%d", fid); mqtt::Publish(subtopic, msg); } void SetModel(uint16_t fid, const std::vector<uint8_t>& payload) { int16_t p = -1; mqtt::Publish("messages", "upload buffer to slot 1"); p = finger.uploadModel(); if (p != FPM_OK) { PublishError("uploadModel", p); return; } yield(); finger.writeRaw(const_cast<uint8_t*>(payload.data()), payload.size()); delay( 100); // load-bearing sleep. Without this, the storeModel doesn't answer. mqtt::Publish("messages", "store model from slot 1 to fid"); p = finger.storeModel(fid); if (p != FPM_OK) { PublishError("storeModel", p); return; } mqtt::Publish("messages", "SetModel successful"); } void DeleteModel(uint16_t fid) { int16_t p = finger.deleteModel(fid); if (p == FPM_OK) { char msg[100]; snprintf(msg, sizeof(msg), "deleted id %d", fid); mqtt::Publish("messages", msg); } else { PublishError("deleteModel", p); } } 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