SerialSCF.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. #include "SerialSCF.h"
  2. #include <cstring>
  3. #include <fcntl.h>
  4. #include <unistd.h>
  5. #include <sys/ioctl.h>
  6. #include <sys/select.h>
  7. #include <errno.h>
  8. #include <algorithm>
  9. SerialSCF::SerialSCF()
  10. : hCom(-1),
  11. m_BaudRate(115200),
  12. m_ByteSize(8),
  13. m_Parity(0),
  14. m_StopBits(1),
  15. m_ReadTimeout(1000),
  16. m_WriteTimeout(1000) {
  17. memset(&m_OriginalTermios, 0, sizeof(termios));
  18. memset(&m_CurrentTermios, 0, sizeof(termios));
  19. }
  20. SerialSCF::~SerialSCF() {
  21. Disconnect();
  22. }
  23. int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize,
  24. uint32_t Parity, uint32_t StopBits) {
  25. // 打开串口设备 (非阻塞模式)
  26. hCom = open(pCom, O_RDWR | O_NOCTTY | O_NONBLOCK);
  27. if (hCom < 0) {
  28. // 记录错误日志
  29. return SCF_OPEN_FAILED;
  30. }
  31. // 保存原始串口设置
  32. if (tcgetattr(hCom, &m_OriginalTermios) != 0) {
  33. close(hCom);
  34. hCom = -1;
  35. return SCF_OPEN_FAILED;
  36. }
  37. // 配置新的串口设置
  38. memset(&m_CurrentTermios, 0, sizeof(termios));
  39. m_CurrentTermios.c_cflag |= CLOCAL | CREAD; // 本地连接,启用接收
  40. // 设置波特率
  41. speed_t speed;
  42. switch (BaudRate) {
  43. case 50: speed = B50; break;
  44. case 75: speed = B75; break;
  45. case 110: speed = B110; break;
  46. case 134: speed = B134; break;
  47. case 150: speed = B150; break;
  48. case 200: speed = B200; break;
  49. case 300: speed = B300; break;
  50. case 600: speed = B600; break;
  51. case 1200: speed = B1200; break;
  52. case 1800: speed = B1800; break;
  53. case 2400: speed = B2400; break;
  54. case 4800: speed = B4800; break;
  55. case 9600: speed = B9600; break;
  56. case 19200: speed = B19200; break;
  57. case 38400: speed = B38400; break;
  58. case 57600: speed = B57600; break;
  59. case 115200: speed = B115200; break;
  60. case 230400: speed = B230400; break;
  61. case 460800: speed = B460800; break;
  62. case 500000: speed = B500000; break;
  63. case 576000: speed = B576000; break;
  64. case 921600: speed = B921600; break;
  65. case 1000000: speed = B1000000; break;
  66. default:
  67. close(hCom);
  68. hCom = -1;
  69. return SCF_PARAMETER_ERR;
  70. }
  71. cfsetispeed(&m_CurrentTermios, speed);
  72. cfsetospeed(&m_CurrentTermios, speed);
  73. // 设置数据位
  74. m_CurrentTermios.c_cflag &= ~CSIZE;
  75. switch (ByteSize) {
  76. case 5: m_CurrentTermios.c_cflag |= CS5; break;
  77. case 6: m_CurrentTermios.c_cflag |= CS6; break;
  78. case 7: m_CurrentTermios.c_cflag |= CS7; break;
  79. case 8: m_CurrentTermios.c_cflag |= CS8; break;
  80. default:
  81. close(hCom);
  82. hCom = -1;
  83. return SCF_PARAMETER_ERR;
  84. }
  85. // 设置校验位
  86. switch (Parity) {
  87. case 0: // None
  88. m_CurrentTermios.c_cflag &= ~PARENB;
  89. break;
  90. case 1: // Odd
  91. m_CurrentTermios.c_cflag |= PARENB;
  92. m_CurrentTermios.c_cflag |= PARODD;
  93. break;
  94. case 2: // Even
  95. m_CurrentTermios.c_cflag |= PARENB;
  96. m_CurrentTermios.c_cflag &= ~PARODD;
  97. break;
  98. default:
  99. close(hCom);
  100. hCom = -1;
  101. return SCF_PARAMETER_ERR;
  102. }
  103. // 设置停止位
  104. switch (StopBits) {
  105. case 1:
  106. m_CurrentTermios.c_cflag &= ~CSTOPB;
  107. break;
  108. case 2:
  109. m_CurrentTermios.c_cflag |= CSTOPB;
  110. break;
  111. default:
  112. close(hCom);
  113. hCom = -1;
  114. return SCF_PARAMETER_ERR;
  115. }
  116. // 设置原始模式 (禁用规范模式)
  117. m_CurrentTermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  118. m_CurrentTermios.c_oflag &= ~OPOST; // 原始输出
  119. // 设置超时和最小读取字节数
  120. m_CurrentTermios.c_cc[VMIN] = 0; // 非阻塞模式
  121. m_CurrentTermios.c_cc[VTIME] = m_ReadTimeout / 100; // 超时时间 (十分之一秒)
  122. // 刷新缓冲区并应用新设置
  123. tcflush(hCom, TCIOFLUSH);
  124. if (tcsetattr(hCom, TCSANOW, &m_CurrentTermios) != 0) {
  125. close(hCom);
  126. hCom = -1;
  127. return SCF_OPEN_FAILED;
  128. }
  129. // 清除所有缓冲区
  130. tcflush(hCom, TCIOFLUSH);
  131. return SCF_SUCCEED;
  132. }
  133. int SerialSCF::Connect(ResDataObject& Connectprameters, PacketParser callback,
  134. SCF_TRANSFERTYPE TransferType, uint32_t CommunicateTimeout) {
  135. int ret = SCF_FAILED;
  136. try {
  137. ResDataObject params = Connectprameters;
  138. params.MakeKeyLower();
  139. std::string ConnectionType = (const char*)Connectprameters["type"];
  140. std::string ThisType = GetConnectionType();
  141. // 转换为小写比较
  142. std::transform(ConnectionType.begin(), ConnectionType.end(), ConnectionType.begin(), ::tolower);
  143. std::transform(ThisType.begin(), ThisType.end(), ThisType.begin(), ::tolower);
  144. if (ConnectionType != ThisType) {
  145. return SCF_PARAMETER_ERR;
  146. }
  147. m_PortName = (const char*)Connectprameters["port"];
  148. m_BaudRate = (uint32_t)Connectprameters["baudrate"];
  149. m_ByteSize = (uint32_t)Connectprameters["bytesize"];
  150. m_Parity = (uint32_t)Connectprameters["parity"];
  151. m_StopBits = (uint32_t)Connectprameters["stopbits"];
  152. ret = ConnectCOM(m_PortName.c_str(), m_BaudRate, m_ByteSize, m_Parity, m_StopBits);
  153. if (ret == SCF_SUCCEED) {
  154. // 初始化日志
  155. std::string NewFileName = "com/s_" + m_PortName;
  156. InitSCF(NewFileName.c_str());
  157. // 调用基类连接方法
  158. ret = SCF::Connect(Connectprameters, callback, TransferType, CommunicateTimeout);
  159. }
  160. }
  161. catch (...) {
  162. ret = SCF_UNKNOWN;
  163. }
  164. return ret;
  165. }
  166. void SerialSCF::Disconnect() {
  167. SCF::Disconnect();
  168. if (hCom >= 0) {
  169. // 恢复原始串口设置
  170. tcsetattr(hCom, TCSANOW, &m_OriginalTermios);
  171. // 关闭串口
  172. close(hCom);
  173. hCom = -1;
  174. }
  175. }
  176. bool SerialSCF::isConnected() {
  177. return (hCom >= 0);
  178. }
  179. const char* SerialSCF::GetConnectionType() {
  180. static const char* nType = "COM";
  181. return nType;
  182. }
  183. int SerialSCF::SendPacket(SCFPacket* pPacket, uint32_t timeout) {
  184. return SendPacket((char*)(*pPacket), pPacket->GetPacketLen(), timeout);
  185. }
  186. int SerialSCF::SendPacket(const char* pPacket, uint32_t length, uint32_t timeout) {
  187. if (!isConnected()) {
  188. return SCF_DISCONNETED;
  189. }
  190. // 设置写超时
  191. struct timeval tv;
  192. tv.tv_sec = timeout / 1000;
  193. tv.tv_usec = (timeout % 1000) * 1000;
  194. fd_set write_fds;
  195. FD_ZERO(&write_fds);
  196. FD_SET(hCom, &write_fds);
  197. uint32_t bytesWritten = 0;
  198. while (bytesWritten < length) {
  199. // 等待串口可写
  200. int selectRet = select(hCom + 1, NULL, &write_fds, NULL, &tv);
  201. if (selectRet <= 0) {
  202. // 超时或错误
  203. return (selectRet == 0) ? SCF_TIMEOUT : SCF_WRITE_FAILED;
  204. }
  205. // 写入数据
  206. ssize_t ret = write(hCom, pPacket + bytesWritten, length - bytesWritten);
  207. if (ret < 0) {
  208. if (errno == EAGAIN || errno == EWOULDBLOCK) {
  209. // 短暂等待后重试
  210. usleep(10000); // 10ms
  211. continue;
  212. }
  213. return SCF_WRITE_FAILED;
  214. }
  215. bytesWritten += ret;
  216. }
  217. return bytesWritten;
  218. }
  219. int SerialSCF::ReadData(char* pPacket, uint32_t length, uint32_t timeout) {
  220. if (!isConnected()) {
  221. return SCF_DISCONNETED;
  222. }
  223. // 设置读超时
  224. struct timeval tv;
  225. tv.tv_sec = timeout / 1000;
  226. tv.tv_usec = (timeout % 1000) * 1000;
  227. fd_set read_fds;
  228. FD_ZERO(&read_fds);
  229. FD_SET(hCom, &read_fds);
  230. // 等待数据到达
  231. int selectRet = select(hCom + 1, &read_fds, NULL, NULL, &tv);
  232. if (selectRet <= 0) {
  233. // 超时或错误
  234. return (selectRet == 0) ? SCF_TIMEOUT : SCF_READ_FAILED;
  235. }
  236. // 读取可用数据
  237. int bytesAvailable = 0;
  238. if (ioctl(hCom, FIONREAD, &bytesAvailable) < 0) {
  239. return SCF_READ_FAILED;
  240. }
  241. // 确保不超过缓冲区大小
  242. uint32_t bytesToRead = std::min(static_cast<uint32_t>(bytesAvailable), length);
  243. // 读取数据
  244. ssize_t ret = read(hCom, pPacket, bytesToRead);
  245. if (ret < 0) {
  246. return SCF_READ_FAILED;
  247. }
  248. return ret;
  249. }
  250. SERIALSCF_C_API SCF* GetSCF() {
  251. SerialSCF* p = new SerialSCF();
  252. return static_cast<SCF*>(p);
  253. }
  254. SERIALSCF_C_API void ReleaseSCF(SCF* p) {
  255. delete static_cast<SerialSCF*>(p);
  256. }