mbrtu.c
上传用户:kongshuqi
上传日期:2013-10-09
资源大小:59k
文件大小:11k
源码类别:

通讯编程

开发平台:

Visual C++

  1.  /*
  2.   * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
  3.   * Copyright (C) 2006 Christian Walter <wolti@sil.at>
  4.   *
  5.   * This library is free software; you can redistribute it and/or
  6.   * modify it under the terms of the GNU Lesser General Public
  7.   * License as published by the Free Software Foundation; either
  8.   * version 2.1 of the License, or (at your option) any later version.
  9.   *
  10.   * This library is distributed in the hope that it will be useful,
  11.   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.   * Lesser General Public License for more details.
  14.   *
  15.   * You should have received a copy of the GNU Lesser General Public
  16.   * License along with this library; if not, write to the Free Software
  17.   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18.   *
  19.   * File: $Id: mbrtu.c,v 1.11 2006/06/18 09:57:03 wolti Exp $
  20.   */
  21. /* ----------------------- System includes ----------------------------------*/
  22. #include "stdlib.h"
  23. #include "string.h"
  24. /* ----------------------- Platform includes --------------------------------*/
  25. #include "port.h"
  26. /* ----------------------- Modbus includes ----------------------------------*/
  27. #include "mb.h"
  28. #include "mbrtu.h"
  29. #include "mbframe.h"
  30. #include "mbcrc.h"
  31. #include "mbport.h"
  32. /* ----------------------- Defines ------------------------------------------*/
  33. #define MB_SER_PDU_SIZE_MIN     4       /*!< Minimum size of a Modbus RTU frame. */
  34. #define MB_SER_PDU_SIZE_MAX     256     /*!< Maximum size of a Modbus RTU frame. */
  35. #define MB_SER_PDU_SIZE_CRC     2       /*!< Size of CRC field in PDU. */
  36. #define MB_SER_PDU_ADDR_OFF     0       /*!< Offset of slave address in Ser-PDU. */
  37. #define MB_SER_PDU_PDU_OFF      1       /*!< Offset of Modbus-PDU in Ser-PDU. */
  38. /* ----------------------- Type definitions ---------------------------------*/
  39. typedef enum
  40. {
  41.     STATE_RX_INIT,              /*!< Receiver is in initial state. */
  42.     STATE_RX_IDLE,              /*!< Receiver is in idle state. */
  43.     STATE_RX_RCV,               /*!< Frame is beeing received. */
  44.     STATE_RX_ERROR,             /*!< If the frame is invalid. */
  45. } eMBRcvState;
  46. typedef enum
  47. {
  48.     STATE_TX_IDLE,              /*!< Transmitter is in idle state. */
  49.     STATE_TX_XMIT,              /*!< Transmitter is in transfer state. */
  50. } eMBSndState;
  51. /* ----------------------- Static variables ---------------------------------*/
  52. static volatile eMBSndState eSndState;
  53. static volatile eMBRcvState eRcvState;
  54. volatile UCHAR  ucRTUBuf[MB_SER_PDU_SIZE_MAX];
  55. static volatile UCHAR *pucSndBufferCur;
  56. static volatile USHORT usSndBufferCount;
  57. static volatile USHORT usRcvBufferPos;
  58. /* ----------------------- Start implementation -----------------------------*/
  59. eMBErrorCode
  60. eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate,
  61.             eMBParity eParity )
  62. {
  63.     eMBErrorCode    eStatus = MB_ENOERR;
  64.     ULONG           usTimerT35_50us;
  65.     ENTER_CRITICAL_SECTION(  );
  66.     /* Modbus RTU uses 8 Databits. */
  67.     if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE )
  68.     {
  69.         eStatus = MB_EPORTERR;
  70.     }
  71.     /* If baudrate > 19200 then we should use the fixed timer values
  72.      * t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
  73.      */
  74.     if( ulBaudRate > 19200 )
  75.     {
  76.         usTimerT35_50us = 35;   /* 1800us. */
  77.     }
  78.     else
  79.     {
  80.         /* The timer reload value for a character is given by:
  81.          *
  82.          * ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )
  83.          *             = 11 * Ticks_per_1s / Baudrate
  84.          *             = 220000 / Baudrate
  85.          * The reload for t3.5 is 1.5 times this value and similary
  86.          * for t3.5.
  87.          */
  88.         usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
  89.     }
  90.     if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )
  91.     {
  92.         eStatus = MB_EPORTERR;
  93.     }
  94.     EXIT_CRITICAL_SECTION(  );
  95.     return eStatus;
  96. }
  97. void
  98. eMBRTUStart( void )
  99. {
  100.     ENTER_CRITICAL_SECTION(  );
  101.     /* Initially the receiver is in the state STATE_RX_INIT. we start
  102.      * the timer and if no character is received within t3.5 we change
  103.      * to STATE_RX_IDLE. This makes sure that we delay startup of the
  104.      * modbus protocol stack until the bus is free.
  105.      */
  106.     eRcvState = STATE_RX_INIT;
  107.     vMBPortSerialEnable( TRUE, FALSE );
  108.     vMBPortTimersEnable(  );
  109.     EXIT_CRITICAL_SECTION(  );
  110. }
  111. void
  112. eMBRTUStop( void )
  113. {
  114.     ENTER_CRITICAL_SECTION(  );
  115.     vMBPortSerialEnable( FALSE, FALSE );
  116.     vMBPortTimersDisable(  );
  117.     EXIT_CRITICAL_SECTION(  );
  118. }
  119. eMBErrorCode
  120. eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
  121. {
  122.     BOOL            xFrameReceived = FALSE;
  123.     eMBErrorCode    eStatus = MB_ENOERR;
  124.     ENTER_CRITICAL_SECTION(  );
  125.     assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
  126.     /* Length and CRC check */
  127.     if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
  128.         && ( usMBCRC16( ( UCHAR * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )
  129.     {
  130.         /* Save the address field. All frames are passed to the upper layed
  131.          * and the decision if a frame is used is done there.
  132.          */
  133.         *pucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF];
  134.         /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
  135.          * size of address field and CRC checksum.
  136.          */
  137.         *pusLength = usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC;
  138.         /* Return the start of the Modbus PDU to the caller. */
  139.         *pucFrame = ( UCHAR * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];
  140.         xFrameReceived = TRUE;
  141.     }
  142.     else
  143.     {
  144.         eStatus = MB_EIO;
  145.     }
  146.     EXIT_CRITICAL_SECTION(  );
  147.     return eStatus;
  148. }
  149. eMBErrorCode
  150. eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
  151. {
  152.     eMBErrorCode    eStatus = MB_ENOERR;
  153.     USHORT          usCRC16;
  154.     ENTER_CRITICAL_SECTION(  );
  155.     /* Check if the receiver is still in idle state. If not we where to
  156.      * slow with processing the received frame and the master sent another
  157.      * frame on the network. We have to abort sending the frame.
  158.      */
  159.     if( eRcvState == STATE_RX_IDLE )
  160.     {
  161.         /* First byte before the Modbus-PDU is the slave address. */
  162.         pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
  163.         usSndBufferCount = 1;
  164.         /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
  165.         pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
  166.         usSndBufferCount += usLength;
  167.         /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
  168.         usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
  169.         ucRTUBuf[usSndBufferCount++] = usCRC16 & 0xFF;
  170.         ucRTUBuf[usSndBufferCount++] = usCRC16 >> 8;
  171.         /* Activate the transmitter. */
  172.         eSndState = STATE_TX_XMIT;
  173.         vMBPortSerialEnable( FALSE, TRUE );
  174.     }
  175.     else
  176.     {
  177.         eStatus = MB_EIO;
  178.     }
  179.     EXIT_CRITICAL_SECTION(  );
  180.     return eStatus;
  181. }
  182. BOOL
  183. xMBRTUReceiveFSM( void )
  184. {
  185.     BOOL            xTaskNeedSwitch = FALSE;
  186.     UCHAR           ucByte;
  187.     assert( eSndState == STATE_TX_IDLE );
  188.     switch ( eRcvState )
  189.     {
  190.             /* If we have received a character in the init state we have to
  191.              * wait until the frame is finished.
  192.              */
  193.         case STATE_RX_INIT:
  194.             vMBPortTimersEnable(  );
  195.             break;
  196.             /* In the error state we wait until all characters in the
  197.              * damaged frame are transmitted.
  198.              */
  199.         case STATE_RX_ERROR:
  200.             vMBPortTimersEnable(  );
  201.             /* In the idle state we wait for a new character. If a character
  202.              * is received the t1.5 and t3.5 timers are started and the
  203.              * receiver is in the state STATE_RX_RECEIVCE.
  204.              */
  205.         case STATE_RX_IDLE:
  206.             usRcvBufferPos = 0;
  207.             ( void )xMBPortSerialGetByte( &ucByte );
  208.             ucRTUBuf[usRcvBufferPos++] = ucByte;
  209.             eRcvState = STATE_RX_RCV;
  210.             /* Enable t1.5 and t3.5 timers. */
  211.             vMBPortTimersEnable(  );
  212.             break;
  213.             /* We are currently receiving a frame. Reset the timer after
  214.              * every character received. If more than the maximum possible
  215.              * number of bytes in a modbus frame is received the frame is
  216.              * ignored.
  217.              */
  218.         case STATE_RX_RCV:
  219.             if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
  220.             {
  221.                 ( void )xMBPortSerialGetByte( &ucByte );
  222.                 ucRTUBuf[usRcvBufferPos++] = ucByte;
  223.             }
  224.             else
  225.             {
  226.                 eRcvState = STATE_RX_ERROR;
  227.             }
  228.             vMBPortTimersEnable(  );
  229.             break;
  230.     }
  231.     return xTaskNeedSwitch;
  232. }
  233. BOOL
  234. xMBRTUTransmitFSM( void )
  235. {
  236.     BOOL            xNeedPoll = FALSE;
  237.     assert( eRcvState == STATE_RX_IDLE );
  238.     switch ( eSndState )
  239.     {
  240.             /* We should not get a transmitter event if the transmitter is in
  241.              * idle state.  */
  242.         case STATE_TX_IDLE:
  243.             /* enable receiver/disable transmitter. */
  244.             vMBPortSerialEnable( TRUE, FALSE );
  245.             break;
  246.         case STATE_TX_XMIT:
  247.             /* check if we are finished. */
  248.             if( usSndBufferCount != 0 )
  249.             {
  250.                 xMBPortSerialPutByte( *pucSndBufferCur );
  251.                 pucSndBufferCur++;      /* next byte in sendbuffer. */
  252.                 usSndBufferCount--;
  253.             }
  254.             else
  255.             {
  256.                 xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
  257.                 /* Disable transmitter. This prevents another transmit buffer
  258.                  * empty interrupt. */
  259.                 vMBPortSerialEnable( TRUE, FALSE );
  260.                 eSndState = STATE_TX_IDLE;
  261.             }
  262.             break;
  263.     }
  264.     return xNeedPoll;
  265. }
  266. BOOL
  267. xMBRTUTimerT35Expired( void )
  268. {
  269.     BOOL            xNeedPoll = FALSE;
  270.     switch ( eRcvState )
  271.     {
  272.             /* Timer t35 expired. Startup phase is finished. */
  273.         case STATE_RX_INIT:
  274.             xNeedPoll = xMBPortEventPost( EV_READY );
  275.             break;
  276.             /* A frame was received and t35 expired. Notify the listener that
  277.              * a new frame was received. */
  278.         case STATE_RX_RCV:
  279.             xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
  280.             break;
  281.             /* An error occured while receiving the frame. */
  282.         case STATE_RX_ERROR:
  283.             break;
  284.             /* Function called in an illegal state. */
  285.         default:
  286.             assert( ( eRcvState == STATE_RX_INIT ) ||
  287.                     ( eRcvState == STATE_RX_RCV ) ||
  288.                     ( eRcvState == STATE_RX_ERROR ) );
  289.     }
  290.     vMBPortTimersDisable(  );
  291.     eRcvState = STATE_RX_IDLE;
  292.     return xNeedPoll;
  293. }