Modbus RTU/ASCII/TCP with lwip TCP working partial, but with errors (retransmitions)

Dependencies:   EthernetNetIf mbed

Committer:
tmav123
Date:
Mon Dec 05 22:49:02 2011 +0000
Revision:
0:f54e9507171b

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tmav123 0:f54e9507171b 1 /*
tmav123 0:f54e9507171b 2 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
tmav123 0:f54e9507171b 3 * Copyright (c) 2006 Christian Walter <wolti@sil.at>
tmav123 0:f54e9507171b 4 * All rights reserved.
tmav123 0:f54e9507171b 5 *
tmav123 0:f54e9507171b 6 * Redistribution and use in source and binary forms, with or without
tmav123 0:f54e9507171b 7 * modification, are permitted provided that the following conditions
tmav123 0:f54e9507171b 8 * are met:
tmav123 0:f54e9507171b 9 * 1. Redistributions of source code must retain the above copyright
tmav123 0:f54e9507171b 10 * notice, this list of conditions and the following disclaimer.
tmav123 0:f54e9507171b 11 * 2. Redistributions in binary form must reproduce the above copyright
tmav123 0:f54e9507171b 12 * notice, this list of conditions and the following disclaimer in the
tmav123 0:f54e9507171b 13 * documentation and/or other materials provided with the distribution.
tmav123 0:f54e9507171b 14 * 3. The name of the author may not be used to endorse or promote products
tmav123 0:f54e9507171b 15 * derived from this software without specific prior written permission.
tmav123 0:f54e9507171b 16 *
tmav123 0:f54e9507171b 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
tmav123 0:f54e9507171b 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
tmav123 0:f54e9507171b 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
tmav123 0:f54e9507171b 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
tmav123 0:f54e9507171b 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
tmav123 0:f54e9507171b 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
tmav123 0:f54e9507171b 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
tmav123 0:f54e9507171b 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
tmav123 0:f54e9507171b 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
tmav123 0:f54e9507171b 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
tmav123 0:f54e9507171b 27 *
tmav123 0:f54e9507171b 28 * File: $Id: mbascii.c,v 1.17 2010/06/06 13:47:07 wolti Exp $
tmav123 0:f54e9507171b 29 */
tmav123 0:f54e9507171b 30
tmav123 0:f54e9507171b 31 /* ----------------------- System includes ----------------------------------*/
tmav123 0:f54e9507171b 32 #include "stdlib.h"
tmav123 0:f54e9507171b 33 #include "string.h"
tmav123 0:f54e9507171b 34
tmav123 0:f54e9507171b 35 /* ----------------------- Platform includes --------------------------------*/
tmav123 0:f54e9507171b 36 #include "port.h"
tmav123 0:f54e9507171b 37
tmav123 0:f54e9507171b 38 /* ----------------------- Modbus includes ----------------------------------*/
tmav123 0:f54e9507171b 39 #include "mb.h"
tmav123 0:f54e9507171b 40 #include "mbconfig.h"
tmav123 0:f54e9507171b 41 #include "mbascii.h"
tmav123 0:f54e9507171b 42 #include "mbframe.h"
tmav123 0:f54e9507171b 43
tmav123 0:f54e9507171b 44 #include "mbcrc.h"
tmav123 0:f54e9507171b 45 #include "mbport.h"
tmav123 0:f54e9507171b 46
tmav123 0:f54e9507171b 47 #if MB_ASCII_ENABLED > 0
tmav123 0:f54e9507171b 48
tmav123 0:f54e9507171b 49 /* ----------------------- Defines ------------------------------------------*/
tmav123 0:f54e9507171b 50 #define MB_ASCII_DEFAULT_CR '\r' /*!< Default CR character for Modbus ASCII. */
tmav123 0:f54e9507171b 51 #define MB_ASCII_DEFAULT_LF '\n' /*!< Default LF character for Modbus ASCII. */
tmav123 0:f54e9507171b 52 #define MB_SER_PDU_SIZE_MIN 3 /*!< Minimum size of a Modbus ASCII frame. */
tmav123 0:f54e9507171b 53 #define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus ASCII frame. */
tmav123 0:f54e9507171b 54 #define MB_SER_PDU_SIZE_LRC 1 /*!< Size of LRC field in PDU. */
tmav123 0:f54e9507171b 55 #define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
tmav123 0:f54e9507171b 56 #define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
tmav123 0:f54e9507171b 57
tmav123 0:f54e9507171b 58 /* ----------------------- Type definitions ---------------------------------*/
tmav123 0:f54e9507171b 59 typedef enum
tmav123 0:f54e9507171b 60 {
tmav123 0:f54e9507171b 61 STATE_RX_IDLE, /*!< Receiver is in idle state. */
tmav123 0:f54e9507171b 62 STATE_RX_RCV, /*!< Frame is beeing received. */
tmav123 0:f54e9507171b 63 STATE_RX_WAIT_EOF /*!< Wait for End of Frame. */
tmav123 0:f54e9507171b 64 } eMBRcvState;
tmav123 0:f54e9507171b 65
tmav123 0:f54e9507171b 66 typedef enum
tmav123 0:f54e9507171b 67 {
tmav123 0:f54e9507171b 68 STATE_TX_IDLE, /*!< Transmitter is in idle state. */
tmav123 0:f54e9507171b 69 STATE_TX_START, /*!< Starting transmission (':' sent). */
tmav123 0:f54e9507171b 70 STATE_TX_DATA, /*!< Sending of data (Address, Data, LRC). */
tmav123 0:f54e9507171b 71 STATE_TX_END, /*!< End of transmission. */
tmav123 0:f54e9507171b 72 STATE_TX_NOTIFY /*!< Notify sender that the frame has been sent. */
tmav123 0:f54e9507171b 73 } eMBSndState;
tmav123 0:f54e9507171b 74
tmav123 0:f54e9507171b 75 typedef enum
tmav123 0:f54e9507171b 76 {
tmav123 0:f54e9507171b 77 BYTE_HIGH_NIBBLE, /*!< Character for high nibble of byte. */
tmav123 0:f54e9507171b 78 BYTE_LOW_NIBBLE /*!< Character for low nibble of byte. */
tmav123 0:f54e9507171b 79 } eMBBytePos;
tmav123 0:f54e9507171b 80
tmav123 0:f54e9507171b 81 /* ----------------------- Static functions ---------------------------------*/
tmav123 0:f54e9507171b 82 static UCHAR prvucMBCHAR2BIN( UCHAR ucCharacter );
tmav123 0:f54e9507171b 83
tmav123 0:f54e9507171b 84 static UCHAR prvucMBBIN2CHAR( UCHAR ucByte );
tmav123 0:f54e9507171b 85
tmav123 0:f54e9507171b 86 static UCHAR prvucMBLRC( UCHAR * pucFrame, USHORT usLen );
tmav123 0:f54e9507171b 87
tmav123 0:f54e9507171b 88 /* ----------------------- Static variables ---------------------------------*/
tmav123 0:f54e9507171b 89 static volatile eMBSndState eSndState;
tmav123 0:f54e9507171b 90 static volatile eMBRcvState eRcvState;
tmav123 0:f54e9507171b 91
tmav123 0:f54e9507171b 92 /* We reuse the Modbus RTU buffer because only one buffer is needed and the
tmav123 0:f54e9507171b 93 * RTU buffer is bigger. */
tmav123 0:f54e9507171b 94 extern volatile UCHAR ucRTUBuf[];
tmav123 0:f54e9507171b 95 static volatile UCHAR *ucASCIIBuf = ucRTUBuf;
tmav123 0:f54e9507171b 96
tmav123 0:f54e9507171b 97 static volatile USHORT usRcvBufferPos;
tmav123 0:f54e9507171b 98 static volatile eMBBytePos eBytePos;
tmav123 0:f54e9507171b 99
tmav123 0:f54e9507171b 100 static volatile UCHAR *pucSndBufferCur;
tmav123 0:f54e9507171b 101 static volatile USHORT usSndBufferCount;
tmav123 0:f54e9507171b 102
tmav123 0:f54e9507171b 103 static volatile UCHAR ucLRC;
tmav123 0:f54e9507171b 104 static volatile UCHAR ucMBLFCharacter;
tmav123 0:f54e9507171b 105
tmav123 0:f54e9507171b 106 /* ----------------------- Start implementation -----------------------------*/
tmav123 0:f54e9507171b 107 eMBErrorCode
tmav123 0:f54e9507171b 108 eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
tmav123 0:f54e9507171b 109 {
tmav123 0:f54e9507171b 110 eMBErrorCode eStatus = MB_ENOERR;
tmav123 0:f54e9507171b 111 ( void )ucSlaveAddress;
tmav123 0:f54e9507171b 112
tmav123 0:f54e9507171b 113 ENTER_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 114 ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
tmav123 0:f54e9507171b 115
tmav123 0:f54e9507171b 116 if( xMBPortSerialInit( ucPort, ulBaudRate, 7, eParity ) != TRUE )
tmav123 0:f54e9507171b 117 {
tmav123 0:f54e9507171b 118 eStatus = MB_EPORTERR;
tmav123 0:f54e9507171b 119 }
tmav123 0:f54e9507171b 120 else if( xMBPortTimersInit( MB_ASCII_TIMEOUT_SEC * 20000UL ) != TRUE )
tmav123 0:f54e9507171b 121 {
tmav123 0:f54e9507171b 122 eStatus = MB_EPORTERR;
tmav123 0:f54e9507171b 123 }
tmav123 0:f54e9507171b 124
tmav123 0:f54e9507171b 125 EXIT_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 126
tmav123 0:f54e9507171b 127 return eStatus;
tmav123 0:f54e9507171b 128 }
tmav123 0:f54e9507171b 129
tmav123 0:f54e9507171b 130 void
tmav123 0:f54e9507171b 131 eMBASCIIStart( void )
tmav123 0:f54e9507171b 132 {
tmav123 0:f54e9507171b 133 ENTER_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 134 vMBPortSerialEnable( TRUE, FALSE );
tmav123 0:f54e9507171b 135 eRcvState = STATE_RX_IDLE;
tmav123 0:f54e9507171b 136 EXIT_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 137
tmav123 0:f54e9507171b 138 /* No special startup required for ASCII. */
tmav123 0:f54e9507171b 139 ( void )xMBPortEventPost( EV_READY );
tmav123 0:f54e9507171b 140 }
tmav123 0:f54e9507171b 141
tmav123 0:f54e9507171b 142 void
tmav123 0:f54e9507171b 143 eMBASCIIStop( void )
tmav123 0:f54e9507171b 144 {
tmav123 0:f54e9507171b 145 ENTER_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 146 vMBPortSerialEnable( FALSE, FALSE );
tmav123 0:f54e9507171b 147 vMBPortTimersDisable( );
tmav123 0:f54e9507171b 148 EXIT_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 149 }
tmav123 0:f54e9507171b 150
tmav123 0:f54e9507171b 151 eMBErrorCode
tmav123 0:f54e9507171b 152 eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
tmav123 0:f54e9507171b 153 {
tmav123 0:f54e9507171b 154 eMBErrorCode eStatus = MB_ENOERR;
tmav123 0:f54e9507171b 155
tmav123 0:f54e9507171b 156 ENTER_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 157 assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
tmav123 0:f54e9507171b 158
tmav123 0:f54e9507171b 159 /* Length and CRC check */
tmav123 0:f54e9507171b 160 if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
tmav123 0:f54e9507171b 161 && ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
tmav123 0:f54e9507171b 162 {
tmav123 0:f54e9507171b 163 /* Save the address field. All frames are passed to the upper layed
tmav123 0:f54e9507171b 164 * and the decision if a frame is used is done there.
tmav123 0:f54e9507171b 165 */
tmav123 0:f54e9507171b 166 *pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF];
tmav123 0:f54e9507171b 167
tmav123 0:f54e9507171b 168 /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
tmav123 0:f54e9507171b 169 * size of address field and CRC checksum.
tmav123 0:f54e9507171b 170 */
tmav123 0:f54e9507171b 171 *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );
tmav123 0:f54e9507171b 172
tmav123 0:f54e9507171b 173 /* Return the start of the Modbus PDU to the caller. */
tmav123 0:f54e9507171b 174 *pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
tmav123 0:f54e9507171b 175 }
tmav123 0:f54e9507171b 176 else
tmav123 0:f54e9507171b 177 {
tmav123 0:f54e9507171b 178 eStatus = MB_EIO;
tmav123 0:f54e9507171b 179 }
tmav123 0:f54e9507171b 180 EXIT_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 181 return eStatus;
tmav123 0:f54e9507171b 182 }
tmav123 0:f54e9507171b 183
tmav123 0:f54e9507171b 184 eMBErrorCode
tmav123 0:f54e9507171b 185 eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
tmav123 0:f54e9507171b 186 {
tmav123 0:f54e9507171b 187 eMBErrorCode eStatus = MB_ENOERR;
tmav123 0:f54e9507171b 188 UCHAR usLRC;
tmav123 0:f54e9507171b 189
tmav123 0:f54e9507171b 190 ENTER_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 191 /* Check if the receiver is still in idle state. If not we where too
tmav123 0:f54e9507171b 192 * slow with processing the received frame and the master sent another
tmav123 0:f54e9507171b 193 * frame on the network. We have to abort sending the frame.
tmav123 0:f54e9507171b 194 */
tmav123 0:f54e9507171b 195 if( eRcvState == STATE_RX_IDLE )
tmav123 0:f54e9507171b 196 {
tmav123 0:f54e9507171b 197 /* First byte before the Modbus-PDU is the slave address. */
tmav123 0:f54e9507171b 198 pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
tmav123 0:f54e9507171b 199 usSndBufferCount = 1;
tmav123 0:f54e9507171b 200
tmav123 0:f54e9507171b 201 /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
tmav123 0:f54e9507171b 202 pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
tmav123 0:f54e9507171b 203 usSndBufferCount += usLength;
tmav123 0:f54e9507171b 204
tmav123 0:f54e9507171b 205 /* Calculate LRC checksum for Modbus-Serial-Line-PDU. */
tmav123 0:f54e9507171b 206 usLRC = prvucMBLRC( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
tmav123 0:f54e9507171b 207 ucASCIIBuf[usSndBufferCount++] = usLRC;
tmav123 0:f54e9507171b 208
tmav123 0:f54e9507171b 209 /* Activate the transmitter. */
tmav123 0:f54e9507171b 210 eSndState = STATE_TX_START;
tmav123 0:f54e9507171b 211 vMBPortSerialEnable( FALSE, TRUE );
tmav123 0:f54e9507171b 212 }
tmav123 0:f54e9507171b 213 else
tmav123 0:f54e9507171b 214 {
tmav123 0:f54e9507171b 215 eStatus = MB_EIO;
tmav123 0:f54e9507171b 216 }
tmav123 0:f54e9507171b 217 EXIT_CRITICAL_SECTION( );
tmav123 0:f54e9507171b 218 return eStatus;
tmav123 0:f54e9507171b 219 }
tmav123 0:f54e9507171b 220
tmav123 0:f54e9507171b 221 BOOL
tmav123 0:f54e9507171b 222 xMBASCIIReceiveFSM( void )
tmav123 0:f54e9507171b 223 {
tmav123 0:f54e9507171b 224 BOOL xNeedPoll = FALSE;
tmav123 0:f54e9507171b 225 UCHAR ucByte;
tmav123 0:f54e9507171b 226 UCHAR ucResult;
tmav123 0:f54e9507171b 227
tmav123 0:f54e9507171b 228 assert( eSndState == STATE_TX_IDLE );
tmav123 0:f54e9507171b 229
tmav123 0:f54e9507171b 230 ( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
tmav123 0:f54e9507171b 231 switch ( eRcvState )
tmav123 0:f54e9507171b 232 {
tmav123 0:f54e9507171b 233 /* A new character is received. If the character is a ':' the input
tmav123 0:f54e9507171b 234 * buffer is cleared. A CR-character signals the end of the data
tmav123 0:f54e9507171b 235 * block. Other characters are part of the data block and their
tmav123 0:f54e9507171b 236 * ASCII value is converted back to a binary representation.
tmav123 0:f54e9507171b 237 */
tmav123 0:f54e9507171b 238 case STATE_RX_RCV:
tmav123 0:f54e9507171b 239 /* Enable timer for character timeout. */
tmav123 0:f54e9507171b 240 vMBPortTimersEnable( );
tmav123 0:f54e9507171b 241 if( ucByte == ':' )
tmav123 0:f54e9507171b 242 {
tmav123 0:f54e9507171b 243 /* Empty receive buffer. */
tmav123 0:f54e9507171b 244 eBytePos = BYTE_HIGH_NIBBLE;
tmav123 0:f54e9507171b 245 usRcvBufferPos = 0;
tmav123 0:f54e9507171b 246 }
tmav123 0:f54e9507171b 247 else if( ucByte == MB_ASCII_DEFAULT_CR )
tmav123 0:f54e9507171b 248 {
tmav123 0:f54e9507171b 249 eRcvState = STATE_RX_WAIT_EOF;
tmav123 0:f54e9507171b 250 }
tmav123 0:f54e9507171b 251 else
tmav123 0:f54e9507171b 252 {
tmav123 0:f54e9507171b 253 ucResult = prvucMBCHAR2BIN( ucByte );
tmav123 0:f54e9507171b 254 switch ( eBytePos )
tmav123 0:f54e9507171b 255 {
tmav123 0:f54e9507171b 256 /* High nibble of the byte comes first. We check for
tmav123 0:f54e9507171b 257 * a buffer overflow here. */
tmav123 0:f54e9507171b 258 case BYTE_HIGH_NIBBLE:
tmav123 0:f54e9507171b 259 if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
tmav123 0:f54e9507171b 260 {
tmav123 0:f54e9507171b 261 ucASCIIBuf[usRcvBufferPos] = ( UCHAR )( ucResult << 4 );
tmav123 0:f54e9507171b 262 eBytePos = BYTE_LOW_NIBBLE;
tmav123 0:f54e9507171b 263 break;
tmav123 0:f54e9507171b 264 }
tmav123 0:f54e9507171b 265 else
tmav123 0:f54e9507171b 266 {
tmav123 0:f54e9507171b 267 /* not handled in Modbus specification but seems
tmav123 0:f54e9507171b 268 * a resonable implementation. */
tmav123 0:f54e9507171b 269 eRcvState = STATE_RX_IDLE;
tmav123 0:f54e9507171b 270 /* Disable previously activated timer because of error state. */
tmav123 0:f54e9507171b 271 vMBPortTimersDisable( );
tmav123 0:f54e9507171b 272 }
tmav123 0:f54e9507171b 273 break;
tmav123 0:f54e9507171b 274
tmav123 0:f54e9507171b 275 case BYTE_LOW_NIBBLE:
tmav123 0:f54e9507171b 276 ucASCIIBuf[usRcvBufferPos] |= ucResult;
tmav123 0:f54e9507171b 277 usRcvBufferPos++;
tmav123 0:f54e9507171b 278 eBytePos = BYTE_HIGH_NIBBLE;
tmav123 0:f54e9507171b 279 break;
tmav123 0:f54e9507171b 280 }
tmav123 0:f54e9507171b 281 }
tmav123 0:f54e9507171b 282 break;
tmav123 0:f54e9507171b 283
tmav123 0:f54e9507171b 284 case STATE_RX_WAIT_EOF:
tmav123 0:f54e9507171b 285 if( ucByte == ucMBLFCharacter )
tmav123 0:f54e9507171b 286 {
tmav123 0:f54e9507171b 287 /* Disable character timeout timer because all characters are
tmav123 0:f54e9507171b 288 * received. */
tmav123 0:f54e9507171b 289 vMBPortTimersDisable( );
tmav123 0:f54e9507171b 290 /* Receiver is again in idle state. */
tmav123 0:f54e9507171b 291 eRcvState = STATE_RX_IDLE;
tmav123 0:f54e9507171b 292
tmav123 0:f54e9507171b 293 /* Notify the caller of eMBASCIIReceive that a new frame
tmav123 0:f54e9507171b 294 * was received. */
tmav123 0:f54e9507171b 295 xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
tmav123 0:f54e9507171b 296 }
tmav123 0:f54e9507171b 297 else if( ucByte == ':' )
tmav123 0:f54e9507171b 298 {
tmav123 0:f54e9507171b 299 /* Empty receive buffer and back to receive state. */
tmav123 0:f54e9507171b 300 eBytePos = BYTE_HIGH_NIBBLE;
tmav123 0:f54e9507171b 301 usRcvBufferPos = 0;
tmav123 0:f54e9507171b 302 eRcvState = STATE_RX_RCV;
tmav123 0:f54e9507171b 303
tmav123 0:f54e9507171b 304 /* Enable timer for character timeout. */
tmav123 0:f54e9507171b 305 vMBPortTimersEnable( );
tmav123 0:f54e9507171b 306 }
tmav123 0:f54e9507171b 307 else
tmav123 0:f54e9507171b 308 {
tmav123 0:f54e9507171b 309 /* Frame is not okay. Delete entire frame. */
tmav123 0:f54e9507171b 310 eRcvState = STATE_RX_IDLE;
tmav123 0:f54e9507171b 311 }
tmav123 0:f54e9507171b 312 break;
tmav123 0:f54e9507171b 313
tmav123 0:f54e9507171b 314 case STATE_RX_IDLE:
tmav123 0:f54e9507171b 315 if( ucByte == ':' )
tmav123 0:f54e9507171b 316 {
tmav123 0:f54e9507171b 317 /* Enable timer for character timeout. */
tmav123 0:f54e9507171b 318 vMBPortTimersEnable( );
tmav123 0:f54e9507171b 319 /* Reset the input buffers to store the frame. */
tmav123 0:f54e9507171b 320 usRcvBufferPos = 0;;
tmav123 0:f54e9507171b 321 eBytePos = BYTE_HIGH_NIBBLE;
tmav123 0:f54e9507171b 322 eRcvState = STATE_RX_RCV;
tmav123 0:f54e9507171b 323 }
tmav123 0:f54e9507171b 324 break;
tmav123 0:f54e9507171b 325 }
tmav123 0:f54e9507171b 326
tmav123 0:f54e9507171b 327 return xNeedPoll;
tmav123 0:f54e9507171b 328 }
tmav123 0:f54e9507171b 329
tmav123 0:f54e9507171b 330 BOOL
tmav123 0:f54e9507171b 331 xMBASCIITransmitFSM( void )
tmav123 0:f54e9507171b 332 {
tmav123 0:f54e9507171b 333 BOOL xNeedPoll = FALSE;
tmav123 0:f54e9507171b 334 UCHAR ucByte;
tmav123 0:f54e9507171b 335
tmav123 0:f54e9507171b 336 assert( eRcvState == STATE_RX_IDLE );
tmav123 0:f54e9507171b 337 switch ( eSndState )
tmav123 0:f54e9507171b 338 {
tmav123 0:f54e9507171b 339 /* Start of transmission. The start of a frame is defined by sending
tmav123 0:f54e9507171b 340 * the character ':'. */
tmav123 0:f54e9507171b 341 case STATE_TX_START:
tmav123 0:f54e9507171b 342 ucByte = ':';
tmav123 0:f54e9507171b 343 xMBPortSerialPutByte( ( CHAR )ucByte );
tmav123 0:f54e9507171b 344 eSndState = STATE_TX_DATA;
tmav123 0:f54e9507171b 345 eBytePos = BYTE_HIGH_NIBBLE;
tmav123 0:f54e9507171b 346 break;
tmav123 0:f54e9507171b 347
tmav123 0:f54e9507171b 348 /* Send the data block. Each data byte is encoded as a character hex
tmav123 0:f54e9507171b 349 * stream with the high nibble sent first and the low nibble sent
tmav123 0:f54e9507171b 350 * last. If all data bytes are exhausted we send a '\r' character
tmav123 0:f54e9507171b 351 * to end the transmission. */
tmav123 0:f54e9507171b 352 case STATE_TX_DATA:
tmav123 0:f54e9507171b 353 if( usSndBufferCount > 0 )
tmav123 0:f54e9507171b 354 {
tmav123 0:f54e9507171b 355 switch ( eBytePos )
tmav123 0:f54e9507171b 356 {
tmav123 0:f54e9507171b 357 case BYTE_HIGH_NIBBLE:
tmav123 0:f54e9507171b 358 ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur >> 4 ) );
tmav123 0:f54e9507171b 359 xMBPortSerialPutByte( ( CHAR ) ucByte );
tmav123 0:f54e9507171b 360 eBytePos = BYTE_LOW_NIBBLE;
tmav123 0:f54e9507171b 361 break;
tmav123 0:f54e9507171b 362
tmav123 0:f54e9507171b 363 case BYTE_LOW_NIBBLE:
tmav123 0:f54e9507171b 364 ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur & 0x0F ) );
tmav123 0:f54e9507171b 365 xMBPortSerialPutByte( ( CHAR )ucByte );
tmav123 0:f54e9507171b 366 pucSndBufferCur++;
tmav123 0:f54e9507171b 367 eBytePos = BYTE_HIGH_NIBBLE;
tmav123 0:f54e9507171b 368 usSndBufferCount--;
tmav123 0:f54e9507171b 369 break;
tmav123 0:f54e9507171b 370 }
tmav123 0:f54e9507171b 371 }
tmav123 0:f54e9507171b 372 else
tmav123 0:f54e9507171b 373 {
tmav123 0:f54e9507171b 374 xMBPortSerialPutByte( MB_ASCII_DEFAULT_CR );
tmav123 0:f54e9507171b 375 eSndState = STATE_TX_END;
tmav123 0:f54e9507171b 376 }
tmav123 0:f54e9507171b 377 break;
tmav123 0:f54e9507171b 378
tmav123 0:f54e9507171b 379 /* Finish the frame by sending a LF character. */
tmav123 0:f54e9507171b 380 case STATE_TX_END:
tmav123 0:f54e9507171b 381 xMBPortSerialPutByte( ( CHAR )ucMBLFCharacter );
tmav123 0:f54e9507171b 382 /* We need another state to make sure that the CR character has
tmav123 0:f54e9507171b 383 * been sent. */
tmav123 0:f54e9507171b 384 eSndState = STATE_TX_NOTIFY;
tmav123 0:f54e9507171b 385 break;
tmav123 0:f54e9507171b 386
tmav123 0:f54e9507171b 387 /* Notify the task which called eMBASCIISend that the frame has
tmav123 0:f54e9507171b 388 * been sent. */
tmav123 0:f54e9507171b 389 case STATE_TX_NOTIFY:
tmav123 0:f54e9507171b 390 eSndState = STATE_TX_IDLE;
tmav123 0:f54e9507171b 391 xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
tmav123 0:f54e9507171b 392
tmav123 0:f54e9507171b 393 /* Disable transmitter. This prevents another transmit buffer
tmav123 0:f54e9507171b 394 * empty interrupt. */
tmav123 0:f54e9507171b 395 vMBPortSerialEnable( TRUE, FALSE );
tmav123 0:f54e9507171b 396 eSndState = STATE_TX_IDLE;
tmav123 0:f54e9507171b 397 break;
tmav123 0:f54e9507171b 398
tmav123 0:f54e9507171b 399 /* We should not get a transmitter event if the transmitter is in
tmav123 0:f54e9507171b 400 * idle state. */
tmav123 0:f54e9507171b 401 case STATE_TX_IDLE:
tmav123 0:f54e9507171b 402 /* enable receiver/disable transmitter. */
tmav123 0:f54e9507171b 403 vMBPortSerialEnable( TRUE, FALSE );
tmav123 0:f54e9507171b 404 break;
tmav123 0:f54e9507171b 405 }
tmav123 0:f54e9507171b 406
tmav123 0:f54e9507171b 407 return xNeedPoll;
tmav123 0:f54e9507171b 408 }
tmav123 0:f54e9507171b 409
tmav123 0:f54e9507171b 410 BOOL
tmav123 0:f54e9507171b 411 xMBASCIITimerT1SExpired( void )
tmav123 0:f54e9507171b 412 {
tmav123 0:f54e9507171b 413 switch ( eRcvState )
tmav123 0:f54e9507171b 414 {
tmav123 0:f54e9507171b 415 /* If we have a timeout we go back to the idle state and wait for
tmav123 0:f54e9507171b 416 * the next frame.
tmav123 0:f54e9507171b 417 */
tmav123 0:f54e9507171b 418 case STATE_RX_RCV:
tmav123 0:f54e9507171b 419 case STATE_RX_WAIT_EOF:
tmav123 0:f54e9507171b 420 eRcvState = STATE_RX_IDLE;
tmav123 0:f54e9507171b 421 break;
tmav123 0:f54e9507171b 422
tmav123 0:f54e9507171b 423 default:
tmav123 0:f54e9507171b 424 assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF ) );
tmav123 0:f54e9507171b 425 break;
tmav123 0:f54e9507171b 426 }
tmav123 0:f54e9507171b 427 vMBPortTimersDisable( );
tmav123 0:f54e9507171b 428
tmav123 0:f54e9507171b 429 /* no context switch required. */
tmav123 0:f54e9507171b 430 return FALSE;
tmav123 0:f54e9507171b 431 }
tmav123 0:f54e9507171b 432
tmav123 0:f54e9507171b 433
tmav123 0:f54e9507171b 434 static UCHAR
tmav123 0:f54e9507171b 435 prvucMBCHAR2BIN( UCHAR ucCharacter )
tmav123 0:f54e9507171b 436 {
tmav123 0:f54e9507171b 437 if( ( ucCharacter >= '0' ) && ( ucCharacter <= '9' ) )
tmav123 0:f54e9507171b 438 {
tmav123 0:f54e9507171b 439 return ( UCHAR )( ucCharacter - '0' );
tmav123 0:f54e9507171b 440 }
tmav123 0:f54e9507171b 441 else if( ( ucCharacter >= 'A' ) && ( ucCharacter <= 'F' ) )
tmav123 0:f54e9507171b 442 {
tmav123 0:f54e9507171b 443 return ( UCHAR )( ucCharacter - 'A' + 0x0A );
tmav123 0:f54e9507171b 444 }
tmav123 0:f54e9507171b 445 else
tmav123 0:f54e9507171b 446 {
tmav123 0:f54e9507171b 447 return 0xFF;
tmav123 0:f54e9507171b 448 }
tmav123 0:f54e9507171b 449 }
tmav123 0:f54e9507171b 450
tmav123 0:f54e9507171b 451 static UCHAR
tmav123 0:f54e9507171b 452 prvucMBBIN2CHAR( UCHAR ucByte )
tmav123 0:f54e9507171b 453 {
tmav123 0:f54e9507171b 454 if( ucByte <= 0x09 )
tmav123 0:f54e9507171b 455 {
tmav123 0:f54e9507171b 456 return ( UCHAR )( '0' + ucByte );
tmav123 0:f54e9507171b 457 }
tmav123 0:f54e9507171b 458 else if( ( ucByte >= 0x0A ) && ( ucByte <= 0x0F ) )
tmav123 0:f54e9507171b 459 {
tmav123 0:f54e9507171b 460 return ( UCHAR )( ucByte - 0x0A + 'A' );
tmav123 0:f54e9507171b 461 }
tmav123 0:f54e9507171b 462 else
tmav123 0:f54e9507171b 463 {
tmav123 0:f54e9507171b 464 /* Programming error. */
tmav123 0:f54e9507171b 465 assert( 0 );
tmav123 0:f54e9507171b 466 }
tmav123 0:f54e9507171b 467 return '0';
tmav123 0:f54e9507171b 468 }
tmav123 0:f54e9507171b 469
tmav123 0:f54e9507171b 470
tmav123 0:f54e9507171b 471 static UCHAR
tmav123 0:f54e9507171b 472 prvucMBLRC( UCHAR * pucFrame, USHORT usLen )
tmav123 0:f54e9507171b 473 {
tmav123 0:f54e9507171b 474 UCHAR ucLRC = 0; /* LRC char initialized */
tmav123 0:f54e9507171b 475
tmav123 0:f54e9507171b 476 while( usLen-- )
tmav123 0:f54e9507171b 477 {
tmav123 0:f54e9507171b 478 ucLRC += *pucFrame++; /* Add buffer byte without carry */
tmav123 0:f54e9507171b 479 }
tmav123 0:f54e9507171b 480
tmav123 0:f54e9507171b 481 /* Return twos complement */
tmav123 0:f54e9507171b 482 ucLRC = ( UCHAR ) ( -( ( CHAR ) ucLRC ) );
tmav123 0:f54e9507171b 483 return ucLRC;
tmav123 0:f54e9507171b 484 }
tmav123 0:f54e9507171b 485
tmav123 0:f54e9507171b 486 #endif