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 |
||||
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) |
@ -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; |
||||
} |
||||
|
@ -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