Modified version of ModbusTCP

Dependencies:   EthernetNetIf mbed

Committer:
paleskyjp
Date:
Tue Mar 13 09:11:49 2012 +0000
Revision:
0:62be54b8975d
The first modification of ModbusTCP

Who changed what in which revision?

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