serial.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. #include "swapi.h"
  2. #include "swmem.h"
  3. #include "swthrd.h"
  4. #include "swtcp.h"
  5. #include "swstring.h"
  6. #include "serial.h"
  7. struct serial_t
  8. {
  9. /* fd */
  10. int fd;
  11. /* 名称 */
  12. char name[128];
  13. /* 波特率 */
  14. int baudrate;
  15. /* 校检位: "odd"-奇校检; "even"-偶校检; "no"-无校检 */
  16. char parityCheck[5];
  17. /* 原有配置 */
  18. struct termios oldtio;
  19. bool bGetOldtioOK;
  20. /* 数据接收线程句柄 */
  21. void *hRecvThrd;
  22. /* 数据接收缓存 */
  23. unsigned char recvBuf[65535];
  24. /* 已接收的字节数 */
  25. int nRecvBytes;
  26. /* 处理已接收的数据(用户回调) */
  27. PSerialRecvHandler pRecvHandler;
  28. /* 无数据空闲时执行(用户回调) */
  29. PSerialIdleHandler pIdleHandler;
  30. /* 日志打印前缀 */
  31. char log_prefix[MAX_LINE_CHARS];
  32. /* 日志打印缓存 */
  33. char *pLogRecvBuf; // 堆内存
  34. };
  35. /* 数据接收处理(线程回调) */
  36. static int serial_data_recv_proc(unsigned long wParam, unsigned long lParam);
  37. /* 打开串口(8个数据位1个停止位), NULL失败, NOT NULL成功 */
  38. void *serial_open(const char *serialName, int baudrate, const char *parityCheck /* "odd"-奇校检; "even"-偶校检; NULL或其它无效值-无校检 */,
  39. PSerialRecvHandler pRecvHandler, PSerialIdleHandler pIdleHandler, void *pUserData)
  40. {
  41. struct serial_t *pSerial;
  42. struct termios newtio;
  43. int nSpeed;
  44. /* 1, 创建串口对象 */
  45. if(!serialName) return NULL;
  46. pSerial = (struct serial_t *)sw_heap_malloc(sizeof(struct serial_t));
  47. if(!pSerial) return NULL;
  48. else
  49. {
  50. memset(pSerial, 0, sizeof(struct serial_t));
  51. strncpy(pSerial->name, serialName, sizeof(pSerial->name)-1);
  52. }
  53. /* 2, 打开串口 */
  54. pSerial->fd = open(pSerial->name, O_RDWR | O_NOCTTY | O_NDELAY | O_CLOEXEC);
  55. if(pSerial->fd == -1) goto ErrorP;
  56. if(flock(pSerial->fd, LOCK_EX | LOCK_NB) == -1) goto ErrorP;
  57. /* 3, 保存当前串口配置 */
  58. if(tcgetattr(pSerial->fd, &pSerial->oldtio) == -1) goto ErrorP;
  59. else pSerial->bGetOldtioOK = true;
  60. /* 4, 设置阻塞 */
  61. if(fcntl(pSerial->fd, F_SETFL, 0) == -1) goto ErrorP;
  62. /* 5, 设置参数(8 databits, no parity, 1 stopbit, 1 second read timeout) */
  63. pSerial->baudrate = baudrate;
  64. switch(pSerial->baudrate)
  65. {
  66. case 0 : nSpeed = B0; break;
  67. case 50 : nSpeed = B50; break;
  68. case 75 : nSpeed = B75; break;
  69. case 110 : nSpeed = B110; break;
  70. case 134 : nSpeed = B134; break;
  71. case 150 : nSpeed = B150; break;
  72. case 200 : nSpeed = B200; break;
  73. case 300 : nSpeed = B300; break;
  74. case 600 : nSpeed = B600; break;
  75. case 1200 : nSpeed = B1200; break;
  76. case 1800 : nSpeed = B1800; break;
  77. case 2400 : nSpeed = B2400; break;
  78. case 4800 : nSpeed = B4800; break;
  79. case 9600 : nSpeed = B9600; break;
  80. case 19200 : nSpeed = B19200; break;
  81. case 38400 : nSpeed = B38400; break;
  82. case 57600 : nSpeed = B57600; break;
  83. case 115200 : nSpeed = B115200; break;
  84. case 230400 : nSpeed = B230400; break;
  85. default : goto ErrorP;
  86. }
  87. memset(&newtio, 0, sizeof(newtio));
  88. newtio.c_cflag = nSpeed | CS8 | CLOCAL | CREAD; // 设置波特率、数据带宽、本地连接、接收使能
  89. newtio.c_cflag &= ~CSTOPB; // 一个停止位
  90. if(xstrcasecmp(parityCheck, "odd") == 0)
  91. { // 使能奇校检
  92. newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD;
  93. newtio.c_iflag |= INPCK; strcpy(pSerial->parityCheck, "odd");
  94. }
  95. else if(xstrcasecmp(parityCheck, "even") == 0)
  96. { // 使能偶校检
  97. newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD;
  98. newtio.c_iflag |= INPCK; strcpy(pSerial->parityCheck, "even");
  99. }
  100. else
  101. { // 无校检
  102. newtio.c_cflag &= ~PARENB;
  103. newtio.c_iflag = IGNPAR; strcpy(pSerial->parityCheck, "no");
  104. }
  105. newtio.c_oflag = 0;
  106. newtio.c_lflag = 0;
  107. newtio.c_cc[VMIN] = 0; // read block untill n bytes are received, 阻塞模式有效
  108. newtio.c_cc[VTIME] = 1; // read block untill a timer expires(单位: 百毫秒, 十分之一秒), 阻塞模式有效
  109. if(tcflush(pSerial->fd, TCIOFLUSH) == -1) goto ErrorP; // 清空串口输入、输出缓存
  110. if(tcsetattr(pSerial->fd, TCSANOW, &newtio) == -1) goto ErrorP; // 激活新配置
  111. /* 6, 生成日志打印前缀 */
  112. if(xstrcasecmp(pSerial->parityCheck, "odd") == 0) sprintf(pSerial->log_prefix, "[%s:%d(odd parity)]", pSerial->name, pSerial->baudrate);
  113. else if(xstrcasecmp(pSerial->parityCheck, "even") == 0) sprintf(pSerial->log_prefix, "[%s:%d(even parity)]", pSerial->name, pSerial->baudrate);
  114. else sprintf(pSerial->log_prefix, "[%s:%d(no parity)]", pSerial->name, pSerial->baudrate);
  115. /* 7, 申请日志打印缓存 */
  116. pSerial->pLogRecvBuf = (char *)sw_heap_malloc(sizeof(pSerial->log_prefix)+MAX_LINE_CHARS+sizeof(pSerial->recvBuf)*2);
  117. if(!pSerial->pLogRecvBuf) goto ErrorP;
  118. /* 8, 打开串口数据接收线程 */
  119. pSerial->pRecvHandler = pRecvHandler; pSerial->pIdleHandler = pIdleHandler; // 用户回调
  120. pSerial->hRecvThrd = sw_thrd_create(pSerial->name, THREAD_DEFAULT_PRIORITY, 4*1024*1024, serial_data_recv_proc, (unsigned long)pSerial, (unsigned long)pUserData);
  121. if(!pSerial->hRecvThrd) goto ErrorP;
  122. else sw_thrd_resume(pSerial->hRecvThrd); // 激活数据接收线程
  123. return (void *)pSerial;
  124. /* 9, 错误 */
  125. ErrorP:
  126. serial_close(pSerial, 0);
  127. return NULL;
  128. }
  129. /* 关闭串口 */
  130. void serial_close(void *hSerial, int timeout)
  131. {
  132. struct serial_t *pSerial = (struct serial_t *)hSerial;
  133. if(pSerial && pSerial->hRecvThrd) sw_thrd_destroy(pSerial->hRecvThrd, timeout); // 销毁数据接收线程
  134. if(pSerial->pLogRecvBuf) sw_heap_free((void *)pSerial->pLogRecvBuf); // 释放日志打印缓存
  135. if(pSerial && pSerial->fd != -1)
  136. {
  137. if(pSerial->bGetOldtioOK) tcsetattr(pSerial->fd, TCSANOW, &pSerial->oldtio); // 恢复原有的串口配置
  138. close(pSerial->fd); // 关闭串口
  139. }
  140. if(pSerial) sw_heap_free((void *)pSerial); // 释放内存, 销毁串口对象
  141. }
  142. /* 获取日志打印前缀 */
  143. char *serial_get_log_prefix(const void *hSerial)
  144. {
  145. struct serial_t *pSerial = (struct serial_t *)hSerial;
  146. if(pSerial) return pSerial->log_prefix;
  147. else return NULL;
  148. }
  149. /* 发送数据, -1失败, >=0发送的字节数 */
  150. int serial_send_data(const void *hSerial, const unsigned char *data, int len)
  151. {
  152. struct serial_t *pSerial = (struct serial_t *)hSerial;
  153. if(pSerial && pSerial->fd != -1)
  154. {
  155. int ret = write(pSerial->fd, data, len);
  156. if(ret < 0) sw_log_error("write error(ret=%d, errno=%d, %s), \"%s\" serial port send failed!!",
  157. ret, errno, strerror(errno), pSerial->name);
  158. return ret;
  159. }
  160. else return -1;
  161. }
  162. /* 取得接收缓存区, NULL失败, NOT NULL成功 */
  163. const unsigned char *serial_get_recv_buffer(const void *hSerial)
  164. {
  165. struct serial_t *pSerial = (struct serial_t *)hSerial;
  166. if(pSerial) return pSerial->recvBuf;
  167. else return NULL;
  168. }
  169. /* 取得接收缓存区中当前有效数据的字节数, -1失败, 返回值>=0 */
  170. int serial_get_recv_buffer_bytes(const void *hSerial)
  171. {
  172. struct serial_t *pSerial = (struct serial_t *)hSerial;
  173. if(pSerial) return pSerial->nRecvBytes;
  174. else return -1;
  175. }
  176. /* 清空接收缓存区 */
  177. void serial_clear_recv_buffer(const void *hSerial)
  178. {
  179. struct serial_t *pSerial = (struct serial_t *)hSerial;
  180. if(pSerial)
  181. {
  182. memset(pSerial->recvBuf, 0, sizeof(pSerial->recvBuf));
  183. pSerial->nRecvBytes = 0;
  184. }
  185. }
  186. /* 打印接收缓存区 */
  187. void serial_printf_recv_buffer(const void *hSerial, int logLevel)
  188. {
  189. struct serial_t *pSerial = (struct serial_t *)hSerial;
  190. if(pSerial)
  191. {
  192. pSerial->pLogRecvBuf[0] = '\0'; // 复位日志缓存
  193. sprintf(pSerial->pLogRecvBuf, "%s the received buffer has %d bytes (hex)",
  194. pSerial->log_prefix, pSerial->nRecvBytes);
  195. if(pSerial->nRecvBytes > 0) { strcat(pSerial->pLogRecvBuf, ":\n");
  196. xstrfromhex(pSerial->recvBuf, pSerial->nRecvBytes, pSerial->pLogRecvBuf, NULL, NULL); }
  197. else strcat(pSerial->pLogRecvBuf, ".");
  198. sw_log_writeWithLevel(logLevel, __FILE__, -1, "%s", pSerial->pLogRecvBuf);
  199. }
  200. }
  201. /* 判断接收线程是否还在 */
  202. bool serial_recvThrd_isAlive(const void *hSerial)
  203. {
  204. struct serial_t *pSerial = (struct serial_t *)hSerial;
  205. return pSerial ? sw_thrd_isAlive(pSerial->hRecvThrd) : false;
  206. }
  207. /* 暂停接收线程接收数据 */
  208. void serial_recvThrd_pause(const void *hSerial)
  209. {
  210. struct serial_t *pSerial = (struct serial_t *)hSerial;
  211. if(pSerial) sw_thrd_pause(pSerial->hRecvThrd);
  212. }
  213. /* 继续接收线程接收数据 */
  214. void serial_recvThrd_resume(const void *hSerial)
  215. {
  216. struct serial_t *pSerial = (struct serial_t *)hSerial;
  217. if(pSerial) sw_thrd_resume(pSerial->hRecvThrd);
  218. }
  219. #ifdef _DEBUG
  220. /* 向接收缓存中写入数据(一般用于仿真串口输入, 模拟测试时使用) */
  221. void serial_write_recv_buffer(const void *hSerial, const unsigned char *hex, int hexCnt)
  222. {
  223. struct serial_t *pSerial = (struct serial_t *)hSerial;
  224. if(pSerial && hex && hexCnt > 0 && hexCnt < sizeof(pSerial->recvBuf))
  225. {
  226. memcpy(pSerial->recvBuf+pSerial->nRecvBytes, hex, hexCnt);
  227. pSerial->nRecvBytes += hexCnt;
  228. }
  229. sw_thrd_delay(1000); // 延时1秒钟, 等待数据被回调处理, 否则会累积(模拟仿真和真实触发还是有区别)
  230. }
  231. #endif
  232. /* 检测串口状态, timeout单位为ms */
  233. #define serial_select sw_tcp_select
  234. /* 数据接收处理(线程回调), "返回值 < 0"时表示处理失败, 将不再调用该接收回调函数, "返回值 >= 0"时表示
  235. 处理成功, 延时一段"返回值"时间(ms)后继续调用该接收回调函数 */
  236. static int serial_data_recv_proc(unsigned long wParam, unsigned long lParam)
  237. {
  238. struct serial_t *pSerial = (struct serial_t *)wParam;
  239. fd_set rSet;
  240. int nRecvBufSize = sizeof(pSerial->recvBuf), nInterval, nRet;
  241. RecvP:
  242. if(!sw_thrd_isAlive(pSerial->hRecvThrd)) return -1;
  243. nRet = serial_select(pSerial->fd, &rSet, NULL, NULL, 0);
  244. if(nRet == 0)
  245. { // 串口无数据
  246. NoneP:
  247. if(pSerial->pIdleHandler) nInterval = pSerial->pIdleHandler(wParam, lParam); // 触发无数据时的用户回调
  248. else nInterval = 1;
  249. goto EndP;
  250. }
  251. else if(nRet > 0 && FD_ISSET(pSerial->fd, &rSet))
  252. { // 串口有数据
  253. if(pSerial->nRecvBytes >= nRecvBufSize)
  254. { // 判断接收缓存是否溢出
  255. sw_log_warn("\"%s\" serial port receiving buffer overflow, the earliest one byte(%02x) will discard!",
  256. pSerial->name, pSerial->recvBuf[0]);
  257. memmove(pSerial->recvBuf, pSerial->recvBuf+1, nRecvBufSize-1); // 丢弃最早的一个字节
  258. pSerial->nRecvBytes = nRecvBufSize-1; // 新的已接收字节数
  259. }
  260. nRet = read(pSerial->fd, pSerial->recvBuf+pSerial->nRecvBytes, 1); // 读一个字节
  261. if(nRet == 1) pSerial->nRecvBytes += 1; // 已接收字节数累加1
  262. else if(nRet == 0 && errno == ETIMEDOUT) goto NoneP; // 读数据超时
  263. else
  264. { // 读一个字节错误
  265. sw_log_error("read one byte error(ret=%d, errno=%d), \"%s\" serial port receiving thread abort!!",
  266. nRet, errno, pSerial->name);
  267. return -1;
  268. }
  269. if(pSerial->pRecvHandler)
  270. { // 处理已接收的数据
  271. nInterval = pSerial->pRecvHandler(wParam, lParam); // 触发有数据时的用户回调
  272. if(nInterval < 0) goto EndP;
  273. }
  274. goto RecvP; // 继续接收后续数据
  275. }
  276. else if(nRet < 0 && errno != EINTR)
  277. { // 有错误发生
  278. sw_log_error("select error(%s), \"%s\" serial port receiving thread abort!!", strerror(errno), pSerial->name);
  279. return -1;
  280. }
  281. else nInterval = 1; // 不满足上述组合判断条件时
  282. EndP:
  283. return nInterval;
  284. }