⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mbrtu.c

📁 freemodbus-v1-1-1-0.zip v1.1.1版本的代码 支持多个平台
💻 C
字号:
 /*  * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.  * Copyright (C) 2006 Christian Walter <wolti@sil.at>  *  * This library is free software; you can redistribute it and/or  * modify it under the terms of the GNU Lesser General Public  * License as published by the Free Software Foundation; either  * version 2.1 of the License, or (at your option) any later version.  *  * This library is distributed in the hope that it will be useful,  * but WITHOUT ANY WARRANTY; without even the implied warranty of  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  * Lesser General Public License for more details.  *  * You should have received a copy of the GNU Lesser General Public  * License along with this library; if not, write to the Free Software  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *  * File: $Id: mbrtu.c,v 1.14 2006/11/19 03:04:11 wolti Exp $  *//* ----------------------- System includes ----------------------------------*/#include "stdlib.h"#include "string.h"/* ----------------------- Platform includes --------------------------------*/#include "port.h"/* ----------------------- Modbus includes ----------------------------------*/#include "mb.h"#include "mbrtu.h"#include "mbframe.h"#include "mbcrc.h"#include "mbport.h"/* ----------------------- Defines ------------------------------------------*/#define MB_SER_PDU_SIZE_MIN     4       /*!< Minimum size of a Modbus RTU frame. */#define MB_SER_PDU_SIZE_MAX     256     /*!< Maximum size of a Modbus RTU frame. */#define MB_SER_PDU_SIZE_CRC     2       /*!< Size of CRC field in PDU. */#define MB_SER_PDU_ADDR_OFF     0       /*!< Offset of slave address in Ser-PDU. */#define MB_SER_PDU_PDU_OFF      1       /*!< Offset of Modbus-PDU in Ser-PDU. *//* ----------------------- Type definitions ---------------------------------*/typedef enum{    STATE_RX_INIT,              /*!< Receiver is in initial state. */    STATE_RX_IDLE,              /*!< Receiver is in idle state. */    STATE_RX_RCV,               /*!< Frame is beeing received. */    STATE_RX_ERROR              /*!< If the frame is invalid. */} eMBRcvState;typedef enum{    STATE_TX_IDLE,              /*!< Transmitter is in idle state. */    STATE_TX_XMIT               /*!< Transmitter is in transfer state. */} eMBSndState;/* ----------------------- Static variables ---------------------------------*/static volatile eMBSndState eSndState;static volatile eMBRcvState eRcvState;volatile UCHAR  ucRTUBuf[MB_SER_PDU_SIZE_MAX];static volatile UCHAR *pucSndBufferCur;static volatile USHORT usSndBufferCount;static volatile USHORT usRcvBufferPos;/* ----------------------- Start implementation -----------------------------*/eMBErrorCodeeMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity ){    eMBErrorCode    eStatus = MB_ENOERR;    ULONG           usTimerT35_50us;    ENTER_CRITICAL_SECTION(  );    /* Modbus RTU uses 8 Databits. */    if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE )    {        eStatus = MB_EPORTERR;    }    /* If baudrate > 19200 then we should use the fixed timer values     * t35 = 1750us. Otherwise t35 must be 3.5 times the character time.     */    if( ulBaudRate > 19200 )    {        usTimerT35_50us = 35;   /* 1800us. */    }    else    {        /* The timer reload value for a character is given by:         *         * ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )         *             = 11 * Ticks_per_1s / Baudrate         *             = 220000 / Baudrate         * The reload for t3.5 is 1.5 times this value and similary         * for t3.5.         */        usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );    }    if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )    {        eStatus = MB_EPORTERR;    }    EXIT_CRITICAL_SECTION(  );    return eStatus;}voideMBRTUStart( void ){    ENTER_CRITICAL_SECTION(  );    /* Initially the receiver is in the state STATE_RX_INIT. we start     * the timer and if no character is received within t3.5 we change     * to STATE_RX_IDLE. This makes sure that we delay startup of the     * modbus protocol stack until the bus is free.     */    eRcvState = STATE_RX_INIT;    vMBPortSerialEnable( TRUE, FALSE );    vMBPortTimersEnable(  );    EXIT_CRITICAL_SECTION(  );}voideMBRTUStop( void ){    ENTER_CRITICAL_SECTION(  );    vMBPortSerialEnable( FALSE, FALSE );    vMBPortTimersDisable(  );    EXIT_CRITICAL_SECTION(  );}eMBErrorCodeeMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength ){    BOOL            xFrameReceived = FALSE;    eMBErrorCode    eStatus = MB_ENOERR;    ENTER_CRITICAL_SECTION(  );    assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );    /* Length and CRC check */    if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )        && ( usMBCRC16( ( UCHAR * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )    {        /* Save the address field. All frames are passed to the upper layed         * and the decision if a frame is used is done there.         */        *pucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF];        /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus         * size of address field and CRC checksum.         */        *pusLength = usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC;        /* Return the start of the Modbus PDU to the caller. */        *pucFrame = ( UCHAR * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];        xFrameReceived = TRUE;    }    else    {        eStatus = MB_EIO;    }    EXIT_CRITICAL_SECTION(  );    return eStatus;}eMBErrorCodeeMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength ){    eMBErrorCode    eStatus = MB_ENOERR;    USHORT          usCRC16;    ENTER_CRITICAL_SECTION(  );    /* Check if the receiver is still in idle state. If not we where to     * slow with processing the received frame and the master sent another     * frame on the network. We have to abort sending the frame.     */    if( eRcvState == STATE_RX_IDLE )    {        /* First byte before the Modbus-PDU is the slave address. */        pucSndBufferCur = ( UCHAR * ) pucFrame - 1;        usSndBufferCount = 1;        /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */        pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;        usSndBufferCount += usLength;        /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */        usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );        ucRTUBuf[usSndBufferCount++] = usCRC16 & 0xFF;        ucRTUBuf[usSndBufferCount++] = usCRC16 >> 8;        /* Activate the transmitter. */        eSndState = STATE_TX_XMIT;        vMBPortSerialEnable( FALSE, TRUE );    }    else    {        eStatus = MB_EIO;    }    EXIT_CRITICAL_SECTION(  );    return eStatus;}BOOLxMBRTUReceiveFSM( void ){    BOOL            xTaskNeedSwitch = FALSE;    UCHAR           ucByte;    assert( eSndState == STATE_TX_IDLE );    switch ( eRcvState )    {        /* If we have received a character in the init state we have to         * wait until the frame is finished.         */    case STATE_RX_INIT:        vMBPortTimersEnable(  );        break;        /* In the error state we wait until all characters in the         * damaged frame are transmitted.         */    case STATE_RX_ERROR:        vMBPortTimersEnable(  );        break;        /* In the idle state we wait for a new character. If a character         * is received the t1.5 and t3.5 timers are started and the         * receiver is in the state STATE_RX_RECEIVCE.         */    case STATE_RX_IDLE:        usRcvBufferPos = 0;        ( void )xMBPortSerialGetByte( ( CHAR * )&ucByte );        ucRTUBuf[usRcvBufferPos++] = ucByte;        eRcvState = STATE_RX_RCV;        /* Enable t3.5 timers. */        vMBPortTimersEnable(  );        break;        /* We are currently receiving a frame. Reset the timer after         * every character received. If more than the maximum possible         * number of bytes in a modbus frame is received the frame is         * ignored.         */    case STATE_RX_RCV:        if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )        {            ( void )xMBPortSerialGetByte( ( CHAR * )&ucByte );            ucRTUBuf[usRcvBufferPos++] = ucByte;        }        else        {            eRcvState = STATE_RX_ERROR;        }        vMBPortTimersEnable(  );        break;    }    return xTaskNeedSwitch;}BOOLxMBRTUTransmitFSM( void ){    BOOL            xNeedPoll = FALSE;    assert( eRcvState == STATE_RX_IDLE );    switch ( eSndState )    {        /* We should not get a transmitter event if the transmitter is in         * idle state.  */    case STATE_TX_IDLE:        /* enable receiver/disable transmitter. */        vMBPortSerialEnable( TRUE, FALSE );        break;    case STATE_TX_XMIT:        /* check if we are finished. */        if( usSndBufferCount != 0 )        {            xMBPortSerialPutByte( *pucSndBufferCur );            pucSndBufferCur++;  /* next byte in sendbuffer. */            usSndBufferCount--;        }        else        {            xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );            /* Disable transmitter. This prevents another transmit buffer             * empty interrupt. */            vMBPortSerialEnable( TRUE, FALSE );            eSndState = STATE_TX_IDLE;        }        break;    }    return xNeedPoll;}BOOLxMBRTUTimerT35Expired( void ){    BOOL            xNeedPoll = FALSE;    switch ( eRcvState )    {        /* Timer t35 expired. Startup phase is finished. */    case STATE_RX_INIT:        xNeedPoll = xMBPortEventPost( EV_READY );        break;        /* A frame was received and t35 expired. Notify the listener that         * a new frame was received. */    case STATE_RX_RCV:        xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );        break;        /* An error occured while receiving the frame. */    case STATE_RX_ERROR:        break;        /* Function called in an illegal state. */    default:        assert( ( eRcvState == STATE_RX_INIT ) ||                ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );    }    vMBPortTimersDisable(  );    eRcvState = STATE_RX_IDLE;    return xNeedPoll;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -