Skip to content
Snippets Groups Projects
Commit 827baa2b authored by Carl Philipp Klemm's avatar Carl Philipp Klemm
Browse files

Add handlers for all devices

parent 0c95da19
No related branches found
No related tags found
No related merge requests found
......@@ -8,8 +8,8 @@ find_package(PkgConfig REQUIRED)
find_package(OpenSSL REQUIRED)
pkg_check_modules(MULTIPLEXER REQUIRED eismuliplexer)
pkg_check_modules(COINCELLHELL REQUIRED libcoincellhell)
pkg_check_modules(EISGEN REQUIRED libeisgenerator)
find_package(PkgConfig REQUIRED)
if(WIN32)
set(COINCELLHELL_LIBRARIES -lws2_32 -L/home/philipp/programing/kiss/coincellhell/libcoincellhell/build-w64/ -l:libcoincellhell.dll.a)
set(MULTIPLEXER_LIBRARIES -L/home/philipp/programing/kiss/eismultiplexer/libeismultiplexer/build-w64/ -l:libeismultiplexer.dll.a)
......@@ -24,11 +24,12 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(SRC_FILES main.cpp log.cpp smtp/smtp.c smtp/SMTPMail.cpp)
set(SRC_FILES main.cpp log.cpp smtp/smtp.c smtp/SMTPMail.cpp panic.cpp vcpps.cpp multiplexers.cpp heater.cpp coincell.cpp)
add_executable(${PROJECT_NAME} ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} ${MULTIPLEXER_LIBRARIES} ${SERIALPORT_LIBRARIES} ${COINCELLHELL_LIBRARIES} ${OPENSSL_LIBRARIES})
target_link_libraries(${PROJECT_NAME} ${MULTIPLEXER_LIBRARIES} ${SERIALPORT_LIBRARIES}
${COINCELLHELL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EISGEN_LIBRARIES})
target_include_directories(${PROJECT_NAME} PUBLIC ${MULTIPLEXER_INCLUDE_DIRS}
${SERIALPORT_INCLUDE_DIRS} ${COINCELLHELL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS})
${SERIALPORT_INCLUDE_DIRS} ${COINCELLHELL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS} ${EISGEN_LIBRARIES_INCLUDE_DIRS})
target_compile_definitions(${PROJECT_NAME} PUBLIC SMTP_OPENSSL)
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
#include "coincell.h"
#include <chrono>
#include <thread>
CoinCell::CoinCell(Heaters* heatersIn, Multiplexers* multiplexersIn, int heaterIdIn, int multiplexerChIn):
heaters(heatersIn), multiplexers(multiplexersIn), heaterId(heaterIdIn), multiplexerCh(multiplexerChIn)
{
}
void CoinCell::connectExclusive()
{
multiplexers->setChExlusive(multiplexerCh, true);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
void CoinCell::dissconnect()
{
multiplexers->setCh(multiplexerCh, false);
}
void CoinCell::setTemperature(float temperature)
{
heaters->setSetpoint(heaterId, temperature);
}
bool CoinCell::measureOcv(float& ocv)
{
connectExclusive();
ocv = 4.2;
dissconnect();
return true;
}
bool CoinCell::isShorted(bool& detected)
{
connectExclusive();
dissconnect();
return false;
}
std::vector<eis::DataPoint> CoinCell::takeMesurement()
{
connectExclusive();
std::vector<eis::DataPoint> mesurement;
dissconnect();
return mesurement;
}
#pragma once
#include "heaters.h"
#include "multiplexers.h"
#include <vector>
#include <eisgenerator/eistype.h>
class CoinCell
{
private:
int heaterId;
int multiplexerCh;
Heaters* heaters;
Multiplexers* multiplexers;
public:
CoinCell(Heaters* heaters, Multiplexers* multiplexers, int heaterId, int multiplexerCh);
void connectExclusive();
void dissconnect();
void setTemperature(float temperature);
bool measureOcv(float& ocv);
bool isShorted(bool& detected);
std::vector<eis::DataPoint> takeMesurement();
};
#include <coincellhell/coincellhell.h>
#include <ctime>
#include <memory>
#include "heaters.h"
#include "startupfailure.h"
......@@ -10,13 +11,14 @@ Heaters::Heaters(const std::vector<uint16_t> serials,
deviceFailCb(deviceFailCbIn), heaterFailCb(heaterFailCbIn)
{
Log(Log::INFO)<<"inializeing "<<serials.size()<<" coincellhell devices with "<<serials.size()*HEATERS_PER_DEVICE<<" heaters";
devices.resize(serials.size(), {});
devices.resize(serials.size());
if(mock)
return;
for(size_t i = 0; i < serials.size(); ++i)
{
devices[i].mutex = std::make_unique<std::mutex>();
int ret = coincellhell_connect(&devices[i].device, serials[i]);
if(ret != 0)
{
......@@ -48,9 +50,11 @@ bool Heaters::heaterBad(int heater)
void Heaters::recoverDevice(int device)
{
devices[device].mutex->lock();
coincellhell_disconnect(&devices[device].device);
int ret = coincellhell_connect(&devices[device].device, devices[device].serial);
devices[device].mutex->unlock();
if(ret == 0)
deviceError(device, ERR_RECOVERED);
}
......@@ -68,7 +72,9 @@ bool Heaters::allReady()
continue;
bool deviceReady;
devices[i].mutex->lock();
int ret = coincellhell_check_ready(&devices[i].device, &deviceReady);
devices[i].mutex->unlock();
if(ret != 0)
deviceError(i, ERR_CONNECTION);
......@@ -93,7 +99,9 @@ bool Heaters::setHeaterEnabled(int heater, bool enabled)
if(device >= devices.size() || devices[device].bad)
return false;
devices[device].mutex->lock();
int ret = coincellhell_set_enabled(&devices[device].device, heater, enabled);
devices[device].mutex->unlock();
if(ret != 0)
{
......@@ -124,7 +132,9 @@ bool Heaters::wait(int timeout)
return false;
bool ready;
devices[i].mutex->lock();
int ret = coincellhell_check_ready(&devices[i].device, &ready);
devices[i].mutex->unlock();
if(ret != 0)
deviceError(i, ERR_CONNECTION);
......@@ -193,7 +203,9 @@ void Heaters::log(Log::Level level)
{
for(ssize_t heater = 0; heater < HEATERS_PER_DEVICE; ++heater)
{
devices[i].mutex->lock();
int ret = coincellhell_get_state(&devices[i].device, heater, &states[heater]);
devices[i].mutex->unlock();
if(ret != 0)
deviceError(i, ERR_CONNECTION);
if(deviceBad(i))
......@@ -254,7 +266,10 @@ void Heaters::safetyCheck()
float frontTemperature;
float sideTemperature;
devices[i].mutex->lock();
int ret = coincellhell_get_temperature(&devices[i].device, heater, TEMP_LOCATION_FRONT, &frontTemperature);
devices[i].mutex->unlock();
if(ret != 0)
deviceError(i, ERR_CONNECTION);
if(deviceBad(i))
......@@ -267,7 +282,9 @@ void Heaters::safetyCheck()
--heater;
}
devices[i].mutex->lock();
ret = coincellhell_get_temperature(&devices[i].device, heater, TEMP_LOCATION_FRONT, &sideTemperature);
devices[i].mutex->unlock();
if(ret != 0)
deviceError(i, ERR_CONNECTION);
if(deviceBad(i))
......@@ -282,7 +299,9 @@ void Heaters::safetyCheck()
if(frontTemperature > PANIC_TEMPERATURE || sideTemperature > PANIC_TEMPERATURE)
{
devices[i].mutex->lock();
coincellhell_set_enabled(&devices[i].device, heater, false);
devices[i].mutex->unlock();
deviceError(i, ERR_OVERTEMP);
}
}
......
......@@ -4,6 +4,8 @@
#include <coincellhell/coincellhell.h>
#include <cstdint>
#include <functional>
#include <mutex>
#include <memory>
#include "log.h"
......@@ -26,6 +28,7 @@ private:
struct device
{
struct coincellhell device;
std::unique_ptr<std::mutex> mutex;
uint16_t serial;
bool bad;
bool badHeater[HEATERS_PER_DEVICE];
......@@ -41,7 +44,7 @@ private:
bool heaterBad(int heater);
void recoverDevice(int device);
private:
public:
Heaters(const std::vector<uint16_t> serials,
std::function<void(int device, uint16_t serial, int code)> deviceFailCb,
......
......@@ -18,6 +18,11 @@
*/
#include "log.h"
#include "smtp/smtp.h"
Log::Log()
{
}
Log::Log(Level type, bool endlineI): endline(endlineI)
{
......@@ -30,14 +35,30 @@ Log::Log(Level type, bool endlineI): endline(endlineI)
Log::~Log()
{
if(opened && endline)
if(opened)
{
bool ret;
if(endline)
{
std::cout<<'\n';
buffer<<'\n';
}
std::string mailbody = buffer.str();
mutex.unlock();
if(sendmailEnabled && msglevel >= sendmailLevel)
{
sendmailEnabled = false;
ret = sendmail("Coincell Expirament", mailbody);
if(!ret)
Log(WARN)<<"Unable to send message to "<<reportingAddr;
sendmailEnabled = true;
}
}
buffer.clear();
opened = false;
}
std::string Log::getLabel(Level level)
{
std::string label;
......@@ -59,5 +80,82 @@ std::string Log::getLabel(Level level)
return label;
}
void Log::setupSendmail(std::string serverIn, std::string portIn, std::string usernameIn,
std::string passwordIn, std::string fromNameIn, std::string reportingAddrIn)
{
server = serverIn;
port = portIn;
username = usernameIn;
password = passwordIn;
fromName = fromNameIn;
reportingAddr = reportingAddrIn;
sendmailEnabled = true;
}
bool Log::sendmail(const std::string& subj, const std::string& body)
{
smtp* mailer;
smtp_status_code ret = smtp_open(server.c_str(), port.c_str(),
SMTP_SECURITY_TLS, SMTP_NO_CERT_VERIFY, NULL, &mailer);
if(ret != SMTP_STATUS_OK)
{
Log(Log::ERROR)<<"Mailer unable open "<<server<<" returns "<<ret;
return false;
}
ret = smtp_auth(mailer, SMTP_AUTH_PLAIN, username.c_str(), password.c_str());
if(ret != SMTP_STATUS_OK)
{
smtp_close(mailer);
Log(Log::ERROR)<<"Mailer unable auth with "<<server<<" smtp returns "<<ret;
return false;
}
ret = smtp_address_add(mailer, SMTP_ADDRESS_FROM, username.c_str(), fromName.c_str());
if(ret != SMTP_STATUS_OK)
{
smtp_close(mailer);
Log(Log::ERROR)<<"Mailer unable add address "<<ret;
return false;
}
ret = smtp_address_add(mailer, SMTP_ADDRESS_TO, reportingAddr.c_str(), NULL);
if(ret != SMTP_STATUS_OK)
{
smtp_close(mailer);
Log(Log::ERROR)<<"Mailer unable add address "<<ret;
return false;
}
ret = smtp_header_add(mailer, "Subject", subj.c_str());
if(ret != SMTP_STATUS_OK)
{
smtp_close(mailer);
Log(Log::ERROR)<<"Mailer unable add subject "<<ret;
return false;
}
ret = smtp_mail(mailer, body.c_str());
if(ret != SMTP_STATUS_OK)
{
smtp_close(mailer);
Log(Log::ERROR)<<"Mailer unable send mail "<<ret;
return false;
}
return true;
}
bool Log::headers = false;
Log::Level Log::level = WARN;
Log::Level Log::sendmailLevel = WARN;
bool Log::sendmailEnabled = false;
std::stringstream Log::buffer;
std::string Log::server;
std::string Log::port;
std::string Log::username;
std::string Log::password;
std::string Log::fromName;
std::string Log::reportingAddr;
std::mutex Log::mutex;
......@@ -20,6 +20,10 @@
#pragma once
#include <iostream>
#include <string>
#include <mutex>
#include <sstream>
#include <ctime>
#include <iomanip>
class Log
{
......@@ -38,23 +42,52 @@ private:
Level msglevel = DEBUG;
bool endline = true;
static std::stringstream buffer;
static bool sendmailEnabled;
static std::string server;
static std::string port;
static std::string username;
static std::string password;
static std::string fromName;
static std::string reportingAddr;
static std::mutex mutex;
std::string getLabel(Level level);
bool sendmail(const std::string& subj, const std::string& body);
public:
static bool headers;
static Level level;
static Level sendmailLevel;
Log() {}
Log();
Log(Level type, bool endlineI = true);
~Log();
static void setupSendmail(std::string serverIn, std::string portIn, std::string usernameIn,
std::string passwordIn, std::string fromNameIn, std::string reportingAddrIn);
template<class T> Log &operator<<(const T &msg)
{
if(msglevel >= level)
{
std::cout<<msg;
if(!opened)
{
mutex.lock();
opened = true;
time_t timestamp = std::time(nullptr);
time_t t = std::time(nullptr);
auto tm = *std::localtime(&t);
std::cout<<std::put_time(&tm, "%Y-%m-%d %H:%M:%S")<<": ";
buffer<<std::put_time(&tm, "%Y-%m-%d %H:%M:%S")<<": ";
}
std::cout<<msg;
buffer<<msg;
}
return *this;
}
......
#include <cstdint>
#include <iostream>
#include <thread>
#include <libserialport.h>
#include <sstream>
#include <thread>
#include <filesystem>
#include <fstream>
#include <vector>
#include <libserialport.h>
#include "coincell.h"
#include "log.h"
#include "heaters.h"
#include "smtp/SMTPMail.h"
#include "multiplexers.h"
#include "vcpps.h"
#include "startupfailure.h"
#include "panic.h"
#define VERSION "0.1"
struct Config
{
std::vector<uint16_t> multiplexerSerials = {1, 2, 3, 4};
std::vector<uint16_t> heaterSerials = {1, 2, 3, 4, 5};
std::string psuPort = "/dev/ttyUSB0";
float psuVoltage = 10;
float psuCurrent = 5;
size_t globalStep = 0;
};
void devicefailed(Vcpps& psu, int device, uint16_t serial, int code)
{
std::stringstream ss;
Log(Log::WARN)<<"Heater device "<<device<<" with serial number "<<serial<<" has "
<<(code == Heaters::ERR_RECOVERED ? "recovered" : "failed")<<" with code "<<code;
if(code == Heaters::ERR_OVERTEMP)
{
Log(Log::ERROR)<<"Critical overtemp on device "<<device<<" with serial number "<<serial<<"\n\nEMERGENCY SHUTDOWN!!";
panic(psu);
}
}
void heaterfailed(int heater, int device)
{
Log(Log::WARN)<<"Heater "<<heater<<" on device "<<device<<" has failed";
}
static void safetyThreadFn(Heaters* heaters)
{
Log(Log::INFO)<<"Safety thread has started";
while(!stop)
{
heaters->safetyCheck();
std::this_thread::sleep_for(std::chrono::seconds(10));
}
}
static void loggingThreadFn(Heaters* heaters, Multiplexers* multiplexers, Vcpps* psu)
{
Log(Log::INFO)<<"Logging thread has started";
while(!stop)
{
time_t t = std::time(nullptr);
auto tm = *std::localtime(&t);
Log(Log::INFO)<<std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
heaters->log(Log::INFO);
Vcpps::Status psustatus;
bool ret = psu->getStatus(psustatus);
Log(Log::ERROR)<<"PSU: ";
if(!ret)
{
Log(Log::ERROR)<<"Could not read psu!";
}
else
{
Log(Log::INFO)<<"\tVoltage: "<<psustatus.voltage;
Log(Log::INFO)<<"\tCurrent: "<<psustatus.current;
Log(Log::INFO)<<"\tCurrent limited: "<<(psustatus.curent_limited ? "true" : "false");
}
multiplexers->log(Log::INFO);
std::this_thread::sleep_for(std::chrono::seconds(30));
}
}
bool listSerialPorts()
{
struct sp_port** ports;
sp_return ret = sp_list_ports(&ports);
if(ret != SP_OK)
{
Log(Log::ERROR)<<"Unable to list serial ports";
return false;
}
for(size_t i = 0; ports[i] != nullptr; ++i)
{
enum sp_transport transport = sp_get_port_transport(ports[i]);
if(transport != SP_TRANSPORT_USB)
continue;
Log(Log::INFO)<<"USB serial port "<<i;
Log(Log::INFO)<<"\tManufacturer: "<<sp_get_port_usb_manufacturer(ports[i]);
Log(Log::INFO)<<"\tProduct: "<<sp_get_port_usb_product(ports[i]);
Log(Log::INFO)<<"\tSerial: "<<sp_get_port_usb_serial(ports[i]);
int vid;
int pid;
sp_get_port_usb_vid_pid(ports[i], &vid, &pid);
Log(Log::INFO)<<std::hex<<"\tVID: "<<vid<<" PID: "<<pid<<std::dec;
}
sp_free_port_list(ports);
return true;
}
int main(int argc, char** argv)
{
Log::level = Log::DEBUG;
Log::sendmailLevel = Log::WARN;
Config config;
Log(Log::INFO)<<"CoinCellExpierament "<<VERSION;
Log(Log::INFO)<<"Running startup sequence";
SMTPMail mailer;
listSerialPorts();
try
{
Log(Log::INFO)<<"Geting PSU";
Vcpps psu(config.psuPort);
Vcpps::Status status;
bool ret = psu.getStatus(status);
if(!ret)
{
Log(Log::ERROR)<<"Unable to read from psu";
return 1;
}
Log(Log::INFO)<<"PSU voltage: "<<status.voltage<<" current: "<<status.current
<<" is currently "<<(status.curent_limited ? "" : "not")<<" current limited";
Log(Log::INFO)<<"Setting psu voltage to "<<config.psuVoltage;
ret = psu.setVoltage(config.psuVoltage);
if(!ret)
{
Log(Log::ERROR)<<"Unable to set psu voltage";
return 1;
}
Log(Log::INFO)<<"Setting psu current to "<<config.psuCurrent;
ret = psu.setCurrent(config.psuCurrent);
if(!ret)
{
Log(Log::ERROR)<<"Unable to set psu current";
return 1;
}
ret = psu.setEnabled(true);
if(!ret)
{
Log(Log::ERROR)<<"Unable to enable psu output";
return 1;
}
Log(Log::INFO)<<"Aquireing heaters and multiplexers";
Heaters heaters(config.heaterSerials,
[&psu](int device, uint16_t serial, int code){devicefailed(psu, device, serial, code);},
&heaterfailed);
Multiplexers multiplexers(config.multiplexerSerials);
std::vector<std::unique_ptr<CoinCell>> coinCells;
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 0, 3));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 1, 2));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 2, 1));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 3, 0));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 4, 7));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 5, 6));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 6, 5));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 7, 4));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 8, 11));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 9, 10));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 10, 9));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 11, 8));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 12, 15));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 13, 14));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 14, 13));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 15, 12));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 16, 19));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 17, 18));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 18, 17));
coinCells.push_back(std::make_unique<CoinCell>(&heaters, &multiplexers, 19, 16));
loggingThreadFn(&heaters, &multiplexers, &psu);
Vcpps psu();
Log(Log::INFO)<<"Checking coincells";
float leadOcv;
for(size_t i = 0; i < coinCells.size(); ++i)
{
Log(Log::INFO)<<"Reading cell "<<i;
bool shorted;
bool ret = coinCells[i]->isShorted(shorted);
if(!ret)
{
Log(Log::ERROR)<<"Unable to read shorted state from cell holder "<<i;
return 1;
}
else if(shorted)
{
Log(Log::ERROR)<<"Coin cell holder "<<i<<" is shorted!";
return 1;
}
float ocv;
ret = coinCells[i]->measureOcv(ocv);
if(!ret)
{
Log(Log::ERROR)<<"Unable read ocv from cell holder "<<i;
return 1;
}
else if(i == 0)
{
leadOcv = ocv;
}
else if(std::abs(leadOcv - ocv) > 0.2)
{
Log(Log::ERROR)<<"Cell "<<i<<" has a voltage delta of "<<std::abs(leadOcv - ocv)<<" compeared to Cell 0, can not continue";
return 1;
}
Log(Log::INFO)<<"Cell "<<i<<" has a voltage of "<<ocv;
}
Log(Log::INFO)<<"Enableing email system";
Log::setupSendmail("smtp.strato.de", "465", "klemm@rhd-instruments.de", "RmUE5jBRkxCGZ1vpa65a", "Carl Klemm", "carl@uvos.xyz");
Log(Log::INFO)<<"Starting Threads";
std::thread safetyThread(safetyThreadFn, &heaters);
std::thread loggingThread(loggingThreadFn, &heaters, &multiplexers, &psu);
while(true)
std::this_thread::sleep_for(std::chrono::seconds(30));
}
catch(const startup_failure& ex)
{
Log(Log::ERROR)<<"Unable startup: "<<ex.what();
return 1;
}
return 0;
}
#include "multiplexers.h"
#include <eismultiplexer.h>
#include "startupfailure.h"
Multiplexers::Multiplexers(const std::vector<uint16_t> serials)
{
devices.resize(serials.size());
for(size_t i = 0; i < serials.size(); ++i)
{
int ret = eismultiplexer_connect(&devices[i].device, serials[i]);
if(ret != 0)
throw startup_failure("Unable to connect to mulitplexer with serial " + std::to_string(serials[i]));
devices[i].mutex = std::make_unique<std::mutex>();
}
disconnectAll();
}
channel_t Multiplexers::chNumberToCh(int ch)
{
switch(ch)
{
case 0:
return CHANNEL_A;
case 1:
return CHANNEL_B;
case 2:
return CHANNEL_C;
case 3:
return CHANNEL_D;
case 4:
return CHANNEL_E;
case 5:
return CHANNEL_F;
case 6:
return CHANNEL_G;
default:
return CHANNEL_NONE;
}
}
bool Multiplexers::connectAll()
{
for(Device& device : devices)
{
device.mutex->lock();
int ret = eismultiplexer_connect_channel(&device.device,
(channel_t)(CHANNEL_A | CHANNEL_B | CHANNEL_C | CHANNEL_D | CHANNEL_E | CHANNEL_F | CHANNEL_G));
device.mutex->unlock();
if(ret != 0)
return false;
}
return true;
}
bool Multiplexers::disconnectAll()
{
for(Device& device : devices)
{
device.mutex->lock();
int ret = eismultiplexer_disconnect_channel(&device.device, (channel_t)(CHANNEL_NONE));
device.mutex->unlock();
if(ret != 0)
return false;
}
return true;
}
bool Multiplexers::setCh(int ch, bool connected)
{
size_t device = ch % 6;
int decodedChannel = ch/6;
Log(Log::DEBUG)<<"Setting channel "<<decodedChannel<<" on device "
<<device<<" to "<<(connected ? "connected" : "disconnected")<<" using mask "
<<(static_cast<int>(chNumberToCh(decodedChannel)));
devices[device].mutex->lock();
int ret = 0;
if(connected)
ret = eismultiplexer_connect_channel(&devices[device].device, chNumberToCh(decodedChannel));
else
ret = eismultiplexer_disconnect_channel(&devices[device].device, chNumberToCh(decodedChannel));
devices[device].mutex->unlock();
return ret == 0;
}
bool Multiplexers::setChExlusive(int ch, bool connected)
{
size_t device = ch % CH_PER_DEVICE;
int decodedChannel = ch/CH_PER_DEVICE;
Log(Log::DEBUG)<<"Exclusively setting channel "<<decodedChannel<<" on device "
<<device<<" to "<<(connected ? "connected" : "disconnected")<<" using mask "
<<(static_cast<int>(chNumberToCh(decodedChannel)));
if(!disconnectAll())
return false;
int ret = eismultiplexer_connect_channel_exclusive(&devices[device].device, chNumberToCh(decodedChannel));
if(ret != 0)
return false;
return true;
}
size_t Multiplexers::chCount()
{
return devices.size()*CH_PER_DEVICE;
}
std::vector<bool> Multiplexers::getConnected()
{
std::vector<bool> connectedChannels(chCount(), false);
for(size_t i = 0; i < devices.size(); ++i)
{
channel_t channels = eismultiplexer_get_connected(&devices[i].device);
connectedChannels[i*CH_PER_DEVICE+0] = channels & CHANNEL_A;
connectedChannels[i*CH_PER_DEVICE+1] = channels & CHANNEL_B;
connectedChannels[i*CH_PER_DEVICE+2] = channels & CHANNEL_C;
connectedChannels[i*CH_PER_DEVICE+3] = channels & CHANNEL_D;
connectedChannels[i*CH_PER_DEVICE+4] = channels & CHANNEL_E;
connectedChannels[i*CH_PER_DEVICE+5] = channels & CHANNEL_F;
connectedChannels[i*CH_PER_DEVICE+6] = channels & CHANNEL_G;
}
return connectedChannels;
}
bool Multiplexers::log(Log::Level level)
{
std::vector<bool> connectedChannels = getConnected();
Log(level, false)<<"Multiplexer channels: ";
for(size_t i = 0; i < connectedChannels.size(); ++i)
Log(level, false)<<(connectedChannels[i] ? "1, " : "0, ");
Log(level)<<"";
return true;
}
#pragma once
#include <eismultiplexer.h>
#include <vector>
#include <mutex>
#include <memory>
#include "log.h"
class Multiplexers
{
private:
static constexpr int CH_PER_DEVICE = 7;
struct Device
{
eismultiplexer device;
std::unique_ptr<std::mutex> mutex;
};
std::vector<Device> devices;
static channel_t chNumberToCh(int ch);
public:
Multiplexers(const std::vector<uint16_t> serials);
bool connectAll();
bool disconnectAll();
bool setCh(int ch, bool connected);
bool setChExlusive(int ch, bool connected);
size_t chCount();
std::vector<bool> getConnected();
bool log(Log::Level level);
};
#include "panic.h"
bool stop = false;
bool fail = false;
void panic(Vcpps& psu)
{
psu.setEnabled(false);
stop = true;
fail = true;
}
#pragma once
#include "vcpps.h"
extern bool stop;
extern bool fail;
void panic(Vcpps& psu);
......@@ -3,7 +3,7 @@
#include "startupfailure.h"
#include <cstdint>
#include <libserialport.h>
#include <string>
Vcpps::Vcpps(const std::string& portName)
{
......@@ -80,3 +80,42 @@ bool Vcpps::setCurrent(float current)
sp_nonblocking_write(port, buff.c_str(), buff.size());
return waitForOk();
}
bool Vcpps::getStatus(Vcpps::Status& status)
{
char buf[10];
std::string outBuf(COMMAND_STATUS);
outBuf.push_back('\r');
sp_blocking_write(port, outBuf.c_str(), outBuf.size(), 300);
int ret = sp_blocking_read(port, buf, 10, 300);
if(ret < 10)
return false;
std::string currentStr;
outBuf.push_back(buf[4]);
outBuf.push_back(buf[5]);
outBuf.push_back('.');
outBuf.push_back(buf[6]);
outBuf.push_back(buf[7]);
std::string voltageStr;
outBuf.push_back(buf[0]);
outBuf.push_back(buf[1]);
outBuf.push_back('.');
outBuf.push_back(buf[2]);
outBuf.push_back(buf[3]);
try
{
status.voltage = std::stof(voltageStr);
status.current = std::stof(currentStr);
status.curent_limited = buf[8] == '1';
}
catch(std::invalid_argument& ex)
{
sp_drain(port);
return false;
}
return waitForOk();
}
......@@ -4,12 +4,22 @@
class Vcpps
{
public:
struct Status
{
float voltage;
float current;
bool curent_limited;
};
private:
struct sp_port* port = nullptr;
inline static const char* COMMAND_OUTPUT_DISABLE = "SOUT";
inline static const char* COMMAND_VOLTAGE = "VOLT";
inline static const char* COMMAND_CURRENT = "CURR";
inline static const char* COMMAND_STATUS = "GETD";
bool waitForOk();
......@@ -22,4 +32,5 @@ public:
bool setEnabled(bool enabled);
bool setVoltage(float voltage);
bool setCurrent(float current);
bool getStatus(Status& status);
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment