diff --git a/coincell.cpp b/coincell.cpp index 127a96552a5f4d2e81e0166250bbcdf6cd052baf..be973084cb0cf13cb1ecceb8fa22f6bab4b86a6e 100644 --- a/coincell.cpp +++ b/coincell.cpp @@ -115,5 +115,15 @@ double CoinCell::getEmptyVoltage() return 3.0; } +int CoinCell::getHeaterId() const +{ + return heaterId; +} + +const std::vector<int>& CoinCell::getMulitplexerChannels() const +{ + return multiplexerChs; +} + BioControl CoinCell::biocontrol; diff --git a/coincell.h b/coincell.h index 00be691c02442de8b041a34a9add2678f1ec60ee..d94e2a2a34c0f7f923a74e17a4c75c9e09518fc3 100644 --- a/coincell.h +++ b/coincell.h @@ -39,6 +39,8 @@ public: void setLastKnownCapacity(double cap); double getFullVoltage(); double getEmptyVoltage(); + int getHeaterId() const; + const std::vector<int>& getMulitplexerChannels() const; static void setBiocontrol(const BioControl& biocontrol); }; diff --git a/expirament.cpp b/expirament.cpp index 8e59c0a4fe45fc852b52833df57a57b78957b21e..acce335674194d25f88f487aea45e5c91d4b1fe0 100644 --- a/expirament.cpp +++ b/expirament.cpp @@ -387,7 +387,7 @@ bool Expirament::startup() Log(Log::ERROR)<<"Unable read ocv from cell holder "<<i; return false; } - else if(ocv < 2.9 || ocv > 4.3) + else if(ocv < (*coinCells)[i]->getEmptyVoltage()-0.1 || ocv > (*coinCells)[i]->getFullVoltage()+0.1) { Log(Log::ERROR)<<"Cell "<<i<<" has a voltage that is out of range"; return false; diff --git a/heater.cpp b/heater.cpp index bfef2fcd190ee44b668bdc48b48bdd3110fe7692..066324ca3761ca0757acd7e17480a4eec2ec37d0 100644 --- a/heater.cpp +++ b/heater.cpp @@ -101,6 +101,29 @@ void Heaters::reconnectDevices() } } +bool Heaters::setMaxCurrent(uint8_t current) +{ + bool ret = true; + for(int i = 0; i < count(); ++i) + { + std::pair<int, int> addr = getAddress(i); + struct device& device = devices[addr.first]; + if(device.bad) + continue; + + device.mutex->lock(); + int retch = coincellhell_set_max_current(&device.device, addr.second, current); + device.mutex->unlock(); + + if(retch != 0) + { + ret = false; + deviceError(i, ERR_CONNECTION); + } + } + return ret; +} + bool Heaters::allReady() { if(mock) @@ -156,8 +179,8 @@ bool Heaters::setHeaterEnabled(int heater, bool enabled) if(mock) return true; - int device = heater / HEATERS_PER_DEVICE; - int heaterId = heater % HEATERS_PER_DEVICE; + int device = getAddress(heater).first; + int heaterId = getAddress(heater).second; if(device >= devices.size() || devices[device].bad) return false; @@ -221,8 +244,8 @@ std::vector<bool> Heaters::getBadDevices() bool Heaters::setSetpoint(int heater, float temperature) { - int device = heater/HEATERS_PER_DEVICE; - int heaterId = heater % HEATERS_PER_DEVICE; + int device = getAddress(heater).first; + int heaterId = getAddress(heater).second; if(devices.size() <= device) return false; @@ -250,8 +273,8 @@ bool Heaters::setSetpoint(int heater, float temperature) bool Heaters::getTemperature(int heater, float& temperature) { - int device = heater / HEATERS_PER_DEVICE; - int heaterId = heater % HEATERS_PER_DEVICE; + int device = getAddress(heater).first; + int heaterId = getAddress(heater).second; if(devices.size() <= device) return false; @@ -394,6 +417,14 @@ void Heaters::safetyCheck() } } +std::pair<int, int> Heaters::getAddress(int heater) const +{ + int device = heater / HEATERS_PER_DEVICE; + int heaterId = heater % HEATERS_PER_DEVICE; + + return {device, heaterId}; +} + void Heaters::enableWatchdogs() { watchdogs = true; diff --git a/heaters.h b/heaters.h index a243d5513e33578b2fb553702d27de8ab62ad6fd..74d9f8def292a97af15ee10207f49cdb9c222ca2 100644 --- a/heaters.h +++ b/heaters.h @@ -59,6 +59,8 @@ public: bool setSetpoint(int heater, float temperature); bool setRamp(int heater, time_t endTime, float temperature); bool getTemperature(int heater, float& temperature); + bool setMaxCurrent(uint8_t current); + std::pair<int, int> getAddress(int heater) const; int count(); void enableWatchdogs(); diff --git a/main.cpp b/main.cpp index b80a2d4ad64eecf9a85c10820dd677ea36387959..8f1c130bec743525c0eed4fd01670c03b55d246c 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,7 @@ #include <cstdint> +#include <eismultiplexer.h> #include <iostream> +#include <memory> #include <thread> #include <libserialport.h> #include <sstream> @@ -111,6 +113,30 @@ static void loggingThreadFn(Heaters* heaters, Multiplexers* multiplexers, } } +static void currentMonitorThreadFn(Heaters* heaters, Vcpps* psu, float minVoltage) +{ + uint8_t maxCurrent = 255; + heaters->setMaxCurrent(maxCurrent); + while(!stop) + { + Vcpps::Status status; + bool ret = psu->getStatus(status); + + if(maxCurrent < 255 && !status.curent_limited) + { + maxCurrent = std::min(255, maxCurrent+20); + Log(Log::INFO)<<"Voltage has recovered at "<<status.voltage<<". Max current now: "<<maxCurrent; + heaters->setMaxCurrent(maxCurrent); + } + else if(status.voltage < minVoltage && maxCurrent > 100) + { + maxCurrent -= 20; + Log(Log::INFO)<<"Voltage low at "<<status.voltage<<", sheading load. Max current now: "<<maxCurrent; + heaters->setMaxCurrent(maxCurrent); + } + } +} + bool listSerialPorts() { struct sp_port** ports; @@ -148,26 +174,29 @@ std::vector<std::unique_ptr<CoinCell>> asign_coincells(std::vector<uint16_t> cel { CoinCell cell(heaters, multiplexers, 0, {3}); std::vector<std::unique_ptr<CoinCell>> coinCells; - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 0, std::vector<int>({3}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 1, std::vector<int>({2}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 2, std::vector<int>({1}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 3, std::vector<int>({0}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 4, std::vector<int>({8}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 5, std::vector<int>({7}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 6, std::vector<int>({5}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 7, std::vector<int>({4}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 8, std::vector<int>({12}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 9, std::vector<int>({11}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 10, std::vector<int>({10}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 11, std::vector<int>({9}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 12, std::vector<int>({17}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 13, std::vector<int>({16}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 14, std::vector<int>({15}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 15, std::vector<int>({14}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 16, std::vector<int>({21}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 17, std::vector<int>({20}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 18, std::vector<int>({19}))); - coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 19, std::vector<int>({18}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 0, std::vector<int>({3, 10}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 1, std::vector<int>({2, 9}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 2, std::vector<int>({1, 0}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 3, std::vector<int>({0, 7}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 4, std::vector<int>({6, 13}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 5, std::vector<int>({5, 12}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 6, std::vector<int>({4, 11}))); + + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 8, std::vector<int>({24, 17}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 9, std::vector<int>({23, 16}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 10, std::vector<int>({22, 15}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 11, std::vector<int>({21, 14}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 12, std::vector<int>({27, 20}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 13, std::vector<int>({26, 19}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 14, std::vector<int>({25, 18}))); + + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 16, std::vector<int>({31}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 17, std::vector<int>({30}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 18, std::vector<int>({29}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 19, std::vector<int>({28}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 20, std::vector<int>({34}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 21, std::vector<int>({33}))); + coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 22, std::vector<int>({32}))); if(!cellids.empty()) { @@ -179,6 +208,24 @@ std::vector<std::unique_ptr<CoinCell>> asign_coincells(std::vector<uint16_t> cel } } + Log(Log::INFO)<<"Connections:"; + for(std::unique_ptr<CoinCell>& cell : coinCells) + { + int heater = cell->getHeaterId(); + const std::vector<int>& muliplexerchs = cell->getMulitplexerChannels(); + + std::pair<int, int> heaterAddr = heaters->getAddress(heater); + + Log(Log::INFO, false)<<"CoincellHell "<<heaterAddr.first<<" unit "<<heaterAddr.second<<" is connected to: "; + + for(int id : muliplexerchs) + { + std::pair<int, channel_t> addr = multiplexers->getAddress(id); + Log(Log::INFO, false)<<" Mulitplexer "<<addr.first<<" channel "<<Multiplexers::chToString(addr.second)<<", "; + } + Log(Log::INFO, false)<<'\n'; + } + return coinCells; } @@ -241,6 +288,7 @@ int main(int argc, char** argv) Log(Log::INFO)<<"Starting Threads"; std::thread safetyThread(safetyThreadFn, &heaters); std::thread loggingThread(loggingThreadFn, &heaters, &multiplexers, &psu, &expirament, config.outdir); + std::thread currentThread(currentMonitorThreadFn, &heaters, &psu, 5); if(!config.skipstart) ret = expirament.startup(); @@ -271,6 +319,7 @@ int main(int argc, char** argv) stop = true; safetyThread.join(); loggingThread.join(); + currentThread.join(); } catch(const startup_failure& ex) { diff --git a/multiplexers.cpp b/multiplexers.cpp index f8d19e6bfec33343ada357d1baf05b924460defd..46f1c979be61b0cb35c405fb5883b1f914c04e0c 100644 --- a/multiplexers.cpp +++ b/multiplexers.cpp @@ -101,37 +101,42 @@ bool Multiplexers::disconnectAll() bool Multiplexers::setCh(int ch, bool connected) { - size_t device = ch/CH_PER_DEVICE ; - channel_t decodedChannel = chNumberToCh(ch % CH_PER_DEVICE); + std::pair<size_t, channel_t> addr = getAddress(ch); - Log(Log::DEBUG)<<"Setting channel "<<chToString(decodedChannel)<<" on device " - <<device<<" to "<<(connected ? "connected" : "disconnected"); + Log(Log::DEBUG)<<"Setting channel "<<chToString(addr.second)<<" on device " + <<addr.first<<" to "<<(connected ? "connected" : "disconnected"); - devices[device].mutex->lock(); + devices[addr.first].mutex->lock(); int ret = 0; if(connected) - ret = eismultiplexer_connect_channel(&devices[device].device, decodedChannel); + ret = eismultiplexer_connect_channel(&devices[addr.first].device, addr.second); else - ret = eismultiplexer_disconnect_channel(&devices[device].device, decodedChannel); - devices[device].mutex->unlock(); + ret = eismultiplexer_disconnect_channel(&devices[addr.first].device, addr.second); + devices[addr.first].mutex->unlock(); return ret == 0; } -bool Multiplexers::setChExlusive(int ch, bool connected) +std::pair<size_t, channel_t> Multiplexers::getAddress(int ch) const { size_t device = ch/CH_PER_DEVICE; channel_t decodedChannel = chNumberToCh(ch % CH_PER_DEVICE); + return {device, decodedChannel}; +} + +bool Multiplexers::setChExlusive(int ch, bool connected) +{ + std::pair<size_t, channel_t> addr = getAddress(ch); - Log(Log::DEBUG)<<"For ch "<<ch<<": exclusively setting channel "<<chToString(decodedChannel)<<" on device " - <<device<<" to "<<(connected ? "connected" : "disconnected"); + Log(Log::DEBUG)<<"For ch "<<ch<<": exclusively setting channel "<<chToString(addr.second)<<" on device " + <<addr.first<<" to "<<(connected ? "connected" : "disconnected"); if(!disconnectAll()) return false; - devices[device].mutex->lock(); - int ret = eismultiplexer_connect_channel_exclusive(&devices[device].device, decodedChannel); - devices[device].mutex->unlock(); + devices[addr.first].mutex->lock(); + int ret = eismultiplexer_connect_channel_exclusive(&devices[addr.first].device, addr.second); + devices[addr.first].mutex->unlock(); if(ret != 0) return false; diff --git a/multiplexers.h b/multiplexers.h index 5d92a9d32b869d63000bdba9e5a57b277a39a370..c556a67fbc129c1cdebb65662c108c2f77426056 100644 --- a/multiplexers.h +++ b/multiplexers.h @@ -23,7 +23,6 @@ private: static channel_t chNumberToCh(int ch); - static std::string chToString(channel_t ch); public: Multiplexers(const std::vector<uint16_t> serials); @@ -31,7 +30,10 @@ public: bool disconnectAll(); bool setCh(int ch, bool connected); bool setChExlusive(int ch, bool connected); + std::pair<size_t, channel_t> getAddress(int ch) const; size_t chCount(); std::vector<bool> getConnected(); bool log(Log::Level level); + + static std::string chToString(channel_t ch); }; diff --git a/options.h b/options.h index 7128b35a2257a92d31166f18b701ca34d03ced28..b08b4a004bd1fbd4fbab42c3d5fbeccd12b6ab90 100644 --- a/options.h +++ b/options.h @@ -37,8 +37,8 @@ static struct argp_option options[] = struct Config { - std::vector<uint16_t> multiplexerSerials = {1, 2, 3, 4}; - std::vector<uint16_t> heaterSerials = {1, 2, 3, 4, 5}; + std::vector<uint16_t> multiplexerSerials = {1, 2, 3, 4, 5}; + std::vector<uint16_t> heaterSerials = {1, 2, 3, 4, 5, 6}; std::string psuPort = "/dev/ttyUSB0"; std::filesystem::path biocontrolpath = "/home/philipp/programming/biocontrol/build/biocontrol.exe"; std::string bioip = "10.2.0.2"; diff --git a/run_expirament.sh b/run_expirament.sh index ffd8acd09ad5aebf17aeeb2151de7eeeebd8151e..62624d7bfafe43c4ca84fee53064867f5f989dd7 100755 --- a/run_expirament.sh +++ b/run_expirament.sh @@ -29,7 +29,7 @@ while [[ $STOP == 0 && RESTART -lt 100 ]]; do echo "Starting expirament at step $STEP substep $SUBSTEP" rm $STEPFILE || true - coincellexpirament -w -l 10 -c "0,1,2,3,4,5,6,7" -o "$OUTDIR-$RESTART" -s $STEP -k $SUBSTEP -f $STEPFILE + coincellexpirament -w -l 10 -c "0,1,2,3,4,5,6" -o "$OUTDIR-$RESTART" -s $STEP -k $SUBSTEP -f $STEPFILE RET=$? RESTART=$((RESTART+1)) @@ -68,8 +68,10 @@ coincellhell_cli -s 2 disable || true coincellhell_cli -s 3 disable || true coincellhell_cli -s 4 disable || true coincellhell_cli -s 5 disable || true +coincellhell_cli -s 6 disable || true eismultiplexer_cli -s 1 clear || true eismultiplexer_cli -s 2 clear || true eismultiplexer_cli -s 3 clear || true eismultiplexer_cli -s 4 clear || true +eismultiplexer_cli -s 5 clear || true rm $STEPFILE || true diff --git a/smtp/smtp.c b/smtp/smtp.c index f90b0907c0e91f26ee68fcbd294403533bfebae8..94c441eb3e75eed3e3484e0f721c2d7de795d1cc 100644 --- a/smtp/smtp.c +++ b/smtp/smtp.c @@ -1775,7 +1775,6 @@ smtp_tls_init(struct smtp *const smtp, SSL_library_init(); SSL_load_error_strings(); - ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); if((smtp->tls_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL){ diff --git a/vcpps.cpp b/vcpps.cpp index cf75c3488e0dadfd79f77e209938b9d108fb9c89..aca109af88b2cb261d349614990bd78aa0fddabf 100644 --- a/vcpps.cpp +++ b/vcpps.cpp @@ -10,6 +10,7 @@ Vcpps::Vcpps(const std::string& portName) { + std::lock_guard<std::mutex> guard(portMutex); sp_return ret = sp_get_port_by_name(portName.c_str(), &port); if(ret != SP_OK) throw startup_failure("No serial port with the name " + portName + "found"); @@ -55,6 +56,7 @@ bool Vcpps::waitForOk() Vcpps& Vcpps::operator=(const Vcpps& in) { + std::lock_guard<std::mutex> guard(portMutex); if(port) sp_free_port(port); if(in.port) @@ -67,6 +69,7 @@ bool Vcpps::setEnabled(bool enabled) std::string buff(COMMAND_OUTPUT_DISABLE); buff.append(std::to_string(!enabled)); buff.push_back('\r'); + std::lock_guard<std::mutex> guard(portMutex); sp_nonblocking_write(port, buff.c_str(), buff.size()); return waitForOk(); } @@ -81,6 +84,7 @@ bool Vcpps::setVoltage(float voltage) std::stringstream ss; ss<<COMMAND_VOLTAGE<<std::setw(3)<<std::setfill('0')<<voltageInt<<'\r'; Log(Log::DEBUG)<<"Writeing "<<ss.str()<<" to psu"; + std::lock_guard<std::mutex> guard(portMutex); sp_nonblocking_write(port, ss.str().c_str(), ss.str().size()); return waitForOk(); } @@ -94,6 +98,7 @@ bool Vcpps::setCurrent(float current) std::stringstream ss; ss<<COMMAND_CURRENT<<std::setw(3)<<std::setfill('0')<<currentInt<<'\r'; Log(Log::DEBUG)<<"Writeing "<<ss.str()<<" to psu"; + std::lock_guard<std::mutex> guard(portMutex); sp_nonblocking_write(port, ss.str().c_str(), ss.str().size()); return waitForOk(); } @@ -103,6 +108,7 @@ bool Vcpps::getStatus(Vcpps::Status& status) char buf[11] = {}; std::string outBuf(COMMAND_STATUS); outBuf.push_back('\r'); + std::lock_guard<std::mutex> guard(portMutex); sp_blocking_write(port, outBuf.c_str(), outBuf.size(), 300); int ret = sp_blocking_read(port, buf, 10, 300); if(ret < 10) diff --git a/vcpps.h b/vcpps.h index 342524b943ffa76a61e8fdc893d8644093402c66..3ee23641dc7d652f666cbfdc9b87296378d3267c 100644 --- a/vcpps.h +++ b/vcpps.h @@ -1,6 +1,7 @@ #pragma once #include <libserialport.h> #include <string> +#include <mutex> class Vcpps { @@ -15,6 +16,7 @@ public: private: struct sp_port* port = nullptr; + std::mutex portMutex; inline static const char* COMMAND_OUTPUT_DISABLE = "SOUT"; inline static const char* COMMAND_VOLTAGE = "VOLT";