#include "portproc.h" const static char* DEVPATH = "/dev/"; //const static char* PARITY[] = { "NONE", "ODD", "EVEN" }; //const static char* STOPBIT[] = { "1", "1.5", "2" }; CPortProcess::CPortProcess() { m_nPortNo = -1; m_serialfd = -1; memset(&buffers, 0, sizeof(buffers)); } CPortProcess::~CPortProcess() { } BOOLEAN CPortProcess::OnPreCreate(int id) { int i, uid; CPortProcessItem *pItem; if (!CProcess::OnPreCreate(id)) return FALSE; m_nPortNo = config.processes[id].order; if(m_nPortNo < 0 || m_nPortNo >= HARDWARE_PORTS_NUM) return FALSE; if (!SerialPortOpen()) return FALSE; for (i = 0; i < PROCESS_UNIT_NUM; i++) { //判断每个进程所链接的单元 uid = GetUnitID(i); if (uid < 0 || uid >= UNIT_NUM) break; pItem = GetItem(i); if (NULL == pItem) break; pItem->Attach(uid, -1); } return TRUE; } BOOLEAN CPortProcess::OnCreated(int id) { return CProcess::OnCreated(id); } void CPortProcess::Destroy(void) { CProcess::Destroy(); SerialPortClose(); } BOOLEAN CPortProcess::SerialPortOpen(void) { int i = 0; struct termios newoptions, oldoptions; const DWORD speed_table[] = { 0L, 50L, 75L, 110L, 134L, 150L, 200L, 300L, 600L, 1200L, 1800L, 2400L, 4800L, 9600L, 19200L, 38400L, 57600L, 115200L, 230400L, 460800L, 500000L, 576000L, 921600L }; const int m_speed[] = { B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600 }; int table_size = sizeof(speed_table) / sizeof(DWORD); char* portname = (char*)malloc(strlen(DEVPATH) + MAX_NAME_SIZE + 1); if (portname == NULL) return FALSE; strcpy(portname, DEVPATH); strcat(portname, config.hardware.ports[m_nPortNo].name); if (m_serialfd > 0) { vLog(LOG_DEBUG, "before open serialfd = %d\n", m_serialfd); close(m_serialfd); m_serialfd = -1; } m_serialfd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL); vLog(LOG_DEBUG, "starting to open port(%d) as %s and serialfd = %d\n", m_nPortNo, portname, m_serialfd); if (m_serialfd == -1) { vLog(LOG_ERROR, "open port(%d) %s error(%d,%s).\n", m_nPortNo, portname, errno, strerror(errno)); free(portname); portname = NULL; return FALSE; } free(portname); portname = NULL; if (fcntl(m_serialfd, F_SETFL, 0) < 0) { vLog(LOG_ERROR, "fcntl error(%d,%s).\n", errno, strerror(errno)); close(m_serialfd); m_serialfd = -1; return FALSE; } if (isatty(m_serialfd) == 0) { vLog(LOG_ERROR, "standard input is not a terminal device!\n"); close(m_serialfd); m_serialfd = -1; return FALSE; } bzero(&oldoptions, sizeof(oldoptions)); if (tcgetattr(m_serialfd, &oldoptions) != 0) { vLog(LOG_ERROR, "get old attr error(%d,%s).\n", errno, strerror(errno)); return FALSE; } bzero(&newoptions, sizeof(newoptions)); cfmakeraw(&newoptions); newoptions.c_cflag |= CLOCAL|CREAD; //set baudrate for (i = 0; i < table_size; i++) { if ((long)speed_table[i] == config.hardware.ports[m_nPortNo].baud) break; } if (i == 0 || i >= table_size) { vLog(LOG_WARN, "baudrate error! baudrate can't be %d and as default 9600.\n", (int)config.hardware.ports[m_nPortNo].baud); i = 13; } if (cfsetispeed(&newoptions, m_speed[i]) != 0) { vLog(LOG_ERROR, "set in speed baudrate error(%d,%s).\n", errno, strerror(errno)); return FALSE; } if (cfsetospeed(&newoptions, m_speed[i]) != 0) { vLog(LOG_ERROR, "set out speed baudrate error(%d,%s).\n", errno, strerror(errno)); return FALSE; } //set bytesize newoptions.c_cflag &= ~CSIZE; switch (config.hardware.ports[m_nPortNo].data) { case 5: newoptions.c_cflag |= CS5; break; case 6: newoptions.c_cflag |= CS6; break; case 7: newoptions.c_cflag |= CS7; break; case 8: newoptions.c_cflag |= CS8; break; default: newoptions.c_cflag |= CS8; break; } //set stopbis switch (config.hardware.ports[m_nPortNo].stop) { case 0: //一位停止位 newoptions.c_cflag &= ~CSTOPB; break; case 2: //两位停止位 newoptions.c_cflag |= CSTOPB; break; default: newoptions.c_cflag &= ~CSTOPB; break; } //set parity switch (config.hardware.ports[m_nPortNo].parity) { case PARITY_NONE: newoptions.c_cflag &= ~PARENB; newoptions.c_iflag &= ~INPCK; break; case PARITY_ODD: newoptions.c_cflag |= PARENB; newoptions.c_cflag |= PARODD; newoptions.c_iflag |= INPCK; break; case PARITY_EVEN: newoptions.c_cflag |= PARENB; newoptions.c_cflag &= ~PARODD; newoptions.c_iflag |= INPCK; break; #if 0 case PARITY_MARK: //Mark校验 newoptions.c_cflag |= PARENB; newoptions.c_cflag |= (CMSPAR | PARODD); newoptions.c_iflag |= INPCK; break; case PARITY_SPACE: //Space校验 newoptions.c_cflag |= PARENB; newoptions.c_cflag &= ~PARODD; newoptions.c_cflag |= CMSPAR; newoptions.c_iflag |= INPCK; break; #endif default: newoptions.c_cflag &= ~PARENB; newoptions.c_iflag &= ~INPCK; break; } newoptions.c_cc[VTIME] = 0; newoptions.c_cc[VMIN] = 0; newoptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); newoptions.c_iflag &= ~(ICRNL | IGNCR | INLCR | IGNBRK | BRKINT); newoptions.c_iflag &= ~(IXON | IXOFF | IXANY); newoptions.c_oflag &= ~(OCRNL | OLCUC | ONLCR | OPOST); tcflush(m_serialfd, TCIFLUSH); if (tcsetattr(m_serialfd, TCSANOW, &newoptions) != 0) { vLog(LOG_ERROR, "setattr error(%d,%s).\n", errno, strerror(errno)); return FALSE; } return TRUE; } void CPortProcess::SerialPortClose(void) { if (m_serialfd < 0) return; close(m_serialfd); m_serialfd = -1; } BOOLEAN CPortProcess::Run(void) { if (!CProcess::Run()) return FALSE; SerialPortRead(); //数据发送 SerialPortWrite(); return TRUE; } BOOLEAN CPortProcess::SerialPortTimeout(void) { return TRUE; } void CPortProcess::SerialPortRead(unsigned long timeout) { int len; int val; int length; BYTE buffer[MAX_PORT_BUFFER_SIZE]; fd_set rfds; struct timeval tv; if (m_serialfd < 0) return; //读取数据 FD_ZERO(&rfds); tv.tv_sec = 0; if (timeout > 0) tv.tv_usec = timeout; else tv.tv_usec = 20000; FD_SET(m_serialfd, &rfds); val = select(m_serialfd + 1, &rfds, NULL, NULL, &tv); if (val > 0) { if (FD_ISSET(m_serialfd, &rfds)) { //该串口有数据需要读取 ioctl(m_serialfd, FIONREAD, &len); if (len > 0) { length = buffers.in_save + MAX_PORT_BUFFER_SIZE - buffers.in_load; length &= (MAX_PORT_BUFFER_SIZE - 1); length = (MAX_PORT_BUFFER_SIZE - length); length = wMin(len, length); len = read(m_serialfd, buffer, length); if (len > 0) { length = wMin(len, (MAX_PORT_BUFFER_SIZE - buffers.in_save)); memcpy(&buffers.in_buf[buffers.in_save], buffer, length); memcpy(buffers.in_buf, &buffer[length], len - length); buffers.in_save += len; buffers.in_save &= (MAX_PORT_BUFFER_SIZE - 1); } } } } else if (val == 0) { //timeout SerialPortTimeout(); } } void CPortProcess::SerialPortWrite(void) { int len; int val; int length; BYTE buffer[MAX_PORT_BUFFER_SIZE]; fd_set wfds; struct timeval tv; if (m_serialfd < 0) return; len = buffers.out_save + MAX_PORT_BUFFER_SIZE - buffers.out_load; len &= (MAX_PORT_BUFFER_SIZE - 1); if (len > 0) { //存在数据发送 FD_ZERO(&wfds); tv.tv_sec = 0; tv.tv_usec = 20000; FD_SET(m_serialfd, &wfds); val = select(m_serialfd + 1, NULL, &wfds, NULL, &tv); if (val > 0) { if (FD_ISSET(m_serialfd, &wfds)) { //该串口可以发送数据 length = wMin(len, (MAX_PORT_BUFFER_SIZE - buffers.out_load)); memcpy(buffer, &buffers.out_buf[buffers.out_load], length); memcpy(&buffer[length], buffers.out_buf, len - length); tcflush(m_serialfd, TCOFLUSH); write(m_serialfd, buffer, len); tcdrain(m_serialfd); buffers.out_load += len; buffers.out_load &= (MAX_PORT_BUFFER_SIZE - 1); } } } } BOOLEAN CPortProcess::OnTimer(void) { if (!CProcess::OnTimer()) return FALSE; return TRUE; } BOOLEAN CPortProcess::FindData(BYTE nChar) { int load; load = buffers.in_load; while (load != buffers.in_save) { if (buffers.in_buf[load] == nChar) { buffers.in_load = load; return TRUE; } load++; load &= (MAX_PORT_BUFFER_SIZE - 1); } buffers.in_load = load; return FALSE; } void CPortProcess::DropData(int count) { buffers.in_load += count; buffers.in_load &= (MAX_PORT_BUFFER_SIZE - 1); } BOOLEAN CPortProcess::GetData(BYTE* pBuf, int count) { int len, load; len = buffers.in_save + MAX_PORT_BUFFER_SIZE - buffers.in_load; len &= (MAX_PORT_BUFFER_SIZE - 1); if (len < count) return FALSE; len = 0; load = buffers.in_load; while (load != buffers.in_save) { *pBuf = buffers.in_buf[load]; pBuf++; len++; load++; load &= (MAX_PORT_BUFFER_SIZE - 1); if (len >= count) break; } return (len == count); } BOOLEAN CPortProcess::WriteData(const BYTE* pData, int count) { int i; int save; save = buffers.out_save; for (i = 0; i < count; i++, pData++) { buffers.out_buf[save] = *pData; save++; save &= (MAX_PORT_BUFFER_SIZE - 1); } buffers.out_save = save; return TRUE; } int CPortProcess::GetTimeout(void) const { int timeout; timeout = config.hardware.ports[m_nPortNo].timeout / DELAY_TIMER; if (timeout <= 0) timeout = TIME_BASE; return timeout; } CPortProcessItem::CPortProcessItem() { m_uid = -1; } CPortProcessItem::~CPortProcessItem() { m_uid = -1; } void CPortProcessItem::Attach(int uid, int physicsAddress /* = 0 */, int commonAddress /* = 0 */, int originatorAddress /* = 0 */) { m_uid = uid; m_physicsAddress = physicsAddress; m_commonAddress = commonAddress; m_originatorAddress = originatorAddress; } void CPortProcessItem::Release(void) { m_physicsAddress = 0; m_commonAddress = 0; m_originatorAddress = 0; } ////CPortProcessItem类实现 CPortProcessItem *CPortProcess::CreateItem(int ord) { return(new CPortProcessItem); } void CPortProcess::DestroyItem(int ord, BOOLEAN bDeleted /* = FALSE */) { if (ord < 0 || ord >= PROCESS_UNIT_NUM) return; if (!bDeleted) { CPortProcessItem *pItem = (CPortProcessItem *)m_pItems[ord]; if (pItem) { delete pItem; } } m_pItems[ord] = NULL; }