예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
        }
    }
}
예제 #4
0
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;
}
예제 #5
0
void vMBPortExitCritical(void)
{
  int ret = pthread_mutex_unlock(&xLock);
  if (ret != 0)
    {
      vMBPortLog(MB_LOG_ERROR, "OTHER", "Locking primitive failed: %d\n", ret);
    }
}
예제 #6
0
/* 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 );
    }
}
예제 #7
0
/* ----------------------- 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;
}
예제 #8
0
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;
}
예제 #9
0
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;
}
예제 #10
0
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;
}
예제 #11
0
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;
}
예제 #12
0
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;
}