|
|
@@ -1,324 +1,338 @@
|
|
|
-#include "swapi.h"
|
|
|
-#include "swmem.h"
|
|
|
-#include "swthrd.h"
|
|
|
-#include "swtcp.h"
|
|
|
-#include "swstring.h"
|
|
|
-#include "serial.h"
|
|
|
-
|
|
|
-struct serial_t
|
|
|
-{
|
|
|
- /* fd */
|
|
|
- int fd;
|
|
|
- /* 名称 */
|
|
|
- char name[128];
|
|
|
- /* 波特率 */
|
|
|
- int baudrate;
|
|
|
- /* 校检位: "odd"-奇校检; "even"-偶校检; "no"-无校检 */
|
|
|
- char parityCheck[5];
|
|
|
-
|
|
|
- /* 原有配置 */
|
|
|
- struct termios oldtio;
|
|
|
- bool bGetOldtioOK;
|
|
|
-
|
|
|
- /* 数据接收线程句柄 */
|
|
|
- void *hRecvThrd;
|
|
|
- /* 数据接收缓存 */
|
|
|
- unsigned char recvBuf[65535];
|
|
|
- /* 已接收的字节数 */
|
|
|
- int nRecvBytes;
|
|
|
- /* 处理已接收的数据(用户回调) */
|
|
|
- PSerialRecvHandler pRecvHandler;
|
|
|
- /* 无数据空闲时执行(用户回调) */
|
|
|
- PSerialIdleHandler pIdleHandler;
|
|
|
-
|
|
|
- /* 日志打印前缀 */
|
|
|
- char log_prefix[MAX_LINE_CHARS];
|
|
|
- /* 日志打印缓存 */
|
|
|
- char *pLogRecvBuf; // 堆内存
|
|
|
-};
|
|
|
-
|
|
|
-/* 数据接收处理(线程回调) */
|
|
|
-static int serial_data_recv_proc(unsigned long wParam, unsigned long lParam);
|
|
|
-
|
|
|
-/* 打开串口(8个数据位1个停止位), NULL失败, NOT NULL成功 */
|
|
|
-void *serial_open(const char *serialName, int baudrate, const char *parityCheck /* "odd"-奇校检; "even"-偶校检; NULL或其它无效值-无校检 */,
|
|
|
- PSerialRecvHandler pRecvHandler, PSerialIdleHandler pIdleHandler, void *pUserData)
|
|
|
-{
|
|
|
- struct serial_t *pSerial;
|
|
|
- struct termios newtio;
|
|
|
- int nSpeed;
|
|
|
-
|
|
|
- /* 1, 创建串口对象 */
|
|
|
- if(!serialName) return NULL;
|
|
|
- pSerial = (struct serial_t *)sw_heap_malloc(sizeof(struct serial_t));
|
|
|
- if(!pSerial) return NULL;
|
|
|
- else
|
|
|
- {
|
|
|
- memset(pSerial, 0, sizeof(struct serial_t));
|
|
|
- strncpy(pSerial->name, serialName, sizeof(pSerial->name)-1);
|
|
|
- }
|
|
|
-
|
|
|
- /* 2, 打开串口 */
|
|
|
- pSerial->fd = open(pSerial->name, O_RDWR | O_NOCTTY | O_NDELAY | O_CLOEXEC);
|
|
|
- if(pSerial->fd == -1) goto ErrorP;
|
|
|
-
|
|
|
- if(flock(pSerial->fd, LOCK_EX | LOCK_NB) == -1) goto ErrorP;
|
|
|
-
|
|
|
- /* 3, 保存当前串口配置 */
|
|
|
- if(tcgetattr(pSerial->fd, &pSerial->oldtio) == -1) goto ErrorP;
|
|
|
- else pSerial->bGetOldtioOK = true;
|
|
|
-
|
|
|
- /* 4, 设置阻塞 */
|
|
|
- if(fcntl(pSerial->fd, F_SETFL, 0) == -1) goto ErrorP;
|
|
|
-
|
|
|
- /* 5, 设置参数(8 databits, no parity, 1 stopbit, 1 second read timeout) */
|
|
|
- pSerial->baudrate = baudrate;
|
|
|
- switch(pSerial->baudrate)
|
|
|
- {
|
|
|
- case 0 : nSpeed = B0; break;
|
|
|
- case 50 : nSpeed = B50; break;
|
|
|
- case 75 : nSpeed = B75; break;
|
|
|
- case 110 : nSpeed = B110; break;
|
|
|
- case 134 : nSpeed = B134; break;
|
|
|
- case 150 : nSpeed = B150; break;
|
|
|
- case 200 : nSpeed = B200; break;
|
|
|
- case 300 : nSpeed = B300; break;
|
|
|
- case 600 : nSpeed = B600; break;
|
|
|
- case 1200 : nSpeed = B1200; break;
|
|
|
- case 1800 : nSpeed = B1800; break;
|
|
|
- case 2400 : nSpeed = B2400; break;
|
|
|
- case 4800 : nSpeed = B4800; break;
|
|
|
- case 9600 : nSpeed = B9600; break;
|
|
|
- case 19200 : nSpeed = B19200; break;
|
|
|
- case 38400 : nSpeed = B38400; break;
|
|
|
- case 57600 : nSpeed = B57600; break;
|
|
|
- case 115200 : nSpeed = B115200; break;
|
|
|
- case 230400 : nSpeed = B230400; break;
|
|
|
- default : goto ErrorP;
|
|
|
- }
|
|
|
- memset(&newtio, 0, sizeof(newtio));
|
|
|
- newtio.c_cflag = nSpeed | CS8 | CLOCAL | CREAD; // 设置波特率、数据带宽、本地连接、接收使能
|
|
|
- newtio.c_cflag &= ~CSTOPB; // 一个停止位
|
|
|
- if(xstrcasecmp(parityCheck, "odd") == 0)
|
|
|
- { // 使能奇校检
|
|
|
- newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD;
|
|
|
- newtio.c_iflag |= INPCK; strcpy(pSerial->parityCheck, "odd");
|
|
|
- }
|
|
|
- else if(xstrcasecmp(parityCheck, "even") == 0)
|
|
|
- { // 使能偶校检
|
|
|
- newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD;
|
|
|
- newtio.c_iflag |= INPCK; strcpy(pSerial->parityCheck, "even");
|
|
|
- }
|
|
|
- else
|
|
|
- { // 无校检
|
|
|
- newtio.c_cflag &= ~PARENB;
|
|
|
- newtio.c_iflag = IGNPAR; strcpy(pSerial->parityCheck, "no");
|
|
|
- }
|
|
|
- newtio.c_oflag = 0;
|
|
|
- newtio.c_lflag = 0;
|
|
|
- newtio.c_cc[VMIN] = 0; // read block untill n bytes are received, 阻塞模式有效
|
|
|
- newtio.c_cc[VTIME] = 1; // read block untill a timer expires(单位: 百毫秒, 十分之一秒), 阻塞模式有效
|
|
|
- if(tcflush(pSerial->fd, TCIOFLUSH) == -1) goto ErrorP; // 清空串口输入、输出缓存
|
|
|
- if(tcsetattr(pSerial->fd, TCSANOW, &newtio) == -1) goto ErrorP; // 激活新配置
|
|
|
-
|
|
|
- /* 6, 生成日志打印前缀 */
|
|
|
- if(xstrcasecmp(pSerial->parityCheck, "odd") == 0) sprintf(pSerial->log_prefix, "[%s:%d(odd parity)]", pSerial->name, pSerial->baudrate);
|
|
|
- else if(xstrcasecmp(pSerial->parityCheck, "even") == 0) sprintf(pSerial->log_prefix, "[%s:%d(even parity)]", pSerial->name, pSerial->baudrate);
|
|
|
- else sprintf(pSerial->log_prefix, "[%s:%d(no parity)]", pSerial->name, pSerial->baudrate);
|
|
|
-
|
|
|
- /* 7, 申请日志打印缓存 */
|
|
|
- pSerial->pLogRecvBuf = (char *)sw_heap_malloc(sizeof(pSerial->log_prefix)+MAX_LINE_CHARS+sizeof(pSerial->recvBuf)*2);
|
|
|
- if(!pSerial->pLogRecvBuf) goto ErrorP;
|
|
|
-
|
|
|
- /* 8, 打开串口数据接收线程 */
|
|
|
- pSerial->pRecvHandler = pRecvHandler; pSerial->pIdleHandler = pIdleHandler; // 用户回调
|
|
|
- pSerial->hRecvThrd = sw_thrd_create(pSerial->name, THREAD_DEFAULT_PRIORITY, 4*1024*1024, serial_data_recv_proc, (unsigned long)pSerial, (unsigned long)pUserData);
|
|
|
- if(!pSerial->hRecvThrd) goto ErrorP;
|
|
|
- else sw_thrd_resume(pSerial->hRecvThrd); // 激活数据接收线程
|
|
|
-
|
|
|
- return (void *)pSerial;
|
|
|
-
|
|
|
- /* 9, 错误 */
|
|
|
-ErrorP:
|
|
|
- serial_close(pSerial, 0);
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/* 关闭串口 */
|
|
|
-void serial_close(void *hSerial, int timeout)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
-
|
|
|
- if(pSerial && pSerial->hRecvThrd) sw_thrd_destroy(pSerial->hRecvThrd, timeout); // 销毁数据接收线程
|
|
|
-
|
|
|
- if(pSerial->pLogRecvBuf) sw_heap_free((void *)pSerial->pLogRecvBuf); // 释放日志打印缓存
|
|
|
-
|
|
|
- if(pSerial && pSerial->fd != -1)
|
|
|
- {
|
|
|
- if(pSerial->bGetOldtioOK) tcsetattr(pSerial->fd, TCSANOW, &pSerial->oldtio); // 恢复原有的串口配置
|
|
|
- close(pSerial->fd); // 关闭串口
|
|
|
- }
|
|
|
-
|
|
|
- if(pSerial) sw_heap_free((void *)pSerial); // 释放内存, 销毁串口对象
|
|
|
-}
|
|
|
-
|
|
|
-/* 获取日志打印前缀 */
|
|
|
-char *serial_get_log_prefix(const void *hSerial)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial) return pSerial->log_prefix;
|
|
|
- else return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/* 发送数据, -1失败, >=0发送的字节数 */
|
|
|
-int serial_send_data(const void *hSerial, const unsigned char *data, int len)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial && pSerial->fd != -1)
|
|
|
- {
|
|
|
- int ret = write(pSerial->fd, data, len);
|
|
|
- if(ret < 0) sw_log_error("write error(ret=%d, errno=%d, %s), \"%s\" serial port send failed!!",
|
|
|
- ret, errno, strerror(errno), pSerial->name);
|
|
|
- return ret;
|
|
|
- }
|
|
|
- else return -1;
|
|
|
-}
|
|
|
-
|
|
|
-/* 取得接收缓存区, NULL失败, NOT NULL成功 */
|
|
|
-const unsigned char *serial_get_recv_buffer(const void *hSerial)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial) return pSerial->recvBuf;
|
|
|
- else return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/* 取得接收缓存区中当前有效数据的字节数, -1失败, 返回值>=0 */
|
|
|
-int serial_get_recv_buffer_bytes(const void *hSerial)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial) return pSerial->nRecvBytes;
|
|
|
- else return -1;
|
|
|
-}
|
|
|
-
|
|
|
-/* 清空接收缓存区 */
|
|
|
-void serial_clear_recv_buffer(const void *hSerial)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial)
|
|
|
- {
|
|
|
- memset(pSerial->recvBuf, 0, sizeof(pSerial->recvBuf));
|
|
|
- pSerial->nRecvBytes = 0;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* 打印接收缓存区 */
|
|
|
-void serial_printf_recv_buffer(const void *hSerial, int logLevel)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial)
|
|
|
- {
|
|
|
- pSerial->pLogRecvBuf[0] = '\0'; // 复位日志缓存
|
|
|
- sprintf(pSerial->pLogRecvBuf, "%s the received buffer has %d bytes (hex)",
|
|
|
- pSerial->log_prefix, pSerial->nRecvBytes);
|
|
|
- if(pSerial->nRecvBytes > 0) { strcat(pSerial->pLogRecvBuf, ":\n");
|
|
|
- xstrfromhex(pSerial->recvBuf, pSerial->nRecvBytes, pSerial->pLogRecvBuf, NULL, NULL); }
|
|
|
- else strcat(pSerial->pLogRecvBuf, ".");
|
|
|
- sw_log_writeWithLevel(logLevel, __FILE__, -1, "%s", pSerial->pLogRecvBuf);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* 判断接收线程是否还在 */
|
|
|
-bool serial_recvThrd_isAlive(const void *hSerial)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- return pSerial ? sw_thrd_isAlive(pSerial->hRecvThrd) : false;
|
|
|
-}
|
|
|
-
|
|
|
-/* 暂停接收线程接收数据 */
|
|
|
-void serial_recvThrd_pause(const void *hSerial)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial) sw_thrd_pause(pSerial->hRecvThrd);
|
|
|
-}
|
|
|
-
|
|
|
-/* 继续接收线程接收数据 */
|
|
|
-void serial_recvThrd_resume(const void *hSerial)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial) sw_thrd_resume(pSerial->hRecvThrd);
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef _DEBUG
|
|
|
-/* 向接收缓存中写入数据(一般用于仿真串口输入, 模拟测试时使用) */
|
|
|
-void serial_write_recv_buffer(const void *hSerial, const unsigned char *hex, int hexCnt)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
- if(pSerial && hex && hexCnt > 0 && hexCnt < sizeof(pSerial->recvBuf))
|
|
|
- {
|
|
|
- memcpy(pSerial->recvBuf+pSerial->nRecvBytes, hex, hexCnt);
|
|
|
- pSerial->nRecvBytes += hexCnt;
|
|
|
- }
|
|
|
- sw_thrd_delay(1000); // 延时1秒钟, 等待数据被回调处理, 否则会累积(模拟仿真和真实触发还是有区别)
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-/* 检测串口状态, timeout单位为ms */
|
|
|
-#define serial_select sw_tcp_select
|
|
|
-
|
|
|
-/* 数据接收处理(线程回调), "返回值 < 0"时表示处理失败, 将不再调用该接收回调函数, "返回值 >= 0"时表示
|
|
|
- 处理成功, 延时一段"返回值"时间(ms)后继续调用该接收回调函数 */
|
|
|
-static int serial_data_recv_proc(unsigned long wParam, unsigned long lParam)
|
|
|
-{
|
|
|
- struct serial_t *pSerial = (struct serial_t *)wParam;
|
|
|
- fd_set rSet;
|
|
|
- int nRecvBufSize = sizeof(pSerial->recvBuf), nInterval, nRet;
|
|
|
-
|
|
|
-RecvP:
|
|
|
- if(!sw_thrd_isAlive(pSerial->hRecvThrd)) return -1;
|
|
|
-
|
|
|
- nRet = serial_select(pSerial->fd, &rSet, NULL, NULL, 0);
|
|
|
- if(nRet == 0)
|
|
|
- { // 串口无数据
|
|
|
-NoneP:
|
|
|
- if(pSerial->pIdleHandler) nInterval = pSerial->pIdleHandler(wParam, lParam); // 触发无数据时的用户回调
|
|
|
- else nInterval = 1;
|
|
|
- goto EndP;
|
|
|
- }
|
|
|
- else if(nRet > 0 && FD_ISSET(pSerial->fd, &rSet))
|
|
|
- { // 串口有数据
|
|
|
- if(pSerial->nRecvBytes >= nRecvBufSize)
|
|
|
- { // 判断接收缓存是否溢出
|
|
|
- sw_log_warn("\"%s\" serial port receiving buffer overflow, the earliest one byte(%02x) will discard!",
|
|
|
- pSerial->name, pSerial->recvBuf[0]);
|
|
|
- memmove(pSerial->recvBuf, pSerial->recvBuf+1, nRecvBufSize-1); // 丢弃最早的一个字节
|
|
|
- pSerial->nRecvBytes = nRecvBufSize-1; // 新的已接收字节数
|
|
|
- }
|
|
|
-
|
|
|
- nRet = read(pSerial->fd, pSerial->recvBuf+pSerial->nRecvBytes, 1); // 读一个字节
|
|
|
- if(nRet == 1) pSerial->nRecvBytes += 1; // 已接收字节数累加1
|
|
|
- else if(nRet == 0 && errno == ETIMEDOUT) goto NoneP; // 读数据超时
|
|
|
- else
|
|
|
- { // 读一个字节错误
|
|
|
- sw_log_error("read one byte error(ret=%d, errno=%d), \"%s\" serial port receiving thread abort!!",
|
|
|
- nRet, errno, pSerial->name);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- if(pSerial->pRecvHandler)
|
|
|
- { // 处理已接收的数据
|
|
|
- nInterval = pSerial->pRecvHandler(wParam, lParam); // 触发有数据时的用户回调
|
|
|
- if(nInterval < 0) goto EndP;
|
|
|
- }
|
|
|
-
|
|
|
- goto RecvP; // 继续接收后续数据
|
|
|
- }
|
|
|
- else if(nRet < 0 && errno != EINTR)
|
|
|
- { // 有错误发生
|
|
|
- sw_log_error("select error(%s), \"%s\" serial port receiving thread abort!!", strerror(errno), pSerial->name);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- else nInterval = 1; // 不满足上述组合判断条件时
|
|
|
-
|
|
|
-EndP:
|
|
|
- return nInterval;
|
|
|
-}
|
|
|
+#include "swapi.h"
|
|
|
+#include "swmem.h"
|
|
|
+#include "swthrd.h"
|
|
|
+#include "swtcp.h"
|
|
|
+#include "swstring.h"
|
|
|
+#include "serial.h"
|
|
|
+
|
|
|
+struct serial_t
|
|
|
+{
|
|
|
+ /* fd */
|
|
|
+ int fd;
|
|
|
+ /* 名称 */
|
|
|
+ char name[128];
|
|
|
+ /* 波特率 */
|
|
|
+ int baudrate;
|
|
|
+ /* 校检位: "odd"-奇校检; "even"-偶校检; "no"-无校检 */
|
|
|
+ char parityCheck[5];
|
|
|
+
|
|
|
+ /* 原有配置 */
|
|
|
+ struct termios oldtio;
|
|
|
+ bool bGetOldtioOK;
|
|
|
+
|
|
|
+ /* 数据接收线程句柄 */
|
|
|
+ void *hRecvThrd;
|
|
|
+ /* 数据接收缓存 */
|
|
|
+ unsigned char recvBuf[65535];
|
|
|
+ /* 已接收的字节数 */
|
|
|
+ int nRecvBytes;
|
|
|
+ /* 处理已接收的数据(用户回调) */
|
|
|
+ PSerialRecvHandler pRecvHandler;
|
|
|
+ /* 无数据空闲时执行(用户回调) */
|
|
|
+ PSerialIdleHandler pIdleHandler;
|
|
|
+
|
|
|
+ /* 日志打印前缀 */
|
|
|
+ char log_prefix[MAX_LINE_CHARS];
|
|
|
+ /* 日志打印缓存 */
|
|
|
+ char *pLogRecvBuf; // 堆内存
|
|
|
+};
|
|
|
+
|
|
|
+/* 数据接收处理(线程回调) */
|
|
|
+static int serial_data_recv_proc(unsigned long wParam, unsigned long lParam);
|
|
|
+
|
|
|
+/* 打开串口(8个数据位1个停止位), NULL失败, NOT NULL成功 */
|
|
|
+void *serial_open(const char *serialName, int baudrate, const char *parityCheck /* "odd"-奇校检; "even"-偶校检; NULL或其它无效值-无校检 */,
|
|
|
+ PSerialRecvHandler pRecvHandler, PSerialIdleHandler pIdleHandler, void *pUserData)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial;
|
|
|
+ struct termios newtio;
|
|
|
+ int nSpeed;
|
|
|
+
|
|
|
+ /* 1, 创建串口对象 */
|
|
|
+ if(!serialName) return NULL;
|
|
|
+ pSerial = (struct serial_t *)sw_heap_malloc(sizeof(struct serial_t));
|
|
|
+ if(!pSerial) return NULL;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ memset(pSerial, 0, sizeof(struct serial_t));
|
|
|
+ strncpy(pSerial->name, serialName, sizeof(pSerial->name)-1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 2, 打开串口 */
|
|
|
+ pSerial->fd = open(pSerial->name, O_RDWR | O_NOCTTY | O_NDELAY | O_CLOEXEC);
|
|
|
+ if(pSerial->fd == -1) goto ErrorP;
|
|
|
+
|
|
|
+ if(flock(pSerial->fd, LOCK_EX | LOCK_NB) == -1) goto ErrorP;
|
|
|
+
|
|
|
+ /* 3, 保存当前串口配置 */
|
|
|
+ if(tcgetattr(pSerial->fd, &pSerial->oldtio) == -1) goto ErrorP;
|
|
|
+ else pSerial->bGetOldtioOK = true;
|
|
|
+
|
|
|
+ /* 4, 设置阻塞 */
|
|
|
+ if(fcntl(pSerial->fd, F_SETFL, 0) == -1) goto ErrorP;
|
|
|
+
|
|
|
+ /* 5, 设置参数(8 databits, no parity, 1 stopbit, 1 second read timeout) */
|
|
|
+ pSerial->baudrate = baudrate;
|
|
|
+ switch(pSerial->baudrate)
|
|
|
+ {
|
|
|
+ case 0 : nSpeed = B0; break;
|
|
|
+ case 50 : nSpeed = B50; break;
|
|
|
+ case 75 : nSpeed = B75; break;
|
|
|
+ case 110 : nSpeed = B110; break;
|
|
|
+ case 134 : nSpeed = B134; break;
|
|
|
+ case 150 : nSpeed = B150; break;
|
|
|
+ case 200 : nSpeed = B200; break;
|
|
|
+ case 300 : nSpeed = B300; break;
|
|
|
+ case 600 : nSpeed = B600; break;
|
|
|
+ case 1200 : nSpeed = B1200; break;
|
|
|
+ case 1800 : nSpeed = B1800; break;
|
|
|
+ case 2400 : nSpeed = B2400; break;
|
|
|
+ case 4800 : nSpeed = B4800; break;
|
|
|
+ case 9600 : nSpeed = B9600; break;
|
|
|
+ case 19200 : nSpeed = B19200; break;
|
|
|
+ case 38400 : nSpeed = B38400; break;
|
|
|
+ case 57600 : nSpeed = B57600; break;
|
|
|
+ case 115200 : nSpeed = B115200; break;
|
|
|
+ case 230400 : nSpeed = B230400; break;
|
|
|
+ default : goto ErrorP;
|
|
|
+ }
|
|
|
+ memset(&newtio, 0, sizeof(newtio));
|
|
|
+ newtio.c_cflag = nSpeed | CS8 | CLOCAL | CREAD; // 设置波特率、数据带宽、本地连接、接收使能
|
|
|
+ newtio.c_cflag &= ~CSTOPB; // 一个停止位
|
|
|
+ if(xstrcasecmp(parityCheck, "odd") == 0)
|
|
|
+ { // 使能奇校检
|
|
|
+ newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD;
|
|
|
+ newtio.c_iflag |= INPCK; strcpy(pSerial->parityCheck, "odd");
|
|
|
+ }
|
|
|
+ else if(xstrcasecmp(parityCheck, "even") == 0)
|
|
|
+ { // 使能偶校检
|
|
|
+ newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD;
|
|
|
+ newtio.c_iflag |= INPCK; strcpy(pSerial->parityCheck, "even");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ { // 无校检
|
|
|
+ newtio.c_cflag &= ~PARENB;
|
|
|
+ newtio.c_iflag = IGNPAR; strcpy(pSerial->parityCheck, "no");
|
|
|
+ }
|
|
|
+ newtio.c_oflag = 0;
|
|
|
+ newtio.c_lflag = 0;
|
|
|
+ newtio.c_cc[VMIN] = 0; // read block untill n bytes are received, 阻塞模式有效
|
|
|
+ newtio.c_cc[VTIME] = 1; // read block untill a timer expires(单位: 百毫秒, 十分之一秒), 阻塞模式有效
|
|
|
+ if(tcflush(pSerial->fd, TCIOFLUSH) == -1) goto ErrorP; // 清空串口输入、输出缓存
|
|
|
+ if(tcsetattr(pSerial->fd, TCSANOW, &newtio) == -1) goto ErrorP; // 激活新配置
|
|
|
+
|
|
|
+ /* 6, 生成日志打印前缀 */
|
|
|
+ if(xstrcasecmp(pSerial->parityCheck, "odd") == 0) sprintf(pSerial->log_prefix, "[%s:%d(odd parity)]", pSerial->name, pSerial->baudrate);
|
|
|
+ else if(xstrcasecmp(pSerial->parityCheck, "even") == 0) sprintf(pSerial->log_prefix, "[%s:%d(even parity)]", pSerial->name, pSerial->baudrate);
|
|
|
+ else sprintf(pSerial->log_prefix, "[%s:%d(no parity)]", pSerial->name, pSerial->baudrate);
|
|
|
+
|
|
|
+ /* 7, 申请日志打印缓存 */
|
|
|
+ pSerial->pLogRecvBuf = (char *)sw_heap_malloc(sizeof(pSerial->log_prefix)+MAX_LINE_CHARS+sizeof(pSerial->recvBuf)*2);
|
|
|
+ if(!pSerial->pLogRecvBuf) goto ErrorP;
|
|
|
+
|
|
|
+ /* 8, 打开串口数据接收线程 */
|
|
|
+ pSerial->pRecvHandler = pRecvHandler; pSerial->pIdleHandler = pIdleHandler; // 用户回调
|
|
|
+ pSerial->hRecvThrd = sw_thrd_create(pSerial->name, THREAD_DEFAULT_PRIORITY, 4*1024*1024, serial_data_recv_proc, (unsigned long)pSerial, (unsigned long)pUserData);
|
|
|
+ if(!pSerial->hRecvThrd) goto ErrorP;
|
|
|
+ else sw_thrd_resume(pSerial->hRecvThrd); // 激活数据接收线程
|
|
|
+
|
|
|
+ return (void *)pSerial;
|
|
|
+
|
|
|
+ /* 9, 错误 */
|
|
|
+ErrorP:
|
|
|
+ serial_close(pSerial, 0);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* 关闭串口 */
|
|
|
+void serial_close(void *hSerial, int timeout)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+
|
|
|
+ if(pSerial && pSerial->hRecvThrd) sw_thrd_destroy(pSerial->hRecvThrd, timeout); // 销毁数据接收线程
|
|
|
+
|
|
|
+ if(pSerial->pLogRecvBuf) sw_heap_free((void *)pSerial->pLogRecvBuf); // 释放日志打印缓存
|
|
|
+
|
|
|
+ if(pSerial && pSerial->fd != -1)
|
|
|
+ {
|
|
|
+ if(pSerial->bGetOldtioOK) tcsetattr(pSerial->fd, TCSANOW, &pSerial->oldtio); // 恢复原有的串口配置
|
|
|
+ close(pSerial->fd); // 关闭串口
|
|
|
+ }
|
|
|
+
|
|
|
+ if(pSerial) sw_heap_free((void *)pSerial); // 释放内存, 销毁串口对象
|
|
|
+}
|
|
|
+
|
|
|
+/* 获取日志打印前缀 */
|
|
|
+char *serial_get_log_prefix(const void *hSerial)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial) return pSerial->log_prefix;
|
|
|
+ else return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* 发送数据, -1失败, >=0发送的字节数 */
|
|
|
+int serial_send_data(const void *hSerial, const unsigned char *data, int len)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial && pSerial->fd != -1)
|
|
|
+ {
|
|
|
+ int ret = write(pSerial->fd, data, len);
|
|
|
+ if(ret < 0) sw_log_error("write error(ret=%d, errno=%d, %s), \"%s\" serial port send failed!!",
|
|
|
+ ret, errno, strerror(errno), pSerial->name);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ else return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/* 取得接收缓存区, NULL失败, NOT NULL成功 */
|
|
|
+const unsigned char *serial_get_recv_buffer(const void *hSerial)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial) return pSerial->recvBuf;
|
|
|
+ else return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* 取得接收缓存区中当前有效数据的字节数, -1失败, 返回值>=0 */
|
|
|
+int serial_get_recv_buffer_bytes(const void *hSerial)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial) return pSerial->nRecvBytes;
|
|
|
+ else return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/* 清空接收缓存区 */
|
|
|
+void serial_clear_recv_buffer(const void *hSerial)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial)
|
|
|
+ {
|
|
|
+ memset(pSerial->recvBuf, 0, sizeof(pSerial->recvBuf));
|
|
|
+ pSerial->nRecvBytes = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 删除接收缓存区 */
|
|
|
+void serial_clear_recv_buffer_head(const void *hSerial, int nBytes)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(!pSerial || nBytes <= 0) return;
|
|
|
+
|
|
|
+ if(nBytes < pSerial->nRecvBytes)
|
|
|
+ {
|
|
|
+ memmove(pSerial->recvBuf, pSerial->recvBuf + nBytes, pSerial->nRecvBytes - nBytes);
|
|
|
+ pSerial->nRecvBytes -= nBytes;
|
|
|
+ }
|
|
|
+ else serial_clear_recv_buffer(pSerial);
|
|
|
+}
|
|
|
+
|
|
|
+/* 打印接收缓存区 */
|
|
|
+void serial_printf_recv_buffer(const void *hSerial, int logLevel)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial)
|
|
|
+ {
|
|
|
+ pSerial->pLogRecvBuf[0] = '\0'; // 复位日志缓存
|
|
|
+ sprintf(pSerial->pLogRecvBuf, "%s the received buffer has %d bytes (hex)",
|
|
|
+ pSerial->log_prefix, pSerial->nRecvBytes);
|
|
|
+ if(pSerial->nRecvBytes > 0) { strcat(pSerial->pLogRecvBuf, ":\n");
|
|
|
+ xstrfromhex(pSerial->recvBuf, pSerial->nRecvBytes, pSerial->pLogRecvBuf, NULL, NULL); }
|
|
|
+ else strcat(pSerial->pLogRecvBuf, ".");
|
|
|
+ sw_log_writeWithLevel(logLevel, __FILE__, -1, "%s", pSerial->pLogRecvBuf);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 判断接收线程是否还在 */
|
|
|
+bool serial_recvThrd_isAlive(const void *hSerial)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ return pSerial ? sw_thrd_isAlive(pSerial->hRecvThrd) : false;
|
|
|
+}
|
|
|
+
|
|
|
+/* 暂停接收线程接收数据 */
|
|
|
+void serial_recvThrd_pause(const void *hSerial)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial) sw_thrd_pause(pSerial->hRecvThrd);
|
|
|
+}
|
|
|
+
|
|
|
+/* 继续接收线程接收数据 */
|
|
|
+void serial_recvThrd_resume(const void *hSerial)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial) sw_thrd_resume(pSerial->hRecvThrd);
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef _DEBUG
|
|
|
+/* 向接收缓存中写入数据(一般用于仿真串口输入, 模拟测试时使用) */
|
|
|
+void serial_write_recv_buffer(const void *hSerial, const unsigned char *hex, int hexCnt)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)hSerial;
|
|
|
+ if(pSerial && hex && hexCnt > 0 && hexCnt < sizeof(pSerial->recvBuf))
|
|
|
+ {
|
|
|
+ memcpy(pSerial->recvBuf+pSerial->nRecvBytes, hex, hexCnt);
|
|
|
+ pSerial->nRecvBytes += hexCnt;
|
|
|
+ }
|
|
|
+ sw_thrd_delay(1000); // 延时1秒钟, 等待数据被回调处理, 否则会累积(模拟仿真和真实触发还是有区别)
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/* 检测串口状态, timeout单位为ms */
|
|
|
+#define serial_select sw_tcp_select
|
|
|
+
|
|
|
+/* 数据接收处理(线程回调), "返回值 < 0"时表示处理失败, 将不再调用该接收回调函数, "返回值 >= 0"时表示
|
|
|
+ 处理成功, 延时一段"返回值"时间(ms)后继续调用该接收回调函数 */
|
|
|
+static int serial_data_recv_proc(unsigned long wParam, unsigned long lParam)
|
|
|
+{
|
|
|
+ struct serial_t *pSerial = (struct serial_t *)wParam;
|
|
|
+ fd_set rSet;
|
|
|
+ int nRecvBufSize = sizeof(pSerial->recvBuf), nInterval, nRet;
|
|
|
+
|
|
|
+RecvP:
|
|
|
+ if(!sw_thrd_isAlive(pSerial->hRecvThrd)) return -1;
|
|
|
+
|
|
|
+ nRet = serial_select(pSerial->fd, &rSet, NULL, NULL, 0);
|
|
|
+ if(nRet == 0)
|
|
|
+ { // 串口无数据
|
|
|
+NoneP:
|
|
|
+ if(pSerial->pIdleHandler) nInterval = pSerial->pIdleHandler(wParam, lParam); // 触发无数据时的用户回调
|
|
|
+ else nInterval = 1;
|
|
|
+ goto EndP;
|
|
|
+ }
|
|
|
+ else if(nRet > 0 && FD_ISSET(pSerial->fd, &rSet))
|
|
|
+ { // 串口有数据
|
|
|
+ if(pSerial->nRecvBytes >= nRecvBufSize)
|
|
|
+ { // 判断接收缓存是否溢出
|
|
|
+ sw_log_warn("\"%s\" serial port receiving buffer overflow, the earliest one byte(%02x) will discard!",
|
|
|
+ pSerial->name, pSerial->recvBuf[0]);
|
|
|
+ memmove(pSerial->recvBuf, pSerial->recvBuf+1, nRecvBufSize-1); // 丢弃最早的一个字节
|
|
|
+ pSerial->nRecvBytes = nRecvBufSize-1; // 新的已接收字节数
|
|
|
+ }
|
|
|
+
|
|
|
+ nRet = read(pSerial->fd, pSerial->recvBuf+pSerial->nRecvBytes, 1); // 读一个字节
|
|
|
+ if(nRet == 1) pSerial->nRecvBytes += 1; // 已接收字节数累加1
|
|
|
+ else if(nRet == 0 && errno == ETIMEDOUT) goto NoneP; // 读数据超时
|
|
|
+ else
|
|
|
+ { // 读一个字节错误
|
|
|
+ sw_log_error("read one byte error(ret=%d, errno=%d), \"%s\" serial port receiving thread abort!!",
|
|
|
+ nRet, errno, pSerial->name);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(pSerial->pRecvHandler)
|
|
|
+ { // 处理已接收的数据
|
|
|
+ nInterval = pSerial->pRecvHandler(wParam, lParam); // 触发有数据时的用户回调
|
|
|
+ if(nInterval < 0) goto EndP;
|
|
|
+ }
|
|
|
+
|
|
|
+ goto RecvP; // 继续接收后续数据
|
|
|
+ }
|
|
|
+ else if(nRet < 0 && errno != EINTR)
|
|
|
+ { // 有错误发生
|
|
|
+ sw_log_error("select error(%s), \"%s\" serial port receiving thread abort!!", strerror(errno), pSerial->name);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ else nInterval = 1; // 不满足上述组合判断条件时
|
|
|
+
|
|
|
+EndP:
|
|
|
+ return nInterval;
|
|
|
+}
|