File GenesysDriver.cpp
File List > midas_fe > power > GenesysDriver.cpp
Go to the documentation of this file
#include "GenesysDriver.h"
#include <chrono>
#include <cstring>
#include <thread>
//
// MIDAS Driver for our TDK Genesys supplies
// FW, Sep. 2020
//
// communicate with SCPI commands
// Setup for 1 supply connected with LAN, the other supplies daisy chained with the RS485 bus
// supply IDs are setup as 0,1,2,...
//
// From manual:
// * Recommended time delay between commands: 5mSec minimum. Some commands might require longer
// time. In such cases, refer to NOTE following command description.
//
GenesysDriver::GenesysDriver(std::string n, EQUIPMENT_INFO* inf) : PowerDriver(n, inf) {
std::cout << " GenesysDriver instantiated " << std::endl;
// device specific constants
}
GenesysDriver::~GenesysDriver() {}
INT GenesysDriver::ConnectODB() {
InitODBArray();
INT status = PowerDriver::ConnectODB();
settings["port"](8003);
settings["reply timout"](50);
settings["min reply"](3); // minimum reply , a char + "\n"
return status;
}
// didn't find a cleaner way to init the array entries, have a prior initialized 'variables', and
// not overwrite Set values
void GenesysDriver::InitODBArray() {
midas::odb settings_array = {{"Channel Names", std::array<std::string, 16>()},
{"Blink", std::array<bool, 16>()},
{"ESR", std::array<int, 16>()}};
settings_array.connect("/Equipment/" + name + "/Settings");
}
INT GenesysDriver::Init() {
std::string ip = settings["IP"];
std::cout << "Call init on " << ip << std::endl;
std::string cmd = "";
std::string reply = "";
INT err;
// global reset if requested
if (settings["Global Reset On FE Start"]) {
cmd = "GLOB:*RST\n";
if (!client->Write(cmd))
cm_msg(MERROR, "Init genesys supply ... ", "could not global reset %s", ip.c_str());
else
cm_msg(MINFO, "power_fe", "Init global reset of %s", ip.c_str());
}
std::this_thread::sleep_for(std::chrono::milliseconds(client->GetWaitTime()));
// figure out the number of supplies connected
for (int i = 0; i < 12; i++) {
cmd = "INST:NSEL " + std::to_string(i) + "\n";
client->Write(cmd);
std::this_thread::sleep_for(std::chrono::milliseconds(client->GetWaitTime()));
bool success = OPC();
if (!success)
cm_msg(MINFO, "power_fe", "Supply nr %d NOT detected", i);
else {
cm_msg(MINFO, "power_fe", "Supply nr %d seen", i);
instrumentID.push_back(i);
}
}
cm_msg(MINFO, "power_fe", " %d supplies registered in daisy chain", int(instrumentID.size()));
int nChannels = instrumentID.size();
if (nChannels != settings["NChannels"])
cm_msg(MINFO, "power_fe", " Different as the set ODB value of %d, updating",
int(settings["NChannels"]));
settings["NChannels"] = instrumentID.size();
// ***** channel by channel settings ***** //
// read system errors
for (int i = 0; i < nChannels; i++) {
std::vector<std::string> error_queue = ReadErrorQueue(i, err);
for (auto& s : error_queue) {
if (s.substr(0, 1) != "0") {
cm_msg(MERROR, "power_fe", " Error from tdk %d supply : %s", instrumentID[i],
s.c_str());
}
}
}
settings["Address"] = instrumentID;
state.resize(nChannels);
voltage.resize(nChannels);
demandvoltage.resize(nChannels);
current.resize(nChannels);
currentlimit.resize(nChannels);
idCode.resize(nChannels);
OVPlevel.resize(nChannels);
interlock_enabled.resize(nChannels);
OVPlevel.resize(nChannels);
QCGEreg.resize(nChannels);
for (int i = 0; i < nChannels; i++) {
idCode[i] = ReadIDCode(i, err);
state[i] = ReadState(i, err);
voltage[i] = ReadVoltage(i, err);
demandvoltage[i] = ReadSetVoltage(i, err);
demandcurrent[i] = ReadSetCurrent(i, err);
current[i] = ReadCurrent(i, err);
currentlimit[i] = ReadCurrentLimit(i, err);
OVPlevel[i] = ReadOVPLevel(i, err);
interlock_enabled[i] = true;
SetInterlock(i, interlock_enabled[i], err);
settings["ESR"] = ReadESR(i, err);
QCGEreg[i] = ReadQCGE(i, err);
if (err != FE_SUCCESS)
return err;
}
settings["Identification Code"] = idCode;
variables["Questionable Condition Register"] = QCGEreg;
variables["State"] = state; // push to odb
variables["Set State"] =
state; // the init function can not change the on/off state of the supply
variables["Voltage"] = voltage;
variables["Demand Voltage"] = demandvoltage;
variables["Current"] = current;
variables["Current Limit"] = currentlimit;
variables["OVP Level"] = OVPlevel;
variables["Interlock"] = InterlockStatus(QCGEreg);
// user arrays.
settings["Channel Names"].resize(nChannels);
settings["Blink"].resize(nChannels);
settings["ESR"].resize(nChannels);
settings["Read ESR"] = false;
// ***** set up watch ***** //
variables["Set State"].watch([&](midas::odb&) { this->SetStateChanged(); });
variables["Demand Voltage"].watch([&](midas::odb&) { this->DemandVoltageChanged(); });
variables["Current Limit"].watch([&](midas::odb&) { this->CurrentLimitChanged(); });
settings["Blink"].watch([&](midas::odb&) { this->BlinkChanged(); });
settings["Read ESR"].watch([&](midas::odb&) { this->ReadESRChanged(); });
return FE_SUCCESS;
}
bool GenesysDriver::AskPermissionToTurnOn(int) // extra check whether it is safe to tunr on supply;
{
return true;
}
// ************ watch functions ************* //
void GenesysDriver::BlinkChanged() {
INT err;
for (unsigned int i = 0; i < instrumentID.size(); i++) {
bool value = settings["Blink"][i];
SetBlink(i, value, err);
if (err != FE_SUCCESS)
cm_msg(MERROR, "Genesys supply ... ",
"changing flashing of channel %d to %d failed, error %d", instrumentID[i], value,
err);
}
}
void GenesysDriver::ReadESRChanged() {
INT err;
bool value = settings["Read ESR"];
cm_msg(MINFO, "Genesys supply ... ", "ESR read request set to %d", value);
if (value) {
for (unsigned int i = 0; i < instrumentID.size(); i++) {
settings["ESR"][i] = ReadESR(i, err);
}
settings["Read ESR"] = false;
}
}
// ************** Set Functions ************** //
void GenesysDriver::SetInterlock(int index, bool value, INT& error) {
std::string cmd;
bool success;
error = FE_SUCCESS;
if (SelectChannel(instrumentID[index])) {
// OUTPut:ILC[:STATe] <Bool>
if (value == true) {
cmd = "OUTP:ILC 1\n";
} else {
cmd = "OUTP:ILC 0\n";
}
client->Write(cmd);
std::this_thread::sleep_for(std::chrono::milliseconds(client->GetWaitTime()));
success = OPC();
if (!success)
error = FE_ERR_DRIVER;
else
cm_msg(MINFO, "Genesys supply ... ", "Interlock enabled[1]/disabled[0]: %d", value);
}
}
void GenesysDriver::SetBlink(int index, bool value, INT& error) {
std::string cmd;
bool success;
error = FE_SUCCESS;
if (SelectChannel(instrumentID[index])) {
if (value == true) {
cmd = "DISP:WIND:FLAS 1\n";
} else {
cmd = "DISP:WIND:FLAS 0\n";
}
client->Write(cmd);
std::this_thread::sleep_for(std::chrono::milliseconds(client->GetWaitTime()));
success = OPC();
if (!success)
error = FE_ERR_DRIVER;
}
}
// ************** Read Functions ************** //
INT GenesysDriver::ReadAll() {
int nChannels = instrumentID.size();
INT err;
INT err_accumulated;
bool status_reg_update = false;
// update local book keeping
for (int i = 0; i < nChannels; i++) {
if (readonlythisindex >= 0 && i != readonlythisindex)
continue;
bool bvalue = ReadState(i, err);
err_accumulated = err;
if (state[i] != bvalue) // only update odb if there is a change
{
state[i] = bvalue;
variables["State"][i] = bvalue;
}
float fvalue = ReadVoltage(i, err);
err_accumulated = err_accumulated | err;
if (fabs(voltage[i] - fvalue) > fabs(relevantchange * voltage[i])) {
voltage[i] = fvalue;
variables["Voltage"][i] = fvalue;
}
fvalue = ReadCurrent(i, err);
err_accumulated = err_accumulated | err;
if (fabs(current[i] - fvalue) > fabs(relevantchange * current[i])) {
current[i] = fvalue;
variables["Current"][i] = fvalue;
}
fvalue = ReadOVPLevel(i, err);
err_accumulated = err_accumulated | err;
if (fabs(OVPlevel[i] - fvalue) > fabs(relevantchange * OVPlevel[i])) {
OVPlevel[i] = fvalue;
variables["OVP Level"][i] = fvalue;
}
std::vector<std::string> error_queue = ReadErrorQueue(i, err);
for (auto& s : error_queue) {
if (s.substr(0, 1) != "0") {
cm_msg(MERROR, "power_fe", " Error from tdk %d supply : %s", instrumentID[i],
s.c_str());
}
}
WORD reg = ReadQCGE(i, err); // Questionable Condition Group Event register
if (reg != QCGEreg[i]) {
variables["Questionable Condition Register"][i] = QCGEreg[i];
status_reg_update = true;
}
if (err_accumulated != FE_SUCCESS)
return err_accumulated & 0xFFFE;
}
if (status_reg_update) {
variables["Interlock"] = InterlockStatus(QCGEreg);
}
return FE_SUCCESS;
}
std::vector<bool> GenesysDriver::InterlockStatus(std::vector<WORD> reg) {
std::vector<bool> vec;
std::transform(reg.begin(), reg.end(), std::back_inserter(vec),
[](DWORD word) { return ((word & 0x8) != 0) ? true : false; });
// std::transform( vec.begin(), vec.end(), interlock_enabled.begin(), vec.begin(), [](bool
// value, bool flag) { return flag ? value : false ;} ); //if the interlock is disabled, we can
// not
return vec;
}
/*
Bit configuration of the Questionable Condition Group Event register is as follows:
Position 15 14 13 12 11 10 9 8
Value - 16384 8192 4096 2048 1024 512 256
Name - POFF PWS PERR GERR PACK UVP ENA
Position 7 6 5 4 3 2 1 0
Value 128 64 32 16 8 4 2 -
Name ILC OFF SO OVP FLD OTP AC -
POFF - Power OFF.
ILC - Interlock.
Set to "1" when the power supply Set to "1" when Interlock signal fault
Power Switch is OFF. occurs.
PWS - Parallel Wait Slave. OFF - DC Output OFF.
Set to "1" when master power supply Set to "1" when the power supply DC
is waiting for slaves to become ready. output is OFF.
PERR - Parallel Error. SO - Shut OFF (Daisy In).
Set to "1" when an error occurs in Set to "1" when Shut OFF signal is high.
Advanced Parallel system. OVP - Over Voltage Protection.
GERR - General Error. Set to "1" when Over Voltage Protection
Unrecoverable system fault. Recycle fault occurs.
AC input.
FLD - Foldback.
PACK - Parallel Acknowledge. Set to "1" when Foldback fault occurs.
Acknowledge new parallel system.
OTP - Over Temperature Protection.
Refer to section 5.9. Set to "1" when Over Temperature
UVP - Under Voltage Protection. Protection fault occurs.
Set to "1" when Under Voltage AC - AC.
Protection fault occurs. Set to "1" when AC fault occurs.
ENA - Enable.
Set to "1" when Enable fault occurs.
*/