map/das-dn/comm/portproc.cpp
2024-10-14 20:26:21 +08:00

455 lines
12 KiB
C++

#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;
}