Mercurial > code > home > repos > homeauto
changeset 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 | 01005d533e0a |
children | 415d7853ad45 |
files | espNode/desk/src/fingerprint.cpp espNode/desk/src/fingerprint.h espNode/desk/src/main.cpp espNode/desk/src/mqtt.cpp espNode/desk/src/mqtt.h |
diffstat | 5 files changed, 201 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/espNode/desk/src/fingerprint.cpp Mon Aug 24 01:35:28 2020 -0700 +++ b/espNode/desk/src/fingerprint.cpp Wed Aug 26 03:06:07 2020 -0700 @@ -1,6 +1,7 @@ #include "fingerprint.h" #include <string> +#include <vector> #include "mqtt.h" @@ -51,7 +52,6 @@ void QueueBlinkConnected() { queued = BlinkConnected; } void ExecuteAnyQueued() { if (queued) { - Serial.println("executing queued function"); queued(); queued = nullptr; } @@ -93,6 +93,12 @@ 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); @@ -112,7 +118,7 @@ if (p == FPM_OK) { mqtt::Publish("messages", "getImage: Image taken"); } else if (p == FPM_NOFINGER) { - if (mqtt::HasPendingCommand() || queued) { + if (mqtt::HasPendingMessage() || queued) { return false; } } else { @@ -269,11 +275,9 @@ void DeleteFingerprint(uint16_t fid) { int p = -1; - p = finger.deleteModel(fid); - if (p == FPM_OK) { - Serial.println("Deleted!"); + mqtt::Publish("messages", "Deleted"); } else { PublishError("deleteModel", p); } @@ -292,7 +296,114 @@ } } -void DownloadPrintImage(uint16_t fid) {} +// 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() {
--- a/espNode/desk/src/fingerprint.h Mon Aug 24 01:35:28 2020 -0700 +++ b/espNode/desk/src/fingerprint.h Wed Aug 26 03:06:07 2020 -0700 @@ -3,18 +3,24 @@ #include <FPM.h> #include <HardwareSerial.h> +#include <vector> + namespace fingerprint { void Setup(); void ExecuteAnyQueued(); void BlinkProgress(); void BlinkNotConnected(); void BlinkConnected(); -void QueueBlinkConnected(); // for inside an ISR +void QueueBlinkConnected(); // for inside an ISR void BlinkSuccess(); void BlinkClearSuccess(); void ScanLoop(); void Enroll(); -void DownloadPrintImage(uint16_t fid); +void DownloadLastImage(); +void DownloadModel(uint16_t fid); void DeleteAll(); -} +void DeleteModel(uint16_t fid); +void SetModel(uint16_t fid, const std::vector<uint8_t>& payload); + +} // namespace fingerprint #endif \ No newline at end of file
--- a/espNode/desk/src/main.cpp Mon Aug 24 01:35:28 2020 -0700 +++ b/espNode/desk/src/main.cpp Wed Aug 26 03:06:07 2020 -0700 @@ -1,5 +1,7 @@ #include <Arduino.h> +#include <string> + #include "display.h" #include "fingerprint.h" #include "mqtt.h" @@ -23,20 +25,47 @@ mqtt::Setup(); } +namespace { +uint16_t LastComponentNumber(const std::string &s) { + return atoi(s.substr(s.rfind("/") + 1).c_str()); +} +} // namespace + 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(); + + if (mqtt::HasPendingMessage()) { + std::pair<std::string, std::vector<byte>> msg = mqtt::PopPendingMessage(); + const std::string &topic = msg.first; + const std::vector<byte> &payload = msg.second; + const std::string payload_string(payload.begin(), payload.end()); + + if (topic == "fingerprint/command") { + if (payload_string == "enroll") { + fingerprint::Enroll(); + } else if (payload_string == "show_success") { + fingerprint::BlinkSuccess(); + while (!mqtt::HasPendingMessage()) yield(); + mqtt::PopPendingMessage(); + // hope it's "clear_success", but who cares + fingerprint::BlinkClearSuccess(); + } else if (payload_string == "delete_all") { + fingerprint::DeleteAll(); + } else if (payload_string.rfind("delete/model/", 0) == 0) { + uint16_t fid = LastComponentNumber(payload_string); + fingerprint::DeleteModel(fid); + } else if (payload_string.rfind("download/model/", 0) == 0) { + uint16_t fid = LastComponentNumber(payload_string); + fingerprint::DownloadModel(fid); + } + } else if (topic.rfind("fingerprint/set/model/", 0) == 0) { + uint16_t fid = LastComponentNumber(topic); + + fingerprint::SetModel(fid, payload); } } }
--- a/espNode/desk/src/mqtt.cpp Mon Aug 24 01:35:28 2020 -0700 +++ b/espNode/desk/src/mqtt.cpp Wed Aug 26 03:06:07 2020 -0700 @@ -7,7 +7,15 @@ namespace mqtt { AsyncMqttClient mqttClient; TimerHandle_t mqttReconnectTimer; -std::string pendingCmd = ""; + +#define MAX_INCOMING_PAYLOAD 1536 +class IncomingMessage { + public: + bool complete; + std::string topic; + std::vector<byte> payload; +}; +IncomingMessage incomingMessage; void StopTimer() { xTimerStop(mqttReconnectTimer, @@ -17,7 +25,9 @@ void Publish(std::string subtopic, std::string msg) { std::string topic = "fingerprint/" + subtopic; - mqttClient.publish(topic.c_str(), 1, /*retain=*/false, msg.c_str()); + mqttClient.publish(topic.c_str(), 1, /*retain=*/false, msg.data(), + msg.size()); + // yield(); } void ConnectToMqtt() { @@ -37,12 +47,13 @@ Serial.println(sessionPresent); mqttClient.subscribe("fingerprint/command", 1); + mqttClient.subscribe("fingerprint/set/#", 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(); } @@ -59,17 +70,28 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { - std::string cmd(payload, len); - pendingCmd = cmd; + if (index == 0) { + incomingMessage.complete = false; + incomingMessage.topic = std::string(topic); + incomingMessage.payload.clear(); + } + + for (int i = 0; i < len; i++) { + incomingMessage.payload.push_back(payload[i]); + } + + if (index + len == total) { + incomingMessage.complete = true; + } } -bool HasPendingCommand() { - return pendingCmd != ""; -} -std::string PopPendingCommand() { - std::string cmd = pendingCmd; - pendingCmd = ""; - return cmd; +// Don't do command right away; wait for main loop to ask for it. +bool HasPendingMessage() { return incomingMessage.complete; } +std::pair<std::string, std::vector<byte>> PopPendingMessage() { + std::pair<std::string, std::vector<byte>> ret{incomingMessage.topic, + incomingMessage.payload}; + incomingMessage.complete = false; + return ret; } void Setup() {
--- a/espNode/desk/src/mqtt.h Mon Aug 24 01:35:28 2020 -0700 +++ b/espNode/desk/src/mqtt.h Wed Aug 26 03:06:07 2020 -0700 @@ -17,8 +17,8 @@ void Publish(std::string subtopic, std::string msg); void StopTimer(); void ConnectToMqtt(); -bool HasPendingCommand(); -std::string PopPendingCommand(); +bool HasPendingMessage(); +std::pair<std::string /*topic*/, std::vector<byte> /*payload*/> PopPendingMessage(); } // namespace mqtt #endif \ No newline at end of file