From c7f1d1d65169482759d8e427b0f68c50f53ffdfc Mon Sep 17 00:00:00 2001
From: Cyril Danilevski <cyril.danilevski@xfel.eu>
Date: Tue, 27 Aug 2024 18:16:26 +0200
Subject: [PATCH] Read pins from MCP23S08 port expander

---
 icbm.ino  |  4 +++
 panel.hpp | 38 +++++++++++------------
 pins.cpp  | 73 +++++++++++++++++++++++++++++++++++++++++++
 pins.hpp  | 31 +++++++++++++++++++
 rest.cpp  | 92 +++++++++++++++++++++++++++++++++----------------------
 5 files changed, 183 insertions(+), 55 deletions(-)
 create mode 100644 pins.cpp
 create mode 100644 pins.hpp

diff --git a/icbm.ino b/icbm.ino
index 885064f..1825fb0 100644
--- a/icbm.ino
+++ b/icbm.ino
@@ -1,6 +1,7 @@
 #include "esp32_ethernet.hpp"
 #include "rest.hpp"
 #include "mpod.hpp"
+#include "pins.hpp"
 
 
 unsigned long start;
@@ -10,6 +11,7 @@ extern SNMP::Manager snmp;
 void setup() {
     Serial.begin(115200);
 
+    initializeMCP();
     initializeNetwork();
     initializeRoutes();
     initializeSNMP();
@@ -33,7 +35,9 @@ void serial_loop() {
 }
 
 void loop() {
+    isr_check_loop();
     snmp.loop();
     restServer.handleClient();
+    toggle_status_led();
     serial_loop();
 }
diff --git a/panel.hpp b/panel.hpp
index 16c296b..ae6e2e0 100644
--- a/panel.hpp
+++ b/panel.hpp
@@ -1,13 +1,14 @@
-String buildPanel(bool plc, bool iob, bool ups) {
+String buildPanel(bool sib, bool plc, bool ups, unsigned long elapsed_secs) {
+    // Shows OK if not triggered (ie bool == false)
     String page = "<!DOCTYPE html><html lang=\"en\">\n";
-    page += "<head><meta name=\"viewport\" page=\"width=device-width, initial-scale=1.0\">\n";
-    page += "<meta http-equiv=\"refresh\" page=\"1\"/>\n";
+    page += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
+    page += "<meta http-equiv=\"refresh\" content=\"1\"/>\n";
     page += "<title>ICBM</title>\n";
     page += "<style>\n";
-    page += "body {font-family: Arial, sans-serif; display: flex; justify-page: center; align-items: center; height: 100vh; margin: 0; background-color: #f0f0f0;}\n";
+    page += "body {font-family: Arial, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: #f0f0f0;}\n";
     page += ".container {background-color: white; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1);}\n";
     page += "h1 {text-align: center; color: #333;}\n";
-    page += ".status-item {margin: 15px 0; padding: 10px; border-radius: 5px; display: flex; justify-page: space-between; align-items: center;}\n";
+    page += ".status-item {margin: 15px 0; padding: 10px; border-radius: 5px; display: flex; justify-content: space-between; align-items: center;}\n";
     page += ".status-label {font-weight: bold; margin-right: 10px;}\n";
     page += ".status-value {padding: 5px 10px; border-radius: 20px; color: white; font-weight: bold;}\n";
     page += ".status-ok { background-color: #4CAF50; }\n";
@@ -16,28 +17,27 @@ String buildPanel(bool plc, bool iob, bool ups) {
     page += "</style>";
     page += "</head><body>\n";
     page += "<div class=\"container\"><h1>INPUTS:</h1>\n";
+
     page += "<div class=\"status-item\">\n";
-    page += "<span class=\"status-label\">PLC:</span>";
-    
-    if (plc) { page += "<span class=\"status-value status-error\">Triggered</span>\n"; }
+    page += "<span class=\"status-label\">SIB:</span>\n";
+    if (!sib) { page += "<span class=\"status-value status-error\">Triggered</span>\n"; }
     else { page += "<span class=\"status-value status-ok\">OK</span>\n"; }
+    page += "</div>\n";
     
-    page += "</div><div class=\"status-item\">\n";
-    page += "<span class=\"status-label\">IOB:</span>\n";
-    
-    if (iob) { page += "<span class=\"status-value status-error\">Triggered</span>\n"; }
+    page += "<div class=\"status-item\">\n";
+    page += "<span class=\"status-label\">PLC:</span>";
+    if (!plc) { page += "<span class=\"status-value status-error\">Triggered</span>\n"; }
     else { page += "<span class=\"status-value status-ok\">OK</span>\n"; }
+    page += "</div>\n";
     
-    page += "</div><div class=\"status-item\">\n";
+    page += "<div class=\"status-item\">\n";
     page += "<span class=\"status-label\">UPS:</span>\n";
-    
-    if (ups) { page += "<span class=\"status-value status-error\">Triggered</span>\n"; }
+    if (!ups) { page += "<span class=\"status-value status-error\">Triggered</span>\n"; }
     else { page += "<span class=\"status-value status-ok\">OK</span>\n"; }
+    page += "</div>\n";
     
-    page += "</div><h3>Last INT: ";
-    
-    page += "5";
-    
+    page += "<h3>Last INT: ";
+    page += elapsed_secs;
     page += "</h3></div></body></html>";
     
     return page;
diff --git a/pins.cpp b/pins.cpp
new file mode 100644
index 0000000..d307577
--- /dev/null
+++ b/pins.cpp
@@ -0,0 +1,73 @@
+#include "pins.hpp"
+
+MCP23S08 MCP(SS, MISO, MOSI, SCK);
+volatile byte ISR_FLAG = 0;
+struct pins PINS;
+
+void IRAM_ATTR isr(){
+  ISR_FLAG = 1;
+}
+
+void initializeMCP()
+{
+  pinMode(ISR_PIN, INPUT_PULLUP);
+  //attachInterrupt(digitalPinToInterrupt(ISR_PIN), isr, CHANGE);
+  attachInterrupt(digitalPinToInterrupt(TRIGGER_SIGNAL), isr, CHANGE);
+
+  SPI.begin();
+  MCP.begin();
+
+  // Enable inputs and interrupts on pins 0-2
+  MCP.pinMode8(0b00000111);
+  MCP.enableInterrupt(0, FALLING);
+  MCP.enableInterrupt(1, FALLING);
+  MCP.enableInterrupt(2, FALLING);
+  Serial.println("MCP23S08 Started");
+
+}
+
+
+void isr_check_loop()
+{
+  if (ISR_FLAG == 1){
+    PINS.sib = false;
+    PINS.plc = false;
+    PINS.ups = false;
+    PINS.last_triggered = millis();
+
+    Serial.print("Interrupt: ");
+    uint8_t regval = MCP.getInterruptCaptureRegister();  //INTCAP
+    Serial.print(regval);
+
+    uint8_t mask = 1 << 0;
+    if (!(regval & mask)) {
+      Serial.print("UPS");
+      PINS.ups = true;
+    }
+
+    mask = 1 << 1;
+    if (!(regval & mask)) {
+      Serial.print("PLC");
+      PINS.plc = true;
+    }
+
+    mask = 1 << 2;
+    if (!(regval & mask)) {
+      Serial.print("SIB");
+      PINS.sib = true;
+    }
+
+    Serial.println();
+    ISR_FLAG = 0;
+  }
+}
+
+bool on = true;
+unsigned long toggle_start = 0;
+void toggle_status_led() {
+    if (millis() - toggle_start  >= 1000) {
+        toggle_start = millis();
+    	on = !on;
+    	MCP.write1(STATUS_LED_PIN, on);
+     }
+}
diff --git a/pins.hpp b/pins.hpp
new file mode 100644
index 0000000..a628949
--- /dev/null
+++ b/pins.hpp
@@ -0,0 +1,31 @@
+#pragma once
+#include "MCP23S08.h"
+
+// Software SPI definitions
+#define MOSI 13
+#define MISO 12
+#define SS 2
+#define SCK 4
+
+// MCP23S08 interrupt
+#define ISR_PIN 15
+
+//AlCon Logic Board interrupt
+#define TRIGGER_SIGNAL 14
+
+// LED pin on MCP23S08 extender
+#define STATUS_LED_PIN 6
+
+struct pins {
+   bool sib;
+   bool plc;
+   bool ups;
+   int last_triggered;
+};
+extern struct pins PINS;
+
+extern MCP23S08 MCP;
+void IRAM_ATTR isr();
+void initializeMCP();
+void isr_check_loop();
+void toggle_status_led();
diff --git a/rest.cpp b/rest.cpp
index 407d1d8..e990fad 100644
--- a/rest.cpp
+++ b/rest.cpp
@@ -1,6 +1,7 @@
 #include "rest.hpp"
 #include "mpod.hpp"
 #include "panel.hpp"
+#include "pins.hpp"
 #include <ETH.h>
 
 #ifndef ICBM_GIT_VERSION
@@ -18,7 +19,7 @@ void initializeRoutes() {
     restServer.on("/restart", restart);
     restServer.onNotFound(notFound);
     restServer.on("/send", sendSNMP);
-    restServer.on("/poll", panel);
+    restServer.on("/", panel);
 
     restServer.begin();
     Serial.println("REST Server Started");
@@ -26,51 +27,70 @@ void initializeRoutes() {
 
 
 void identify() {
-	int seconds = millis() / 1000;
-	int hours = seconds / 3600;
-	int minutes = (seconds / 60) % 60;
-	seconds = seconds % 60;
-
-	String message = "{\n";
-
-	message += "\"mac\":\"";
-	message += ETH.macAddress();
-	message += "\",\n";
-
-	message += "\"version\":\"";
-	message += ICBM_GIT_VERSION;
-	message += "\",\n";
-
-	message += "\"build date\":\"";
-	message += ICBM_GIT_TIMESTAMP;
-	message += "\",\n";
-
-	message += "\"uptime\": \"";
-	message += hours;
-	message += ":";
-	message += minutes;
-	message += ":";
-	message += seconds;
-	message += "\"";
-
-    // TODO: Add here mcp23s08 info:
-    // Pin status;
-    // Interrupt status;
-    // seconds since last interrupt.
-    //
+    int seconds = millis() / 1000;
+    int hours = seconds / 3600;
+    int minutes = (seconds / 60) % 60;
+    seconds = seconds % 60;
+
+    String message = "{\n";
+
+    message += "\"mac\":\"";
+    message += ETH.macAddress();
+    message += "\",\n";
+
+    message += "\"version\":\"";
+    message += ICBM_GIT_VERSION;
+    message += "\",\n";
+
+    message += "\"build date\":\"";
+    message += ICBM_GIT_TIMESTAMP;
+    message += "\",\n";
+
+    message += "\"uptime\": \"";
+    message += hours;
+    message += ":";
+    message += minutes;
+    message += ":";
+    message += seconds;
+    message += "\",\n";
+
+    message += "\"inputs\":{\n";
+    message += "\"sib\":";
+    message += PINS.sib;
+    message += ",\n";
+
+    message += "\"plc\":";
+    message += PINS.plc;
+    message += ",\n";
+
+    message += "\"ups\":";
+    message += PINS.ups;
+    message += ",\n";
+
+    unsigned long elapsed_seconds = (millis() - PINS.last_triggered) / 1000;
+    message += "\"sec_since_interrupt\":";
+    message += elapsed_seconds;
+    message += ",\n";
+    message += "\n}";
+
     // TODO: Add here power sequence status
     // is_ramping_down
     // current step
     // percentage
 
-	message += "\n}";
+    message += "\n}";
 
     restServer.send(200, "text/json", message);
 }
 
-
 void panel() {
-    String content = buildPanel(true, true, true);
+    unsigned long elapsed_seconds = (millis() - PINS.last_triggered) / 1000;
+    String content = buildPanel(
+        PINS.sib,
+        PINS.plc,
+        PINS.ups,
+        elapsed_seconds
+    );
     restServer.send(200, "text/html", content);
 }
 
-- 
GitLab