diff --git a/CMakeLists.txt b/CMakeLists.txt index 364e85a473b1dd70bf690c96f56da001d9ea6b26..af8ca29bda7815bc59318047f6106c6c0ebcaade 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ find_package(OpenSSL REQUIRED) pkg_check_modules(MULTIPLEXER REQUIRED eismuliplexer) pkg_check_modules(COINCELLHELL REQUIRED libcoincellhell) pkg_check_modules(EISGEN REQUIRED libeisgenerator) +pkg_check_modules(READLINE readline) if(WIN32) set(COINCELLHELL_LIBRARIES -lws2_32 -L/home/philipp/programing/kiss/coincellhell/libcoincellhell/build-w64/ -l:libcoincellhell.dll.a) @@ -34,6 +35,7 @@ set(SRC_FILES multiplexers.cpp heater.cpp coincell.cpp + coincells.cpp biocontrol.cpp tokenize.cpp expirament.cpp @@ -47,3 +49,27 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${MULTIPLEXER_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) + + +if(READLINE_FOUND) + message("Readline found, will build testing application") + set(SRC_FILES_TEST + test.cpp + log.cpp + multiplexers.cpp + smtp/smtp.c + smtp/SMTPMail.cpp + biocontrol.cpp + vcpps.cpp + heater.cpp + coincell.cpp + coincells.cpp + tokenize.cpp + randomgen.cpp) + add_executable(${PROJECT_NAME}_test ${SRC_FILES_TEST}) + target_link_libraries(${PROJECT_NAME}_test ${READLINE_LIBRARIES} ${MULTIPLEXER_LIBRARIES} ${SERIALPORT_LIBRARIES} + ${COINCELLHELL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EISGEN_LIBRARIES}) + target_include_directories(${PROJECT_NAME}_test PUBLIC ${READLINE_INCLUDE_DIRS} ${MULTIPLEXER_INCLUDE_DIRS} + ${SERIALPORT_INCLUDE_DIRS} ${COINCELLHELL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS} ${EISGEN_LIBRARIES_INCLUDE_DIRS}) + target_compile_definitions(${PROJECT_NAME}_test PUBLIC SMTP_OPENSSL) +endif(READLINE_FOUND) diff --git a/coincells.cpp b/coincells.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7c45851b9ed7df52b586aba43df44e4b425aa6c --- /dev/null +++ b/coincells.cpp @@ -0,0 +1,62 @@ +#include "coincells.h" + +#include "log.h" + +std::vector<std::unique_ptr<CoinCell>> asign_coincells(std::vector<uint16_t> cellids, Heaters* heaters, Multiplexers* multiplexers) +{ + 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, 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, 8}))); + 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()) + { + for(ssize_t i = coinCells.size()-1; i >= 0; --i) + { + auto search = std::find(cellids.begin(), cellids.end(), i); + if(search == cellids.end()) + coinCells.erase(coinCells.begin()+i); + } + } + + 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, false)<<" Mulitplexer "<<addr.first<<" channel "<<Multiplexers::chToString(addr.second)<<", "; + } + Log(Log::INFO, false)<<'\n'; + } + + return coinCells; +} diff --git a/coincells.h b/coincells.h new file mode 100644 index 0000000000000000000000000000000000000000..668cc05087620e410aaa9713b69454e8fab96086 --- /dev/null +++ b/coincells.h @@ -0,0 +1,7 @@ +#pragma once + +#include "coincell.h" +#include "multiplexers.h" +#include "heaters.h" + +std::vector<std::unique_ptr<CoinCell>> asign_coincells(std::vector<uint16_t> cellids, Heaters* heaters, Multiplexers* multiplexers); diff --git a/log.cpp b/log.cpp index 285016010859c8984bdfc37a5d20a91feef7d82a..f59aa2e213a21df247124baa05f9f9b010ef10c7 100644 --- a/log.cpp +++ b/log.cpp @@ -19,6 +19,7 @@ #include "log.h" #include "smtp/smtp.h" +#include <cassert> Log::Log() { @@ -77,6 +78,9 @@ std::string Log::getLabel(Level level) case ERROR: label = "ERROR"; break; + case NEVER: + assert(false); + break; } return label; } diff --git a/log.h b/log.h index 73f971feec689b065b63740d6a778083d477f65e..695a841833fa39099441119aaf78acedade8d819 100644 --- a/log.h +++ b/log.h @@ -34,7 +34,8 @@ public: DEBUG, INFO, WARN, - ERROR + ERROR, + NEVER }; private: diff --git a/main.cpp b/main.cpp index 786ffb74d0e22b97b52fe0d74a24905e53d8ecc8..a1a4612e02fd879f487378c81f4d27e80d68f402 100644 --- a/main.cpp +++ b/main.cpp @@ -13,8 +13,10 @@ #include <sys/stat.h> #include <fstream> + #include "biocontrol.h" #include "coincell.h" +#include "coincells.h" #include "log.h" #include "heaters.h" #include "multiplexers.h" @@ -171,65 +173,6 @@ bool listSerialPorts() return true; } -std::vector<std::unique_ptr<CoinCell>> asign_coincells(std::vector<uint16_t> cellids, Heaters* heaters, Multiplexers* multiplexers) -{ - 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, 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, 8}))); - 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()) - { - for(ssize_t i = coinCells.size()-1; i >= 0; --i) - { - auto search = std::find(cellids.begin(), cellids.end(), i); - if(search == cellids.end()) - coinCells.erase(coinCells.begin()+i); - } - } - - 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, false)<<" Mulitplexer "<<addr.first<<" channel "<<Multiplexers::chToString(addr.second)<<", "; - } - Log(Log::INFO, false)<<'\n'; - } - - return coinCells; -} - int main(int argc, char** argv) { umask(0); diff --git a/test.cpp b/test.cpp index 6f2d1ef812a7c479cf39c7d5730396203b6adc99..a38ace51a71437cd657bf0da2fc7ffd967eeee6c 100644 --- a/test.cpp +++ b/test.cpp @@ -1,45 +1,195 @@ #include <thread> +#include <readline/readline.h> +#include <readline/history.h> +#include "coincell.h" #include "log.h" +#include "options.h" -static void logThread() +#include "tokenize.h" +#include "vcpps.h" +#include "heaters.h" +#include "multiplexers.h" +#include "coincells.h" +#include "startupfailure.h" + +void devicefailed(Vcpps& psu, int device, uint16_t serial, int code) { - static int a = 42; + std::stringstream ss; + Log(Log::WARN)<<"Heater device "<<device<<" with serial number "<<serial<<" has " + <<(code == Heaters::ERR_RECOVERED ? "recovered" : "failed")<<" with code "<<code; +} - while(true) - { - Log(Log::INFO)<<"DEBUG"<<' '<<++a; - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } +void heaterfailed(int heater, int device) +{ + Log(Log::WARN)<<"Heater "<<heater<<" on device "<<device<<" has failed"; } -static void logThreadTwo() +bool preparePsu(Vcpps* psu, float voltage, float current) { - static unsigned int a = 0; + Vcpps::Status status; + Log(Log::INFO)<<"Setting psu voltage to "<<voltage; + bool ret = psu->setVoltage(voltage); + if(!ret) + { + Log(Log::ERROR)<<"Unable to set psu voltage"; + return false; + } + Log(Log::INFO)<<"Setting psu current to "<<current; + ret = psu->setCurrent(current); + if(!ret) + { + Log(Log::ERROR)<<"Unable to set psu current"; + return false; + } + ret = psu->setEnabled(true); + if(!ret) + { + Log(Log::ERROR)<<"Unable to enable psu output"; + return false; + } + Log(Log::INFO)<<"Waiting for psu to stablize"; + std::this_thread::sleep_for(std::chrono::seconds(2)); - while(true) + ret = psu->getStatus(status); + if(!ret || status.curent_limited) { - a+=2; - Log(Log::INFO)<<"DEBUG 2"<<' '<<a; - std::this_thread::sleep_for(std::chrono::microseconds(1)); + Log(Log::ERROR)<<"Psu is overcurrent, abort"; + psu->setEnabled(false); + return false; } + + Log(Log::INFO)<<"PSU voltage: "<<status.voltage<<" current: "<<status.current + <<" is currently "<<(status.curent_limited ? "" : "not")<<" current limited"; + return true; +} + +void print_cmd_help(const std::string& line) +{ + Log(Log::INFO)<<line<<" is not a valid command. Valid commands: connect (c), disconnect (d), set (s), get (g), clear."<< + "all commands except clear require a number containing the id of the coincell after the command"; } -int main() +int main(int argc, char** argv) { Log::level = Log::INFO; + Log::sendmailLevel = Log::NEVER; + Log::headers = false; - Log(Log::INFO)<<"Starting thread"; + Config config; + argp_parse(&argp, argc, argv, 0, 0, &config); - std::thread threadA(logThread); - std::thread threadB(logThreadTwo); + try + { + Log(Log::INFO)<<"Geting PSU"; + Vcpps psu(config.psuPort); + psu.setEnabled(false); + + 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 = asign_coincells(config.cells, &heaters, &multiplexers); + + bool ret = preparePsu(&psu, 10, 10); + if(!ret) + return 2; + + while(true) + { + std::string line = std::string(readline("> ")); + + if(line.empty()) + continue; + + std::vector<std::string> tokens = tokenize(line, ' '); - while(true) + int coincellId = 0; + + if(tokens.size() < 2 && tokens[0] != "clear") + { + print_cmd_help(line); + continue; + } + else if(tokens[0] != "clear" && tokens[0] != "get" && tokens.size() >= 2) + { + coincellId = std::stol(tokens[1]); + if(coincellId < 0 || coincellId > coinCells.size()) + Log(Log::ERROR)<<"Invalid coin cell id: "<<tokens[1]; + } + else if(tokens.size() < 2 && tokens[0] != "clear" && tokens[0] != "get") + { + print_cmd_help(line); + } + + if(tokens[0] == "connect" || tokens[0] == "c") + { + bool ret = coinCells[coincellId]->setConnected(true); + if(!ret) + Log(Log::ERROR)<<"unable to connect coin cell "<<coincellId; + else + Log(Log::ERROR)<<"connected coin cell "<<coincellId; + } + else if(tokens[0] == "disconnect" || tokens[0] == "d") + { + bool ret = coinCells[coincellId]->setConnected(false); + if(!ret) + Log(Log::ERROR)<<"unable to disconnect coin cell "<<coincellId; + else + Log(Log::ERROR)<<"disconnected coin cell "<<coincellId; + } + else if(tokens[0] == "set" || tokens[0] == "s") + { + if(tokens.size() < 3) + { + Log(Log::ERROR)<<"This command requires a temperature"; + continue; + } + + float temperature = std::stod(tokens[2]); + if(temperature < 10 || temperature > 100) + { + Log(Log::ERROR)<<"Temperature "<<tokens[2]<<" is invalid"; + continue; + } + coinCells[coincellId]->setEnabled(true); + coinCells[coincellId]->setTemperature(temperature); + + } + else if(tokens[0] == "get" || tokens[0] == "g") + { + for(size_t i = 0; i < coinCells.size(); ++i) + { + std::unique_ptr<CoinCell>& cell = coinCells[i]; + float temperature; + bool ret = cell->getTemperature(temperature); + + if(!ret) + Log(Log::ERROR)<<"Cell "<<i<<" UNABLE TO READ"; + else + Log(Log::INFO)<<"Cell "<<i<<" temperature "<<temperature; + } + + auto connected = multiplexers.getConnected(); + for(size_t i = 0; i < connected.size(); ++i) + Log(Log::INFO)<<"multiplexer channel "<<i<<' '<<(connected[i] ? "connected" : "disconnected"); + } + else if(tokens[0] == "clear") + { + multiplexers.disconnectAll(); + for(std::unique_ptr<CoinCell>& cell :coinCells) + cell->setEnabled(false); + } + add_history(line.c_str()); + } + } + catch(const startup_failure& err) { - Log(Log::INFO)<<"MAIN"<<" Thread"; - std::this_thread::sleep_for(std::chrono::microseconds(1)); + Log(Log::ERROR)<<err.what(); + return 1; } - return 0; } diff --git a/vcpps.cpp b/vcpps.cpp index aca109af88b2cb261d349614990bd78aa0fddabf..8172225b283ae1510df8790a751ff5ef42a5c31d 100644 --- a/vcpps.cpp +++ b/vcpps.cpp @@ -13,7 +13,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"); + throw startup_failure("No serial port with the name " + portName + " found"); ret = sp_open(port, SP_MODE_READ_WRITE); if(ret != SP_OK) {