Skip to content
Snippets Groups Projects
Select Git revision
  • 2123696e4de17f3f98f12581b2ca6f1ff1500b07
  • master default
  • main protected
3 results

biocontrol.cpp

Blame
  • 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;
    }