From 8fa85fdc258741151217b45e3447fb0d085f3d22 Mon Sep 17 00:00:00 2001 From: Cyril Danilevski <cyril.danilevski@xfel.eu> Date: Thu, 13 Feb 2025 12:46:40 +0100 Subject: [PATCH 1/6] Set all DSSC2 M1 channels --- powerproc.cpp | 22 +++++++++++++--------- powerproc.hpp | 2 +- rest.cpp | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/powerproc.cpp b/powerproc.cpp index 51d1ab6..231419f 100644 --- a/powerproc.cpp +++ b/powerproc.cpp @@ -6,17 +6,21 @@ PowerProcedure::PowerProcedure(const IPAddress& ipAddr) : ipAddr(ipAddr), stagesCount(STAGESCOUNT), currentStage(""), currentChannel(-1) { stages = new Stage[stagesCount]; - stages[0].name = "ASICS"; - stages[0].size = 9; - stages[0].channels = new int[stages[0].size]{508, 708, 502, 503, 504, 501, 507, 607, 608}; + stages[0].name = "AON"; + stages[0].size = 1; + stages[0].channels = new int[stages[0].size]{604}; - stages[1].name = "HV"; - stages[1].size = 10; - stages[1].channels = new int[stages[1].size]{1, 2, 101, 103, 102, 104, 105, 106, 107, 108}; + stages[1].name = "ASICS"; + stages[1].size = 9; + stages[1].channels = new int[stages[1].size]{508, 708, 502, 503, 504, 501, 507, 607, 608}; - stages[2].name = "PLCSOURCE"; - stages[2].size = 9; - stages[2].channels = new int[stages[2].size]{701, 801, 802, 803, 804, 301, 302, 303, 304}; + stages[2].name = "HV"; + stages[2].size = 10; + stages[2].channels = new int[stages[2].size]{1, 2, 101, 103, 102, 104, 105, 106, 107, 108}; + + stages[3].name = "PLCSOURCE"; + stages[3].size = 9; + stages[3].channels = new int[stages[3].size]{701, 801, 802, 803, 804, 301, 302, 303, 304}; } PowerProcedure::~PowerProcedure() { diff --git a/powerproc.hpp b/powerproc.hpp index e95939f..859f00b 100644 --- a/powerproc.hpp +++ b/powerproc.hpp @@ -1,7 +1,7 @@ #pragma once #include <Arduino.h> -#define STAGESCOUNT 3 +#define STAGESCOUNT 4 class PowerProcedure { private: diff --git a/rest.cpp b/rest.cpp index cb439c4..3ecbbd0 100644 --- a/rest.cpp +++ b/rest.cpp @@ -231,7 +231,7 @@ void powerAllOff() { } if (success) { - for (uint8_t groupIdx = pproc.stagesCount; groupIdx >= 0; groupIdx--) { + for (uint8_t groupIdx = pproc.stagesCount - 1; groupIdx >= 0; groupIdx--) { group = pproc.stages[groupIdx].name; groups += group; groups += ","; -- GitLab From 557475ec6a65eab6c08903f0b1e180b0a30e22f1 Mon Sep 17 00:00:00 2001 From: Cyril Danilevski <cyril.danilevski@xfel.eu> Date: Thu, 13 Feb 2025 12:48:00 +0100 Subject: [PATCH 2/6] Make use of PowerProcedure define IP adress --- rest.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/rest.cpp b/rest.cpp index 3ecbbd0..49cdf41 100644 --- a/rest.cpp +++ b/rest.cpp @@ -148,7 +148,7 @@ void sendSNMP() { } } - auto ipAddr = IPAddress(192, 168, 140, 79); + auto ipAddr = pproc.ipAddr; if (output != NONE && channel != 0) { setChannelAndWait(&ipAddr, channel, output); @@ -243,13 +243,12 @@ void powerAllOff() { } String http_msg = "{\n"; - http_msg += "\"arguments\":{"; http_msg += "\"groups\":\"" + groups + "\","; http_msg += "\"success\":" + String(success); - if (success) { - http_msg += ",\n\"status\":\n"; - http_msg += pproc.toJSON(); - } + // if (success) { + // http_msg += ",\n\"status\":\n"; + // http_msg += pproc.toJSON(); + // } http_msg += "\n}"; restServer.send(success ? 200 : 406, "text/json", http_msg); @@ -267,9 +266,8 @@ void pollMPODChannel() { if (!channel) { ret = "\"reason\": \"Invalid channel\""; } else { - auto ipAddr = IPAddress(192, 168, 140, 79); SNMP::Message *snmp_msg = mpod.read(channel); - snmp.send(snmp_msg, ipAddr, SNMP::Port::SNMP); + snmp.send(snmp_msg, pproc.ipAddr, SNMP::Port::SNMP); delete snmp_msg; delay(MPOD_UPDATE_LATENCY); -- GitLab From 7bc009431daadd337ce34f1df8aec7170759f1ec Mon Sep 17 00:00:00 2001 From: Cyril Danilevski <cyril.danilevski@xfel.eu> Date: Thu, 13 Feb 2025 13:22:40 +0100 Subject: [PATCH 3/6] Specify all auto-on channels --- powerproc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerproc.cpp b/powerproc.cpp index 231419f..e74432a 100644 --- a/powerproc.cpp +++ b/powerproc.cpp @@ -7,8 +7,8 @@ PowerProcedure::PowerProcedure(const IPAddress& ipAddr) stages = new Stage[stagesCount]; stages[0].name = "AON"; - stages[0].size = 1; - stages[0].channels = new int[stages[0].size]{604}; + stages[0].size = 4; + stages[0].channels = new int[stages[0].size]{604, 705, 706, 707}; stages[1].name = "ASICS"; stages[1].size = 9; -- GitLab From 0287dd2008bd9ba06c45d06a1c5fd7584202d22a Mon Sep 17 00:00:00 2001 From: Cyril Danilevski <cyril.danilevski@xfel.eu> Date: Thu, 13 Feb 2025 14:38:17 +0100 Subject: [PATCH 4/6] Add ramp status to panel and idn endpoints --- icbm.ino | 2 ++ mpod.cpp | 2 +- panel.hpp | 17 ++++++++++++++--- pins.hpp | 2 ++ powerproc.hpp | 2 ++ rest.cpp | 16 ++++++++++++++-- 6 files changed, 35 insertions(+), 6 deletions(-) diff --git a/icbm.ino b/icbm.ino index 4b1580e..c43b3cf 100644 --- a/icbm.ino +++ b/icbm.ino @@ -18,6 +18,8 @@ void setup() { start = millis(); poll_port_expander(); + PINS.stage = ""; + PINS.ramping = false; } enum { diff --git a/mpod.cpp b/mpod.cpp index ff68d80..04c602f 100644 --- a/mpod.cpp +++ b/mpod.cpp @@ -34,7 +34,7 @@ SNMP::Message *MPOD::read(uint16_t channel) { return message; } -// Create an SNMP SETREQUEST message to switch on or off the MPOD +// Create an SNMP SETREQUEST message to switch on or off the specified channel SNMP::Message *MPOD::output(const uint16_t channel, const bool on) { SNMP::Message *message = new SNMP::Message(SNMP::Version::V2C, "guru", SNMP::Type::SetRequest); // In SETREQUEST, use node type and set the value. diff --git a/panel.hpp b/panel.hpp index 1d62bda..884ba68 100644 --- a/panel.hpp +++ b/panel.hpp @@ -1,4 +1,4 @@ -String buildPanel(bool sib, bool plc, bool ups, unsigned long elapsed_secs) { +String buildPanel(const bool sib, const bool plc, const bool ups, const unsigned long elapsed_secs, const String& status, const bool ramping) { // Shows OK if not triggered (ie bool == false) String page = "<!DOCTYPE html><html lang=\"en\">\n"; page += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"; @@ -38,8 +38,19 @@ String buildPanel(bool sib, bool plc, bool ups, unsigned long elapsed_secs) { page += "<h3>Last Interrupt: "; page += elapsed_secs; - page += " secs. ago"; - page += "</h3></div></body></html>"; + page += " secs. ago<h3>"; + + page += "<h3>Status: "; + page += status; + page += "</h3>"; + + page += "<div class=\"status-item\">\n"; + page += "<span class=\"status-label\">Ramping:</span>\n"; + if (ramping) { page += "<span class=\"status-value status-error\">Powering Down</span>\n"; } + else { page += "<span class=\"status-value status-ok\">Idle</span>\n"; } + page += "</div>\n"; + + page += "</div></body></html>"; return page; } diff --git a/pins.hpp b/pins.hpp index e07afbf..0cd10be 100644 --- a/pins.hpp +++ b/pins.hpp @@ -21,6 +21,8 @@ struct pins { bool plc; bool ups; int last_triggered; + String stage; + bool ramping; }; extern struct pins PINS; diff --git a/powerproc.hpp b/powerproc.hpp index 859f00b..5f0236f 100644 --- a/powerproc.hpp +++ b/powerproc.hpp @@ -1,6 +1,8 @@ #pragma once #include <Arduino.h> +#include "pins.hpp" + #define STAGESCOUNT 4 class PowerProcedure { diff --git a/rest.cpp b/rest.cpp index 49cdf41..8a5a577 100644 --- a/rest.cpp +++ b/rest.cpp @@ -76,12 +76,20 @@ void identify() { 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 += "\"status\":{\n"; + message += "\"ramping\":"; + message += PINS.ramping; + message += ",\n"; + message += "\"stage\":"; + message += PINS.stage; + message += ",\n"; + message += "\n}"; message += "\n}"; @@ -90,7 +98,8 @@ void identify() { void panel() { unsigned long elapsed_seconds = (millis() - PINS.last_triggered) / 1000; - String content = buildPanel(PINS.sib, PINS.plc, PINS.ups, elapsed_seconds); + String content = + buildPanel(PINS.sib, PINS.plc, PINS.ups, elapsed_seconds, PINS.stage, PINS.ramping); restServer.send(200, "text/html", content); } @@ -231,15 +240,18 @@ void powerAllOff() { } if (success) { + PINS.ramping = true; for (uint8_t groupIdx = pproc.stagesCount - 1; groupIdx >= 0; groupIdx--) { group = pproc.stages[groupIdx].name; groups += group; groups += ","; + PINS.stage = group; success = pproc.powerOff(group); if (!success) { break; } } + PINS.ramping = false; } String http_msg = "{\n"; -- GitLab From 4f3c386d1d733873fd13d9762093792c463e8307 Mon Sep 17 00:00:00 2001 From: Cyril Danilevski <cyril.danilevski@xfel.eu> Date: Fri, 14 Feb 2025 18:19:05 +0100 Subject: [PATCH 5/6] Add channel target voltage set in power procedure --- mpod.cpp | 40 +++++++++++++++++++++++++++++++++++++--- mpod.hpp | 6 ++++-- powerproc.cpp | 49 ++++++++++++++++++++++++++++++++++++------------- powerproc.hpp | 8 +++++++- rest.cpp | 2 +- 5 files changed, 85 insertions(+), 20 deletions(-) diff --git a/mpod.cpp b/mpod.cpp index 04c602f..61940bb 100644 --- a/mpod.cpp +++ b/mpod.cpp @@ -35,7 +35,7 @@ SNMP::Message *MPOD::read(uint16_t channel) { } // Create an SNMP SETREQUEST message to switch on or off the specified channel -SNMP::Message *MPOD::output(const uint16_t channel, const bool on) { +SNMP::Message *MPOD::setChannelState(const uint16_t channel, const bool on) { SNMP::Message *message = new SNMP::Message(SNMP::Version::V2C, "guru", SNMP::Type::SetRequest); // In SETREQUEST, use node type and set the value. // OUTPUT SWITCH, integer type, 0 is OFF and 1 is ON. @@ -45,6 +45,17 @@ SNMP::Message *MPOD::output(const uint16_t channel, const bool on) { return message; } +// Create an SNMP SETREQUEST message to set the channel voltage +SNMP::Message *MPOD::setTargetVoltage(const uint16_t channel, const float targetVoltage) { + SNMP::Message *message = new SNMP::Message(SNMP::Version::V2C, "guru", SNMP::Type::SetRequest); + // In SETREQUEST, use node type and set the value. + // OUTPUT VOLTAGE, float type. + String snmp_cmd = OID::NAMES[OID::OUTPUTVOLTAGE]; + snmp_cmd += channel; + message->add(snmp_cmd.c_str(), new OpaqueBER(new OpaqueFloatBER(targetVoltage))); + return message; +} + // Parse incoming message bool MPOD::message(const SNMP::Message *message) { unsigned int found = 0; @@ -194,9 +205,9 @@ void initializeSNMP() { /* setChannelAndWait * Set a channel's parameters and wait until it's settled. */ -void setChannelAndWait(const IPAddress *ipAddr, const uint16_t channel, const uint8_t output) { +void setChannelStateAndWait(const IPAddress *ipAddr, const uint16_t channel, const uint8_t output) { // Send set command - SNMP::Message *snmp_msg = mpod.output(channel, output); + SNMP::Message *snmp_msg = mpod.setChannelState(channel, output); snmp.send(snmp_msg, *ipAddr, SNMP::Port::SNMP); delete snmp_msg; @@ -213,3 +224,26 @@ void setChannelAndWait(const IPAddress *ipAddr, const uint16_t channel, const ui snmp.loop(); } while (mpod.isOn() != (bool)output || mpod.isRampingDown() || mpod.isRampingUp()); } + +void setChannelVoltageAndWait(const IPAddress *ipAddr, const uint16_t channel, + const float targetVoltage) { + // Send set command + SNMP::Message *snmp_msg = mpod.setTargetVoltage(channel, targetVoltage); + + snmp.send(snmp_msg, *ipAddr, SNMP::Port::SNMP); + delete snmp_msg; + + // wait for channel reply + delay(MPOD_UPDATE_LATENCY); + snmp.loop(); + + // Poll channel until it's settled + do { + SNMP::Message *snmp_msg = mpod.read(channel); + snmp.send(snmp_msg, *ipAddr, SNMP::Port::SNMP); + delete snmp_msg; + delay(MPOD_UPDATE_LATENCY); + snmp.loop(); + } while (mpod.isRampingDown() || + mpod.isRampingUp()); // TODO check applied voltage close to target voltage +} diff --git a/mpod.hpp b/mpod.hpp index 03c4a4c..639d993 100644 --- a/mpod.hpp +++ b/mpod.hpp @@ -62,7 +62,8 @@ class MPOD { // Create an SNMP SETREQUEST message to setup MPOD MPOD(); SNMP::Message* read(const uint16_t); - SNMP::Message* output(const uint16_t, const bool); + SNMP::Message* setChannelState(const uint16_t, const bool); + SNMP::Message* setTargetVoltage(const uint16_t, const float); bool message(const SNMP::Message*); bool isOn() const; bool isRampingUp() const; @@ -95,5 +96,6 @@ extern MPOD mpod; // Event handler to process SNMP messages void onSNMPMessage(const SNMP::Message *message, const IPAddress remote, const uint16_t port); void initializeSNMP(); -void setChannelAndWait(const IPAddress*, uint16_t, uint8_t); +void setChannelStateAndWait(const IPAddress*, const uint16_t, const uint8_t); +void setChannelVoltageAndWait(const IPAddress*, const uint16_t, const float); diff --git a/powerproc.cpp b/powerproc.cpp index e74432a..3264c4c 100644 --- a/powerproc.cpp +++ b/powerproc.cpp @@ -6,19 +6,25 @@ PowerProcedure::PowerProcedure(const IPAddress& ipAddr) : ipAddr(ipAddr), stagesCount(STAGESCOUNT), currentStage(""), currentChannel(-1) { stages = new Stage[stagesCount]; - stages[0].name = "AON"; - stages[0].size = 4; - stages[0].channels = new int[stages[0].size]{604, 705, 706, 707}; - - stages[1].name = "ASICS"; - stages[1].size = 9; - stages[1].channels = new int[stages[1].size]{508, 708, 502, 503, 504, 501, 507, 607, 608}; - - stages[2].name = "HV"; - stages[2].size = 10; - stages[2].channels = new int[stages[2].size]{1, 2, 101, 103, 102, 104, 105, 106, 107, 108}; + stages[0].name = "ASICS"; + stages[0].type = SWITCH; + stages[0].size = 9; + stages[0].channels = new int[stages[0].size]{508, 708, 502, 503, 504, 501, 507, 607, 608}; + + stages[1].name = "HV"; + stages[1].type = SWITCH; + stages[1].size = 10; + stages[1].channels = new int[stages[1].size]{1, 2, 101, 103, 102, 104, 105, 106, 107, 108}; + + stages[2].name = "ISVOLTAGE"; + stages[2].type = VOLTAGE; + stages[2].size = 2; + stages[2].channels = new int[stages[2].size]{1, 2}; + stages[2].onValue = new float[stages[2].size]{10, 10}; + stages[2].offValue = new float[stages[2].size]{2.5, 2.5}; stages[3].name = "PLCSOURCE"; + stages[3].type = SWITCH; stages[3].size = 9; stages[3].channels = new int[stages[3].size]{701, 801, 802, 803, 804, 301, 302, 303, 304}; } @@ -26,6 +32,10 @@ PowerProcedure::PowerProcedure(const IPAddress& ipAddr) PowerProcedure::~PowerProcedure() { for (size_t stageIdx = 0; stageIdx < stagesCount; stageIdx++) { delete[] stages[stageIdx].channels; + if (stages[stageIdx].type == VOLTAGE) { + delete[] stages[stageIdx].onValue; + delete[] stages[stageIdx].offValue; + } } delete[] stages; } @@ -37,6 +47,9 @@ String PowerProcedure::toJSON() { for (size_t stageIdx = 0; stageIdx < stagesCount; stageIdx++) { Stage* currentStage = &stages[stageIdx]; + if (currentStage->type == VOLTAGE) { + continue; + } json += "{\"name\":\"" + currentStage->name + "\","; json += "\"channels\":[\n"; @@ -71,7 +84,12 @@ bool PowerProcedure::powerOn(const String& stage) { Stage* currentStage = &stages[stageIdx]; if (currentStage->name == stage) { for (size_t chIdx = 0; chIdx < currentStage->size; chIdx++) { - setChannelAndWait(&ipAddr, currentStage->channels[chIdx], 1); // 1 == ON + if (currentStage->type == SWITCH) { + setChannelStateAndWait(&ipAddr, currentStage->channels[chIdx], 1); // 1 == ON + } else if (currentStage->type == VOLTAGE) { + setChannelVoltageAndWait(&ipAddr, currentStage->channels[chIdx], + currentStage->onValue[chIdx]); + } } return true; } @@ -84,7 +102,12 @@ bool PowerProcedure::powerOff(const String& stage) { Stage* currentStage = &stages[stageIdx]; if (currentStage->name == stage) { for (int chIdx = currentStage->size - 1; chIdx >= 0; chIdx--) { - setChannelAndWait(&ipAddr, currentStage->channels[chIdx], 0); // 0 == OFF + if (currentStage->type == SWITCH) { + setChannelStateAndWait(&ipAddr, currentStage->channels[chIdx], 0); // 0 == OFF + } else if (currentStage->type == VOLTAGE) { + setChannelVoltageAndWait(&ipAddr, currentStage->channels[chIdx], + currentStage->offValue[chIdx]); + } } return true; } diff --git a/powerproc.hpp b/powerproc.hpp index 5f0236f..979df46 100644 --- a/powerproc.hpp +++ b/powerproc.hpp @@ -3,15 +3,21 @@ #include "pins.hpp" +#define SWITCH "SWITCH" +#define VOLTAGE "VOLTAGE" #define STAGESCOUNT 4 + class PowerProcedure { private: String currentStage; // Stores the current stage name int currentChannel; // Stores the current channel struct Stage { - String name; // Name of the stage (e.g., "ASICS") + String name; // Name of the stage (e.g. "ASICS") + String type; // Type of stage (i.e. "SWITCH", "VOLTAGE") int* channels; // Pointer to dynamically allocated channel array + float* onValue; // Pointer to dynamically allocated array, when type == VOLTAGE + float* offValue; // Pointer to dynamically allocated array, when type == VOLTAGE size_t size; // Number of channels in the stage }; diff --git a/rest.cpp b/rest.cpp index 8a5a577..61af9a2 100644 --- a/rest.cpp +++ b/rest.cpp @@ -160,7 +160,7 @@ void sendSNMP() { auto ipAddr = pproc.ipAddr; if (output != NONE && channel != 0) { - setChannelAndWait(&ipAddr, channel, output); + setChannelStateAndWait(&ipAddr, channel, output); success = true; // validates input parameters, not MPOD status, reported separately } -- GitLab From eb2be556a4559579c2eaf0ccc7165c45d5d2bd82 Mon Sep 17 00:00:00 2001 From: Cyril Danilevski <cyril.danilevski@xfel.eu> Date: Fri, 14 Feb 2025 18:53:22 +0100 Subject: [PATCH 6/6] Check target voltage and target current on channel poll --- mpod.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mpod.cpp b/mpod.cpp index 61940bb..86030b7 100644 --- a/mpod.cpp +++ b/mpod.cpp @@ -23,6 +23,10 @@ SNMP::Message *MPOD::read(uint16_t channel) { snmp_cmd += channel; message->add(snmp_cmd.c_str()); + snmp_cmd = OID::NAMES[OID::OUTPUTVOLTAGE]; + snmp_cmd += channel; + message->add(snmp_cmd.c_str()); + snmp_cmd = OID::NAMES[OID::OUTPUTMEASUREMENTSENSEVOLTAGE]; snmp_cmd += channel; message->add(snmp_cmd.c_str()); @@ -31,6 +35,10 @@ SNMP::Message *MPOD::read(uint16_t channel) { snmp_cmd += channel; message->add(snmp_cmd.c_str()); + snmp_cmd = OID::NAMES[OID::OUTPUTCURRENT]; + snmp_cmd += channel; + message->add(snmp_cmd.c_str()); + return message; } @@ -202,9 +210,6 @@ void initializeSNMP() { Serial.println("SNMP Server Started"); } -/* setChannelAndWait - * Set a channel's parameters and wait until it's settled. - */ void setChannelStateAndWait(const IPAddress *ipAddr, const uint16_t channel, const uint8_t output) { // Send set command SNMP::Message *snmp_msg = mpod.setChannelState(channel, output); @@ -244,6 +249,5 @@ void setChannelVoltageAndWait(const IPAddress *ipAddr, const uint16_t channel, delete snmp_msg; delay(MPOD_UPDATE_LATENCY); snmp.loop(); - } while (mpod.isRampingDown() || - mpod.isRampingUp()); // TODO check applied voltage close to target voltage + } while (mpod.isRampingDown() || mpod.isRampingUp()); } -- GitLab