123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /**
- * @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/<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<std::string> &comList, vector<std::string> &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<std::string> &comList, vector<std::string> comList8250)
- {
- struct serial_struct serinfo;
- vector<std::string>::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<std::string> 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<std::string> comList;
- vector<std::string> 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<SerialPortInfo> getPortInfoList()
- {
- vector<SerialPortInfo> portInfoList;
- #ifdef I_OS_LINUX
- // TODO: need to optimize
- SerialPortInfo m_serialPort;
- vector<std::string> 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<SerialPortInfo> availablePortInfos(){
- return getPortInfoList();
- }
- };
- #endif //__CSERIALPORTINFOUNIXBASE_H__
|