From 57ef5cfd0780bac1ca51199d9d2db953ea6fabb1 Mon Sep 17 00:00:00 2001 From: Thad House Date: Thu, 24 Nov 2016 21:53:04 -0800 Subject: [PATCH] Splits out SerialHelper to allow using OS or VISA resources (#365) Also removes regex and uses simple splits instead --- hal/lib/athena/SerialHelper.cpp | 324 ++++++++++++++++++++------------ hal/lib/athena/SerialHelper.h | 9 +- hal/lib/athena/SerialPort.cpp | 2 +- 3 files changed, 209 insertions(+), 126 deletions(-) diff --git a/hal/lib/athena/SerialHelper.cpp b/hal/lib/athena/SerialHelper.cpp index 5361d80d52..fe428c5997 100644 --- a/hal/lib/athena/SerialHelper.cpp +++ b/hal/lib/athena/SerialHelper.cpp @@ -10,14 +10,16 @@ #include #include #include -#include #include "HAL/Errors.h" #include "llvm/StringRef.h" #include "visa/visa.h" -constexpr const char* OnboardResource = "ASRL1::INSTR"; -constexpr const char* MxpResource = "ASRL2::INSTR"; +constexpr const char* OnboardResourceVISA = "ASRL1::INSTR"; +constexpr const char* MxpResourceVISA = "ASRL2::INSTR"; + +constexpr const char* OnboardResourceOS = "ttyS0"; +constexpr const char* MxpResourceOS = "ttyS1"; namespace hal { std::string SerialHelper::m_usbNames[2]{"", ""}; @@ -27,12 +29,12 @@ priority_mutex SerialHelper::m_nameMutex; SerialHelper::SerialHelper(int32_t resourceHandle) : m_resourceHandle(resourceHandle) {} -std::string SerialHelper::GetSerialPortName(HAL_SerialPort port, - int32_t* status) { +std::string SerialHelper::GetVISASerialPortName(HAL_SerialPort port, + int32_t* status) { if (port == HAL_SerialPort::HAL_SerialPort_Onboard) { - return OnboardResource; + return OnboardResourceVISA; } else if (port == HAL_SerialPort::HAL_SerialPort_MXP) { - return MxpResource; + return MxpResourceVISA; } QueryHubPaths(status); @@ -44,59 +46,7 @@ std::string SerialHelper::GetSerialPortName(HAL_SerialPort port, return ""; } - // Hold lock whenever we're using the names array - std::lock_guard lock(m_nameMutex); - - std::string portString = m_usbNames[port - 2]; - - llvm::SmallVector indices; - - // If port has not been assigned, find the one to assign - if (portString.empty()) { - for (size_t i = 0; i < 2; i++) { - // Remove all used ports - auto idx = std::find(m_sortedHubPath.begin(), m_sortedHubPath.end(), - m_usbNames[i]); - if (idx != m_sortedHubPath.end()) { - // found - m_sortedHubPath.erase(idx); - } - if (m_usbNames[i] == "") { - indices.push_back(i); - } - } - - int32_t idx = -1; - for (size_t i = 0; i < indices.size(); i++) { - if (indices[i] == port - 2) { - idx = i; - break; - } - } - - if (idx == -1) { - *status = HAL_SERIAL_PORT_NOT_FOUND; - return ""; - } - - if (idx >= static_cast(m_sortedHubPath.size())) { - *status = HAL_SERIAL_PORT_NOT_FOUND; - return ""; - } - - portString = m_sortedHubPath[idx].str(); - m_usbNames[port - 2] = portString; - } - - int visaIndex = -1; - - for (size_t i = 0; i < m_sortedHubPath.size(); i++) { - if (m_sortedHubPath[i].equals(portString)) { - visaIndex = i; - break; - } - } - + int32_t visaIndex = GetIndexForPort(port, status); if (visaIndex == -1) { *status = HAL_SERIAL_PORT_NOT_FOUND; return ""; @@ -106,6 +56,79 @@ std::string SerialHelper::GetSerialPortName(HAL_SerialPort port, } } +std::string SerialHelper::GetOSSerialPortName(HAL_SerialPort port, + int32_t* status) { + if (port == HAL_SerialPort::HAL_SerialPort_Onboard) { + return OnboardResourceOS; + } else if (port == HAL_SerialPort::HAL_SerialPort_MXP) { + return MxpResourceOS; + } + + QueryHubPaths(status); + + // If paths are empty or status error, return error + if (*status != 0 || m_visaResource.empty() || m_osResource.empty() || + m_sortedHubPath.empty()) { + *status = HAL_SERIAL_PORT_NOT_FOUND; + return ""; + } + + int32_t osIndex = GetIndexForPort(port, status); + if (osIndex == -1) { + *status = HAL_SERIAL_PORT_NOT_FOUND; + return ""; + // Error + } else { + return m_osResource[osIndex].str(); + } +} + +std::vector SerialHelper::GetVISASerialPortList(int32_t* status) { + std::vector retVec; + + // Always add 2 onboard ports + retVec.emplace_back(OnboardResourceVISA); + retVec.emplace_back(MxpResourceVISA); + + QueryHubPaths(status); + + // If paths are empty or status error, return only onboard list + if (*status != 0 || m_visaResource.empty() || m_osResource.empty() || + m_sortedHubPath.empty()) { + *status = 0; + return retVec; + } + + for (auto& i : m_visaResource) { + retVec.emplace_back(i.str()); + } + + return retVec; +} + +std::vector SerialHelper::GetOSSerialPortList(int32_t* status) { + std::vector retVec; + + // Always add 2 onboard ports + retVec.emplace_back(OnboardResourceOS); + retVec.emplace_back(MxpResourceOS); + + QueryHubPaths(status); + + // If paths are empty or status error, return only onboard list + if (*status != 0 || m_visaResource.empty() || m_osResource.empty() || + m_sortedHubPath.empty()) { + *status = 0; + return retVec; + } + + for (auto& i : m_osResource) { + retVec.emplace_back(i.str()); + } + + return retVec; +} + void SerialHelper::SortHubPathVector() { m_sortedHubPath.clear(); m_sortedHubPath = m_unsortedHubPath; @@ -156,16 +179,12 @@ void SerialHelper::QueryHubPaths(int32_t* status) { char osName[256]; char execBuffer[128]; - // Regex to filter out the device name - // Will be index 1 on success - std::regex devMatch("[^\\s]+\\s+\\(\\/dev\\/([^\\s]+)\\)"); - // Loop through all returned VISA objects. // Increment the internal VISA ptr every loop for (size_t i = 0; i < retCnt; i++, viFindNext(viList, desc)) { // Ignore any matches to the 2 onboard ports - if (std::strcmp(OnboardResource, desc) == 0 || - std::strcmp(MxpResource, desc) == 0) { + if (std::strcmp(OnboardResourceVISA, desc) == 0 || + std::strcmp(MxpResourceVISA, desc) == 0) { continue; } @@ -183,75 +202,74 @@ void SerialHelper::QueryHubPaths(int32_t* status) { if (closeStatus < 0) return; *status = 0; - std::smatch regexMatcher; - auto regexVal = - std::regex_match(std::string(osName), regexMatcher, devMatch); + // split until (/dev/ + llvm::StringRef devNameRef = llvm::StringRef{osName}.split("(/dev/").second; + // String not found, continue + if (devNameRef.equals("")) continue; - if (regexVal > 0 && regexMatcher.size() > 1) { - // Store our match string, as output was ocassionally being corrupted - // before being accessed - auto matchString = regexMatcher[1].str(); + // Split at ) + llvm::StringRef matchString = devNameRef.split(')').first; + if (matchString.equals(devNameRef)) continue; - // Run find using pipe to get a list of system accessors - llvm::SmallString<128> val( - "sh -c \"find /sys/devices/soc0 | grep amba | grep usb | grep "); - val += matchString; - val += "\""; + // Run find using pipe to get a list of system accessors + llvm::SmallString<128> val( + "sh -c \"find /sys/devices/soc0 | grep amba | grep usb | grep "); + val += matchString; + val += "\""; - // Pipe code found on StackOverflow - // http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c-using-posix + // Pipe code found on StackOverflow + // http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c-using-posix - // Using std::string because this is guarenteed to be large - std::string output = ""; + // Using std::string because this is guarenteed to be large + std::string output = ""; - std::shared_ptr pipe(popen(val.c_str(), "r"), pclose); - // Just check the next item on a pipe failure - if (!pipe) continue; - while (!feof(pipe.get())) { - if (std::fgets(execBuffer, 128, pipe.get()) != 0) output += execBuffer; - } + std::shared_ptr pipe(popen(val.c_str(), "r"), pclose); + // Just check the next item on a pipe failure + if (!pipe) continue; + while (!feof(pipe.get())) { + if (std::fgets(execBuffer, 128, pipe.get()) != 0) output += execBuffer; + } - if (!output.empty()) { - llvm::SmallVector pathSplitVec; - // Split output by line, grab first line, and split it into - // individual directories - llvm::StringRef{output}.split('\n').first.split(pathSplitVec, '/', -1, - false); + if (!output.empty()) { + llvm::SmallVector pathSplitVec; + // Split output by line, grab first line, and split it into + // individual directories + llvm::StringRef{output}.split('\n').first.split(pathSplitVec, '/', -1, + false); - // Find each individual item index + // Find each individual item index - const char* usb1 = "usb1"; - const char* tty = "tty"; + const char* usb1 = "usb1"; + const char* tty = "tty"; - int findusb = -1; - int findtty = -1; - int findregex = -1; - for (size_t i = 0; i < pathSplitVec.size(); i++) { - if (findusb == -1 && pathSplitVec[i].equals(usb1)) { - findusb = i; - } - if (findtty == -1 && pathSplitVec[i].equals(tty)) { - findtty = i; - } - if (findregex == -1 && pathSplitVec[i].equals(matchString)) { - findregex = i; - } + int findusb = -1; + int findtty = -1; + int findregex = -1; + for (size_t i = 0; i < pathSplitVec.size(); i++) { + if (findusb == -1 && pathSplitVec[i].equals(usb1)) { + findusb = i; + } + if (findtty == -1 && pathSplitVec[i].equals(tty)) { + findtty = i; + } + if (findregex == -1 && pathSplitVec[i].equals(matchString)) { + findregex = i; } - - // Get the index for our device - int hubIndex = findtty; - if (findtty == -1) hubIndex = findregex; - - int devStart = findusb + 1; - - if (hubIndex < devStart) continue; - - // Add our devices to our list - m_unsortedHubPath.push_back( - llvm::StringRef{pathSplitVec[hubIndex - 2]}); - m_visaResource.push_back(llvm::StringRef{desc}); - m_osResource.push_back(llvm::StringRef{matchString}); } + + // Get the index for our device + int hubIndex = findtty; + if (findtty == -1) hubIndex = findregex; + + int devStart = findusb + 1; + + if (hubIndex < devStart) continue; + + // Add our devices to our list + m_unsortedHubPath.emplace_back( + llvm::StringRef{pathSplitVec[hubIndex - 2]}); + m_visaResource.emplace_back(desc); + m_osResource.emplace_back(matchString); } } @@ -260,4 +278,62 @@ void SerialHelper::QueryHubPaths(int32_t* status) { CoiteratedSort(m_visaResource); CoiteratedSort(m_osResource); } + +int32_t SerialHelper::GetIndexForPort(HAL_SerialPort port, int32_t* status) { + // Hold lock whenever we're using the names array + std::lock_guard lock(m_nameMutex); + + std::string portString = m_usbNames[port - 2]; + + llvm::SmallVector indices; + + // If port has not been assigned, find the one to assign + if (portString.empty()) { + for (size_t i = 0; i < 2; i++) { + // Remove all used ports + auto idx = std::find(m_sortedHubPath.begin(), m_sortedHubPath.end(), + m_usbNames[i]); + if (idx != m_sortedHubPath.end()) { + // found + m_sortedHubPath.erase(idx); + } + if (m_usbNames[i] == "") { + indices.push_back(i); + } + } + + int32_t idx = -1; + for (size_t i = 0; i < indices.size(); i++) { + if (indices[i] == port - 2) { + idx = i; + break; + } + } + + if (idx == -1) { + *status = HAL_SERIAL_PORT_NOT_FOUND; + return -1; + } + + if (idx >= static_cast(m_sortedHubPath.size())) { + *status = HAL_SERIAL_PORT_NOT_FOUND; + return -1; + } + + portString = m_sortedHubPath[idx].str(); + m_usbNames[port - 2] = portString; + } + + int retIndex = -1; + + for (size_t i = 0; i < m_sortedHubPath.size(); i++) { + if (m_sortedHubPath[i].equals(portString)) { + retIndex = i; + break; + } + } + + return retIndex; +} + } // namespace hal diff --git a/hal/lib/athena/SerialHelper.h b/hal/lib/athena/SerialHelper.h index 17bb2407ef..469e85cf15 100644 --- a/hal/lib/athena/SerialHelper.h +++ b/hal/lib/athena/SerialHelper.h @@ -10,6 +10,7 @@ #include #include +#include #include "HAL/SerialPort.h" #include "HAL/cpp/priority_mutex.h" @@ -21,13 +22,19 @@ class SerialHelper { public: explicit SerialHelper(int32_t resourceHandle); - std::string GetSerialPortName(HAL_SerialPort port, int32_t* status); + std::string GetVISASerialPortName(HAL_SerialPort port, int32_t* status); + std::string GetOSSerialPortName(HAL_SerialPort port, int32_t* status); + + std::vector GetVISASerialPortList(int32_t* status); + std::vector GetOSSerialPortList(int32_t* status); private: void SortHubPathVector(); void CoiteratedSort(llvm::SmallVectorImpl>& vec); void QueryHubPaths(int32_t* status); + int32_t GetIndexForPort(HAL_SerialPort port, int32_t* status); + // Vectors to hold data before sorting. // Note we will most likely have at max 2 instances, and the longest string // is around 12, so these should never touch the heap; diff --git a/hal/lib/athena/SerialPort.cpp b/hal/lib/athena/SerialPort.cpp index 47b3f993af..42a18c677f 100644 --- a/hal/lib/athena/SerialPort.cpp +++ b/hal/lib/athena/SerialPort.cpp @@ -25,7 +25,7 @@ void HAL_InitializeSerialPort(HAL_SerialPort port, int32_t* status) { hal::SerialHelper serialHelper(resourceManagerHandle); - portName = serialHelper.GetSerialPortName(port, status); + portName = serialHelper.GetVISASerialPortName(port, status); if (*status < 0) { return;