BOOL xMBPortSerialPoll( ) { BOOL bStatus = TRUE; DWORD dwBytesRead; DWORD dwBytesWritten; DWORD i; while( bRxEnabled ) { /* buffer wrap around. */ if( uiRxBufferPos >= BUF_SIZE ) uiRxBufferPos = 0; if( ReadFile( g_hSerial, &ucBuffer[uiRxBufferPos], BUF_SIZE - uiRxBufferPos, &dwBytesRead, NULL ) ) { if( dwBytesRead == 0 ) { /* timeout with no bytes. */ break; } else if( dwBytesRead > 0 ) { vMBPortLog( MB_LOG_DEBUG, _T( "SER-POLL" ), _T( "detected end of frame (t3.5 expired.)\r\n" ) ); for( i = 0; i < dwBytesRead; i++ ) { /* Call the modbus stack and let him fill the buffers. */ ( void )pxMBFrameCBByteReceived( ); } } } else { vMBPortLog( MB_LOG_ERROR, _T( "SER-POLL" ), _T( "I/O error on serial device: %s" ), Error2String( GetLastError ( ) ) ); bStatus = FALSE; } } if( bTxEnabled ) { while( bTxEnabled ) { ( void )pxMBFrameCBTransmitterEmpty( ); /* Call the modbus stack to let him fill the buffer. */ } dwBytesWritten = 0; if( !WriteFile ( g_hSerial, &ucBuffer[0], uiTxBufferPos, &dwBytesWritten, NULL ) || ( dwBytesWritten != uiTxBufferPos ) ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-POLL" ), _T( "I/O error on serial device: %s" ), Error2String( GetLastError ( ) ) ); bStatus = FALSE; } } return bStatus; }
bool xMBPortSerialPoll(void) { bool bStatus = true; uint16_t usBytesRead; int i; while (bRxEnabled) { if (prvbMBPortSerialRead(&ucBuffer[0], BUF_SIZE, &usBytesRead)) { if (usBytesRead == 0) { /* timeout with no bytes. */ break; } else if (usBytesRead > 0) { for (i = 0; i < usBytesRead; i++) { /* Call the modbus stack and let him fill the buffers. */ (void)pxMBFrameCBByteReceived(); } uiRxBufferPos = 0; } } else { vMBPortLog(MB_LOG_ERROR, "SER-POLL", "read failed on serial device: %d\n", errno); bStatus = false; } } if (bTxEnabled) { while (bTxEnabled) { (void)pxMBFrameCBTransmitterEmpty(); /* Call the modbus stack to let him fill the buffer. */ } if (!prvbMBPortSerialWrite(&ucBuffer[0], uiTxBufferPos)) { vMBPortLog(MB_LOG_ERROR, "SER-POLL", "write failed on serial device: %d\n", errno); bStatus = false; } } return bStatus; }
void prvvMBPortReleaseClient( struct tcp_pcb *pxPCB ) { if( pxPCB != NULL ) { if( tcp_close( pxPCB ) != ERR_OK ) { tcp_abort( pxPCB ); } if( pxPCB == pxPCBClient ) { #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n", ip4_addr1( &( pxPCB->remote_ip ) ), ip4_addr2( &( pxPCB->remote_ip ) ), ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); #endif pxPCBClient = NULL; } if( pxPCB == pxPCBListen ) { pxPCBListen = NULL; } } }
BOOL xMBPortSerialSetTimeout( DWORD dwTimeoutMs ) { BOOL bStatus; COMMTIMEOUTS cto; /* usTimeOut is the inter character timeout used to detect the end * of frame. The total timeout is set to 50ms to make sure we * can exit the blocking read. */ cto.ReadIntervalTimeout = dwTimeoutMs; cto.ReadTotalTimeoutConstant = 50; cto.ReadTotalTimeoutMultiplier = 0; cto.WriteTotalTimeoutConstant = 0; cto.WriteTotalTimeoutMultiplier = 0; if( !SetCommTimeouts( g_hSerial, &cto ) ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-INIT" ), _T( "Can't set timeouts for serial device: %s" ), Error2String( GetLastError( ) ) ); bStatus = FALSE; } else { bStatus = TRUE; } return bStatus; }
void vMBPortExitCritical(void) { int ret = pthread_mutex_unlock(&xLock); if (ret != 0) { vMBPortLog(MB_LOG_ERROR, "OTHER", "Locking primitive failed: %d\n", ret); } }
/* Called in case of an unrecoverable error. In any case we drop the client * connection. */ void prvvMBTCPPortError( void *pvArg, err_t xErr ) { struct tcp_pcb *pxPCB = pvArg; if( pxPCB != NULL ) { #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" ); #endif prvvMBPortReleaseClient( pxPCB ); } }
/* ----------------------- Begin implementation -----------------------------*/ BOOL xMBTCPPortInit( USHORT usTCPPort ) { struct tcp_pcb *pxPCBListenNew, *pxPCBListenOld; BOOL bOkay = FALSE; USHORT usPort; if( usTCPPort == 0 ) { usPort = MB_TCP_DEFAULT_PORT; } else { usPort = ( USHORT ) usTCPPort; } if( ( pxPCBListenNew = pxPCBListenOld = tcp_new( ) ) == NULL ) { /* Can't create TCP socket. */ bOkay = FALSE; } else if( tcp_bind( pxPCBListenNew, IP_ADDR_ANY, ( u16_t ) usPort ) != ERR_OK ) { /* Bind failed - Maybe illegal port value or in use. */ ( void )tcp_close( pxPCBListenOld ); bOkay = FALSE; } else if( ( pxPCBListenNew = tcp_listen( pxPCBListenNew ) ) == NULL ) { ( void )tcp_close( pxPCBListenOld ); bOkay = FALSE; } else { /* Register callback function for new clients. */ tcp_accept( pxPCBListenNew, prvxMBTCPPortAccept ); /* Everything okay. Set global variable. */ pxPCBListen = pxPCBListenNew; #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" ); #endif } bOkay = TRUE; return bOkay; }
err_t prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ) { err_t error; if( xErr != ERR_OK ) { return xErr; } /* We can handle only one client. */ if( pxPCBClient == NULL ) { /* Register the client. */ pxPCBClient = pxPCB; /* Set up the receive function prvxMBTCPPortReceive( ) to be called when data * arrives. */ tcp_recv( pxPCB, prvxMBTCPPortReceive ); /* Register error handler. */ tcp_err( pxPCB, prvvMBTCPPortError ); /* Set callback argument later used in the error handler. */ tcp_arg( pxPCB, pxPCB ); /* Reset the buffers and state variables. */ usTCPBufPos = 0; #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n", ip4_addr1( &( pxPCB->remote_ip ) ), ip4_addr2( &( pxPCB->remote_ip ) ), ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); #endif error = ERR_OK; } else { prvvMBPortReleaseClient( pxPCB ); error = ERR_OK; } return error; }
bool xMBPortSerialInit(uint8_t ucPort, speed_t ulBaudRate, uint8_t ucDataBits, eMBParity eParity) { char szDevice[16]; bool bStatus = true; #ifdef CONFIG_SERIAL_TERMIOS struct termios xNewTIO; #endif snprintf(szDevice, 16, "/dev/ttyS%d", ucPort); if ((iSerialFd = open(szDevice, O_RDWR | O_NOCTTY)) < 0) { vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't open serial port %s: %d\n", szDevice, errno); } #ifdef CONFIG_SERIAL_TERMIOS else if (tcgetattr(iSerialFd, &xOldTIO) != 0) { vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't get settings from port %s: %d\n", szDevice, errno); } else { bzero(&xNewTIO, sizeof(struct termios)); xNewTIO.c_iflag |= IGNBRK | INPCK; xNewTIO.c_cflag |= CREAD | CLOCAL; switch (eParity) { case MB_PAR_NONE: break; case MB_PAR_EVEN: xNewTIO.c_cflag |= PARENB; break; case MB_PAR_ODD: xNewTIO.c_cflag |= PARENB | PARODD; break; default: bStatus = false; } switch (ucDataBits) { case 8: xNewTIO.c_cflag |= CS8; break; case 7: xNewTIO.c_cflag |= CS7; break; default: bStatus = false; } if (bStatus) { /* Set the new baud. The following might be compatible with other * OSs for the following reason. * * (1) In NuttX, cfset[i|o]speed always return OK so failures will * really only be reported when tcsetattr() is called. * (2) NuttX does not support separate input and output speeds so it * is not necessary to call both cfsetispeed() and * cfsetospeed(), and * (3) In NuttX, the input value to cfiset[i|o]speed is not * encoded, but is the absolute baud value. The following might * not be */ if (cfsetispeed(&xNewTIO, ulBaudRate) != 0 /* || cfsetospeed(&xNewTIO, ulBaudRate) != 0 */) { vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %d\n", ulBaudRate, szDevice, errno); } else if (tcsetattr(iSerialFd, TCSANOW, &xNewTIO) != 0) { vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't set settings for port %s: %d\n", szDevice, errno); } else { vMBPortSerialEnable(false, false); bStatus = true; } } } #endif return bStatus; }
err_t prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr ) { USHORT usLength; err_t error; if( xErr != ERR_OK ) { return xErr; } /* If pbuf is NULL then remote end has closed connection. */ if( p == NULL ) { prvvMBPortReleaseClient( pxPCB ); return ERR_OK; } /* Acknowledge that we have received the data bytes. */ tcp_recved( pxPCB, p->len ); /* Check for internal buffer overflow. In case of an error drop the * client. */ if( ( usTCPBufPos + p->len ) >= MB_TCP_BUF_SIZE ) { prvvMBPortReleaseClient( pxPCB ); error = ERR_OK; } else { memcpy( &aucTCPBuf[usTCPBufPos], p->payload, p->len ); usTCPBufPos += p->len; /* If we have received the MBAP header we can analyze it and calculate * the number of bytes left to complete the current request. If complete * notify the protocol stack. */ if( usTCPBufPos >= MB_TCP_FUNC ) { /* Length is a byte count of Modbus PDU (function code + data) and the * unit identifier. */ usLength = aucTCPBuf[MB_TCP_LEN] << 8U; usLength |= aucTCPBuf[MB_TCP_LEN + 1]; /* Is the frame already complete. */ if( usTCPBufPos < ( MB_TCP_UID + usLength ) ) { } else if( usTCPBufPos == ( MB_TCP_UID + usLength ) ) { #ifdef MB_TCP_DEBUG prvvMBTCPLogFrame( "MBTCP-RECV", &aucTCPBuf[0], usTCPBufPos ); #endif ( void )xMBPortEventPost( EV_FRAME_RECEIVED ); } else { #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Received to many bytes! Droping client.\r\n" ); #endif /* This should not happen. We can't deal with such a client and * drop the connection for security reasons. */ prvvMBPortReleaseClient( pxPCB ); } } } pbuf_free( p ); return error; }
BOOL xMBPortSerialInit( UCHAR ucPort, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) { TCHAR szDevice[8]; BOOL bStatus = TRUE; DCB dcb; memset( &dcb, 0, sizeof( dcb ) ); dcb.DCBlength = sizeof( dcb ); dcb.BaudRate = ulBaudRate; _stprintf_s( szDevice, 8, _T( "COM%d" ), ucPort ); switch ( eParity ) { case MB_PAR_NONE: dcb.Parity = NOPARITY; dcb.fParity = 0; break; case MB_PAR_EVEN: dcb.Parity = EVENPARITY; dcb.fParity = 1; break; case MB_PAR_ODD: dcb.Parity = ODDPARITY; dcb.fParity = 1; break; default: bStatus = FALSE; } switch ( ucDataBits ) { case 8: dcb.ByteSize = 8; break; case 7: dcb.ByteSize = 7; break; default: bStatus = FALSE; } if( bStatus ) { /* we don't use XON/XOFF flow control. */ dcb.fInX = dcb.fOutX = FALSE; /* we don't need hardware handshake. */ dcb.fOutxCtsFlow = dcb.fOutxCtsFlow = FALSE; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fDtrControl = DTR_CONTROL_ENABLE; /* misc parameters */ dcb.fErrorChar = FALSE; dcb.fBinary = TRUE; dcb.fNull = FALSE; dcb.fAbortOnError = FALSE; dcb.wReserved = 0; dcb.XonLim = 2; dcb.XoffLim = 4; dcb.XonChar = 0x13; dcb.XoffChar = 0x19; dcb.EvtChar = 0; /* Open the serial device. */ g_hSerial = CreateFile( szDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); if( g_hSerial == INVALID_HANDLE_VALUE ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-INIT" ), _T( "Can't open serial port %s: %s" ), szDevice, Error2String( GetLastError( ) ) ); bStatus = FALSE; } else if( !SetCommState( g_hSerial, &dcb ) ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-INIT" ), _T( "Can't set settings for serial device %s: %s" ), szDevice, Error2String( GetLastError( ) ) ); bStatus = FALSE; } else if( !SetCommMask( g_hSerial, 0 ) ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-INIT" ), _T( "Can't set communication event mask for serial device %s: %s" ), szDevice, Error2String( GetLastError( ) ) ); bStatus = FALSE; } else { vMBPortSerialEnable( FALSE, FALSE ); bStatus = TRUE; } } return bStatus; }
BOOL xMBPortSerialInit( UCHAR ucPort, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) { CHAR szDevice[16]; BOOL bStatus = TRUE; struct termios xNewTIO; speed_t xNewSpeed; if(ucPort != 255) { snprintf( szDevice, 16, "/dev/ttyS%d", ucPort ); } else { snprintf( szDevice, 16, "%s", devString ); } if( ( iSerialFd = open( szDevice, O_RDWR | O_NOCTTY ) ) < 0 ) { vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't open serial port %s: %s\n", szDevice, strerror( errno ) ); bStatus = FALSE; } else if( tcgetattr( iSerialFd, &xOldTIO ) != 0 ) { vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't get settings from port %s: %s\n", szDevice, strerror( errno ) ); bStatus = FALSE; } else { bzero( &xNewTIO, sizeof( struct termios ) ); xNewTIO.c_iflag |= IGNBRK | INPCK; xNewTIO.c_cflag |= CREAD | CLOCAL; switch ( eParity ) { case MB_PAR_NONE: break; case MB_PAR_EVEN: xNewTIO.c_cflag |= PARENB; break; case MB_PAR_ODD: xNewTIO.c_cflag |= PARENB | PARODD; break; default: bStatus = FALSE; } switch ( ucDataBits ) { case 8: xNewTIO.c_cflag |= CS8; break; case 7: xNewTIO.c_cflag |= CS7; break; default: bStatus = FALSE; } switch ( ulBaudRate ) { case 9600: xNewSpeed = B9600; break; case 19200: xNewSpeed = B19200; break; case 38400: xNewSpeed = B38400; break; case 57600: xNewSpeed = B57600; break; case 115200: xNewSpeed = B115200; break; default: bStatus = FALSE; } if( bStatus ) { if( cfsetispeed( &xNewTIO, xNewSpeed ) != 0 ) { vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %s\n", ulBaudRate, strerror( errno ) ); } else if( cfsetospeed( &xNewTIO, xNewSpeed ) != 0 ) { vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %s\n", ulBaudRate, szDevice, strerror( errno ) ); } else if( tcsetattr( iSerialFd, TCSANOW, &xNewTIO ) != 0 ) { vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set settings for port %s: %s\n", szDevice, strerror( errno ) ); } else { vMBPortSerialEnable( FALSE, FALSE ); bStatus = TRUE; } } } return bStatus; }