Sergey Markov
3 years ago
7 changed files with 307 additions and 8 deletions
@ -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" |
||||||
|
} |
||||||
|
} |
@ -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) |
@ -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) |
@ -1,7 +1,15 @@ |
|||||||
ExternalProject_Add(wiringOP |
ExternalProject_Add(wiringOP |
||||||
GIT_REPOSITORY https://github.com/orangepi-xunlong/wiringOP |
GIT_REPOSITORY git@git.markow.su:markow/WiringOP.git |
||||||
BUILD_IN_SOURCE true |
CONFIGURE_COMMAND cmake -DBOARD=orangepipc-h3 <SOURCE_DIR> |
||||||
CONFIGURE_COMMAND ./build clean |
) |
||||||
BUILD_COMMAND BOARD=orangepipc-h3 ./build |
|
||||||
INSTALL_COMMAND "" |
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) |
@ -1,6 +1,44 @@ |
|||||||
|
#include <wiringPi.h> |
||||||
#include "cmd_line_args.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) { |
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; |
return 0; |
||||||
} |
} |
||||||
|
@ -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…
Reference in new issue