diff --git a/src/device/power_switch.cpp b/src/device/power_switch.cpp index 0de5b7d..cabf942 100644 --- a/src/device/power_switch.cpp +++ b/src/device/power_switch.cpp @@ -6,7 +6,7 @@ #include /** - * @brief Insert a integer value between two string + * @brief Insert an integer value between two strings * @param str1 first string * @param int value to insert * @param str2 second string @@ -49,9 +49,7 @@ TMFeResult powerSwitch::HandleInit(const std::vector &args) { {{EDITABLE_VARNAME.c_str(), COMMAND_VARNAME}, {UNIT_VARNAME.c_str(), UNIT_VALUE.c_str()}}}, {VARIABLES_DIR.c_str(), - {{COMMAND_VARNAME.c_str(), {""}}, {READBACK_VARNAME.c_str(), {""}}}} - - }; + {{COMMAND_VARNAME.c_str(), {0}}, {READBACK_VARNAME.c_str(), {0}}}}}; o.connect(this->equipmentPath.c_str()); @@ -129,7 +127,16 @@ void powerSwitch::sendCommand(int index) { return; } midas::odb o(this->equipmentPath); - std::string command = o[COMMAND_PATH.c_str()][index]; + int command = o[COMMAND_PATH.c_str()][index]; + + if (command < 0 || command > 2) { + fMfe->Msg( + MERROR, __FUNCTION__, + "Invalid command value %d for outlet %d (expected 0, 1, or 2)", + command, index); + return; + } + Outlet *outlet = &outlets.at(index); outlet->writeSetRecord(command); -} +} \ No newline at end of file diff --git a/src/utils/outlet.cpp b/src/utils/outlet.cpp index 9cba3c8..9f3d051 100644 --- a/src/utils/outlet.cpp +++ b/src/utils/outlet.cpp @@ -4,42 +4,69 @@ #include "tmfe.h" #include +// ---------------------------------------------- +// Mapping API int - EPICS string +// ---------------------------------------------- + +static std::string stateToEpicsString(Outlet::State state) { + switch (state) { + case Outlet::State::OFF: + return "Off"; + case Outlet::State::ON: + return "On"; + case Outlet::State::RST: + return "Restart"; + default: + return "UNKNOWN"; + } +} + +static Outlet::State epicsStringToState(const std::string &value) { + if (value == "On" || value == "ON") + return Outlet::State::ON; + if (value == "Off" || value == "OFF") + return Outlet::State::OFF; + if (value == "Restart" || value == "Rst" || value == "RST" || + value == "Res" || value == "RES" || value == "RESTART") + return Outlet::State::RST; + return Outlet::State::UNKNOWN; // UNKNOWN +} + +// ---------------------------------------------- +// Constructor +// ---------------------------------------------- + Outlet::Outlet(int index, std::string inputRecordName, std::string outputRecordName) - : input(mEpicsCa(inputRecordName)), - output(mEpicsCa(outputRecordName)) { - this->index = index; - this->innerState = State::UNKNOWN; + : index(index), input(mEpicsCa(inputRecordName)), + output(mEpicsCa(outputRecordName)), + innerState(State::UNKNOWN), // UNKNOWN + lastCommand(State::UNKNOWN), wasOutputConnected(false), + wasInputConnected(false), gracePeriod(3) {} - this->wasOutputConnected = false; - this->wasInputConnected = false; - this->gracePeriod = 3; -} - -std::string Outlet::readGetRecord() { +int Outlet::readGetRecord() { this->updateState(); - return this->stateToString(this->innerState); + return static_cast(this->innerState); } -std::string Outlet::readSetRecord() { - State command = this->_getCommand(); +int Outlet::readSetRecord() { + State command = this->getCommand(); this->lastCommand = command; - return this->stateToString(command); + return static_cast(command); } bool Outlet::hasGetRecordChanged() { - return this->lastCommand != this->_getCommand(); + return this->lastCommand != this->getCommand(); } -void Outlet::writeSetRecord(State state) { - this->bufferedCommand = state; +void Outlet::writeSetRecord(int state) { + if (state < 0 || + state > 2) // Only autorize state to be between 0 and 2 included + return; + this->bufferedCommand = static_cast(state); this->updateState(); } -void Outlet::writeSetRecord(std::string state) { - this->writeSetRecord(this->stringToState(state)); -} - void Outlet::turnOn() { std::string msg = "On"; int returnCode = this->output.put(&msg); @@ -74,141 +101,102 @@ void Outlet::updateState() { bool outputConnected = this->isOutputConnected(); bool inputConnected = this->isInputConnected(); - if (!outputConnected || !inputConnected) { + if (!outputConnected || !inputConnected) // Error message are above return; + + // Grace period + if (this->gracePeriod > 0) { + this->gracePeriod--; + this->bufferedCommand.reset(); + return; } - // Adding a grace period to prevent reseting at start - if (this->gracePeriod > 0) { - this->gracePeriod--; - bufferedCommand.reset(); - } - + // Read current state from EPICS input std::string value; - int returnCode = this->input.get(&value); if (returnCode != CM_SUCCESS) { TMFE::Instance()->Msg( MERROR, __FUNCTION__, "Outlet %d : Error %d : unable to read from input record", this->index, returnCode); + return; } - this->innerState = stringToState(value); + this->innerState = epicsStringToState(value); - if (bufferedCommand.has_value()) { - State state = bufferedCommand.value(); + // Apply buffered command if any + if (this->bufferedCommand.has_value()) { + State cmd = this->bufferedCommand.value(); switch (this->innerState) { - case State::ON: - if (state == State::OFF) + case State::ON: // ON + if (cmd == State::OFF) this->turnOff(); - if (state == State::RST) + if (cmd == State::RST) this->restart(); - bufferedCommand.reset(); - break; - case State::OFF: - if (state == State::ON) - this->turnOn(); - if (state == State::RST) - this->restart(); - bufferedCommand.reset(); - break; - case State::RST: - // Do nothing - break; - case State::UNKNOWN: - TMFE::Instance()->Msg(MINFO, __FUNCTION__, - "Outlet %d : Unknown state, sending command " - "and continuing as normal", - this->index); - if (state == State::ON) - this->turnOn(); - if (state == State::OFF) - this->turnOff(); - if (state == State::RST) - this->restart(); - bufferedCommand.reset(); break; - default: // This state doesn't exist - TMFE::Instance()->Msg(MERROR, __FUNCTION__, - "Outlet %d : new state left unmapped", - this->index); - exit(EXIT_FAILURE); + case State::OFF: // OFF + if (cmd == State::ON) + this->turnOn(); + if (cmd == State::RST) + this->restart(); + break; + + case State::RST: // RST - do nothing + break; + + case State::UNKNOWN: // UNKNOWN + default: + TMFE::Instance()->Msg( + MINFO, __FUNCTION__, + "Outlet %d : Unknown state, sending command and continuing", + this->index); + if (cmd == State::ON) + this->turnOn(); + if (cmd == State::OFF) + this->turnOff(); + if (cmd == State::RST) + this->restart(); break; } + this->bufferedCommand.reset(); } } -Outlet::State Outlet::stringToState(std::string value) { - if (value == "ON" || value == "On") { - return State::ON; - } - if (value == "OFF" || value == "Off") { - return State::OFF; - } - if (value == "RST" || value == "Rst" || value == "Res" || value == "RES" || - value == "RESTART" || value == "Restart") { - return State::RST; - } - return State::UNKNOWN; -} - -std::string Outlet::stateToString(State state) { - switch (state) { - case State::ON: - return std::string("On"); - break; - case State::OFF: - return std::string("Off"); - break; - case State::RST: - return std::string("Restart"); - break; - default: - return std::string("UNKNOWN"); - break; - }; -} - -Outlet::State Outlet::_getCommand() { +Outlet::State Outlet::getCommand() { if (!this->isInputConnected()) return this->lastCommand; + std::string value; int returnCode = this->output.get(&value); - if (returnCode != CM_SUCCESS) + if (returnCode != CM_SUCCESS) { TMFE::Instance()->Msg( MERROR, __FUNCTION__, "Outlet %d : Error %d : unable to read from output record", this->index, returnCode); - return stringToState(value); + return this->lastCommand; + } + return epicsStringToState(value); } bool Outlet::isOutputConnected() { - bool outputConnected = this->output.connected(); - - if (!outputConnected && this->wasOutputConnected) { + bool connected = this->output.connected(); + if (!connected && this->wasOutputConnected) TMFE::Instance()->Msg(MERROR, __FUNCTION__, "Outlet %d : Output channel disconnected", this->index); - } - - this->wasOutputConnected = outputConnected; - return outputConnected; + this->wasOutputConnected = connected; + return connected; } bool Outlet::isInputConnected() { - bool inputConnected = this->input.connected(); - - if (!inputConnected && this->wasInputConnected) { + bool connected = this->input.connected(); + if (!connected && this->wasInputConnected) TMFE::Instance()->Msg(MERROR, __FUNCTION__, "Outlet %d : Input channel disconnected", this->index); - } - - this->wasInputConnected = inputConnected; - - return inputConnected; -} + this->wasInputConnected = connected; + return connected; +} \ No newline at end of file diff --git a/src/utils/outlet.h b/src/utils/outlet.h index 8a5898e..565cd1c 100644 --- a/src/utils/outlet.h +++ b/src/utils/outlet.h @@ -8,58 +8,51 @@ class Outlet { Outlet(int index, std::string inputRecordName, std::string outputRecordName); - enum class State { ON, OFF, RST, UNKNOWN }; + enum class State { ON = 1, OFF = 0, RST = 2, UNKNOWN = -1 }; /** * @brief get the current state of the device by reading it's get record * @return the current state */ - std::string readGetRecord(); + int readGetRecord(); /** * @brief get the value of the command stored in the set record * @return the current command */ - std::string readSetRecord(); + int readSetRecord(); /** * @brief return true if the last value readed from this object if not equal * to the current device state */ bool hasGetRecordChanged(); - /** - * @brief set to a new state the device - */ - void writeSetRecord(State state); /** * @brief set to a new state the device. If string not recognize, will put * UNKNOWN to the outlet state */ - void writeSetRecord(std::string state); + void writeSetRecord(int state); private: + State getCommand(); + bool isInputConnected(); + bool isOutputConnected(); + + int index; mEpicsCa input; mEpicsCa output; - bool wasInputConnected; - bool wasOutputConnected; - - int gracePeriod; - - std::optional bufferedCommand; State innerState; - int index; + State lastCommand; + std::optional bufferedCommand; + + bool wasOutputConnected; + bool wasInputConnected; + int gracePeriod; void turnOn(); void turnOff(); void restart(); void updateState(); - Outlet::State stringToState(std::string value); - std::string stateToString(State state); - State _getCommand(); - State lastCommand; - - bool isInputConnected(); - bool isOutputConnected(); }; #endif \ No newline at end of file