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