diff --git a/ChangeLog.txt b/ChangeLog.txt index d20abd343..9edc37c4e 100755 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -255,5 +255,7 @@ has been added to the NuttX apps/ source tree. * apps/examples/modbus: A port of the freemodbus-v1.5.0 "demo" program that will be used to verify the FreeModBus port - - + * apps/modbus: Don't use strerror(). It is just too big. + * apps/modbus: Add CONFIG_MB_TERMIOS. If the driver doesn't support + termios ioctls, then don't bother trying to configure the baud, parity + etc. diff --git a/modbus/Kconfig b/modbus/Kconfig index da95abf6a..d4c93fdae 100644 --- a/modbus/Kconfig +++ b/modbus/Kconfig @@ -24,6 +24,15 @@ config MB_TCP_ENABLED depends on MODBUS default y +config MB_TERMIOS + bool "Driver TERMIOS supported" + depends on MB_ASCII_ENABLED || MB_RTU_ENABLED + default n + ---help--- + Serial driver supports termios.h interfaces (tcsetattr, tcflush, etc.). + If this is not defined, then the terminal settings (baud, parity, etc). + are not configurable at runtime; serial streams will not be flushed when closed. + config MB_ASCII_TIMEOUT_SEC int "Character timeout" depends on MB_ASCII_ENABLED diff --git a/modbus/README.txt b/modbus/README.txt index 1f2c9c3eb..46b6b2b0e 100644 --- a/modbus/README.txt +++ b/modbus/README.txt @@ -60,6 +60,10 @@ The NuttX-named configuration options that are available include: CONFIG_MB_ASCII_ENABLED - Modbus ASCII support CONFIG_MB_RTU_ENABLED - Modbus RTU support CONFIG_MB_TCP_ENABLED - Modbus TCP support + CONFIG_MB_TERMIOS - Serial driver supports termios.h interfaces (tcsetattr, + tcflush, etc.). If this is not defined, then the terminal settings (baud, + parity, etc.) are not configurable at runtime; serial streams will not be + flushed when closed. CONFIG_MB_ASCII_TIMEOUT_SEC - Character timeout value for Modbus ASCII. The character timeout value is not fixed for Modbus ASCII and is therefore a configuration option. It should be set to the maximum expected delay diff --git a/modbus/nuttx/portother.c b/modbus/nuttx/portother.c index 12f79defe..fef826760 100644 --- a/modbus/nuttx/portother.c +++ b/modbus/nuttx/portother.c @@ -22,6 +22,7 @@ */ /* ----------------------- Standard includes --------------------------------*/ + #include #include #include @@ -33,72 +34,73 @@ #include "port.h" /* ----------------------- Modbus includes ----------------------------------*/ + #include #include /* ----------------------- Defines ------------------------------------------*/ -#define NELEMS( x ) ( sizeof( ( x ) )/sizeof( ( x )[0] ) ) + +#define NELEMS(x) (sizeof((x))/sizeof((x)[0])) /* ----------------------- Static variables ---------------------------------*/ + static FILE *fLogFile = NULL; static eMBPortLogLevel eLevelMax = MB_LOG_DEBUG; static pthread_mutex_t xLock = PTHREAD_MUTEX_INITIALIZER; /* ----------------------- Start implementation -----------------------------*/ -void -vMBPortLogLevel( eMBPortLogLevel eNewLevelMax ) + +void vMBPortLogLevel(eMBPortLogLevel eNewLevelMax) { - eLevelMax = eNewLevelMax; + eLevelMax = eNewLevelMax; } -void -vMBPortLogFile( FILE * fNewLogFile ) +void vMBPortLogFile(FILE * fNewLogFile) { - fLogFile = fNewLogFile; + fLogFile = fNewLogFile; } -void -vMBPortLog( eMBPortLogLevel eLevel, const char * szModule, const char * szFmt, ... ) +void vMBPortLog(eMBPortLogLevel eLevel, const char * szModule, const char * szFmt, ...) { - char szBuf[512]; - int i; - va_list args; - FILE *fOutput = fLogFile == NULL ? stderr : fLogFile; + char szBuf[512]; + int i; + va_list args; + FILE *fOutput = fLogFile == NULL ? stderr : fLogFile; - static const char *arszLevel2Str[] = { "ERROR", "WARN", "INFO", "DEBUG" }; + static const char *arszLevel2Str[] = { "ERROR", "WARN", "INFO", "DEBUG" }; - i = snprintf( szBuf, NELEMS( szBuf ), "%s: %s: ", arszLevel2Str[eLevel], szModule ); + i = snprintf(szBuf, NELEMS(szBuf), "%s: %s: ", arszLevel2Str[eLevel], szModule); - if( i != 0 ) + if (i != 0) { - va_start( args, szFmt ); - i += vsnprintf( &szBuf[i], NELEMS( szBuf ) - i, szFmt, args ); - va_end( args ); + va_start(args, szFmt); + i += vsnprintf(&szBuf[i], NELEMS(szBuf) - i, szFmt, args); + va_end(args); } - if( i != 0 ) + if (i != 0) { - if( eLevel <= eLevelMax ) + if (eLevel <= eLevelMax) { - fputs( szBuf, fOutput ); + fputs(szBuf, fOutput); } } } -void -vMBPortEnterCritical( void ) +void vMBPortEnterCritical(void) { - if( pthread_mutex_lock( &xLock ) != 0 ) + int ret = pthread_mutex_lock(&xLock); + if (ret != 0) { - vMBPortLog( MB_LOG_ERROR, "OTHER", "Locking primitive failed: %s\n", strerror( errno ) ); + vMBPortLog(MB_LOG_ERROR, "OTHER", "Locking primitive failed: %d\n", ret); } } -void -vMBPortExitCritical( void ) +void vMBPortExitCritical(void) { - if( pthread_mutex_unlock( &xLock ) != 0 ) + int ret = pthread_mutex_unlock(&xLock); + if (ret != 0) { - vMBPortLog( MB_LOG_ERROR, "OTHER", "Locking primitive failed: %s\n", strerror( errno ) ); + vMBPortLog(MB_LOG_ERROR, "OTHER", "Locking primitive failed: %d\n", ret); } } diff --git a/modbus/nuttx/portserial.c b/modbus/nuttx/portserial.c index f62166373..bf862bd22 100644 --- a/modbus/nuttx/portserial.c +++ b/modbus/nuttx/portserial.c @@ -22,6 +22,7 @@ */ /* ----------------------- Standard includes --------------------------------*/ + #include #include #include @@ -31,17 +32,22 @@ #include #include #include -#include #include #include +#ifdef CONFIG_MB_TERMIOS +# include +#endif + #include "port.h" /* ----------------------- Modbus includes ----------------------------------*/ + #include #include /* ----------------------- Defines -----------------------------------------*/ + #ifdef CONFIG_MB_ASCII_ENABLED #define BUF_SIZE 513 /* must hold a complete ASCII frame. */ #else @@ -49,6 +55,7 @@ #endif /* ----------------------- Static variables ---------------------------------*/ + static int iSerialFd = -1; static bool bRxEnabled; static bool bTxEnabled; @@ -58,277 +65,298 @@ static uint8_t ucBuffer[BUF_SIZE]; static int uiRxBufferPos; static int uiTxBufferPos; +#ifdef CONFIG_MB_TERMIOS static struct termios xOldTIO; +#endif /* ----------------------- Function prototypes ------------------------------*/ -static bool prvbMBPortSerialRead( uint8_t * pucBuffer, uint16_t usNBytes, uint16_t * usNBytesRead ); -static bool prvbMBPortSerialWrite( uint8_t * pucBuffer, uint16_t usNBytes ); + +static bool prvbMBPortSerialRead(uint8_t *pucBuffer, uint16_t usNBytes, uint16_t *usNBytesRead); +static bool prvbMBPortSerialWrite(uint8_t *pucBuffer, uint16_t usNBytes); /* ----------------------- Begin implementation -----------------------------*/ -void -vMBPortSerialEnable( bool bEnableRx, bool bEnableTx ) -{ - /* it is not allowed that both receiver and transmitter are enabled. */ - ASSERT( !bEnableRx || !bEnableTx ); - if( bEnableRx ) +void vMBPortSerialEnable(bool bEnableRx, bool bEnableTx) +{ + /* it is not allowed that both receiver and transmitter are enabled. */ + + ASSERT(!bEnableRx || !bEnableTx); + + if (bEnableRx) { - ( void )tcflush( iSerialFd, TCIFLUSH ); - uiRxBufferPos = 0; - bRxEnabled = true; +#ifdef CONFIG_MB_TERMIOS + (void)tcflush(iSerialFd, TCIFLUSH); +#endif + uiRxBufferPos = 0; + bRxEnabled = true; } - else + else { - bRxEnabled = false; + bRxEnabled = false; } - if( bEnableTx ) + + if (bEnableTx) { - bTxEnabled = true; - uiTxBufferPos = 0; + bTxEnabled = true; + uiTxBufferPos = 0; } - else + else { - bTxEnabled = false; + bTxEnabled = false; } } -bool -xMBPortSerialInit( uint8_t ucPort, uint32_t ulBaudRate, uint8_t ucDataBits, eMBParity eParity ) +bool xMBPortSerialInit(uint8_t ucPort, uint32_t ulBaudRate, + uint8_t ucDataBits, eMBParity eParity) { - char szDevice[16]; - bool bStatus = true; + char szDevice[16]; + bool bStatus = true; - struct termios xNewTIO; - speed_t xNewSpeed; +#ifdef CONFIG_MB_TERMIOS + struct termios xNewTIO; + speed_t xNewSpeed; +#endif - snprintf( szDevice, 16, "/dev/ttyS%d", ucPort ); + snprintf(szDevice, 16, "/dev/ttyS%d", ucPort); - if( ( iSerialFd = open( szDevice, O_RDWR | O_NOCTTY ) ) < 0 ) + 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 ) ); + vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't open serial port %s: %d\n", + szDevice, errno); } - else if( tcgetattr( iSerialFd, &xOldTIO ) != 0 ) - { - vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't get settings from port %s: %s\n", szDevice, - strerror( errno ) ); - } - else - { - bzero( &xNewTIO, sizeof( struct termios ) ); - xNewTIO.c_iflag |= IGNBRK | INPCK; - xNewTIO.c_cflag |= CREAD | CLOCAL; - switch ( eParity ) +#ifdef CONFIG_MB_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: + case MB_PAR_NONE: break; - case MB_PAR_EVEN: + case MB_PAR_EVEN: xNewTIO.c_cflag |= PARENB; break; - case MB_PAR_ODD: + case MB_PAR_ODD: xNewTIO.c_cflag |= PARENB | PARODD; break; - default: + default: bStatus = false; } - switch ( ucDataBits ) + + switch (ucDataBits) { - case 8: + case 8: xNewTIO.c_cflag |= CS8; break; - case 7: + case 7: xNewTIO.c_cflag |= CS7; break; - default: + default: bStatus = false; } - switch ( ulBaudRate ) + + switch (ulBaudRate) { - case 9600: + case 9600: xNewSpeed = B9600; break; - case 19200: + case 19200: xNewSpeed = B19200; break; - case 38400: + case 38400: xNewSpeed = B38400; break; - case 57600: + case 57600: xNewSpeed = B57600; break; - case 115200: + case 115200: xNewSpeed = B115200; break; - default: + default: bStatus = false; } - if( bStatus ) + + if (bStatus) { - if( cfsetispeed( &xNewTIO, xNewSpeed ) != 0 ) + 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 ) ); + vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %d\n", + ulBaudRate, errno); } - else if( cfsetospeed( &xNewTIO, xNewSpeed ) != 0 ) + 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 ) ); + 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 ) + 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 ) ); + vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't set settings for port %s: %d\n", + szDevice, errno); } - else + else { - vMBPortSerialEnable( false, false ); - bStatus = true; + vMBPortSerialEnable(false, false); + bStatus = true; } } } - return bStatus; +#endif + + return bStatus; +} + +bool xMBPortSerialSetTimeout(uint32_t ulNewTimeoutMs) +{ + if (ulNewTimeoutMs > 0) + { + ulTimeoutMs = ulNewTimeoutMs; + } + else + { + ulTimeoutMs = 1; + } + + return true; +} + +void vMBPortClose(void) +{ + if (iSerialFd != -1) + { +#ifdef CONFIG_MB_TERMIOS + (void)tcsetattr(iSerialFd, TCSANOW, &xOldTIO); +#endif + (void)close(iSerialFd); + iSerialFd = -1; + } +} + +bool prvbMBPortSerialRead(uint8_t *pucBuffer, uint16_t usNBytes, uint16_t *usNBytesRead) +{ + bool bResult = true; + ssize_t res; + fd_set rfds; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 50000; + FD_ZERO(&rfds); + FD_SET(iSerialFd, &rfds); + + /* Wait until character received or timeout. Recover in case of an + * interrupted read system call. + */ + + do + { + if (select(iSerialFd + 1, &rfds, NULL, NULL, &tv) == -1) + { + if (errno != EINTR) + { + bResult = false; + } + } + else if (FD_ISSET(iSerialFd, &rfds)) + { + if ((res = read(iSerialFd, pucBuffer, usNBytes)) == -1) + { + bResult = false; + } + else + { + *usNBytesRead = (uint16_t)res; + break; + } + } + else + { + *usNBytesRead = 0; + break; + } + } + + while(bResult == true); + return bResult; +} + +bool prvbMBPortSerialWrite(uint8_t *pucBuffer, uint16_t usNBytes) +{ + ssize_t res; + size_t left = (size_t) usNBytes; + size_t done = 0; + + while(left > 0) + { + if ((res = write(iSerialFd, pucBuffer + done, left)) == -1) + { + if (errno != EINTR) + { + break; + } + + /* call write again because of interrupted system call. */ + continue; + } + + done += res; + left -= res; + } + + return left == 0 ? true : false; } bool -xMBPortSerialSetTimeout( uint32_t ulNewTimeoutMs ) -{ - if( ulNewTimeoutMs > 0 ) - { - ulTimeoutMs = ulNewTimeoutMs; - } - else - { - ulTimeoutMs = 1; - } - return true; -} - -void -vMBPortClose( void ) -{ - if( iSerialFd != -1 ) - { - ( void )tcsetattr( iSerialFd, TCSANOW, &xOldTIO ); - ( void )close( iSerialFd ); - iSerialFd = -1; - } -} - -bool -prvbMBPortSerialRead( uint8_t * pucBuffer, uint16_t usNBytes, uint16_t * usNBytesRead ) -{ - bool bResult = true; - ssize_t res; - fd_set rfds; - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 50000; - FD_ZERO( &rfds ); - FD_SET( iSerialFd, &rfds ); - - /* Wait until character received or timeout. Recover in case of an - * interrupted read system call. */ - do - { - if( select( iSerialFd + 1, &rfds, NULL, NULL, &tv ) == -1 ) - { - if( errno != EINTR ) - { - bResult = false; - } - } - else if( FD_ISSET( iSerialFd, &rfds ) ) - { - if( ( res = read( iSerialFd, pucBuffer, usNBytes ) ) == -1 ) - { - bResult = false; - } - else - { - *usNBytesRead = ( uint16_t ) res; - break; - } - } - else - { - *usNBytesRead = 0; - break; - } - } - while( bResult == true ); - return bResult; -} - -bool -prvbMBPortSerialWrite( uint8_t * pucBuffer, uint16_t usNBytes ) -{ - ssize_t res; - size_t left = ( size_t ) usNBytes; - size_t done = 0; - - while( left > 0 ) - { - if( ( res = write( iSerialFd, pucBuffer + done, left ) ) == -1 ) - { - if( errno != EINTR ) - { - break; - } - /* call write again because of interrupted system call. */ - continue; - } - done += res; - left -= res; - } - return left == 0 ? true : false; -} - -bool -xMBPortSerialPoll( ) +xMBPortSerialPoll() { bool bStatus = true; uint16_t usBytesRead; int i; - while( bRxEnabled ) + while(bRxEnabled) { - if( prvbMBPortSerialRead( &ucBuffer[0], BUF_SIZE, &usBytesRead ) ) + if (prvbMBPortSerialRead(&ucBuffer[0], BUF_SIZE, &usBytesRead)) { - if( usBytesRead == 0 ) + if (usBytesRead == 0) { /* timeout with no bytes. */ break; } - else if( usBytesRead > 0 ) + else if (usBytesRead > 0) { - for( i = 0; i < usBytesRead; i++ ) + for(i = 0; i < usBytesRead; i++) { /* Call the modbus stack and let him fill the buffers. */ - ( void )pxMBFrameCBByteReceived( ); + (void)pxMBFrameCBByteReceived(); } uiRxBufferPos = 0; } } else { - vMBPortLog( MB_LOG_ERROR, "SER-POLL", "read failed on serial device: %s\n", - strerror( errno ) ); + vMBPortLog(MB_LOG_ERROR, "SER-POLL", "read failed on serial device: %d\n", + errno); bStatus = false; } } - if( bTxEnabled ) + if (bTxEnabled) { - while( bTxEnabled ) + while(bTxEnabled) { - ( void )pxMBFrameCBTransmitterEmpty( ); + (void)pxMBFrameCBTransmitterEmpty(); /* Call the modbus stack to let him fill the buffer. */ } - if( !prvbMBPortSerialWrite( &ucBuffer[0], uiTxBufferPos ) ) + if (!prvbMBPortSerialWrite(&ucBuffer[0], uiTxBufferPos)) { - vMBPortLog( MB_LOG_ERROR, "SER-POLL", "write failed on serial device: %s\n", - strerror( errno ) ); + vMBPortLog(MB_LOG_ERROR, "SER-POLL", "write failed on serial device: %d\n", + errno); bStatus = false; } } @@ -337,18 +365,18 @@ xMBPortSerialPoll( ) } bool -xMBPortSerialPutByte( int8_t ucByte ) +xMBPortSerialPutByte(int8_t ucByte) { - ASSERT( uiTxBufferPos < BUF_SIZE ); + ASSERT(uiTxBufferPos < BUF_SIZE); ucBuffer[uiTxBufferPos] = ucByte; uiTxBufferPos++; return true; } bool -xMBPortSerialGetByte( int8_t * pucByte ) +xMBPortSerialGetByte(int8_t *pucByte) { - ASSERT( uiRxBufferPos < BUF_SIZE ); + ASSERT(uiRxBufferPos < BUF_SIZE); *pucByte = ucBuffer[uiRxBufferPos]; uiRxBufferPos++; return true;