| |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <termios.h> |
| #include <sys/time.h> |
| #include <string.h> |
| #include <errno.h> |
| #include "LogInfo.h" |
| #include "CSerial.h" |
| |
| /******************************************************************************* |
| * 宏定义 * |
| *******************************************************************************/ |
| #define DEV_RSP_COUNT (1024) |
| |
| /******************************************************************************* |
| * 全局变量 * |
| *******************************************************************************/ |
| static int m_fd; |
| static char rspBufex[DEV_RSP_COUNT] = {0}; |
| |
| /******************************************************************************* |
| * 函数声明 * |
| *******************************************************************************/ |
| static ssize_t SendAT(const char *pData, size_t length); |
| static ssize_t ReadAT(BYTE *pbyReadBuffer, size_t dwReadCount); |
| |
| |
| /******************************************************************************* |
| * 内部函数 * |
| *******************************************************************************/ |
| /** |
| * @brief 发送AT命令 |
| * @param pData 入参,AT命令写入缓冲区 |
| * @param length 入参,AT命令长度 |
| * @return 成功返回成功写入的字节数,失败返回-1 |
| * @retval |
| * @note length不计算结尾\0 |
| * @warning |
| */ |
| static ssize_t SendAT(const char *pData, size_t length) |
| { |
| ssize_t dwBytesWritten = -1; |
| ssize_t writeCount = 0; |
| struct timeval timeout; |
| fd_set fds, temps; |
| int result = 0; |
| |
| if (m_fd < 0) |
| { |
| return -1; |
| } |
| if (pData != NULL) |
| { |
| LogInfo("pData= (%s) length = %ld ", pData, length); |
| } |
| |
| // gettimeofday(&end, NULL); |
| // gettimeofday(&begin, NULL); |
| FD_ZERO(&fds); |
| FD_SET(m_fd, &fds); |
| /* 超时不能在此设置! |
| 因为调用select后,结构体timeval的成员tv_sec和tv_usec的值将被替换为超时前剩余时间. |
| 调用select函数前,每次都需要初始化timeval结构体变量. |
| timeout.tv_sec = 1; |
| timeout.tv_usec = 0; */ |
| |
| while (1) |
| { |
| /* 将准备好的fd_set变量reads的内容复制到temps变量,因为调用select函数后,除了发生变化的fd对应位外, |
| 剩下的所有位都将初始化为0,为了记住初始值,必须经过这种复制过程。*/ |
| temps = fds; |
| // 设置超时 |
| timeout.tv_sec = 1; |
| timeout.tv_usec = 0; |
| // 调用select函数 |
| result = select(m_fd + 1, NULL, &temps, NULL, &timeout); |
| if (result <= 0) |
| { |
| if (0 == result) |
| { |
| LogInfo("timeout"); |
| } |
| else |
| { |
| LogInfo("select() error"); |
| } |
| break; |
| // return -1; |
| } |
| else |
| { |
| // 判断m_fd是否可写,若可写,写入数据 |
| if (FD_ISSET(m_fd, &temps)) |
| { |
| dwBytesWritten = write(m_fd, pData + writeCount, length - writeCount); |
| LogInfo("pData= (%s) dwBytesWritten = %ld ", pData, dwBytesWritten); |
| if (dwBytesWritten > 0) |
| { |
| writeCount += dwBytesWritten; |
| if (writeCount >= length) |
| { |
| break; |
| } |
| } |
| if (dwBytesWritten < 0 && errno != EINTR) |
| { |
| printf("SendAT:: write error, dwBytesWritten = %ld, %s\r\n", dwBytesWritten, strerror(errno)); |
| break; |
| } |
| } |
| } |
| } |
| |
| if (dwBytesWritten > 0) |
| { |
| return dwBytesWritten; |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| |
| /** |
| * @brief 接收AT命令应答 |
| * @param pbyReadBuffer 出参,应答读取缓冲区 |
| * @param dwReadCount 入参,应答读取长度 |
| * @return 成功返回成功写入的字节数,失败返回-1 |
| * @retval |
| * @note |
| * @warning |
| */ |
| static ssize_t ReadAT(BYTE *pbyReadBuffer, size_t dwReadCount) |
| { |
| ssize_t dwBytesRead = -1; |
| ssize_t readCount = 0; |
| int result; |
| fd_set fds, temps; |
| struct timeval timeout; |
| |
| if (m_fd < 0) |
| { |
| return -1; |
| } |
| LogInfo("ReadAT start"); |
| |
| FD_ZERO(&fds); |
| FD_SET(m_fd, &fds); |
| |
| while (1) |
| { |
| temps = fds; |
| // 设置超时 |
| timeout.tv_sec = 1; |
| timeout.tv_usec = 0; |
| // 调用select函数 |
| result = select(m_fd + 1, &temps, NULL, NULL, &timeout); |
| if (result <= 0) |
| { |
| if (0 == result) |
| { |
| LogInfo("timeout"); |
| } |
| else |
| { |
| LogInfo("select() error"); |
| } |
| return -1; |
| } |
| else |
| { |
| // 判断m_fd是否可读,若可读,读取数据 |
| if (FD_ISSET(m_fd, &temps)) |
| { |
| dwBytesRead = read(m_fd, pbyReadBuffer + readCount, dwReadCount - readCount); |
| LogInfo("pData= (%s) dwBytesWritten = %ld ", pbyReadBuffer, dwBytesRead); |
| if (dwBytesRead > 0) |
| { |
| readCount += dwBytesRead; |
| if (readCount >= dwReadCount) |
| { |
| break; |
| } |
| } |
| if (dwBytesRead < 0 && errno != EINTR) |
| { |
| printf("ReadAT::read error, dwBytesRead = %ld, %s\r\n", dwBytesRead, strerror(errno)); |
| break; |
| } |
| } |
| } |
| } |
| |
| if (dwBytesRead > 0) |
| { |
| return dwBytesRead; |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| |
| |
| /******************************************************************************* |
| * 外部函数 * |
| *******************************************************************************/ |
| /** |
| * @brief 打开设备文件,并设置波特率等参数 |
| * @param portName 入参,端口名 |
| * @return 成功返回0,失败返回-1 |
| * @retval |
| * @note |
| * @warning |
| */ |
| int Open(const char *portName) |
| { |
| // char portname_full[20] = "/dev/"; |
| // strcat(portname_full, portName); |
| // portName = +portName ; |
| |
| struct termios attr; |
| int flags; |
| |
| if (portName != NULL) |
| { |
| LogInfo("portname = (%s)", portName); |
| } |
| m_fd = open(portName, O_RDWR | O_NONBLOCK | O_NOCTTY | O_TRUNC); |
| if (m_fd < 0) |
| { |
| LogInfo("Open m_fd < 0 m_fd = %d\n", m_fd); |
| return -1; |
| } |
| else |
| { |
| LogInfo("Open m_fd > 0 m_fd = %d\n", m_fd); |
| } |
| tcflush(m_fd, TCIOFLUSH); // clear serial data |
| if (tcgetattr(m_fd, &attr) < 0) |
| { |
| close(m_fd); |
| return -1; |
| } |
| attr.c_iflag = IXON | IXOFF; |
| attr.c_oflag = 0; |
| attr.c_cflag &= ~(CSIZE | CFLAGS_TO_CLEAR | CFLAGS_HARDFLOW); |
| attr.c_cflag |= (CS8 | CFLAGS_TO_SET); |
| attr.c_cflag |= CFLAGS_HARDFLOW; |
| attr.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ISIG); |
| attr.c_lflag &= ~OPOST; |
| int i; |
| #ifdef _POSIX_VDISABLE |
| attr.c_cc[0] = _POSIX_VDISABLE; |
| #else |
| attr.c_cc[0] = fpathconf(m_fd, _PC_VDISABLE); |
| #endif |
| |
| for (i = 1; i < NCCS; i++) |
| { |
| attr.c_cc[i] = attr.c_cc[0]; |
| } |
| |
| attr.c_cc[VMIN] = 0; |
| attr.c_cc[VTIME] = 5; |
| cfsetispeed(&attr, BAUDRATE); |
| cfsetospeed(&attr, BAUDRATE); |
| if (tcsetattr(m_fd, TCSANOW, &attr) < 0) |
| { |
| close(m_fd); |
| return -1; |
| } |
| flags = fcntl(m_fd, F_GETFL, 0); |
| if (flags < 0) |
| { |
| close(m_fd); |
| return -1; |
| } |
| if (fcntl(m_fd, F_SETFL, flags) < 0) |
| { |
| close(m_fd); |
| return -1; |
| } |
| // m_isOpen = true; |
| // StartRead(); |
| return 0; |
| } |
| |
| /** |
| * @brief 关闭设备文件 |
| * @param 无 |
| * @return 成功关闭返回0,否则返回-1 |
| * @retval |
| * @note |
| * @warning |
| */ |
| int Close() |
| { |
| tcflush(m_fd, TCIOFLUSH); // clear serial data |
| if (m_fd > 0) |
| { |
| // printf("close m_fd\n"); |
| close(m_fd); |
| } |
| else |
| { |
| printf("%s:: close->else\n", __FUNCTION__); |
| return -1; |
| } |
| m_fd = 0; |
| return 0; |
| } |
| |
| /** |
| * @brief 发送AT命令并读取返回值 |
| * @param Dev_tty 入参,打开的AT口设备路径 |
| * @param AtString 入参,发送的AT命令字符串 |
| * @param RebackString 出参,AT命令返回的字符串 |
| * @return 成功返回0,失败返回-1 |
| * @retval |
| * @note |
| * @warning |
| */ |
| int SendATString(const char *Dev_tty, const char *AtString, char *RebackString) |
| { |
| BYTE tmp[1024] = {0}; |
| |
| printf("%s:: Before Open port, (%s)\n", __FUNCTION__, Dev_tty); |
| if (-1 == (Open(Dev_tty))) |
| { |
| if (AtString != NULL) |
| { |
| LogInfo("SendATString Failed AtString = (%s)", AtString); |
| } |
| printf("%s:: Open port error\r\n", __FUNCTION__); |
| return -1; |
| } |
| if (AtString != NULL) |
| { |
| LogInfo("SendATString OK, AtString = (%s)", AtString); |
| } |
| |
| LogInfo("Before SendAT"); |
| if(SendAT(AtString, strlen(AtString)) < 0) |
| { |
| LogInfo("SendAT failed"); |
| Close(); |
| return -1; |
| } |
| LogInfo("After SendAT"); |
| |
| ReadAT(tmp, 1024); |
| LogInfo("out ReadAT"); |
| |
| memcpy(RebackString, tmp, 1024); |
| LogInfo("after memcpy"); |
| |
| Close(); |
| return 0; |
| } |
| |
| /** |
| * @brief 发送数据 |
| * @param pbyWriteBuffer 入参,写入数据缓冲区 |
| * @param dwWriteCount 入参,写入数据长度 |
| * @param dwSleepAfterAction 入参, |
| * @param dwTimeoutCount 入参,超时时间,单位秒 |
| * @return 成功返回TRUE,失败返回FALSE |
| * @retval |
| * @note |
| * @warning |
| */ |
| BOOL SendData(const BYTE *pbyWriteBuffer, size_t dwWriteCount, DWORD dwSleepAfterAction, DWORD dwTimeoutCount) |
| { |
| ssize_t sBytesWritten = -1; |
| ssize_t writeCount = 0; |
| struct timeval timeout; |
| fd_set fds, temps; |
| int result = 0; |
| // int count = 0; // 超时计数 |
| |
| LogInfo("writecount %d, timeout %d s", dwWriteCount, dwTimeoutCount); |
| if (m_fd < 0) |
| { |
| LogInfo("m_fd < 0"); |
| return FALSE; |
| } |
| |
| FD_ZERO(&fds); |
| FD_SET(m_fd, &fds); |
| |
| tcflush(m_fd, TCIOFLUSH); // clear serial data |
| |
| if (dwTimeoutCount < 10) |
| { |
| dwTimeoutCount = 10; |
| } |
| /* 超时不能在此设置! |
| 因为调用select后,结构体timeval的成员tv_sec和tv_usec的值将被替换为超时前剩余时间. |
| 调用select函数前,每次都需要初始化timeval结构体变量. |
| timeout.tv_sec = 1; |
| timeout.tv_usec = 0; */ |
| |
| while (1) |
| { |
| /*将准备好的fd_set变量reads的内容复制到temps变量,因为调用select函数后,除了发生变化的fd对应位外, |
| 剩下的所有位都将初始化为0,为了记住初始值,必须经过这种复制过程。*/ |
| temps = fds; |
| // 设置超时 |
| timeout.tv_sec = dwTimeoutCount; |
| timeout.tv_usec = 0; |
| // 调用select函数 |
| result = select(m_fd + 1, NULL, &temps, NULL, &timeout); |
| LogInfo("select result = %d ", result); |
| if (-1 == result) |
| { |
| LogInfo("select() error\n"); |
| perror("SendData:: select() error\n"); |
| break; |
| } |
| else if (0 == result) |
| { |
| puts("SendData:: timeout\r\n"); |
| break; |
| } |
| else |
| { |
| // 判断m_fd是否可写,若可写,写入数据 |
| if (FD_ISSET(m_fd, &temps)) |
| { |
| sBytesWritten = write(m_fd, (char *)pbyWriteBuffer + writeCount, dwWriteCount - writeCount); |
| LogInfo("pbyWriteBuffer= (%s) dwBytesWritten = %ld ", pbyWriteBuffer, sBytesWritten); |
| if (sBytesWritten > 0) |
| { |
| writeCount += sBytesWritten; |
| if (writeCount >= dwWriteCount) |
| { |
| return TRUE; // complete success |
| } |
| } |
| else |
| { |
| if (sBytesWritten < 0 && errno != EINTR) |
| { |
| printf("SendData::write error, dwBytesWritten = %ld, %s\r\n", sBytesWritten, strerror(errno)); |
| } |
| return FALSE; |
| } |
| } |
| } |
| } |
| return FALSE; |
| } |
| |
| /** |
| * @brief 接收数据 |
| * @param pbyReadBuffer 入参,读取数据缓冲区 |
| * @param dwReadCount 入参,读取数据长度 |
| * @param dwSleepAfterAction 入参, |
| * @param dwTimeoutCount 入参,超时时间,单位秒 |
| * @return 成功返回TRUE,失败返回FALSE |
| * @retval |
| * @note |
| * @warning |
| */ |
| BOOL ReadData(BYTE *pbyReadBuffer, size_t dwReadCount, DWORD dwSleepAfterAction, DWORD dwTimeoutCount) |
| { |
| ssize_t sBytesReadn = -1; |
| ssize_t readCount = 0; |
| int result; |
| fd_set fds, temps; |
| struct timeval timeout; |
| // int readCount = 0; |
| // int count = 0; // 超时计数 |
| |
| LogInfo("ReadData reacount %d, timeout %d s\n", dwReadCount, dwTimeoutCount); |
| if (m_fd < 0) |
| { |
| LogInfo("m_fd < 0"); |
| return -1; |
| } |
| |
| FD_ZERO(&fds); |
| FD_SET(m_fd, &fds); |
| |
| if (dwTimeoutCount < 10) |
| { |
| dwTimeoutCount = 10; |
| } |
| |
| while (1) |
| { |
| temps = fds; |
| timeout.tv_sec = dwTimeoutCount; |
| timeout.tv_usec = 0; |
| |
| result = select(m_fd + 1, &temps, NULL, NULL, &timeout); |
| LogInfo("select result = %d ", result); |
| if (-1 == result) |
| { |
| LogInfo("select() error\n"); |
| perror("ReadData:: select() error\n"); |
| break; |
| } |
| else if (0 == result) |
| { |
| puts("ReadData:: timeout\n"); |
| break; |
| } |
| else |
| { |
| // 判断m_fd是否可读,若可读,读取数据 |
| if (FD_ISSET(m_fd, &temps)) |
| { |
| sBytesReadn = read(m_fd, pbyReadBuffer + readCount, dwReadCount - readCount); |
| LogInfo("pbyReadBuffer= (%s) sBytesReadn = %ld ", pbyReadBuffer, sBytesReadn); |
| if (sBytesReadn > 0) |
| { |
| readCount += sBytesReadn; |
| if (readCount >= dwReadCount) |
| { |
| return TRUE; // complete success |
| } |
| } |
| else |
| { |
| if (sBytesReadn < 0 && errno != EINTR) |
| { |
| printf("ReadData::read error, sBytesReadn = %ld, %s\r\n", sBytesReadn, strerror(errno)); |
| } |
| return FALSE; |
| } |
| } |
| } |
| } |
| return FALSE; |
| } |
| |
| /** |
| * @brief 接收数据缓冲 |
| * @param dwReadCount 入参,读取数据长度 |
| * @param dwSleepAfterAction 入参, |
| * @param dwTimeoutCount 入参,超时时间,单位秒 |
| * @return 成功返回读取的数据指针,失败返回NULL |
| * @retval |
| * @note |
| * @warning |
| */ |
| BYTE *ReadDataExtraFuncB(DWORD dwReadCount, DWORD dwSleepAfterAction, DWORD dwTimeoutCount) |
| { |
| ssize_t sBytesReadn = -1; |
| ssize_t readCount = 0; |
| int result; |
| fd_set fds, temps; |
| struct timeval timeout; |
| |
| LogInfo("readcount %d, timeout %d s", dwReadCount, dwTimeoutCount); |
| |
| memset(rspBufex, 0, DEV_RSP_COUNT); |
| |
| if (m_fd < 0) |
| { |
| LogInfo("m_fd < 0"); |
| return rspBufex; |
| } |
| |
| FD_ZERO(&fds); |
| FD_SET(m_fd, &fds); |
| |
| if (dwTimeoutCount < 10) |
| { |
| dwTimeoutCount = 10; |
| } |
| |
| while (1) |
| { |
| temps = fds; |
| timeout.tv_sec = dwTimeoutCount; |
| timeout.tv_usec = 0; |
| |
| result = select(m_fd + 1, &fds, NULL, NULL, &timeout); |
| LogInfo("select result = %d ", result); |
| if (-1 == result) |
| { |
| LogInfo("select() error\n"); |
| perror("ReadDataExtraFuncB:: select() error\n"); |
| break; |
| } |
| else if (0 == result) |
| { |
| puts("ReadDataExtraFuncB:: timeout\n"); |
| break; |
| } |
| else |
| { |
| // 判断m_fd是否可读,若可读,读取数据 |
| if (FD_ISSET(m_fd, &temps)) |
| { |
| sBytesReadn = read(m_fd, rspBufex + readCount, DEV_RSP_COUNT - readCount); |
| LogInfo("pbyReadBuffer= (%s) sBytesReadn = %ld ", rspBufex, sBytesReadn); |
| if (sBytesReadn > 0) |
| { |
| readCount += sBytesReadn; |
| printf("ReadDataExtraFuncB:: readCount = %ld, dwReadCount = %d \r\n", readCount, dwReadCount); |
| if (readCount >= dwReadCount) |
| { |
| break; // complete success |
| } |
| } |
| else |
| { |
| if (sBytesReadn < 0 && errno != EINTR) |
| { |
| printf("ReadData::read error, sBytesReadn = %ld, %s\r\n", sBytesReadn, strerror(errno)); |
| } |
| break; |
| } |
| } |
| } |
| } |
| LogInfo("rspBufex = (%s)", rspBufex); |
| |
| return rspBufex; |
| } |