From c8cde2a06236774e1cace4ca17f9d9bca9b45d68 Mon Sep 17 00:00:00 2001 From: Cyril Danilevski <cyril.danilevski@xfel.eu> Date: Tue, 25 Feb 2025 16:56:05 +0100 Subject: [PATCH] Perform power down sequence from port expander interrupt --- icbm.ino | 13 +++-- pins.cpp | 138 ++++++++++++++++++++++++++++++++++++++------------ pins.hpp | 6 ++- powerproc.hpp | 2 + 4 files changed, 121 insertions(+), 38 deletions(-) diff --git a/icbm.ino b/icbm.ino index c43b3cf..cb83fd8 100644 --- a/icbm.ino +++ b/icbm.ino @@ -15,11 +15,13 @@ void setup() { initializeRoutes(); initializeSNMP(); - start = millis(); - + // Poll port expander to initialize the PINS struct. poll_port_expander(); + PINS.last_triggered = millis(); PINS.stage = ""; PINS.ramping = false; + + start = millis(); } enum { @@ -28,7 +30,7 @@ enum { OFF, }; -void serial_loop() { +void serialLoop() { if (millis() - start >= 1000) { start = millis(); Serial.print(eth_connected ? "." : "-"); @@ -40,5 +42,8 @@ void loop() { snmp.loop(); restServer.handleClient(); toggle_status_led(); - serial_loop(); + serialLoop(); + if (eth_connected) { // We may be triggered, but disconnected from the network. + powerOffCheckLoop(); + } } diff --git a/pins.cpp b/pins.cpp index c64146c..03a94cc 100644 --- a/pins.cpp +++ b/pins.cpp @@ -1,10 +1,16 @@ #include "pins.hpp" +#include "powerproc.hpp" + MCP23S08 MCP(SS, MISO, MOSI, SCK); -volatile byte ISR_FLAG = 0; + +// Semaphores for handling interrupts and power down events. +volatile byte MCP_ISR_FLAG = 0; +volatile byte PERFORM_PROCEDURE_FROM_INTERRUPT = 0; + struct pins PINS; -void IRAM_ATTR isr() { ISR_FLAG = 1; } +void IRAM_ATTR isr() { MCP_ISR_FLAG = 1; } void initializeMCP() { pinMode(ISR_PIN, INPUT_PULLUP); @@ -18,40 +24,54 @@ void initializeMCP() { MCP.enableInterrupt(0, CHANGE); MCP.enableInterrupt(1, CHANGE); MCP.enableInterrupt(2, CHANGE); + + // Inform SIB we're ready + MCP.write1(ALERT_SIB_PIN, HIGH); + 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, BIN); - - 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; + if (MCP_ISR_FLAG == 0) { + return; + } + // False means triggered (not ok). + PINS.sib = false; + PINS.plc = false; + PINS.ups = false; + PINS.last_triggered = millis(); + + // Get the pins status at the time of the interrupt, and check their statuses. + Serial.print("Interrupt: "); + uint8_t regval = MCP.getInterruptCaptureRegister(); // INTCAP + Serial.print(regval, BIN); + + 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(); + + // This interrupt was handled + MCP_ISR_FLAG = 0; + + // If not all ok, set the power down flag, later handled. + if (!(PINS.sib && PINS.plc && PINS.ups)) { + PERFORM_PROCEDURE_FROM_INTERRUPT = 1; } } @@ -59,7 +79,6 @@ void poll_port_expander() { PINS.sib = false; PINS.plc = false; PINS.ups = false; - PINS.last_triggered = millis(); int regval = MCP.read8(); uint8_t mask = 1 << 0; @@ -92,3 +111,56 @@ void toggle_status_led() { MCP.write1(STATUS_LED_PIN, on); } } + +void powerOffCheckLoop() { + if (!PERFORM_PROCEDURE_FROM_INTERRUPT) { + return; + } + // Disable interrupts while performing power procedure. + // Once we've been triggered, we perform the power down procedure, uninterrupted, + // regardless of changes in the environment. + detachInterrupt(digitalPinToInterrupt(ISR_PIN)); + + // Update status on serial interface and status webpage. + PINS.ramping = true; + Serial.println("POWERING DOWN DUE TO TRIGGER."); + + // Inform SIB that we're about to perform a procedure. + MCP.write1(ALERT_SIB_PIN, LOW); + Serial.println("asked sib down"); + + // Wait for SIB to acknowledge by checking its input (should go to triggered). + /* This require hardware changes, not implemented yet. + // TODO: apply a timeout and go ahead anyway? + do { + delay(200); + poll_port_expander(); + } while(!(PINS.sib)); + Serial.println("SIB ACK"); + */ + + // Iterate through each group and power down. + String group; + String groups; + for (int8_t groupIdx = pproc.stagesCount - 1; groupIdx >= 0; groupIdx--) { + group = pproc.stages[groupIdx].name; + groups += group; + groups += ","; + PINS.stage = group; + pproc.powerOff(group); + delay(1000); + } + + // Clear statuses on webpage and serial interfaces. + PINS.ramping = false; + Serial.print("Finished powering down from interrupt: "); + Serial.println(groups); + PINS.stage = "Ramped down"; + + // This event has been handled. + PERFORM_PROCEDURE_FROM_INTERRUPT = 0; + // Inform SIB that we're done and it can take data again. + MCP.write1(ALERT_SIB_PIN, HIGH); + // Re-enable interrupts before exiting. + attachInterrupt(digitalPinToInterrupt(ISR_PIN), isr, CHANGE); +} diff --git a/pins.hpp b/pins.hpp index 0cd10be..e1efb05 100644 --- a/pins.hpp +++ b/pins.hpp @@ -13,9 +13,12 @@ //AlCon Logic Board interrupt #define TRIGGER_SIGNAL 14 -// LED pin on MCP23S08 extender +// LED pin on MCP23S08 expander #define STATUS_LED_PIN 6 +// Pin to inform SIB that a power down is about to happen, on MCP23S08 expander +#define ALERT_SIB_PIN 7 + struct pins { bool sib; bool plc; @@ -32,3 +35,4 @@ void initializeMCP(); void isr_check_loop(); void poll_port_expander(); void toggle_status_led(); +void powerOffCheckLoop(); diff --git a/powerproc.hpp b/powerproc.hpp index 979df46..8e91b88 100644 --- a/powerproc.hpp +++ b/powerproc.hpp @@ -34,4 +34,6 @@ public: String toJSON(); }; +void powerOffCheckLoop(); + extern PowerProcedure pproc; -- GitLab