diff options
-rw-r--r-- | include/Device/Device.h | 11 | ||||
-rw-r--r-- | include/General.h | 4 | ||||
-rw-r--r-- | src/Device/Device.cpp | 119 |
3 files changed, 118 insertions, 16 deletions
diff --git a/include/Device/Device.h b/include/Device/Device.h index e02c352..42dad24 100644 --- a/include/Device/Device.h +++ b/include/Device/Device.h @@ -23,12 +23,15 @@ class Device { static std::map<std::string, bool> capabilityList; static std::map<std::string, std::string> ethSwitchList; static std::map<std::string, std::string> deviceInfoList; + static std::vector<std::string> dInputs; + static std::vector<std::string> dOutputs; static const std::regex apFilters; static const std::regex serialModeFilter; static const std::regex storeFilters; static const std::regex showFilters; static const std::regex mtcdt3HwVersionFilters; + static const std::regex iotRtrVersionFilters; static const std::regex mtrFilters; const unsigned int accessoryCardsListSize = 7; @@ -128,7 +131,7 @@ class Device { void AddToDeviceInfo(const std::string Port, const std::string ProductID); }; - + class gpio_request { private: struct gpiod_request_config *request_config; @@ -146,7 +149,7 @@ class Device { }; std::vector<std::unique_ptr<AccessoryCard>> accessoryCardsList; - + public: Device(); void getSystemTreeJson(const char *dir_name); @@ -171,9 +174,11 @@ class Device { void sortAccessoryCards(); void store(std::string name, std::string value); void storeTrigger(std::string name, std::string value); + void storeOutputStateToNonvolatile(const std::string& name, const std::string& value); void Verbose(bool val); bool Verbose(); - void writeJson(); + void writeJson(const rapidjson::Document &json, const std::string &file); + bool readJson(rapidjson::Document &json, const std::string &file); void simpleError(std::string msg, int error, int exitval); }; diff --git a/include/General.h b/include/General.h index 5e32f0b..4429b3d 100644 --- a/include/General.h +++ b/include/General.h @@ -72,6 +72,10 @@ typedef unsigned int uint; // 32 bit - even on 64 bit machines #define RESET_SHORT_CMD "reset_short_handler" #define RESET_LONG_CMD "reset_long_handler" #define KILL_SIGNAL "kill -l " +#define STORED_DIGITAL_OUTPUTS_STATE_FILE "/var/config/pin_states.json" +#define KEY_EXTIO "extIo" +#define KEY_DOUTPUTS "dOutputs" +#define KEY_DINPUTS "dInputs" enum HardwareType { HARDWARE_MTCDT, diff --git a/src/Device/Device.cpp b/src/Device/Device.cpp index 9a9e36c..e7e295b 100644 --- a/src/Device/Device.cpp +++ b/src/Device/Device.cpp @@ -25,6 +25,7 @@ const std::regex Device::apFilters("(modalias)|(power)(.*)|(subsystem)|(uevent)"); const std::regex Device::serialModeFilter("(.*)(serial-mode)"); const std::regex Device::mtcdt3HwVersionFilters("(MTCDT3AC)(.*)"); +const std::regex Device::iotRtrVersionFilters("(MTCAP3)(.*)"); // TODO - change it after getting IOTROUTER hardware const std::regex Device::mtrFilters("(MTR-)(.*)"); const std::regex Device::storeFilters( "(.*)(mac-)(.*)|(.*)(-id)|(uuid)|(.*)(/eui)|(.*)(/" @@ -61,6 +62,8 @@ std::map<std::string, bool> Device::capabilityList = { {"userDataEncryption", false}}; std::map<std::string, std::string> Device::ethSwitchList; +std::vector<std::string> Device::dInputs; +std::vector<std::string> Device::dOutputs; std::map<std::string, std::string> Device::deviceInfoList = { {"deviceId", ""}, @@ -116,7 +119,6 @@ bool Device::isValidDirectory(const struct dirent *entry, std::string fullPath, void Device::getSystemTreeJson(const char *dir_name) { std::string fullPath = SYSFS_PLATFORM + std::string(dir_name); DIR *d = opendir(fullPath.c_str()); - if (!d) { printError("Cannot open directory %s", fullPath); exitHandler(99); @@ -184,6 +186,16 @@ void Device::getSystemTreeJson(const char *dir_name) { capabilityList["rs485"] = true; capabilityList["serial"] = true; } + if (regex_match(fileData, iotRtrVersionFilters)) { + capabilityList["din"] = true; // TODO - remove it when it will be in EEPROM + capabilityList["dout"] = true; // TODO - remove it when it will be in EEPROM + /* + The order of the elements is important! This array is used to access Digital IOs, + in particular in SMS commands! + */ + dInputs.push_back("led-power"); //TODO - change it to real names after getting IOTRouter HW + dOutputs.push_back("led-lora"); //TODO - change it to real names after getting IOTRouter HW + } } else if (strcmp(d_name, "mac-eth") == 0) { deviceInfoList["macAddress"] = fileData; } else if (strcmp(d_name, "has-radio") == 0 && @@ -208,8 +220,8 @@ void Device::getSystemTreeJson(const char *dir_name) { getSystemTreeJson(d_name); /* Recursively call with the new path */ } } - if (closedir( - d)) { /* After going through all the entries, close the directory */ + if (closedir(d)) { + /* After going through all the entries, close the directory */ printError("Could not close %s", fullPath); exitHandler(errno); } @@ -221,7 +233,7 @@ void Device::init() { exitHandler(99); } load(); - writeJson(); + writeJson(deviceInfo, DEVICE_INFO_FILE); exitHandler(0); } @@ -309,6 +321,28 @@ void Device::load() { deviceInfo.AddMember("capabilities", capabilities, alloc); deviceInfo.AddMember("ethSwitch", ethSwitch, alloc); deviceInfo.AddMember("accessoryCards", accessoryCards, alloc); + rapidjson::Document inp; + auto &inpAlloc = inp.GetAllocator(); + inp.SetArray(); + for (const auto &input : dInputs) { + rapidjson::Value value; + value.SetString(input.c_str(), input.length(), inpAlloc); + inp.PushBack(value, inpAlloc); + } + rapidjson::Document out; + auto &outAlloc = out.GetAllocator(); + out.SetArray(); + for (const auto &output : dOutputs) { + rapidjson::Value value; + value.SetString(output.c_str(), output.length(), outAlloc); + out.PushBack(value, outAlloc); + } + rapidjson::Document extIo; + extIo.SetObject(); + auto &extAlloc = extIo.GetAllocator(); + extIo.AddMember(KEY_DINPUTS, inp, extAlloc); + extIo.AddMember(KEY_DOUTPUTS, out, extAlloc); + deviceInfo.AddMember(KEY_EXTIO, extIo, extAlloc); } void Device::mapFileToCapability() { @@ -563,7 +597,7 @@ struct gpiod_chip * Device::gpio_request::gpiod_ctxless_find_line(Device *device gpiodevname = NULL; break; } - + chip_info = gpiod_chip_get_info(found_chip); if (!chip_info) { int error = errno; @@ -583,7 +617,7 @@ struct gpiod_chip * Device::gpio_request::gpiod_ctxless_find_line(Device *device return found_chip; // Caller must close chip } gpiod_line_info_free(info); - + } gpiod_chip_close(found_chip); } @@ -635,7 +669,7 @@ Device::gpio_request:: gpio_request(Device *device, const std::string name) device->simpleError("Could not request lines gpiod chip_request_lines", errno, 108); } Device::gpio_request:: ~gpio_request() -{ +{ if(line_request) gpiod_line_request_release(line_request); if(settings) @@ -731,8 +765,10 @@ void Device::store(std::string name, std::string value) { if (gr.request()) { retval = gpiod_line_request_set_value(gr.request(),gr.offset(),lv); - if(retval != -1) + if(retval != -1) { + storeOutputStateToNonvolatile(name, value); exitHandler(0); + } else simpleError("Could not set GPIO value",errno,111); } @@ -747,6 +783,7 @@ void Device::store(std::string name, std::string value) { name.c_str(),strerror(errno)); exitHandler(98); } + storeOutputStateToNonvolatile(name, value); fileToWrite.close(); exitHandler(0); } @@ -777,15 +814,71 @@ void Device::storeTrigger(std::string name, std::string value) { exitHandler(99); } -void Device::writeJson() { +void Device::writeJson(const rapidjson::Document &json, const std::string &file) { rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); - deviceInfo.Accept(writer); - std::ofstream os(DEVICE_INFO_FILE); - if (!os) { - printError("Can't write to %s: %s", DEVICE_INFO_FILE,strerror(errno)); + json.Accept(writer); + std::ofstream os(file); + if (!os.is_open()) { + printError("Can't write to %s: %s", file.c_str(),strerror(errno)); exitHandler(99); } else { os << buffer.GetString(); } } + +bool Device::readJson(rapidjson::Document &json, const std::string &file) { + std::ifstream is(file); + if (!is.is_open()) { + printWarning("Can't read to %s: %s", file.c_str(), strerror(errno)); + return false; + } + rapidjson::IStreamWrapper isw { is }; + json.ParseStream(isw); + if (json.HasParseError()) { + printError("%s Parse error", file.c_str()); + return false; + } + return true; +} + +void Device::storeOutputStateToNonvolatile(const std::string& name, const std::string& value) { + rapidjson::Document deviceInfo; + if (!readJson(deviceInfo, DEVICE_INFO_FILE)){ + return; + } + + if (!deviceInfo.HasMember(KEY_EXTIO)){ + return; + } + if (!deviceInfo[KEY_EXTIO].HasMember(KEY_DOUTPUTS)){ + return; + } + const rapidjson::Value &outputs = deviceInfo[KEY_EXTIO][KEY_DOUTPUTS]; + bool found = false; + for (auto itr = outputs.Begin(); itr != outputs.End(); ++itr) { + auto listedOutput = (*itr).GetString(); + if (name == listedOutput) { + found = true; + break; + } + } + if (!found) { + return; + } + + rapidjson::Document stateIo; + rapidjson::Document::AllocatorType &alloc = stateIo.GetAllocator(); + rapidjson::Value jname(name.c_str(), alloc); + rapidjson::Value jvalue(value.c_str(), alloc); + readJson( stateIo, STORED_DIGITAL_OUTPUTS_STATE_FILE); + if (stateIo.IsNull()) { + stateIo.SetObject(); + }; + if (!stateIo.HasMember(jname)) { + stateIo.AddMember(jname, jvalue, alloc); + } else { + stateIo[jname] = jvalue; + } + writeJson(stateIo, STORED_DIGITAL_OUTPUTS_STATE_FILE); +} |