mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
Splits out SerialHelper to allow using OS or VISA resources (#365)
Also removes regex and uses simple splits instead
This commit is contained in:
committed by
Peter Johnson
parent
4bbb7c0bcc
commit
57ef5cfd07
@@ -10,14 +10,16 @@
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <regex>
|
||||
|
||||
#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<priority_mutex> lock(m_nameMutex);
|
||||
|
||||
std::string portString = m_usbNames[port - 2];
|
||||
|
||||
llvm::SmallVector<int32_t, 4> 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<int32_t>(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<std::string> SerialHelper::GetVISASerialPortList(int32_t* status) {
|
||||
std::vector<std::string> 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<std::string> SerialHelper::GetOSSerialPortList(int32_t* status) {
|
||||
std::vector<std::string> 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<FILE> 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<FILE> 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<llvm::StringRef, 16> 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<llvm::StringRef, 16> 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<priority_mutex> lock(m_nameMutex);
|
||||
|
||||
std::string portString = m_usbNames[port - 2];
|
||||
|
||||
llvm::SmallVector<int32_t, 4> 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<int32_t>(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
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<std::string> GetVISASerialPortList(int32_t* status);
|
||||
std::vector<std::string> GetOSSerialPortList(int32_t* status);
|
||||
|
||||
private:
|
||||
void SortHubPathVector();
|
||||
void CoiteratedSort(llvm::SmallVectorImpl<llvm::SmallString<16>>& 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user