diff --git a/CMakeLists.txt b/CMakeLists.txt index e8521515240a52a85eec3605a256414d22755392..1eff89b1d29b8af692c38ef11a4966972c82a2c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,8 @@ set(SRC_FILES coincell.cpp biocontrol.cpp tokenize.cpp - expirament.cpp) + expirament.cpp + randomgen.cpp) add_executable(${PROJECT_NAME} ${SRC_FILES}) target_link_libraries(${PROJECT_NAME} ${MULTIPLEXER_LIBRARIES} ${SERIALPORT_LIBRARIES} diff --git a/expirament.cpp b/expirament.cpp index f59fbc95b47369ba5c282ec3fdd8f610b840f632..a30def72b6dbec580add0e2ebdf99fe9cdfbe031 100644 --- a/expirament.cpp +++ b/expirament.cpp @@ -4,6 +4,8 @@ #include "expiramentimpl.h" #include "vcpps.h" #include "panic.h" +#include "randomgen.h" +#include "watchdog.h" #include <chrono> #include <filesystem> @@ -66,6 +68,7 @@ bool Expirament::run(size_t startstep, size_t substep) for(globalstep = startstep; globalstep < MAX_LOOP*STEP_COUNT && !stop; ++globalstep) { Log(Log::INFO)<<"System starting globalstep "<<globalstep; + watchdog::reset(); bool ret = step(substep); substep = 0; if(!ret) @@ -140,28 +143,62 @@ bool Expirament::heatMeasureSeq(float fraction) return true; } +std::vector<double> Expirament::createStepSequence(size_t upSteps, size_t downSteps, double low, double high) +{ + std::vector<double> out; + + double closeToLow = low+(high-low)*0.05; + double closeToHigh = low+(high-low)*0.95; + + double last = low; + for(size_t i = 0; i < upSteps - 1; ++i) + { + double step = rd::rand(closeToHigh, last); + out.push_back(step); + last = step; + } + + out.push_back(high); + + last = high; + for(size_t i = 0; i < downSteps - 1; ++i) + { + double step = rd::rand(last, closeToLow); + out.push_back(step); + last = step; + } + + out.push_back(low); + + assert(out.size() == upSteps+downSteps); + + return out; +} + bool Expirament::thermalCycle(size_t count, size_t start) { bool ret = true; + for(size_t i = 0; i < count; ++i) { Log(Log::INFO)<<"Cycle "<<i<<" for globalsetp "<<globalstep; saveStep(i); - if(i % 2 == 0) + if(i == 0) { - ret = heatMeasureSeq(0.5); + std::vector<double> steps = createStepSequence(2, 3, 0, 1); + ret = heatMeasureSeq(steps[0]); if(!ret) return false; - ret = heatMeasureSeq(1); + ret = heatMeasureSeq(steps[1]); if(!ret) return false; - ret = heatMeasureSeq(0.66); + ret = heatMeasureSeq(steps[2]); if(!ret) return false; - ret = heatMeasureSeq(0.33); + ret = heatMeasureSeq(steps[3]); if(!ret) return false; - ret = heatMeasureSeq(0); + ret = heatMeasureSeq(steps[4]); if(!ret) return false; } @@ -221,6 +258,7 @@ bool Expirament::charge(float fraction, bool all) if(current > 0.9) current = 0.9; Log(Log::INFO)<<"Doing charge sequence to "<<fraction<<" at "<<current<<'A'; + watchdog::reset(); for(size_t i = 0; i < coinCells->size(); ++i) { if(all) diff --git a/expirament.h b/expirament.h index 370efd37fb74563aff08ab56e2f94799027cd37e..86c5af0225725e587a9aefb7a4ea693df7ef74e1 100644 --- a/expirament.h +++ b/expirament.h @@ -45,6 +45,8 @@ private: std::filesystem::path createCsvPath(const std::filesystem::path& filename); + static std::vector<double> createStepSequence(size_t upSteps, size_t downSteps, double low = 0, double high = 1); + public: Expirament(std::vector<std::unique_ptr<CoinCell>>* coinCells, Vcpps* psu, float voltage, float current, diff --git a/expiramentimpl.h b/expiramentimpl.h index 9fe7ba4fab0176567320369aa116e90ccca2e4d9..780c9d451106f19d8d6cafa89536e598aab86885 100644 --- a/expiramentimpl.h +++ b/expiramentimpl.h @@ -10,6 +10,8 @@ bool Expirament::step(size_t startsubstep) saveStep(startsubstep); + std::vector<double> steps = createStepSequence(3, 2, 0, 1); + bool ret = true; switch(globalstep % STEP_COUNT) { @@ -17,35 +19,35 @@ bool Expirament::step(size_t startsubstep) ret = thermalCycle(CYCLES_PER_STEP, startsubstep); break; case 1: - ret = charge(0.0); + ret = charge(steps[0]); ret &= takeMesurements(); break; case 2: ret = thermalCycle(CYCLES_PER_STEP, startsubstep); break; case 3: - ret = charge(0.33); + ret = charge(steps[1]); ret &= takeMesurements(); break; case 4: ret = thermalCycle(CYCLES_PER_STEP, startsubstep); break; case 5: - ret = charge(0.66); + ret = charge(steps[2]); ret &= takeMesurements(); break; case 6: ret = thermalCycle(CYCLES_PER_STEP); break; case 7: - ret = charge(1); + ret = charge(steps[3]); ret &= takeMesurements(); break; case 8: ret = thermalCycle(CYCLES_PER_STEP, startsubstep); break; case 9: - ret = charge(0.5); + ret = charge(steps[4]); ret &= takeMesurements(); break; case 10: diff --git a/main.cpp b/main.cpp index c5c078415c152e169523559457aaf56d8dea200a..022fda6de0f389be14d4bb254975a0fda4b910eb 100644 --- a/main.cpp +++ b/main.cpp @@ -16,11 +16,13 @@ #include "log.h" #include "heaters.h" #include "multiplexers.h" +#include "randomgen.h" #include "vcpps.h" #include "startupfailure.h" #include "panic.h" #include "options.h" #include "expirament.h" +#include "watchdog.h" void devicefailed(Vcpps& psu, int device, uint16_t serial, int code) { @@ -185,6 +187,9 @@ int main(int argc, char** argv) Log::level = Log::INFO; Log::sendmailLevel = Log::WARN; + rd::init(); + watchdog::init(10*60*60); + Config config; argp_parse(&argp, argc, argv, 0, 0, &config); diff --git a/randomgen.cpp b/randomgen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eac93dfc1e6ea0b0fa4673d78976278677fe0a66 --- /dev/null +++ b/randomgen.cpp @@ -0,0 +1,25 @@ +#include "randomgen.h" +#include <assert.h> +#include <cstddef> +#include <cstdint> +#include <random> + +static std::default_random_engine randomEngine; + +double rd::rand(double max, double min) +{ + std::uniform_real_distribution<double> dist(min, max); + return dist(randomEngine); +} + +size_t rd::uid() +{ + static std::uniform_int_distribution<size_t> distSt(0, SIZE_MAX); + return distSt(randomEngine); +} + +void rd::init() +{ + std::random_device randomDevice; + randomEngine.seed(randomDevice()); +} diff --git a/randomgen.h b/randomgen.h new file mode 100644 index 0000000000000000000000000000000000000000..1d81450a4db9613e1bb87912c2c503e86077a0a7 --- /dev/null +++ b/randomgen.h @@ -0,0 +1,10 @@ +#pragma once + +#include <cstddef> +namespace rd +{ + double rand(double max = 1, double min = 0); + void init(); + size_t uid(); + +} diff --git a/watchdog.cpp b/watchdog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e1adcc9d213c25aa9baa0498fd3d1ee6c78424a --- /dev/null +++ b/watchdog.cpp @@ -0,0 +1,54 @@ +#include "watchdog.h" + +#include <thread> +#include <atomic> +#include <cstdio> + +#include "log.h" + +namespace watchdog +{ + +static std::atomic<long> timer = 0; +static std::atomic<bool> join = false; +static std::thread* thread = nullptr; +static unsigned long timeout; + +static void threadFn() +{ + Log(Log::INFO)<<"Watchdog started with timeout "<<timeout; + while(!join) + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + if(timer-- < 0) + { + Log(Log::ERROR)<<"Watchdog timeout, exiting"; + std::exit(2); + } + } + Log(Log::INFO)<<"Watchdog shutdown"; +} + +void reset() +{ + timer = timeout; +} + +void init(unsigned long timeoutIn = 600) +{ + exit(); + timeout = timeoutIn; + timer = timeout; + join = false; + thread = new std::thread(&watchdog::threadFn); +} + +void exit() +{ + join = true; + if(thread) + thread->join(); + thread = nullptr; +} + +} diff --git a/watchdog.h b/watchdog.h new file mode 100644 index 0000000000000000000000000000000000000000..aeacc4c1d4a514468fc8cc504bcb1d213e32b7f2 --- /dev/null +++ b/watchdog.h @@ -0,0 +1,10 @@ +#pragma once + +namespace watchdog +{ + +void init(unsigned long timeout); +void reset(); +void exit(); + +}