summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Klug <john.klug@multitech.com>2023-11-08 14:17:55 -0600
committerJohn Klug <john.klug@multitech.com>2023-11-08 14:24:41 -0600
commita826d13ae7b3e20648566ddecca23bd6fe8f856b (patch)
tree9bf8cf2ef563de953e581493aeb6d5ac60e1a2e1
parentced9991aafb6b1b30649fd34b0d17399686d4843 (diff)
downloadmts-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--Makefile2
-rw-r--r--include/Device/Device.h19
-rw-r--r--src/Device/Device.cpp216
-rw-r--r--src/Device/Device.cpp.orig630
4 files changed, 234 insertions, 633 deletions
diff --git a/Makefile b/Makefile
index 16aa846..142a58e 100644
--- a/Makefile
+++ b/Makefile
@@ -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 &ethSwitchAlloc = 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();
- }
-}