fork frdm kl25z slave

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mb.cpp Source File

mb.cpp

00001 /*
00002  * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
00003  * Copyright (c) 2006 Christian Walter <wolti@sil.at>
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. The name of the author may not be used to endorse or promote products
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  *
00028  * File: $Id: mb.c,v 1.27 2007/02/18 23:45:41 wolti Exp $
00029  */
00030 
00031 /* ----------------------- System includes ----------------------------------*/
00032 #include "stdlib.h"
00033 #include "string.h"
00034 
00035 /* ----------------------- Platform includes --------------------------------*/
00036 #include "port.h"
00037 
00038 /* ----------------------- Modbus includes ----------------------------------*/
00039 #include "mb.h"
00040 #include "mbconfig.h"
00041 #include "mbframe.h"
00042 #include "mbproto.h"
00043 #include "mbfunc.h"
00044 #include "mbport.h"
00045 #if MB_RTU_ENABLED == 1
00046 #include "mbrtu.h"
00047 #endif
00048 #if MB_ASCII_ENABLED == 1
00049 #include "mbascii.h"
00050 #endif
00051 #if MB_TCP_ENABLED == 1
00052 #include "mbtcp.h"
00053 #endif
00054 
00055 #ifndef MB_PORT_HAS_CLOSE
00056 #define MB_PORT_HAS_CLOSE 0
00057 #endif
00058 
00059 /* ----------------------- Static variables ---------------------------------*/
00060 
00061 #include "mbed.h"
00062 
00063 static UCHAR    ucMBAddress;
00064 static eMBMode  eMBCurrentMode;
00065 
00066 static enum {
00067     STATE_ENABLED,
00068     STATE_DISABLED,
00069     STATE_NOT_INITIALIZED
00070 } eMBState = STATE_NOT_INITIALIZED;
00071 
00072 /* Functions pointer which are initialized in eMBInit( ). Depending on the
00073  * mode (RTU or ASCII) the are set to the correct implementations.
00074  */
00075 static peMBFrameSend peMBFrameSendCur;
00076 static pvMBFrameStart pvMBFrameStartCur;
00077 static pvMBFrameStop pvMBFrameStopCur;
00078 static peMBFrameReceive peMBFrameReceiveCur;
00079 static pvMBFrameClose pvMBFrameCloseCur;
00080 
00081 /* Callback functions required by the porting layer. They are called when
00082  * an external event has happend which includes a timeout or the reception
00083  * or transmission of a character.
00084  */
00085 BOOL( *pxMBFrameCBByteReceived ) ( void );
00086 BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
00087 BOOL( *pxMBPortCBTimerExpired ) ( void );
00088 
00089 BOOL( *pxMBFrameCBReceiveFSMCur ) ( void );
00090 BOOL( *pxMBFrameCBTransmitFSMCur ) ( void );
00091 
00092 /* An array of Modbus functions handlers which associates Modbus function
00093  * codes with implementing functions.
00094  */
00095 static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
00096 #if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
00097     {MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
00098 #endif
00099 #if MB_FUNC_READ_INPUT_ENABLED > 0
00100     {MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister},
00101 #endif
00102 #if MB_FUNC_READ_HOLDING_ENABLED > 0
00103     {MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister},
00104 #endif
00105 #if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
00106     {MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister},
00107 #endif
00108 #if MB_FUNC_WRITE_HOLDING_ENABLED > 0
00109     {MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister},
00110 #endif
00111 #if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
00112     {MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister},
00113 #endif
00114 #if MB_FUNC_READ_COILS_ENABLED > 0
00115     {MB_FUNC_READ_COILS, eMBFuncReadCoils},
00116 #endif
00117 #if MB_FUNC_WRITE_COIL_ENABLED > 0
00118     {MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil},
00119 #endif
00120 #if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
00121     {MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils},
00122 #endif
00123 #if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
00124     {MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs},
00125 #endif
00126 };
00127 
00128 /* ----------------------- Start implementation -----------------------------*/
00129 eMBErrorCode
00130 eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity ) {
00131     eMBErrorCode    eStatus = MB_ENOERR ;
00132 
00133     /* check preconditions */
00134     if ( ( ucSlaveAddress == MB_ADDRESS_BROADCAST ) ||
00135             ( ucSlaveAddress < MB_ADDRESS_MIN ) || ( ucSlaveAddress > MB_ADDRESS_MAX ) ) {
00136         eStatus = MB_EINVAL ;
00137     } else {
00138         ucMBAddress = ucSlaveAddress;
00139 
00140         switch ( eMode ) {
00141 #if MB_RTU_ENABLED > 0
00142             case MB_RTU :
00143                 pvMBFrameStartCur = eMBRTUStart;
00144                 pvMBFrameStopCur = eMBRTUStop;
00145                 peMBFrameSendCur = eMBRTUSend;
00146                 peMBFrameReceiveCur = eMBRTUReceive;
00147                 pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
00148                 pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
00149                 pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;
00150                 pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;
00151 
00152                 eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
00153                 break;
00154 #endif
00155 #if MB_ASCII_ENABLED > 0
00156             case MB_ASCII :
00157                 pvMBFrameStartCur = eMBASCIIStart;
00158                 pvMBFrameStopCur = eMBASCIIStop;
00159                 peMBFrameSendCur = eMBASCIISend;
00160                 peMBFrameReceiveCur = eMBASCIIReceive;
00161                 pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
00162                 pxMBFrameCBByteReceived = xMBASCIIReceiveFSM;
00163                 pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM;
00164                 pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired;
00165 
00166                 eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity );
00167                 break;
00168 #endif
00169             default:
00170                 eStatus = MB_EINVAL ;
00171         }
00172 
00173         if ( eStatus == MB_ENOERR  ) {
00174             if ( !xMBPortEventInit(  ) ) {
00175                 /* port dependent event module initalization failed. */
00176                 eStatus = MB_EPORTERR ;
00177             } else {
00178                 eMBCurrentMode = eMode;
00179                 eMBState = STATE_DISABLED;
00180             }
00181         }
00182     }
00183     return eStatus;
00184 }
00185 
00186 #if MB_TCP_ENABLED > 0
00187 eMBErrorCode
00188 eMBTCPInit( USHORT ucTCPPort ) {
00189     eMBErrorCode    eStatus = MB_ENOERR ;
00190 
00191     if ( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR  ) {
00192         eMBState = STATE_DISABLED;
00193     } else if ( !xMBPortEventInit(  ) ) {
00194         /* Port dependent event module initalization failed. */
00195         eStatus = MB_EPORTERR ;
00196     } else {
00197         pvMBFrameStartCur = eMBTCPStart;
00198         pvMBFrameStopCur = eMBTCPStop;
00199         peMBFrameReceiveCur = eMBTCPReceive;
00200         peMBFrameSendCur = eMBTCPSend;
00201         pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
00202         ucMBAddress = MB_TCP_PSEUDO_ADDRESS;
00203         eMBCurrentMode = MB_TCP ;
00204         eMBState = STATE_DISABLED;
00205     }
00206     return eStatus;
00207 }
00208 #endif
00209 
00210 
00211 eMBErrorCode
00212 eMBRegisterCB( UCHAR ucFunctionCode, pxMBFunctionHandler pxHandler ) {
00213     int             i;
00214     eMBErrorCode    eStatus;
00215 
00216     if ( ( 0 < ucFunctionCode ) && ( ucFunctionCode <= 127 ) ) {
00217         ENTER_CRITICAL_SECTION(  );
00218         if ( pxHandler != NULL ) {
00219             for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) {
00220                 if ( ( xFuncHandlers[i].pxHandler == NULL ) ||
00221                         ( xFuncHandlers[i].pxHandler == pxHandler ) ) {
00222                     xFuncHandlers[i].ucFunctionCode = ucFunctionCode;
00223                     xFuncHandlers[i].pxHandler = pxHandler;
00224                     break;
00225                 }
00226             }
00227             eStatus = ( i != MB_FUNC_HANDLERS_MAX ) ? MB_ENOERR  : MB_ENORES ;
00228         } else {
00229             for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) {
00230                 if ( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ) {
00231                     xFuncHandlers[i].ucFunctionCode = 0;
00232                     xFuncHandlers[i].pxHandler = NULL;
00233                     break;
00234                 }
00235             }
00236             /* Remove can't fail. */
00237             eStatus = MB_ENOERR ;
00238         }
00239         EXIT_CRITICAL_SECTION(  );
00240     } else {
00241         eStatus = MB_EINVAL ;
00242     }
00243     return eStatus;
00244 }
00245 
00246 
00247 eMBErrorCode
00248 eMBClose( void ) {
00249     eMBErrorCode    eStatus = MB_ENOERR ;
00250 
00251     if ( eMBState == STATE_DISABLED ) {
00252         if ( pvMBFrameCloseCur != NULL ) {
00253             pvMBFrameCloseCur(  );
00254         }
00255     } else {
00256         eStatus = MB_EILLSTATE ;
00257     }
00258     return eStatus;
00259 }
00260 
00261 eMBErrorCode
00262 eMBEnable( void ) {
00263     eMBErrorCode    eStatus = MB_ENOERR ;
00264 
00265     if ( eMBState == STATE_DISABLED ) {
00266         /* Activate the protocol stack. */
00267         pvMBFrameStartCur(  );
00268         eMBState = STATE_ENABLED;
00269     } else {
00270         eStatus = MB_EILLSTATE ;
00271     }
00272     return eStatus;
00273 }
00274 
00275 eMBErrorCode
00276 eMBDisable( void ) {
00277     eMBErrorCode    eStatus;
00278 
00279     if ( eMBState == STATE_ENABLED ) {
00280         pvMBFrameStopCur(  );
00281         eMBState = STATE_DISABLED;
00282         eStatus = MB_ENOERR ;
00283     } else if ( eMBState == STATE_DISABLED ) {
00284         eStatus = MB_ENOERR ;
00285     } else {
00286         eStatus = MB_EILLSTATE ;
00287     }
00288     return eStatus;
00289 }
00290 
00291 eMBErrorCode
00292 eMBPoll( void ) {
00293     static UCHAR   *ucMBFrame;
00294     static UCHAR    ucRcvAddress;
00295     static UCHAR    ucFunctionCode;
00296     static USHORT   usLength;
00297     static eMBException eException;
00298 
00299     int             i;
00300     eMBErrorCode    eStatus = MB_ENOERR ;
00301     eMBEventType    eEvent;
00302 
00303     /* Check if the protocol stack is ready. */
00304     if ( eMBState != STATE_ENABLED ) {
00305         return MB_EILLSTATE ;
00306     }
00307 
00308     /* Check if there is a event available. If not return control to caller.
00309      * Otherwise we will handle the event. */
00310     if ( xMBPortEventGet( &eEvent ) == TRUE ) {
00311         switch ( eEvent ) {
00312             case EV_READY:
00313                 break;
00314 
00315             case EV_FRAME_RECEIVED:
00316                 eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
00317                 //printf("[EV_FRAME_RECEIVED] usLength=%d \r\n", usLength );
00318                 if ( eStatus == MB_ENOERR  ) {
00319                     #if 0
00320                     if ( ucMBFrame )
00321                     {
00322                          printf( "\r\n" );                         
00323                          printf( "-->" );
00324                          for ( int i=0; i< usLength; i++ )
00325                             printf("%02x ", ucMBFrame[i]);
00326                          printf( "\r\n" );
00327                     }
00328                     #endif
00329                     /* Check if the frame is for us. If not ignore the frame. */
00330                     if ( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) ) {
00331                         ( void )xMBPortEventPost( EV_EXECUTE );
00332                     } //else
00333                        //printf("Drop\r\n");
00334                 } //else  printf("Error\r\n");
00335                 break;
00336 
00337             case EV_EXECUTE:
00338                 ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
00339                 eException = MB_EX_ILLEGAL_FUNCTION;
00340                 
00341  
00342                 for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) {
00343                     /* No more function handlers registered. Abort. */
00344                     if ( xFuncHandlers[i].ucFunctionCode == 0 ) {
00345                         break;
00346                     } else if ( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ) {
00347                         eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
00348                         break;
00349                     }
00350                 }
00351 
00352                 /* If the request was not sent to the broadcast address we
00353                  * return a reply. */
00354                 if ( ucRcvAddress != MB_ADDRESS_BROADCAST ) {
00355                     if ( eException != MB_EX_NONE ) {
00356                         /* An exception occured. Build an error frame. */
00357                         usLength = 0;
00358                         ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
00359                         ucMBFrame[usLength++] = eException;
00360                     }
00361                     eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
00362                     #if 0
00363                     if ( ucMBFrame )
00364                     {
00365                         printf( "\r\n" );                                                 
00366                         printf( "<--" );
00367                         for ( int i=0; i< usLength; i++ )
00368                             printf("%02x ", ucMBFrame[i]);
00369                         printf( "\r\n" );
00370                     #endif
00371                 }
00372                 break;
00373 
00374             case EV_FRAME_SENT:
00375                 break;
00376         }
00377     }
00378     return MB_ENOERR ;
00379 }