SerialPortInfoUnixBase.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /**
  2. * @file SerialPortInfoUnixBase.h
  3. * @author itas109 (itas109@qq.com) \n\n
  4. * Blog : https://blog.csdn.net/itas109 \n
  5. * Github : https://github.com/itas109 \n
  6. * QQ Group : 12951803
  7. * @brief the CSerialPortInfo unix class unix串口信息辅助类基类
  8. * @todo Not implemented 未实现
  9. * @date 2020-04-29
  10. * @copyright The CSerialPort is Copyright (C) 2021 itas109. \n
  11. * Contact: itas109@qq.com \n\n
  12. * You may use, distribute and copy the CSerialPort under the terms of \n
  13. * GNU Lesser General Public License version 3, which is displayed below.
  14. */
  15. #ifndef __CSERIALPORTINFOUNIXBASE_H__
  16. #define __CSERIALPORTINFOUNIXBASE_H__
  17. #include "SerialPortInfoBase.h"
  18. #include "CSerialPort/osplatformutil.h"
  19. #ifdef I_OS_LINUX
  20. std::string get_driver(const std::string &tty)
  21. {
  22. struct stat st;
  23. std::string devicedir = tty;
  24. // Append '/device' to the tty-path
  25. /// sys/class/tty/ttyS0/device
  26. devicedir += "/device";
  27. // Stat the devicedir and handle it if it is a symlink
  28. if (lstat(devicedir.c_str(), &st) == 0 && S_ISLNK(st.st_mode))
  29. {
  30. char buffer[1024];
  31. memset(buffer, 0, sizeof(buffer));
  32. // Append '/driver' and return basename of the target
  33. // VCs, ptys, etc don't have /sys/class/tty/<tty>/device/driver's
  34. // /sys/class/tty/ttyS0/device/driver
  35. devicedir += "/driver";
  36. if (readlink(devicedir.c_str(), buffer, sizeof(buffer)) > 0)
  37. {
  38. // std::cout << "readlink " << devicedir << ", baseName " << basename(buffer) << std::endl;
  39. return basename(buffer);
  40. }
  41. else
  42. {
  43. // std::cout << "readlink error " << devicedir << std::endl;
  44. }
  45. }
  46. else
  47. {
  48. // std::cout << "lstat error " << devicedir << std::endl;
  49. }
  50. return "";
  51. }
  52. void register_comport(vector<std::string> &comList, vector<std::string> &comList8250, const std::string &dir)
  53. {
  54. // Get the driver the device is using
  55. std::string driver = get_driver(dir);
  56. // Skip devices without a driver
  57. if (driver.size() > 0)
  58. {
  59. std::string devfile = std::string("/dev/") + basename(dir.c_str());
  60. // std::cout << "driver : " << driver << ", devfile : " << devfile << std::endl;
  61. // Put serial8250-devices in a seperate list
  62. if (driver == "serial8250")
  63. {
  64. comList8250.push_back(devfile);
  65. }
  66. else
  67. {
  68. comList.push_back(devfile);
  69. }
  70. }
  71. }
  72. void probe_serial8250_comports(vector<std::string> &comList, vector<std::string> comList8250)
  73. {
  74. struct serial_struct serinfo;
  75. vector<std::string>::iterator it = comList8250.begin();
  76. // Iterate over all serial8250-devices
  77. while (it != comList8250.end())
  78. {
  79. // Try to open the device
  80. int fd = open((*it).c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY);
  81. if (fd >= 0)
  82. {
  83. // Get serial_info
  84. if (ioctl(fd, TIOCGSERIAL, &serinfo) == 0)
  85. {
  86. // If device type is no PORT_UNKNOWN we accept the port
  87. if (serinfo.type != PORT_UNKNOWN)
  88. {
  89. comList.push_back(*it);
  90. // std::cout << "+++ " << *it << std::endl;
  91. }
  92. else
  93. {
  94. // std::cout << "PORT_UNKNOWN " << *it << std::endl;
  95. }
  96. }
  97. close(fd);
  98. }
  99. ++it;
  100. }
  101. }
  102. vector<std::string> getPortInfoListLinux()
  103. {
  104. // https://stackoverflow.com/questions/2530096/how-to-find-all-serial-devices-ttys-ttyusb-on-linux-without-opening-them
  105. int n = -1;
  106. struct dirent **namelist;
  107. vector<std::string> comList;
  108. vector<std::string> comList8250;
  109. const char *sysDir = "/sys/class/tty/";
  110. const char *ptsDir = "/dev/pts/";
  111. // 1.Scan through /sys/class/tty - it contains all tty-devices in the system
  112. n = scandir(sysDir, &namelist, NULL, NULL);
  113. if (n >= 0)
  114. {
  115. while (n--)
  116. {
  117. if (strcmp(namelist[n]->d_name, "..") && strcmp(namelist[n]->d_name, "."))
  118. {
  119. // Construct full absolute file path
  120. std::string devicedir = sysDir;
  121. devicedir += namelist[n]->d_name;
  122. // Register the device
  123. register_comport(comList, comList8250, devicedir);
  124. }
  125. free(namelist[n]);
  126. }
  127. free(namelist);
  128. }
  129. // Only non-serial8250 has been added to comList without any further testing
  130. // serial8250-devices must be probe to check for validity
  131. probe_serial8250_comports(comList, comList8250);
  132. // 2.Scan through /dev/pts/- it contains all pseudo terminal(such as telnet, ssh etc.) in the system
  133. n = scandir(ptsDir, &namelist, NULL, NULL);
  134. if (n >= 0)
  135. {
  136. while (n--)
  137. {
  138. if (strcmp(namelist[n]->d_name, "..") && strcmp(namelist[n]->d_name, ".") &&
  139. strcmp(namelist[n]->d_name, "ptmx"))
  140. {
  141. // Construct full absolute file path
  142. std::string ptsName = ptsDir;
  143. ptsName += namelist[n]->d_name;
  144. comList.push_back(ptsName);
  145. }
  146. free(namelist[n]);
  147. }
  148. free(namelist);
  149. }
  150. // Return the lsit of detected comports
  151. return comList;
  152. }
  153. #endif
  154. vector<SerialPortInfo> getPortInfoList()
  155. {
  156. vector<SerialPortInfo> portInfoList;
  157. #ifdef I_OS_LINUX
  158. // TODO: need to optimize
  159. SerialPortInfo m_serialPort;
  160. vector<std::string> portList = getPortInfoListLinux();
  161. int count = portList.size();
  162. for (int i = 0; i < count; i++)
  163. {
  164. m_serialPort.portName = portList[i];
  165. portInfoList.push_back(m_serialPort);
  166. }
  167. #endif
  168. return portInfoList;
  169. }
  170. /**
  171. * @brief the CSerialPortInfo unix class unix串口信息辅助类基类
  172. *
  173. */
  174. class CSerialPortInfoUnixBase : public CSerialPortInfoBase
  175. {
  176. public:
  177. CSerialPortInfoUnixBase(){}
  178. ~CSerialPortInfoUnixBase(){}
  179. /**
  180. * @brief availablePortInfos 获取串口信息列表
  181. * @return return available port infolist 返回可用串口名称列表
  182. */
  183. static std::vector<SerialPortInfo> availablePortInfos(){
  184. return getPortInfoList();
  185. }
  186. };
  187. #endif //__CSERIALPORTINFOUNIXBASE_H__