new version of powerSwitch
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
#include "powerSwitch.h"
|
||||
#include "odbxx.h"
|
||||
#include "powerSwitchConfig.h"
|
||||
#include "tmfe.h"
|
||||
#include <string>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
/**
|
||||
* @brief Insert a integer value between two string
|
||||
* @param str1 first string
|
||||
* @param int value to insert
|
||||
* @param str2 second string
|
||||
*
|
||||
* @return a new string instance
|
||||
*/
|
||||
std::string insert(const std::string *str1, int value,
|
||||
const std::string *str2) {
|
||||
return *str1 + std::to_string(value) + *str2;
|
||||
}
|
||||
|
||||
powerSwitch::powerSwitch(std::string equipmentName,
|
||||
const char *equipmentFilename)
|
||||
: TMFeEquipment(equipmentName.c_str(), equipmentFilename),
|
||||
outletNumberRecord(mEpicsCa<int>(EPOWERSWITCH_OUTLETNUMBER_INFO_PREFIX)) {
|
||||
fEqConfReadOnlyWhenRunning = false;
|
||||
|
||||
this->equipmentPath = std::string("/Equipment/") + equipmentName;
|
||||
}
|
||||
|
||||
void powerSwitch::HandlePeriodic() {
|
||||
|
||||
updateOutletNumber();
|
||||
midas::odb o(this->equipmentPath);
|
||||
|
||||
for (int i = 0; i < this->numberOfOutlet; i++) {
|
||||
Outlet *outlet = &this->outlets.at(i);
|
||||
|
||||
if (outlet->commandHasChange()) {
|
||||
o[COMMAND_PATH.c_str()][i] = outlet->getCommand();
|
||||
}
|
||||
o[READBACK_PATH.c_str()][i] = outlet->getState();
|
||||
}
|
||||
}
|
||||
TMFeResult powerSwitch::HandleInit(const std::vector<std::string> &args) {
|
||||
|
||||
midas::odb o = {
|
||||
{SETTING_DIR.c_str(), {{EDITABLE_VARNAME.c_str(), COMMAND_VARNAME}}}};
|
||||
|
||||
o.connect(this->equipmentPath.c_str());
|
||||
|
||||
midas::odb to_watch(this->equipmentPath + SLASH + VARIABLES_DIR + SLASH +
|
||||
COMMAND_VARNAME);
|
||||
|
||||
to_watch.watch(
|
||||
[&](midas::odb &arg) { this->sendCommand(arg.get_last_index()); });
|
||||
return TMFeOk();
|
||||
}
|
||||
void powerSwitch::updateOutletNumber() {
|
||||
int newNumberOfOutlet = 0;
|
||||
|
||||
int returnCode = outletNumberRecord.get(&newNumberOfOutlet);
|
||||
if (returnCode != CM_SUCCESS) {
|
||||
fMfe->Msg(MERROR, __FUNCTION__, "Unable to read outlet record number");
|
||||
}
|
||||
|
||||
if (this->numberOfOutlet < newNumberOfOutlet)
|
||||
fMfe->Msg(MDEBUG, __FUNCTION__,
|
||||
"Outlet number increasing, creating %d new outlet(s)",
|
||||
newNumberOfOutlet - this->numberOfOutlet);
|
||||
|
||||
for (int i = this->numberOfOutlet; i < newNumberOfOutlet; i++) {
|
||||
std::string epicsSetRecordName;
|
||||
{
|
||||
static const std::string *str1 = &EPOWERSWITCH_OUTLET_SET_PREFIX;
|
||||
static const std::string str2 = "";
|
||||
epicsSetRecordName = insert(str1, i + 1, &str2);
|
||||
}
|
||||
std::string epicsGetRecordName;
|
||||
{
|
||||
static const std::string *str1 = &EPOWERSWITCH_OUTLET_GET_PREFIX;
|
||||
static const std::string str2 = "";
|
||||
epicsGetRecordName = insert(str1, i + 1, &str2);
|
||||
}
|
||||
this->outlets.emplace_back(i, epicsGetRecordName, epicsSetRecordName);
|
||||
}
|
||||
|
||||
if (this->numberOfOutlet > newNumberOfOutlet)
|
||||
fMfe->Msg(MDEBUG, __FUNCTION__,
|
||||
"Outlet number decreasing, destroying %d outlet(s)",
|
||||
this->numberOfOutlet - newNumberOfOutlet);
|
||||
|
||||
for (int i = newNumberOfOutlet; i < this->numberOfOutlet; i++) {
|
||||
this->outlets.pop_back();
|
||||
}
|
||||
|
||||
this->numberOfOutlet = newNumberOfOutlet;
|
||||
}
|
||||
|
||||
void powerSwitch::sendCommand(int index) {
|
||||
midas::odb o(this->equipmentPath);
|
||||
std::string command = o[COMMAND_PATH.c_str()][index];
|
||||
Outlet *outlet = &outlets.at(index);
|
||||
outlet->setState(command);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef POWER_SWITCH_H
|
||||
#define POWER_SWITCH_H
|
||||
|
||||
#include "../utils/outlet.h"
|
||||
#include "tmfe.h"
|
||||
#include <vector>
|
||||
|
||||
class powerSwitch : public TMFeEquipment {
|
||||
public:
|
||||
powerSwitch(std::string equipmentName, const char *equipmentFilename);
|
||||
void HandlePeriodic();
|
||||
TMFeResult HandleInit(const std::vector<std::string> &args);
|
||||
|
||||
private:
|
||||
std::vector<Outlet> outlets;
|
||||
mEpicsCa<int> outletNumberRecord;
|
||||
int numberOfOutlet;
|
||||
std::string equipmentPath;
|
||||
|
||||
void updateOutletNumber();
|
||||
|
||||
void sendCommand(int index);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef POWER_SWITCH_CONFIG_H
|
||||
#define POWER_SWITCH_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
const std::string EPOWERSWITCH_OUTLETNUMBER_INFO_PREFIX =
|
||||
"ePowerSwitch_config_maxOutlet";
|
||||
|
||||
const std::string VARIABLES_DIR = "Variables";
|
||||
const std::string SETTING_DIR = "Settings";
|
||||
const std::string COMMAND_VARNAME = "Command";
|
||||
const std::string READBACK_VARNAME = "Readback";
|
||||
|
||||
const std::string SLASH = "/";
|
||||
|
||||
const std::string EPOWERSWITCH_OUTLET_SET_PREFIX = "ePowerSwitch_set_outlet_";
|
||||
const std::string EPOWERSWITCH_OUTLET_GET_PREFIX = "ePowerSwitch_get_outlet_";
|
||||
|
||||
const std::string EDITABLE_VARNAME = std::string("Editable");
|
||||
|
||||
// ##################################################
|
||||
// Paths names : do not modify
|
||||
// ##################################################
|
||||
|
||||
const std::string COMMAND_PATH = VARIABLES_DIR + SLASH + COMMAND_VARNAME;
|
||||
const std::string READBACK_PATH = VARIABLES_DIR + SLASH + READBACK_VARNAME;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,202 @@
|
||||
#include "outlet.h"
|
||||
#include "m_epics_ca.h"
|
||||
#include "odbxx.h"
|
||||
#include "tmfe.h"
|
||||
#include <string>
|
||||
|
||||
Outlet::Outlet(int index, std::string inputRecordName,
|
||||
std::string outputRecordName)
|
||||
: input(mEpicsCa<std::string>(inputRecordName)),
|
||||
output(mEpicsCa<std::string>(outputRecordName)) {
|
||||
this->index = index;
|
||||
this->innerState = State::UNKNOW;
|
||||
|
||||
this->isOutputConnected = true;
|
||||
this->isInputConnected = true;
|
||||
this->gracePeriod = 3;
|
||||
}
|
||||
|
||||
std::string Outlet::getState() {
|
||||
this->updateState();
|
||||
return this->stateToString(this->innerState);
|
||||
}
|
||||
|
||||
std::string Outlet::getCommand() {
|
||||
State command = this->_getCommand();
|
||||
this->lastCommand = command;
|
||||
return this->stateToString(command);
|
||||
}
|
||||
|
||||
bool Outlet::commandHasChange() {
|
||||
return this->lastCommand != this->_getCommand();
|
||||
}
|
||||
|
||||
void Outlet::setState(State state) {
|
||||
printf("set a new states \n");
|
||||
this->buffered = state;
|
||||
this->updateState();
|
||||
}
|
||||
|
||||
void Outlet::setState(std::string state) {
|
||||
this->setState(this->stringToState(state));
|
||||
}
|
||||
|
||||
void Outlet::turnOn() {
|
||||
std::string msg = "On";
|
||||
int returnCode = this->output.put(&msg);
|
||||
if (returnCode != CM_SUCCESS)
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Outlet %d : Error %d : unable to write into output record",
|
||||
this->index, returnCode);
|
||||
}
|
||||
|
||||
void Outlet::turnOff() {
|
||||
std::string msg = "Off";
|
||||
int returnCode = this->output.put(&msg);
|
||||
if (returnCode != CM_SUCCESS)
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Outlet %d : Error %d : unable to write into output record",
|
||||
this->index, returnCode);
|
||||
}
|
||||
|
||||
void Outlet::restart() {
|
||||
std::string msg = "Restart";
|
||||
int returnCode = this->output.put(&msg);
|
||||
if (returnCode != CM_SUCCESS)
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Outlet %d : Error %d : unable to write into output record",
|
||||
this->index, returnCode);
|
||||
}
|
||||
|
||||
void Outlet::updateState() {
|
||||
bool outputConnected = this->output.connected();
|
||||
bool inputConnected = this->input.connected();
|
||||
|
||||
if (!outputConnected && this->isOutputConnected) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Outlet %d : Output channel disconnected",
|
||||
this->index);
|
||||
}
|
||||
|
||||
if (!inputConnected && this->isInputConnected) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Outlet %d : Input channel disconnected",
|
||||
this->index);
|
||||
}
|
||||
|
||||
this->isOutputConnected = outputConnected;
|
||||
this->isInputConnected = inputConnected;
|
||||
|
||||
if (!outputConnected || !inputConnected) {
|
||||
// Error message are above
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->gracePeriod > 0) {
|
||||
this->gracePeriod--;
|
||||
buffered.reset();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
this->innerState = stringToState(value);
|
||||
|
||||
if (buffered.has_value()) {
|
||||
State state = buffered.value();
|
||||
printf("update state to \"%s\" sur l'outlet %d\n", value.c_str(),
|
||||
this->index);
|
||||
switch (this->innerState) {
|
||||
case State::ON:
|
||||
if (state == State::OFF)
|
||||
this->turnOff();
|
||||
if (state == State::RST)
|
||||
this->restart();
|
||||
buffered.reset();
|
||||
break;
|
||||
case State::OFF:
|
||||
if (state == State::ON)
|
||||
this->turnOn();
|
||||
if (state == State::RST)
|
||||
this->restart();
|
||||
buffered.reset();
|
||||
break;
|
||||
case State::RST:
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Outlet %d in restarting state, command "
|
||||
"pending in a buffered state",
|
||||
this->index);
|
||||
break;
|
||||
case State::UNKNOW:
|
||||
TMFE::Instance()->Msg(MINFO, __FUNCTION__,
|
||||
"Outlet %d : Unknow state", this->index);
|
||||
if (state == State::ON)
|
||||
this->turnOn();
|
||||
if (state == State::OFF)
|
||||
this->turnOff();
|
||||
if (state == State::RST)
|
||||
this->restart();
|
||||
buffered.reset();
|
||||
break;
|
||||
|
||||
default: // This state doesn't exist
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Outlet %d : FATAL ERROR : unvalide state",
|
||||
this->index);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::UNKNOW;
|
||||
}
|
||||
|
||||
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("Unknow");
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
Outlet::State Outlet::_getCommand() {
|
||||
std::string value;
|
||||
int returnCode = this->output.get(&value);
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef OUTLET_H
|
||||
#define OUTLET_H
|
||||
|
||||
#include "m_epics_ca.h"
|
||||
|
||||
class Outlet {
|
||||
public:
|
||||
Outlet(int index, std::string inputRecordName,
|
||||
std::string outputRecordName);
|
||||
|
||||
enum class State { ON, OFF, RST, UNKNOW };
|
||||
|
||||
Outlet(Outlet &&other) noexcept = default;
|
||||
|
||||
std::string getState();
|
||||
std::string getCommand();
|
||||
bool commandHasChange();
|
||||
void setState(State state);
|
||||
void setState(std::string state);
|
||||
|
||||
private:
|
||||
mEpicsCa<std::string> input;
|
||||
mEpicsCa<std::string> output;
|
||||
|
||||
bool isInputConnected;
|
||||
bool isOutputConnected;
|
||||
|
||||
int gracePeriod;
|
||||
|
||||
std::optional<State> buffered;
|
||||
State innerState;
|
||||
int index;
|
||||
|
||||
void turnOn();
|
||||
void turnOff();
|
||||
void restart();
|
||||
void updateState();
|
||||
Outlet::State stringToState(std::string value);
|
||||
std::string stateToString(State state);
|
||||
State _getCommand();
|
||||
State lastCommand;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user