#include <thread> #include <readline/readline.h> #include <readline/history.h> #include "coincell.h" #include "log.h" #include "options.h" #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) { std::stringstream ss; Log(Log::WARN)<<"Heater device "<<device<<" with serial number "<<serial<<" has " <<(code == Heaters::ERR_RECOVERED ? "recovered" : "failed")<<" with code "<<code; } void heaterfailed(int heater, int device) { Log(Log::WARN)<<"Heater "<<heater<<" on device "<<device<<" has failed"; } bool preparePsu(Vcpps* psu, float voltage, float current) { Vcpps::Status status; Log(Log::INFO, true, false)<<"Setting psu voltage to "<<voltage; bool ret = psu->setVoltage(voltage); if(!ret) { Log(Log::ERROR, true, false)<<"Unable to set psu voltage"; return false; } Log(Log::INFO, true, false)<<"Setting psu current to "<<current; ret = psu->setCurrent(current); if(!ret) { Log(Log::ERROR, true, false)<<"Unable to set psu current"; return false; } ret = psu->setEnabled(true); if(!ret) { Log(Log::ERROR, true, false)<<"Unable to enable psu output"; return false; } Log(Log::INFO, true, false)<<"Waiting for psu to stablize"; std::this_thread::sleep_for(std::chrono::seconds(2)); ret = psu->getStatus(status); ret = psu->getStatus(status); if(!ret) { Log(Log::ERROR)<<"Unable to read psu state, abort"; psu->setEnabled(false); return false; } else if(status.curent_limited) { Log(Log::ERROR)<<"Psu is overcurrent at "<<status.current<<" abort"; psu->setEnabled(false); return false; } Log(Log::INFO, true, false)<<"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, true, false)<<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 argc, char** argv) { Log::level = Log::INFO; Log::sendmailLevel = Log::NEVER; Log::headers = false; Config config; argp_parse(&argp, argc, argv, 0, 0, &config); try { Log(Log::INFO, true, false)<<"Geting PSU"; Vcpps psu(config.psuPort); psu.setEnabled(false); Log(Log::INFO, true, false)<<"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) { const char* linePtr = readline("> "); if(!linePtr) continue; std::string line = std::string(linePtr); if(line.empty()) continue; std::vector<std::string> tokens = tokenize(line, ' '); int coincellId = -1; if(tokens.size() >= 2) { coincellId = std::stol(tokens[1]); if(coincellId < 0 || coincellId > coinCells.size()) Log(Log::ERROR, true, false)<<"Invalid coin cell id: "<<tokens[1]; } if(coincellId < 0 && 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, true, false)<<"unable to connect coin cell "<<coincellId; else Log(Log::ERROR, true, false)<<"connected coin cell "<<coincellId; } else if(tokens[0] == "disconnect" || tokens[0] == "d") { bool ret = coinCells[coincellId]->setConnected(false); if(!ret) Log(Log::ERROR, true, false)<<"unable to disconnect coin cell "<<coincellId; else Log(Log::ERROR, true, false)<<"disconnected coin cell "<<coincellId; } else if(tokens[0] == "set" || tokens[0] == "s") { if(tokens.size() < 3) { Log(Log::ERROR, true, false)<<"This command requires a temperature"; continue; } float temperature = std::stod(tokens[2]); if(temperature < 10 || temperature > 100) { Log(Log::ERROR, true, false)<<"Temperature "<<tokens[2]<<" is invalid"; continue; } coinCells[coincellId]->setEnabled(true); coinCells[coincellId]->setTemperature(temperature); } else if(tokens[0] == "get" || tokens[0] == "g") { float temperature; if(coincellId < 0) { for(size_t i = 0; i < coinCells.size(); ++i) { std::unique_ptr<CoinCell>& cell = coinCells[i]; bool ret = cell->getTemperature(temperature); if(!ret) Log(Log::ERROR, true, false)<<"Cell "<<i<<" UNABLE TO READ"; else Log(Log::INFO, true, false)<<"Cell "<<i<<" temperature: "<<temperature; } auto connected = multiplexers.getConnected(); for(size_t i = 0; i < connected.size(); ++i) Log(Log::INFO, true, false)<<"multiplexer channel "<<i<<' '<<(connected[i] ? "connected" : "disconnected"); } else { bool ret = coinCells[coincellId]->getTemperature(temperature); if(!ret) { Log(Log::ERROR, true, false)<<"Cell "<<coincellId<<" UNABLE TO READ"; continue; } float setpoint; ret = coinCells[coincellId]->getSetpoint(setpoint); if(!ret) { Log(Log::ERROR, true, false)<<"Cell "<<coincellId<<" UNABLE TO READ"; continue; } bool enabled = coinCells[coincellId]->getEnabled(); Log(Log::ERROR, true, false)<<"Cell "<<coincellId<<':'; Log(Log::ERROR, true, false)<<"\ttemperature: "<<temperature<<"\n\tsetpoint: "<<setpoint; Log(Log::ERROR, true, false)<<"\tenabled: "<<(enabled ? "true" : "false"); } } 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::ERROR, true, false)<<err.what(); return 1; } }