diff options
author | John Klug <john.klug@multitech.com> | 2023-11-08 14:17:55 -0600 |
---|---|---|
committer | John Klug <john.klug@multitech.com> | 2023-11-08 14:24:41 -0600 |
commit | a826d13ae7b3e20648566ddecca23bd6fe8f856b (patch) | |
tree | 9bf8cf2ef563de953e581493aeb6d5ac60e1a2e1 | |
parent | ced9991aafb6b1b30649fd34b0d17399686d4843 (diff) | |
download | mts-io-sysfs-a826d13ae7b3e20648566ddecca23bd6fe8f856b.tar.gz mts-io-sysfs-a826d13ae7b3e20648566ddecca23bd6fe8f856b.tar.bz2 mts-io-sysfs-a826d13ae7b3e20648566ddecca23bd6fe8f856b.zip |
libgpiod 2 added for GPIO store and show in IOTR/MTR3
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | include/Device/Device.h | 19 | ||||
-rw-r--r-- | src/Device/Device.cpp | 216 | ||||
-rw-r--r-- | src/Device/Device.cpp.orig | 630 |
4 files changed, 234 insertions, 633 deletions
@@ -35,7 +35,7 @@ CFLAGS += -Werror -Wno-unused-function CXXFLAGS += -std=c++14 -Wno-unused-function -LIBS := -lmts -lrt -lssl -lcrypto +LIBS := -lmts -lrt -lssl -lcrypto -lgpiod INC=-Iinclude -Iinclude/Utility -Iinclude/AccessoryCards -Iinclude/Device -Iinclude/Fpga INCLUDES = $(wildcard include/*.h) diff --git a/include/Device/Device.h b/include/Device/Device.h index 7a20f04..e02c352 100644 --- a/include/Device/Device.h +++ b/include/Device/Device.h @@ -128,9 +128,25 @@ class Device { void AddToDeviceInfo(const std::string Port, const std::string ProductID); }; + + class gpio_request { + private: + struct gpiod_request_config *request_config; + struct gpiod_line_config *line_config; + struct gpiod_line_settings *settings; + struct gpiod_line_request *line_request; // Result of creating a request + struct gpiod_chip *chip; + unsigned int rq_offset; + struct gpiod_chip *gpiod_ctxless_find_line(Device *device, std::string name, unsigned int *r_offset); + public: + struct gpiod_line_request *request(); + unsigned int offset(); + gpio_request(Device *device, const std::string name); + ~gpio_request(); + }; std::vector<std::unique_ptr<AccessoryCard>> accessoryCardsList; - + public: Device(); void getSystemTreeJson(const char *dir_name); @@ -158,6 +174,7 @@ class Device { void Verbose(bool val); bool Verbose(); void writeJson(); + void simpleError(std::string msg, int error, int exitval); }; #endif /* DEVICE_H_ */ diff --git a/src/Device/Device.cpp b/src/Device/Device.cpp index feb763d..9a9e36c 100644 --- a/src/Device/Device.cpp +++ b/src/Device/Device.cpp @@ -15,8 +15,10 @@ * ***********************************************************************/ +#include <gpiod.h> #include "Device.h" +const std::string cmdname ("mts-io-sysfs"); const std::vector<std::string> Device::apIdentifiers = { "ap1", "ap2", "lora", "lora-2", "slot1", "slot2"}; const std::regex @@ -494,8 +496,196 @@ void Device::printUsage(std::string program) { exitHandler(0); } +/* + * Print an error message with errno string + * and exit with internal identifying number. + * parm1: Message to be printed + * parm2: Saved errno value + * parm3: An integer exit value (-1 means don't exit) + * Returns: Void + */ +const int NOEXIT = -1; +void Device::simpleError(std::string msg, int error, int exitval) { + std::cerr << cmdname; + std::cerr << ": "; + std::cerr << msg; + std::cerr << ": "; + const int len = 512; + char buf[len]; + std::cerr << strerror_r(error,buf,len); + std::cerr << "\n"; + if (exitval > NOEXIT) + exitHandler(exitval); +} + +/* + * Given a GPIO name, find the chip and line number + * parm1: Name of GPIO + * parm2: pointer to GPIO offset where the name + * was found on return + * Returns: chip where GPIO name was found + * + * Caller should free the chip pointer with + * gpiod_chip_close. + * + * It is assumed the gpio devices are numbered + * starting at 0, and are all sequential. + * + * This function was in the old libgpiod and + * was removed from the new library. This + * functionality should not have been removed. + */ +struct gpiod_chip * Device::gpio_request::gpiod_ctxless_find_line(Device *device, std::string name, unsigned int *r_offset) +{ + const std::string gpioDevPrefix = "/dev/gpiochip"; + int chipnum; + char *gpiodevname = NULL; + struct gpiod_chip *found_chip; + struct gpiod_chip_info *chip_info; + struct gpiod_line_info *info; + int num_lines = 0; + int offset; + const char *nm; + Device d; + + for(chipnum=0;1;chipnum++) { + std::string gpioDevName = gpioDevPrefix; + gpioDevName += std::to_string(chipnum); + found_chip = gpiod_chip_open(gpioDevName.c_str()); + if (found_chip == NULL) { + if(chipnum == 0) { + int error = errno; + std::string msg = "Could not open "; + msg.append(gpiodevname); + device->simpleError(msg,error,NOEXIT); + } + free(gpiodevname); + gpiodevname = NULL; + break; + } + + chip_info = gpiod_chip_get_info(found_chip); + if (!chip_info) { + int error = errno; + std::string msg = "Can't read info from GPIO "; + msg.append(gpiodevname); + device->simpleError(msg,error,100); + } + num_lines = gpiod_chip_info_get_num_lines(chip_info); + gpiod_chip_info_free(chip_info); + free(gpiodevname); + for (offset = 0; offset < num_lines; offset++) { + info = gpiod_chip_get_line_info(found_chip, offset); + nm = gpiod_line_info_get_name(info); + if (nm && (name.compare(nm) == 0)) { + *r_offset = offset; + gpiod_line_info_free(info); + return found_chip; // Caller must close chip + } + gpiod_line_info_free(info); + + } + gpiod_chip_close(found_chip); + } + *r_offset = 0xffffffff; + return NULL; +} + +Device::gpio_request:: gpio_request(Device *device, const std::string name) +{ + line_request = NULL; + settings = NULL; + line_config = NULL; + request_config = NULL; + + if(name.empty()) + device->simpleError("Name not provided\n",EINVAL,101); + chip = gpiod_ctxless_find_line(device, name, &rq_offset); + if(chip == NULL) + return; + request_config = gpiod_request_config_new(); + if (request_config == NULL) + device->simpleError("Could not allocate gpiod request_config", errno, 102); + gpiod_request_config_set_consumer(request_config,"mts-io-sysfs"); + line_config = gpiod_line_config_new(); + if (line_config == NULL) + device->simpleError("Could not allocate gpiod line_config", errno, 103); + settings = gpiod_line_settings_new(); + if (settings == NULL) + device->simpleError("Could not allocate gpiod line_settings", errno, 104); + int result = -1; + result = gpiod_line_settings_set_direction(settings,GPIOD_LINE_DIRECTION_AS_IS); + if (result == -1) + device->simpleError("Could not set direction gpiod line_settings_set_direction GPIOD_LINE_DIRECTION_AS_IS", errno, 105); + + result = gpiod_line_settings_set_bias(settings,GPIOD_LINE_BIAS_AS_IS); + if (result == -1) + device->simpleError("Could not set bias gpiod line_settings_set_bias GPIOD_LINE_BIAS_AS_IS", errno, 106); + + unsigned int offsets[1]; + size_t num_offsets = 1; + offsets[0] = rq_offset; // Exactly one GPIO is being queried + + result = gpiod_line_config_add_line_settings(line_config,offsets,num_offsets,settings); + if (result == -1) + device->simpleError("Could not add line settings gpiod line_config_add_line_settings", errno, 107); + + line_request = gpiod_chip_request_lines(chip,request_config,line_config); // acquire line(s) for exclusive usage. + if (line_request == NULL) + 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) + gpiod_line_settings_free(settings); + if(line_config) + gpiod_line_config_free(line_config); + if(request_config) + gpiod_request_config_free(request_config); + if(chip) + gpiod_chip_close(chip); +} + +struct gpiod_line_request * Device::gpio_request::request() +{ + /* This value can be NULL if the gpio name was + * not found. + */ + return this->line_request; +}; + +unsigned int Device::gpio_request::offset() +{ + return this->rq_offset; +}; + + +/* If the name starts in upper case, assume + * the name is a GPIO line name from gpio-hog + * in device tree. If it starts in lower case + * assume the name is an attribute of the mts-io + * driver. GPIOs can only be zero + * or one, never a text string. + */ void Device::show(std::string name) { std::string fileData; + if(isupper(name[0])) { + gpio_request gr(this, name); + if (gr.request()) { + enum gpiod_line_value lv = gpiod_line_request_get_value(gr.request(),gr.offset()); + if(lv != GPIOD_LINE_VALUE_ERROR) { + if(lv == GPIOD_LINE_VALUE_INACTIVE) + std::cout << "0\n"; + else + std::cout << "1\n"; + exitHandler(0); + } else + simpleError("Invalid GPIO line value", errno, 109); + } + } // Upper case name + int32_t code = MTS::System::readFile(SYSFS_PLATFORM + name, fileData); if (code == 0) { printf("%s", fileData.c_str()); @@ -504,7 +694,7 @@ void Device::show(std::string name) { printError("cat: can't open %s%s: %s", SYSFS_PLATFORM, name.c_str(),strerror(errno)); exitHandler(99); -} +} // End of show void Device::showTrigger(std::string name) { std::string fileData; @@ -519,12 +709,36 @@ void Device::showTrigger(std::string name) { exitHandler(99); } +// Prefer gpiod if name starts with upper case and is value 0 or 1 void Device::store(std::string name, std::string value) { if (!isRoot) { printError("Must be root to store to %s", name.c_str()); exitHandler(99); } + printDebug("Setting %s to %s", name.c_str(), value.c_str()); + + if(isupper(name[0])) { + enum gpiod_line_value lv = GPIOD_LINE_VALUE_ERROR; + + if (value.compare("0") == 0) + lv = GPIOD_LINE_VALUE_INACTIVE; + if (value.compare("1") == 0) + lv = GPIOD_LINE_VALUE_ACTIVE; + if (lv != GPIOD_LINE_VALUE_ERROR) { + gpio_request gr(this, name); + int retval; + if (gr.request()) { + retval = gpiod_line_request_set_value(gr.request(),gr.offset(),lv); + + if(retval != -1) + exitHandler(0); + else + simpleError("Could not set GPIO value",errno,111); + } + } + } + std::ofstream fileToWrite(SYSFS_PLATFORM + name); if (fileToWrite.is_open()) { fileToWrite << value; diff --git a/src/Device/Device.cpp.orig b/src/Device/Device.cpp.orig deleted file mode 100644 index d52fa93..0000000 --- a/src/Device/Device.cpp.orig +++ /dev/null @@ -1,630 +0,0 @@ -/********************************************************************** - * COPYRIGHT 2020 MULTI-TECH SYSTEMS, INC. - * - * ALL RIGHTS RESERVED BY AND FOR THE EXCLUSIVE BENEFIT OF - * MULTI-TECH SYSTEMS, INC. - * - * MULTI-TECH SYSTEMS, INC. - CONFIDENTIAL AND PROPRIETARY - * INFORMATION AND/OR TRADE SECRET. - * - * NOTICE: ALL CODE, PROGRAM, INFORMATION, SCRIPT, INSTRUCTION, - * DATA, AND COMMENT HEREIN IS AND SHALL REMAIN THE CONFIDENTIAL - * INFORMATION AND PROPERTY OF MULTI-TECH SYSTEMS, INC. - * USE AND DISCLOSURE THEREOF, EXCEPT AS STRICTLY AUTHORIZED IN A - * WRITTEN AGREEMENT SIGNED BY MULTI-TECH SYSTEMS, INC. IS PROHIBITED. - * - ***********************************************************************/ - -#include <gpiod.h> -#include "Device.h" - -const std::vector<std::string> Device::apIdentifiers = { - "ap1", "ap2", "lora", "lora-2", "slot1", "slot2"}; -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::mtrFilters("(MTR-)(.*)"); -const std::regex Device::storeFilters( - "(.*)(mac-)(.*)|(.*)(-id)|(uuid)|(.*)(/eui)|(.*)(/" - "cdone)|(.*)(hw-version)|(oem-string)(.*)|(imei)|(capability)(.*)|(radio-" - "reset-backoff-seconds)|(modalias)|(power)|((subsystem)(.*))|(uevent)|(" - "board-temperature)|(reset)|(led3)|(led-ls)|(usbhd-ps-oc)|(.*)(adc[0-9])|(." - "*)(din[0-9])|(gpi[0-9])|(gpi[0-9][0-9])"); -const std::regex Device::showFilters("(modalias)|(subsystem)|(uevent)"); - -std::map<std::string, bool> Device::capabilityList = { - {"adc", false}, - {"battery", false}, - {"bluetooth", false}, - {"cell", false}, - {"cellPpp", false}, - {"cellWwan", false}, - {"din", false}, - {"dout", false}, - {"externalSerialPort", false}, - {"gpio", false}, - {"gps", false}, - {"lora", false}, - {"loraLbt", false}, - {"loraNetworkServer", false}, - {"nodeRed", false}, - {"rs232", false}, - {"rs422", false}, - {"rs485", false}, - {"serial", false}, - {"supercap", false}, - {"wifi", false}, - {"docker", false}, - {"tpm", false}, - {"userDataEncryption", false}}; - -std::map<std::string, std::string> Device::ethSwitchList; - -std::map<std::string, std::string> Device::deviceInfoList = { - {"deviceId", ""}, - {"hardwareVersion", ""}, - {"imei", ""}, - {"macAddress", "00:00:00:00:00:00"}, - {"macBluetooth", "00:00:00:00:00:00"}, - {"macWifi", "00:00:00:00:00:00"}, - {"productId", ""}, - {"uuid", ""}, - {"vendorId", ""}, - {"oemString1", ""}, - {"oemString2", ""}}; - -Device::Device() { - isRoot = !getuid(); - accessoryCardsList.reserve(accessoryCardsListSize); - accessoryCardsList.push_back(std::make_unique<Lora21Card>(*this)); - accessoryCardsList.push_back(std::make_unique<Lora21ExtCard>(*this)); - accessoryCardsList.push_back(std::make_unique<Lora03Card>(*this)); - accessoryCardsList.push_back(std::make_unique<Lora10Card>(*this)); - accessoryCardsList.push_back(std::make_unique<Lora15Card>(*this)); - accessoryCardsList.push_back(std::make_unique<Lora2G4Card>(*this)); - accessoryCardsList.push_back(std::make_unique<Gpiob>(*this)); - accessoryCardsList.push_back(std::make_unique<Mfser>(*this)); -} - -bool Device::isAccessoryCard(const char *d_name, const char *dir_name) { - return std::binary_search(apIdentifiers.begin(), apIdentifiers.end(), - dir_name) && - !regex_match(d_name, apFilters); -} - -void Device::sortAccessoryCards() { - rapidjson::SizeType i, j; - for (i = 0; i < accessoryCards.Size() - 1; i++) { - for (j = 0; j < accessoryCards.Size() - i - 1; j++) { - if (accessoryCards[j]["port"].GetString() < - accessoryCards[j + 1]["port"].GetString()) { - accessoryCards[j].Swap(accessoryCards[j + 1]); - } - } - } -} - -bool Device::isValidDirectory(const struct dirent *entry, std::string fullPath, - const char *d_name) { - std::string path = fullPath + "/" + std::string(d_name); - return (entry->d_type & DT_DIR) && strcmp(d_name, "..") != 0 && - strcmp(d_name, ".") != 0 && (path.length() < PATH_MAX); -} - -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); - } - while (1) { - struct dirent *entry = - readdir(d); /* Gets subsequent entries from "d" */ - if (!entry) { /* If there are no more entries, exit */ - break; - } - const char *d_name = entry->d_name; /* Get file name */ - std::string fileData; - if (!(entry->d_type & DT_DIR) && - (MTS::System::readFile(fullPath + "/" + std::string(d_name), - fileData) == 0)) { - fileData = MTS::Text::trim(fileData); - if (strlen(dir_name) > 0) { - if (isAccessoryCard(d_name, dir_name)) { - if (accessoryCard.IsNull()) { - accessoryCard.SetObject(); - accessoryCard.AddMember( - "port", - rapidjson::Value().SetString(dir_name, acAlloc), - acAlloc); - } else if (accessoryCard["port"] != dir_name) { - accessoryCards.PushBack(accessoryCard, acAlloc); - accessoryCard.SetObject(); - accessoryCard.AddMember( - "port", - rapidjson::Value().SetString(dir_name, acAlloc), - acAlloc); - } - if (strcmp(d_name, "product-id") == - 0) { /* Map card specific details based on the product - id */ - for (unsigned int i = 0; i < accessoryCardsList.size(); - i++) { - if (regex_match(fileData, - accessoryCardsList[i]->GetName())) { - accessoryCardsList[i]->AddToDeviceInfo( - dir_name, fileData); - break; - } - } - } - accessoryCard.AddMember( - rapidjson::Value().SetString( - toCamelCase(d_name).c_str(), acAlloc), - rapidjson::Value().SetString(fileData.c_str(), acAlloc), - acAlloc); - } else if (strcmp(dir_name, "capability") == 0 && - fileData == "1") { - capabilityList[toCamelCase(d_name)] = true; - } else if (strcmp(dir_name, "eth-switch") == 0) { - ethSwitchList[toCamelCase(d_name)] = fileData; - } - } else if ((entry->d_type != DT_LNK)) { - if (deviceInfoList.count(toCamelCase(d_name)) > 0) { - deviceInfoList[toCamelCase(d_name)] = fileData; - } else if (strcmp(d_name, "hw-version") == 0) { - deviceInfoList["hardwareVersion"] = fileData; - if (regex_match(fileData, mtcdt3HwVersionFilters)) { - capabilityList["rs232"] = true; - capabilityList["rs422"] = true; - capabilityList["rs485"] = true; - capabilityList["serial"] = true; - } - } else if (strcmp(d_name, "mac-eth") == 0) { - deviceInfoList["macAddress"] = fileData; - } else if (strcmp(d_name, "has-radio") == 0 && - fileData == "1") { - capabilityList["cell"] = true; - } else if (strcmp(d_name, "oem-string1") == 0) { - deviceInfoList["oemString1"] = fileData; - } else if (strcmp(d_name, "oem-string2") == 0) { - deviceInfoList["oemString2"] = fileData; - }; - if (strcmp(d_name, "product-id") == 0) { - if (regex_match(fileData, mtrFilters)) { - capabilityList["rs232"] = true; - capabilityList["serial"] = true; - } - } - } - } - if (isValidDirectory(entry, fullPath, - d_name)) { /* Check that the directory is not "d" - or d's parent */ - getSystemTreeJson(d_name); /* Recursively call with the new path */ - } - } - if (closedir( - d)) { /* After going through all the entries, close the directory */ - printError("Could not close %s", fullPath); - exitHandler(errno); - } -} - -void Device::init() { - if (!isRoot) { - printError("Must be root to generate device_info.json"); - exitHandler(99); - } - load(); - writeJson(); - exitHandler(0); -} - -void Device::json() { - if (!isRoot) { - printError("Must be root to generate json"); - exitHandler(99); - } - load(); - printJson(); - exitHandler(0); -} - -void Device::load() { - deviceInfo.SetObject(); - capabilities.SetObject(); - ethSwitch.SetObject(); - accessoryCards.SetArray(); - getSystemTreeJson(""); - if (!accessoryCard.IsNull()) { - accessoryCards.PushBack(accessoryCard, acAlloc); - if (accessoryCards.Size() > 1) { - sortAccessoryCards(); - } - } - - mapFileToCapability(); - mapFirmware(); - mapMacAddress2(); - for (const auto capability : capabilityList) { - capabilities.AddMember( - rapidjson::Value().SetString(capability.first.c_str(), - capability.first.length(), acAlloc), - capability.second, acAlloc); - } - - if (ethSwitchList.count("chip") && ethSwitchList.count("numPorts")) { - auto ðSwitchAlloc = ethSwitch.GetAllocator(); - const std::string &chip = ethSwitchList.at("chip"); - ethSwitch.AddMember("chip", - rapidjson::Value().SetString( - chip.c_str(), chip.length(), ethSwitchAlloc), - ethSwitchAlloc); - rapidjson::Value ports; - ports.SetObject(); - for (int i = 0; i < std::stoi(ethSwitchList.at("numPorts")); ++i) { - const std::string num = std::to_string(i); - const std::string keyLabel = "port" + num + "Label"; - const std::string keyId = "port" + num + "Id"; - const std::string keyMac = "port" + num + "Mac"; - ; - if (ethSwitchList.count(keyLabel) && ethSwitchList.count(keyId) && - ethSwitchList.count(keyMac)) { - rapidjson::Value port; - port.SetObject(); - port.AddMember("id", - rapidjson::Value().SetInt( - std::stoi(ethSwitchList.at(keyId))), - ethSwitchAlloc); - port.AddMember("mac", - rapidjson::Value().SetString( - ethSwitchList.at(keyMac).c_str(), - ethSwitchList.at(keyMac).length(), - ethSwitchAlloc), - ethSwitchAlloc); - ports.AddMember(rapidjson::Value().SetString( - ethSwitchList.at(keyLabel).c_str(), - ethSwitchList.at(keyLabel).length(), - ethSwitchAlloc), - std::move(port), ethSwitchAlloc); - } - } - ethSwitch.AddMember("ports", std::move(ports), ethSwitchAlloc); - } - - for (const auto device : deviceInfoList) { - deviceInfo.AddMember( - rapidjson::Value().SetString(device.first.c_str(), - device.first.length(), alloc), - rapidjson::Value().SetString(device.second.c_str(), - device.second.length(), alloc), - alloc); - } - - deviceInfo.AddMember("capabilities", capabilities, alloc); - deviceInfo.AddMember("ethSwitch", ethSwitch, alloc); - deviceInfo.AddMember("accessoryCards", accessoryCards, alloc); -} - -void Device::mapFileToCapability() { - if (fileType("/opt/node-red") == S_IFDIR) { /* node-red is a directory */ - capabilityList["nodeRed"] = true; - } - if (fileType("/opt/lora/lora-network-server") == - S_IFREG) { /* lora-network-server is a regular file */ - capabilityList["loraNetworkServer"] = true; - } - if (capabilityList["cell"]) { /* only on devices with Cellular */ - if (fileType("/dev/cdc-wdm0") == S_IFCHR) { - /* Cellular modem is wwan/qmi/mbim character device */ - capabilityList["cellWwan"] = true; - } - if (!fileExists("/dev/modem_at0") && fileType("/dev/modem_at1") == S_IFCHR) { - /* Cellular modem without PPP support, probably uses ECM WWAN */ - capabilityList["cellWwan"] = true; - } else { - /* all other radios - assume PPP is supported */ - capabilityList["cellPpp"] = true; - } - } - if (fileType("/dev/ext_serial") == - S_IFCHR) { /* ext_serial is a character device */ - capabilityList["externalSerialPort"] = true; - } - if (fileType("/usr/bin/dockerd") == - S_IFREG) { /* Docker is a regular file */ - capabilityList["docker"] = true; - } - if (findFileGlob("/dev/tpm*") == S_IFCHR) { /* tpm* is a character device */ - capabilityList["tpm"] = true; - } -} - -void Device::mapMacAddress2() { - std::ifstream file("/sys/devices/platform/mts-io/base/mac-eth"); - if (file.is_open()) { - std::string line = ""; - std::getline(file, line); - deviceInfoList["macAddress1"] = line; - } -} - -void Device::mapFirmware() { - std::ifstream file(FIRMWARE_FILE); - if (!file.is_open()) { - return; - } - std::string line; - while (std::getline(file, line)) { - if (line.find(FIRMWARE_VERSION) != std::string::npos) { - deviceInfoList["firmware"] = line.substr(line.find(" ") + 1); - } else if (line.find(FIRMWARE_DATE) != std::string::npos) { - deviceInfoList["firmwareDate"] = line.substr(line.find(" ") + 1); - } else if (line.find(FIRMWARE_RELEASE) != std::string::npos) { - deviceInfoList["firmwareRelease"] = line.substr(line.find(" ") + 1); - } - } -} - -void Device::printDir(const std::string dir_name, - std::vector<std::string> &results) { - 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); - } - while (1) { - struct dirent *entry = readdir(d); - if (!entry) { - break; - } - const char *d_name = entry->d_name; - if (!(entry->d_type & DT_DIR)) { - std::string result; - if (dir_name.size() > 0) { - result = (dir_name + "/"); - } - result.append(d_name); - results.push_back(result); - } - if (isValidDirectory(entry, fullPath, - d_name)) { /* Check that the directory is not "d" - or d's parent. */ - printDir(d_name, results); - } - } - if (closedir(d)) { /* After going through all the entries, close the - directory. */ - printError("Could not close %s", fullPath); - exitHandler(errno); - } -} - -void Device::printJson() { - rapidjson::StringBuffer buffer; - rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); - deviceInfo.Accept(writer); - std::cout << buffer.GetString(); -} - -void Device::printVersion(std::string name) { - printInfo( - "%s %s\nCopyright (C) 2022 by Multi-Tech Systems\nThis program is free " - "software; you may redistribute it under the terms of\nthe GNU General " - "Public License version 2 or (at your option) any later version.\nThis " - "program has absolutely no warranty.", - name.c_str(), Version::version.c_str()); - exitHandler(0); -} - -void Device::printUsage(std::string program) { - std::vector<std::string> showResults; - printf("Usage: %s [ OPTIONS ] OBJECT [--] [ ARGUMENTS ]\n", program.c_str()); - printf("Legacy OBJECT options:\n"); - printf(" init : init & make device info json\n"); - printf(" json : init & make device info json\n"); - printf(" show : show data for file\n"); - printf(" show-trigger : show trigger data for file\n"); - printf(" store : store data for file\n"); - printf(" store-trigger : store trigger data for file\n"); - printf(" load-fpga : load fpga version\n"); - printf("Updated OBJECT options:\n"); - printf(" -I, --init : init & make device info json\n"); - printf(" -j, --json : output device info json\n"); - printf(" -s, --show : show data for file\n"); - printf(" -S, --show-trigger : show trigger data for file\n"); - printf(" -t, --store : store data for file\n"); - printf(" -T, --store-trigger : store trigger data for file\n"); - printf(" -l, --load-fpga : update fpga version\n"); - printf(" -c, --check : check fpga version\n"); - printf(" -v, --version : show version\n"); - printf(" -h, --help : show help\n"); - printf("\n"); - printf("Options\n"); - printf(" -V, --verbose : show additional debug output\n"); - printf("FPGA\n"); - printf("Arguments:\n"); - printf(" -p, --path : path for card\n"); - printf(" : options: 1 for ap1, 2 for ap2 everything else\n"); - printf(" : is an expected full path. i.e. /dev/spidevX.X\n"); - printf(" -i, --input : input file for upgrade\n"); - printf(" : files are stored in /usr/lib/mts-flash-binaries\n"); - printf("Usage:\n"); - printf(" Load : mts-io-sysfs -l -p <path> -i <file>\n"); - printf(" Check : mts-io-sysfs -c -p <path>\n"); - printf("\n"); - printf("show-name:\n"); - printf("Usage:\n"); - printf("--show-name <name>\n"); - printDir("", showResults); - sort(showResults.begin(), - showResults.end()); // Unix file tree is not sorted - - for (std::string showResult : showResults) { - if (!regex_match(showResult, showFilters)) - printf(" %s\n", showResult.c_str()); - } - printf("\n"); - printf("store-name:\n"); - printf("Usage:\n"); - printf("--store-name <name> <value>\n"); - for (std::string showResult : showResults) { - if (showResult == "radio-reset") { - printf(" %s { 0 }\n", showResult.c_str()); - } else if (showResult == "reset-monitor") { - printf(" %s { pid short-signal long-signal " - "[extra-long-signal] }\n", - showResult.c_str()); - } else if (showResult == "reset-monitor-intervals") { - printf(" %s { short-interval long-interval }\n", - showResult.c_str()); - } else if (regex_match(showResult, serialModeFilter)) { - printf(" %s { loopback | rs232 | rs485-half | " - "rs422-485-full }\n", - showResult.c_str()); - } else if (!regex_match(showResult, storeFilters)) { - printf(" %s BOOLEAN\n", showResult.c_str()); - } - } - printf("\n"); - exitHandler(0); -} - -/* If the name starts in upper case, assume - * the name is a GPIO line name from gpio-hog - * in device tree. If it starts in lower case - * assume the name is an attribute of the mts-io - * driver. GPIOs can only be zero - * or one, never a text string. - */ -void Device::show(std::string name) { - std::string fileData; - char chipname[64]; - unsigned int offset; - int retval; - - if(isupper(name[0])) { - retval = gpiod_ctxless_find_line(name.c_str(), chipname, - sizeof chipname,&offset); - if(retval != -1) - retval = gpiod_ctxless_get_value(chipname, offset, - false, CMDNAME); - if(retval != -1) { - if(retval == 0) - printf("0\n"); - else - printf("1\n"); - exitHandler(0); - } - } - - int32_t code = MTS::System::readFile(SYSFS_PLATFORM + name, fileData); - if (code == 0) { - printf("%s", fileData.c_str()); - exitHandler(0); - } - printError("cat: can't open %s%s: %s", - SYSFS_PLATFORM, name.c_str(),strerror(errno)); - exitHandler(99); -} - -void Device::showTrigger(std::string name) { - std::string fileData; - int32_t code = - MTS::System::readFile(LEDS_GPIO_DIR + name + "/trigger", fileData); - if (code == 0) { - printf("%s", fileData.c_str()); - exitHandler(0); - } - printError("Can't open %s%s/trigger: %s", - LEDS_GPIO_DIR, name.c_str(),strerror(errno)); - exitHandler(99); -} - -// Prefer gpiod if name starts with upper case and is value 0 or 1 -void Device::store(std::string name, std::string value) { - int intvalue = -1; - int prefergpiod = 0; - char chipname[64]; - unsigned int offset; - int retval; - - if (!isRoot) { - printError("Must be root to store to %s", name.c_str()); - exitHandler(99); - } - printDebug("Setting %s to %s", name.c_str(), value.c_str()); - if(isupper(name[0])) { - if (value.compare("0") == 0) - intvalue = 0; - if (value.compare("1") == 0) - intvalue = 1; - if ((intvalue != -1)) - prefergpiod = 1; - } - - if(prefergpiod) { - retval = gpiod_ctxless_find_line(name.c_str(), chipname, - sizeof chipname,&offset); - if(retval != -1) - retval = gpiod_ctxless_set_value(chipname, offset, intvalue, - false, CMDNAME, NULL, NULL); - if(retval != -1) - exitHandler(0); - } - - std::ofstream fileToWrite(SYSFS_PLATFORM + name); - if (fileToWrite.is_open()) { - fileToWrite << value; - if (fileToWrite.bad()) { - printError("Can't write %s%s: %s", SYSFS_PLATFORM, - name.c_str(),strerror(errno)); - exitHandler(98); - } - fileToWrite.close(); - exitHandler(0); - } - printError("Can't open %s%s: %s", SYSFS_PLATFORM, - name.c_str(),strerror(errno)); - exitHandler(99); -} - -void Device::storeTrigger(std::string name, std::string value) { - if (!isRoot) { - printError("Must be root to storeTrigger to %s/trigger", name.c_str()); - exitHandler(99); - } - printDebug("Setting %s to %s", name.c_str(), value.c_str()); - std::ofstream fileToWrite(LEDS_GPIO_DIR + name + "/trigger"); - if (fileToWrite.is_open()) { - fileToWrite << value; - if(fileToWrite.bad()) { - printError("Can't write %s%s/trigger: %s", - LEDS_GPIO_DIR, name.c_str(), strerror(errno)); - exitHandler(98); - } - fileToWrite.close(); - exitHandler(0); - } - printError("Can't open %s%s/trigger: %s", - LEDS_GPIO_DIR, name.c_str(), strerror(errno)); - exitHandler(99); -} - -void Device::writeJson() { - 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)); - exitHandler(99); - } else { - os << buffer.GetString(); - } -} |