From 0b55b2997d17bbce5bea3ebe1f5700dca184574f Mon Sep 17 00:00:00 2001 From: Serhii Voloshynov Date: Wed, 15 May 2024 16:20:54 +0300 Subject: [MTX-5302] MTR3 R.7.0: Serial IP functionality support GP-2336 --- include/Device/Device.h | 23 +++++- include/General.h | 1 + src/Device/Device.cpp | 190 +++++++++++++++++++++++++++++++++++------------- src/MtsIoSysfs.cpp | 17 +++-- 4 files changed, 171 insertions(+), 60 deletions(-) diff --git a/include/Device/Device.h b/include/Device/Device.h index bcf0cff..a1c0b1b 100644 --- a/include/Device/Device.h +++ b/include/Device/Device.h @@ -23,8 +23,6 @@ class Device { static std::map capabilityList; static std::map ethSwitchList; static std::map deviceInfoList; - static std::vector dInputs; - static std::vector dOutputs; static const std::regex apFilters; static const std::regex serialModeFilter; @@ -33,6 +31,8 @@ class Device { static const std::regex mtcdt3HwVersionFilters; static const std::regex iotRtrVersionFilters; static const std::regex mtrFilters; + static std::string extIoStr; + static std::string serialStr; const unsigned int accessoryCardsListSize = 7; @@ -150,6 +150,18 @@ class Device { std::vector> accessoryCardsList; + const std::string SERIAL_MODE = "mode"; + const std::string SERIAL_TERMINATION = "rs4xx-term-res"; + const std::string SERIAL_MODE_RS232 = "rs232"; + const std::string SERIAL_MODE_RS485 = "rs485-half"; + const std::map mModes = {{SERIAL_MODE_RS232, 0}, {SERIAL_MODE_RS485, 0}}; + + const std::string CONTROL_PIN_SERIAL_MODE = "MXC2_RS485_EN"; + const std::string CONTROL_PIN_TERMINATION = "MXC2_RS485_TERM_EN"; + const std::string HW_VERSION_FILE = "/sys/devices/platform/mts-io/hw-version"; + std::string program_name; + std::string hw_version; + public: Device(); void getSystemTreeJson(const char *dir_name); @@ -169,7 +181,7 @@ class Device { std::vector &results); void printJson(); void printVersion(std::string name); - void printUsage(std::string program); + void printUsage(); void show(std::string program); void showTrigger(std::string name); void sortAccessoryCards(); @@ -181,6 +193,11 @@ class Device { 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); + void setSerialModesMTR3(const std::string &mode, const std::string &value); + void showSerialModesMTR3(const std::string &mode); + int getPinValue(const std::string &name); + void setProgramName(const std::string &name); + void setHWVersion(); }; #endif /* DEVICE_H_ */ diff --git a/include/General.h b/include/General.h index 4429b3d..58c2a09 100644 --- a/include/General.h +++ b/include/General.h @@ -76,6 +76,7 @@ typedef unsigned int uint; // 32 bit - even on 64 bit machines #define KEY_EXTIO "extIo" #define KEY_DOUTPUTS "dOutputs" #define KEY_DINPUTS "dInputs" +#define KEY_SERIALS "serialPorts" enum HardwareType { HARDWARE_MTCDT, diff --git a/src/Device/Device.cpp b/src/Device/Device.cpp index b2588eb..be198f1 100644 --- a/src/Device/Device.cpp +++ b/src/Device/Device.cpp @@ -42,16 +42,12 @@ std::map Device::capabilityList = { {"cell", 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}, @@ -60,8 +56,8 @@ std::map Device::capabilityList = { {"userDataEncryption", false}}; std::map Device::ethSwitchList; -std::vector Device::dInputs; -std::vector Device::dOutputs; +std::string Device::extIoStr; +std::string Device::serialStr; std::map Device::deviceInfoList = { {"deviceId", ""}, @@ -179,19 +175,33 @@ void Device::getSystemTreeJson(const char *dir_name) { } 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; } if (regex_match(fileData, iotRtrVersionFilters)) { + mapMacAddress2Iotr(); /* The order of the elements is important! This array is used to access Digital IOs, in particular in SMS commands! */ - dInputs.push_back("USER_DIO_IN"); - dOutputs.push_back("USER_DIO_OUT"); - mapMacAddress2Iotr(); + extIoStr = "{\"dInputs\":[\"USER_DIO_IN\"],\"dOutputs\":[\"USER_DIO_OUT\"]}"; + capabilityList["serial"] = true; + serialStr = "[{" + "\"available\": true," + "\"id\": \"serial0\"," + "\"name\": \"RS232\"," + "\"device\": \"/dev/ttymxc1\"," + "\"role\": \"DCE\"," + "\"modes\": {\"RS-232\": [\"hw-flowcontrol\", \"dcd-dtr\"]}," + "\"speed\": [9600, 19200, 38400, 57600, 115200]" + "},{" + "\"available\": true," + "\"id\": \"serial1\"," + "\"name\": \"RS232/485\"," + "\"device\": \"/dev/ttymxc2\"," + "\"role\": \"DCE\"," + "\"modes\": {\"RS-232\": [\"hw-flowcontrol\"], \"RS-485-HALF\": [\"rs4xx-termination\"]}," + "\"speed\": [9600, 19200, 38400, 57600, 115200, 230400, 460800, 930600]" + "}]"; } } else if (strcmp(d_name, "mac-eth") == 0) { deviceInfoList["macAddress"] = fileData; @@ -318,28 +328,14 @@ 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(); + extIo.Parse<0>(extIoStr.c_str()); auto &extAlloc = extIo.GetAllocator(); - extIo.AddMember(KEY_DINPUTS, inp, extAlloc); - extIo.AddMember(KEY_DOUTPUTS, out, extAlloc); deviceInfo.AddMember(KEY_EXTIO, extIo, extAlloc); + rapidjson::Document serial; + serial.Parse<0>(serialStr.c_str()); + auto &serAlloc = serial.GetAllocator(); + deviceInfo.AddMember(KEY_SERIALS, serial, serAlloc); } void Device::mapFileToCapability() { @@ -350,10 +346,6 @@ void Device::mapFileToCapability() { S_IFREG) { /* lora-network-server is a regular file */ capabilityList["loraNetworkServer"] = 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; @@ -450,9 +442,10 @@ void Device::printVersion(std::string name) { exitHandler(0); } -void Device::printUsage(std::string program) { + +void Device::printUsage() { std::vector showResults; - printf("Usage: %s [ OPTIONS ] OBJECT [--] [ ARGUMENTS ]\n", program.c_str()); + printf("Usage: %s [ OPTIONS ] OBJECT [--] [ ARGUMENTS ]\n", program_name.c_str()); printf("Legacy OBJECT options:\n"); printf(" init : init & make device info json\n"); printf(" json : init & make device info json\n"); @@ -489,7 +482,7 @@ void Device::printUsage(std::string program) { printf("\n"); printf("show-name:\n"); printf("Usage:\n"); - printf("--show-name \n"); + printf("--show \n"); printDir("", showResults); sort(showResults.begin(), showResults.end()); // Unix file tree is not sorted @@ -498,10 +491,15 @@ void Device::printUsage(std::string program) { if (!regex_match(showResult, showFilters)) printf(" %s\n", showResult.c_str()); } + if (regex_match(hw_version, iotRtrVersionFilters)) { + printf(" serial1/%s\n", SERIAL_TERMINATION.c_str()); + printf(" serial1/%s\n", SERIAL_MODE.c_str()); + printf("}\n"); + } printf("\n"); printf("store-name:\n"); printf("Usage:\n"); - printf("--store-name \n"); + printf("--store \n"); for (std::string showResult : showResults) { if (showResult == "radio-reset") { printf(" %s { 0 }\n", showResult.c_str()); @@ -512,14 +510,23 @@ void Device::printUsage(std::string program) { } 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()); } } + if (regex_match(hw_version, iotRtrVersionFilters)) { + printf(" serial1/%s { 0 | 1 }\n", SERIAL_TERMINATION.c_str()); + printf(" serial1/%s {", SERIAL_MODE.c_str()); + unsigned int c = 1; + for (auto const &m : mModes) { + printf(" %s ", m.first.c_str()); + if (c != mModes.size()) { + printf("|"); + } + c++; + }; + printf("}\n"); + } printf("\n"); exitHandler(0); } @@ -697,7 +704,8 @@ unsigned int Device::gpio_request::offset() * driver. GPIOs can only be zero * or one, never a text string. */ -void Device::show(std::string name) { + +int Device::getPinValue(const std::string &name) { std::string fileData; if(isupper(name[0])) { gpio_request gr(this, name); @@ -705,10 +713,9 @@ void Device::show(std::string name) { 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"; + return 0; else - std::cout << "1\n"; - exitHandler(0); + return 1; } else simpleError("Invalid GPIO line value", errno, 109); } @@ -716,12 +723,24 @@ void Device::show(std::string name) { int32_t code = MTS::System::readFile(SYSFS_PLATFORM + name, fileData); if (code == 0) { - printf("%s", fileData.c_str()); - exitHandler(0); + if (fileData == "1") { + return 1; + } else { + return 0; + } } printError("cat: can't open %s%s: %s", SYSFS_PLATFORM, name.c_str(),strerror(errno)); exitHandler(99); + return 99; // never be returned +} + +void Device::show(std::string name) { + if (regex_match(hw_version, iotRtrVersionFilters)) { + showSerialModesMTR3(name); + } + printf("%i", getPinValue(name)); + exitHandler(0); } // End of show void Device::showTrigger(std::string name) { @@ -745,7 +764,9 @@ void Device::store(std::string name, std::string value) { } printDebug("Setting %s to %s", name.c_str(), value.c_str()); - + if (regex_match(hw_version, iotRtrVersionFilters)) { + setSerialModesMTR3(name, value); + } if(isupper(name[0])) { enum gpiod_line_value lv = GPIOD_LINE_VALUE_ERROR; @@ -872,3 +893,72 @@ void Device::storeOutputStateToNonvolatile(const std::string& name, const std::s } writeJson(stateIo, STORED_DIGITAL_OUTPUTS_STATE_FILE); } + +void Device::setSerialModesMTR3(const std::string ¶meter, const std::string &value) { + std::vector parts = MTS::Text::split(parameter, '/'); + if (parts.size() < 2) { + return; + } + const std::string &serialName = parts[0]; + const std::string &mode = parts[1]; + if (serialName != "serial1") { + printUsage(); + } + if ((mode != SERIAL_MODE) && (mode != SERIAL_TERMINATION)) { + printUsage(); + } + if (mode == SERIAL_MODE) { + if ((value != SERIAL_MODE_RS232) && (value != SERIAL_MODE_RS485)) { + printUsage(); + } + if (value == SERIAL_MODE_RS232) { + store(CONTROL_PIN_SERIAL_MODE, "0"); + } + if (value == SERIAL_MODE_RS485) { + store(CONTROL_PIN_SERIAL_MODE, "1"); + } + exitHandler(0); + } else if (mode == SERIAL_TERMINATION) { + store(CONTROL_PIN_TERMINATION, value); + exitHandler(0); + } +} + +void Device::showSerialModesMTR3(const std::string ¶meter) { + std::vector parts = MTS::Text::split(parameter, '/'); + if (parts.size() < 2) { + return; + } + const std::string &serialName = parts[0]; + const std::string &mode = parts[1]; + if (serialName != "serial1") { + printUsage(); + } + if ((mode != SERIAL_MODE) && (mode != SERIAL_TERMINATION)) { + printUsage(); + } + if (mode == SERIAL_MODE) { + if (getPinValue(CONTROL_PIN_SERIAL_MODE) == 1) { + std::cout << SERIAL_MODE_RS485 << std::endl; + } else { + std::cout << SERIAL_MODE_RS232 << std::endl; + } + exitHandler(0); + } else if (mode == SERIAL_TERMINATION) { + std::cout << getPinValue(CONTROL_PIN_TERMINATION) << std::endl; + exitHandler(0); + } +} + +void Device::setProgramName(const std::string &name){ + program_name = name; +} + +void Device::setHWVersion(){ + std::ifstream is(HW_VERSION_FILE); + if (!is.is_open()) { + printDebug("Can't read to %s: %s", HW_VERSION_FILE, strerror(errno)); + return; + } + std::getline(is, hw_version); +} \ No newline at end of file diff --git a/src/MtsIoSysfs.cpp b/src/MtsIoSysfs.cpp index ab68c8c..20e2925 100644 --- a/src/MtsIoSysfs.cpp +++ b/src/MtsIoSysfs.cpp @@ -44,10 +44,9 @@ static enum action_code action; int main(int argc, char **argv) { Device m; + m.setProgramName(argv[0]); action = ACTION_NONE; - if (argc < 2) { - m.printUsage(argv[0]); - } + std::string fpgaFilePath = ""; std::string forcedAP = ""; std::string name = ""; @@ -55,6 +54,10 @@ int main(int argc, char **argv) { int duration = 0; MTS::Logger::setPrintLevel(MTS::Logger::PrintLevel::INFO_LEVEL, true); + m.setHWVersion(); + if (argc < 2) { + m.printUsage(); + } int c; static struct option long_options[] = { {"help", no_argument, nullptr, 'h'}, @@ -148,11 +151,11 @@ int main(int argc, char **argv) { exit(-1); } case 'h': { - m.printUsage(argv[0]); + m.printUsage(); exit(0); } default: - m.printUsage(argv[0]); + m.printUsage(); exit(-1); } } @@ -213,7 +216,7 @@ int main(int argc, char **argv) { switch (action) { case ACTION_NONE: { - m.printUsage(argv[0]); + m.printUsage(); } case ACTION_SHOW: { m.show(name); @@ -251,7 +254,7 @@ int main(int argc, char **argv) { case ACTION_VERSION: { m.printVersion(argv[0]); } - default: { m.printUsage(argv[0]); } + default: { m.printUsage(); } } return 0; -- cgit v1.2.3