/** * @file SerialPortInfoUnixBase.h * @author itas109 (itas109@qq.com) \n\n * Blog : https://blog.csdn.net/itas109 \n * Github : https://github.com/itas109 \n * QQ Group : 12951803 * @brief the CSerialPortInfo unix class unix串口信息辅助类基类 * @todo Not implemented 未实现 * @date 2020-04-29 * @copyright The CSerialPort is Copyright (C) 2021 itas109. \n * Contact: itas109@qq.com \n\n * You may use, distribute and copy the CSerialPort under the terms of \n * GNU Lesser General Public License version 3, which is displayed below. */ #ifndef __CSERIALPORTINFOUNIXBASE_H__ #define __CSERIALPORTINFOUNIXBASE_H__ #include "SerialPortInfoBase.h" #include "CSerialPort/osplatformutil.h" #ifdef I_OS_LINUX std::string get_driver(const std::string &tty) { struct stat st; std::string devicedir = tty; // Append '/device' to the tty-path /// sys/class/tty/ttyS0/device devicedir += "/device"; // Stat the devicedir and handle it if it is a symlink if (lstat(devicedir.c_str(), &st) == 0 && S_ISLNK(st.st_mode)) { char buffer[1024]; memset(buffer, 0, sizeof(buffer)); // Append '/driver' and return basename of the target // VCs, ptys, etc don't have /sys/class/tty//device/driver's // /sys/class/tty/ttyS0/device/driver devicedir += "/driver"; if (readlink(devicedir.c_str(), buffer, sizeof(buffer)) > 0) { // std::cout << "readlink " << devicedir << ", baseName " << basename(buffer) << std::endl; return basename(buffer); } else { // std::cout << "readlink error " << devicedir << std::endl; } } else { // std::cout << "lstat error " << devicedir << std::endl; } return ""; } void register_comport(vector &comList, vector &comList8250, const std::string &dir) { // Get the driver the device is using std::string driver = get_driver(dir); // Skip devices without a driver if (driver.size() > 0) { std::string devfile = std::string("/dev/") + basename(dir.c_str()); // std::cout << "driver : " << driver << ", devfile : " << devfile << std::endl; // Put serial8250-devices in a seperate list if (driver == "serial8250") { comList8250.push_back(devfile); } else { comList.push_back(devfile); } } } void probe_serial8250_comports(vector &comList, vector comList8250) { struct serial_struct serinfo; vector::iterator it = comList8250.begin(); // Iterate over all serial8250-devices while (it != comList8250.end()) { // Try to open the device int fd = open((*it).c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY); if (fd >= 0) { // Get serial_info if (ioctl(fd, TIOCGSERIAL, &serinfo) == 0) { // If device type is no PORT_UNKNOWN we accept the port if (serinfo.type != PORT_UNKNOWN) { comList.push_back(*it); // std::cout << "+++ " << *it << std::endl; } else { // std::cout << "PORT_UNKNOWN " << *it << std::endl; } } close(fd); } ++it; } } vector getPortInfoListLinux() { // https://stackoverflow.com/questions/2530096/how-to-find-all-serial-devices-ttys-ttyusb-on-linux-without-opening-them int n = -1; struct dirent **namelist; vector comList; vector comList8250; const char *sysDir = "/sys/class/tty/"; const char *ptsDir = "/dev/pts/"; // 1.Scan through /sys/class/tty - it contains all tty-devices in the system n = scandir(sysDir, &namelist, NULL, NULL); if (n >= 0) { while (n--) { if (strcmp(namelist[n]->d_name, "..") && strcmp(namelist[n]->d_name, ".")) { // Construct full absolute file path std::string devicedir = sysDir; devicedir += namelist[n]->d_name; // Register the device register_comport(comList, comList8250, devicedir); } free(namelist[n]); } free(namelist); } // Only non-serial8250 has been added to comList without any further testing // serial8250-devices must be probe to check for validity probe_serial8250_comports(comList, comList8250); // 2.Scan through /dev/pts/- it contains all pseudo terminal(such as telnet, ssh etc.) in the system n = scandir(ptsDir, &namelist, NULL, NULL); if (n >= 0) { while (n--) { if (strcmp(namelist[n]->d_name, "..") && strcmp(namelist[n]->d_name, ".") && strcmp(namelist[n]->d_name, "ptmx")) { // Construct full absolute file path std::string ptsName = ptsDir; ptsName += namelist[n]->d_name; comList.push_back(ptsName); } free(namelist[n]); } free(namelist); } // Return the lsit of detected comports return comList; } #endif vector getPortInfoList() { vector portInfoList; #ifdef I_OS_LINUX // TODO: need to optimize SerialPortInfo m_serialPort; vector portList = getPortInfoListLinux(); int count = portList.size(); for (int i = 0; i < count; i++) { m_serialPort.portName = portList[i]; portInfoList.push_back(m_serialPort); } #endif return portInfoList; } /** * @brief the CSerialPortInfo unix class unix串口信息辅助类基类 * */ class CSerialPortInfoUnixBase : public CSerialPortInfoBase { public: CSerialPortInfoUnixBase(){} ~CSerialPortInfoUnixBase(){} /** * @brief availablePortInfos 获取串口信息列表 * @return return available port infolist 返回可用串口名称列表 */ static std::vector availablePortInfos(){ return getPortInfoList(); } }; #endif //__CSERIALPORTINFOUNIXBASE_H__