Browse Source

task manager feature

master
Sergey Markov 3 years ago
parent
commit
89b7d8fe96
  1. 72
      .vscode/settings.json
  2. 6
      CMakeLists.txt
  3. 9
      cmake/croncpp.cmake
  4. 11
      cmake/easyloggingpp.cmake
  5. 20
      cmake/wiringOP.cmake
  6. 40
      main.cpp
  7. 157
      task_manager.hpp

72
.vscode/settings.json vendored

@ -0,0 +1,72 @@
{
"cmake.generator": "Unix Makefiles",
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"condition_variable": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"any": "cpp",
"complex": "cpp",
"iomanip": "cpp",
"typeindex": "cpp",
"variant": "cpp",
"future": "cpp",
"regex": "cpp",
"shared_mutex": "cpp"
}
}

6
CMakeLists.txt

@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.15.0)
set (CMAKE_CXX_STANDARD 17)
set(CMAKE_TOOLCHAIN_FILE cmake/toolchain.cmake)
project(miner_scheduler VERSION 0.1.0)
@ -11,10 +12,13 @@ add_definitions(-DAPP_GCC="${CMAKE_C_COMPILER_VERSION}")
include(ExternalProject)
include(cmake/fmt.cmake)
include(cmake/wiringOP.cmake)
include(cmake/easyloggingpp.cmake)
include(cmake/croncpp.cmake)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_executable(miner_scheduler main.cpp
cmd_line_args.cpp)
add_dependencies(miner_scheduler fmt wiringOP)
add_dependencies(miner_scheduler fmt wiringOP easyloggingpp croncpp)
target_link_options(miner_scheduler PRIVATE -static-libgcc -static-libstdc++)

9
cmake/croncpp.cmake

@ -0,0 +1,9 @@
ExternalProject_Add(croncpp
GIT_REPOSITORY https://github.com/mariusbancila/croncpp.git
CONFIGURE_COMMAND cmake -DCMAKE_INSTALL_PREFIX=<BINARY_DIR> <SOURCE_DIR>
)
ExternalProject_Get_property(croncpp BINARY_DIR)
set(CRONCPP_BINARY_DIR ${BINARY_DIR})
include_directories(${CRONCPP_BINARY_DIR}/include)

11
cmake/easyloggingpp.cmake

@ -0,0 +1,11 @@
ExternalProject_Add(easyloggingpp
URL https://github.com/amrayn/easyloggingpp/archive/refs/tags/v9.97.0.tar.gz
CONFIGURE_COMMAND cmake -DCMAKE_INSTALL_PREFIX=<BINARY_DIR> <SOURCE_DIR>
#BUILD_COMMAND ""
#INSTALL_COMMAND ""
)
ExternalProject_Get_property(easyloggingpp BINARY_DIR)
set(EASYLOGGINGPP_BINARY_DIR ${BINARY_DIR})
include_directories(${EASYLOGGINGPP_BINARY_DIR}/include)

20
cmake/wiringOP.cmake

@ -1,7 +1,15 @@
ExternalProject_Add(wiringOP
GIT_REPOSITORY https://github.com/orangepi-xunlong/wiringOP
BUILD_IN_SOURCE true
CONFIGURE_COMMAND ./build clean
BUILD_COMMAND BOARD=orangepipc-h3 ./build
INSTALL_COMMAND ""
)
GIT_REPOSITORY git@git.markow.su:markow/WiringOP.git
CONFIGURE_COMMAND cmake -DBOARD=orangepipc-h3 <SOURCE_DIR>
)
ExternalProject_Get_property(wiringOP BINARY_DIR)
set(WIRING_OP_BINARY_DIR ${BINARY_DIR})
ExternalProject_Get_property(wiringOP SOURCE_DIR)
set(WIRING_OP_SRC_DIR ${SOURCE_DIR})
include_directories(${WIRING_OP_SRC_DIR}/wiringPi)
link_directories(${WIRING_OP_BINARY_DIR}/lib)
link_libraries(wiringPi.a pthread m rt)

40
main.cpp

@ -1,6 +1,44 @@
#include <wiringPi.h>
#include "cmd_line_args.h"
#include "easylogging++.h"
#include "easylogging++.cc"
#include "task_manager.hpp"
#include <iostream>
#include <sstream>
INITIALIZE_EASYLOGGINGPP
#define PIN 0
static std::stringstream schedule = std::stringstream(
"0 0 10 ? * MON-SAT HIGH(0)\n"
"0 0 13 ? * MON-SAT LOW(0)\n"
"0 0 15 ? * MON-SAT HIGH(0)\n"
"0 0 19 ? * MON-SAT LOW(0)\n"
"* * * * * SUN LOW(0)\n"
);
int main(int argc, char** argv) {
parse_opts(argc, argv);
el::Loggers::reconfigureAllLoggers(el::ConfigurationType::ToStandardOutput, "true");
el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
parsed_opts opts = parse_opts(argc, argv);
if(opts.config_file.empty()) {
LOG(ERROR) << "Config file is not set!";
return 0;
}
LOG(INFO) << opts.config_file;
TaskManager manager{schedule, digitalWrite};
wiringPiSetup ();
pinMode (PIN, OUTPUT);
while(true) {
manager.doWork();
}
return 0;
}

157
task_manager.hpp

@ -0,0 +1,157 @@
#ifndef TASK_MANAGER_HPP
#define TASK_MANAGER_HPP
#include <iostream>
#include <sstream>
#include <string>
#include <chrono>
#include <thread>
#include <functional>
#include <croncpp.h>
#include "easylogging++.h"
using callable = std::function<void (int pin, int value)>;
enum TaskAction {
TASK_ACTION_LOW = 0,
TASK_ACTION_HIGH = 1,
TASK_ACTION_NONE
};
class Task {
private:
cron::cronexpr cronexpr;
TaskAction action;
callable action_fn;
int pin;
public:
Task(cron::cronexpr cronexpr, std::string command, callable action_fn);
Task(Task &task);
void doAction();
std::time_t next();
friend std::ostream& operator<< (std::ostream &out, const Task &task);
};
class TaskManager {
private:
std::map<std::time_t, Task> tasks;
public:
TaskManager(std::istream &stream, callable action_fn);
int doWork();
};
inline TaskManager::TaskManager(std::istream &stream, callable action_fn) {
std::string line;
while (std::getline(stream, line).good()) {
auto fields = cron::utils::split(line, ' ');
fields.erase(
std::remove_if(std::begin(fields), std::end(fields),
[](CRONCPP_STRING_VIEW s) {return s.empty(); }),
std::end(fields));
if (fields.size() != 7)
throw cron::bad_cronexpr("cron expression must have 7 fields");
std::stringstream schedule;
for (int i = 0; i < 6; ++i) {
schedule << fields[i] << ' ';
}
auto cron = cron::make_cron(schedule.str());
std::time_t now = std::time(0);
std::time_t next = cron::cron_next(cron, now);
tasks.emplace(std::piecewise_construct,
std::forward_as_tuple(next),
std::forward_as_tuple(cron, fields[6], action_fn));
}
LOG(INFO) << "Schedule table:";
for (const auto& [key, value] : tasks) {
LOG(INFO) << key << ' ' << value;
}
}
inline int TaskManager::doWork() {
auto it = tasks.begin();
if(it == tasks.end()) return 0;
std::time_t now = std::time(0);
std::time_t stop = it->first;
LOG(DEBUG) << "Will sleep till next action " << stop - now << 's';
std::this_thread::sleep_for(std::chrono::seconds{stop - now});
it->second.doAction();
tasks.emplace(std::piecewise_construct,
std::forward_as_tuple(it->second.next()),
std::forward_as_tuple(it->second));
tasks.erase(it);
return 0;
}
inline std::ostream& operator<< (std::ostream &out, const Task &task) {
out << "Action: ";
switch (task.action)
{
case TASK_ACTION_HIGH:
out << "HIGH";
break;
case TASK_ACTION_LOW:
out << "LOW";
break;
default:
break;
}
out << " Pin:" << task.pin;
return out;
}
inline Task::Task(cron::cronexpr cronexpr, std::string command, callable action_fn):
cronexpr{cronexpr},
action{TASK_ACTION_NONE},
pin{0},
action_fn{action_fn}
{
if(command.rfind("HIGH", 0) == 0) {
action = TASK_ACTION_HIGH;
} else if((command.rfind("LOW", 0) == 0)) {
action = TASK_ACTION_LOW;
}
auto start = command.find('(');
auto stop = command.find(')');
if(start == std::string::npos && stop == std::string::npos) {
throw cron::bad_cronexpr("pin is not set in command");
}
LOG(DEBUG) << "pin to parse " << command.substr(start + 1, stop - start - 1);
pin = std::stoi(command.substr(start + 1, stop - start - 1));
}
inline Task::Task(Task &task):
cronexpr{task.cronexpr},
action{task.action},
action_fn{task.action_fn},
pin{task.pin}
{}
inline void Task::doAction() {
if(action == TASK_ACTION_NONE) return;
action_fn(pin, action);
}
inline std::time_t Task::next() {
std::time_t now = std::time(0);
return cron::cron_next(cronexpr, now);
}
#endif //TASK_MANAGER_HPP
Loading…
Cancel
Save