Select Git revision
biocontrol.cpp
biocontrol.cpp 4.69 KiB
#include "biocontrol.h"
#include <chrono>
#include <string>
#include <thread>
#include <unistd.h>
#include <errno.h>
#include <stdexcept>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sstream>
#include <fstream>
#include <signal.h>
#include "log.h"
BioControl::BioControl(const std::filesystem::path& exepathIn, const std::string& ipAddrIn):
exepath(exepathIn), ipAddr(ipAddrIn)
{
}
void BioControl::execBiocontrol(const std::string& command, const std::string& userstr, std::string& output, float voltage, float current)
{
static const char biopipefilename[] = "/tmp/biopipe";
int ret = mkfifo(biopipefilename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(ret < 0 && errno != EEXIST)
throw std::runtime_error(std::string(__func__) + ": unable to create pipe: " + std::string(strerror(errno)));
std::string voltageStr = std::to_string(voltage);
std::string currentStr = std::to_string(current);
const char* const argv[] = {"/usr/bin/wine", exepath.c_str(),
"-i", ipAddr.c_str(), "-c", command.c_str(), "-f", biopipefilename,
"-u", userstr.c_str(), "-g", voltageStr.c_str(), "-r", currentStr.c_str(), NULL};
Log(Log::INFO, false)<<"Starting";
for(size_t i = 0; argv[i]; ++i)
Log(Log::INFO, false, false)<<' '<<argv[i];
Log(Log::INFO, true, false)<<"";
int childPid = fork();
if(childPid == 0)
{
ret = execv("/usr/bin/wine", const_cast<char* const*>(argv));
Log(Log::ERROR)<<"Execution of "<<exepath.string()<<" failed: "<<strerror(errno);
exit(8);
}
else
{
int biopipe = open(biopipefilename, O_RDONLY | O_CLOEXEC);
if(biopipe < 0)
{
kill(childPid, SIGTERM);
throw std::runtime_error(std::string(__func__) + ": unable to open pipe: " + std::string(strerror(errno)));
}
if(biopipe >= 0)
{
char buffer[256] = {};
while (read(biopipe, buffer, 255) >= 1)
{
output.append(buffer);
memset(buffer, 0, 256);
}
}
Log(Log::DEBUG)<<"Wating for biocontrol to exit";
int exitCode;
int timeout = 7200*2;
ret = 0;
while((ret = waitpid(childPid, &exitCode, WNOHANG)) == 0 && --timeout > 0)
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if(ret == 0)
{
kill(childPid, SIGKILL);
throw std::runtime_error(std::string(__func__) + ": biocontol has hanged");
}
if(exitCode != 0)
{
close(biopipe);
throw std::runtime_error(std::string(__func__) + ": biocontol failed with: " + std::to_string(exitCode));
}
}
}
bool BioControl::measure_eis(const std::filesystem::path& outPath, const std::string& userstr, bool retry)
{
std::string mesurement;
try
{
execBiocontrol("geis", userstr, mesurement);
}
catch(const std::runtime_error& err)
{
Log(Log::ERROR)<<err.what();
return retry ? measure_eis(outPath, userstr, false) : false;
}
std::fstream file(outPath, std::ios_base::out);
if(!file.is_open())
{
Log(Log::ERROR)<<"Could not open file "<<outPath;
return false;
}
file<<mesurement;
file.close();
return true;
}
bool BioControl::measure_ocv(float& ocv, bool retry)
{
std::string mesurement;
try
{
execBiocontrol("ocv", "", mesurement);
ocv = std::stof(mesurement);
}
catch(const std::runtime_error& err)
{
Log(Log::ERROR)<<err.what();
return retry ? measure_ocv(ocv, false) : false;
}
catch(const std::invalid_argument& err)
{
Log(Log::ERROR)<<"Could not convert "<<mesurement<<": "<<err.what();
return retry ? measure_ocv(ocv, false) : false;
}
return true;
}
bool BioControl::shorted(bool& shorted)
{
Log(Log::DEBUG)<<__func__<<" is stubbed out";
shorted = false;
return true;
}
bool BioControl::charge(float fraction, float current, const std::filesystem::path& outPath, const std::string& userstr, bool retry)
{
return chargeToVoltage(3.1 + fraction*(4.2-3.1), current, outPath, userstr, retry);
}
bool BioControl::chargeToVoltage(float voltage, float current, const std::filesystem::path& outPath, const std::string& userstr, bool retry)
{
float ocv;
bool ret = measure_ocv(ocv);
if(!ret)
return false;
Log(Log::INFO)<<"Requesting charge to "<<voltage<<" volts";
if(std::abs(ocv - voltage) < 0.1)
{
Log(Log::INFO)<<"OCV is already close enough, not performing charge";
return true;
}
std::string output;
try
{
if(voltage > ocv)
execBiocontrol("charge", userstr, output, voltage, current);
else
execBiocontrol("discharge", userstr, output, voltage, current);
}
catch(const std::runtime_error& err)
{
Log(Log::ERROR)<<err.what();
return retry ? chargeToVoltage(voltage, current, outPath, userstr, false) : false;
}
std::fstream file(outPath, std::ios_base::out);
if(!file.is_open())
{
Log(Log::ERROR)<<"Could not open file "<<outPath;
return false;
}
file<<output;
file.close();
return true;
}