Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 00046 #if MB_RTU_ENABLED == 1 00047 #include "mbrtu.h" 00048 #endif 00049 #if MB_RTU_CUSTOM_ENABLED == 1 00050 #include "mbrtucustom.h" 00051 #endif 00052 #if MB_ASCII_ENABLED == 1 00053 #include "mbascii.h" 00054 #endif 00055 #if MB_TCP_ENABLED == 1 00056 #include "mbtcp.h" 00057 #endif 00058 00059 #ifndef MB_PORT_HAS_CLOSE 00060 #define MB_PORT_HAS_CLOSE 0 00061 #endif 00062 00063 /* ----------------------- Static variables ---------------------------------*/ 00064 00065 00066 static UCHAR ucMBAddress; 00067 static eMBMode eMBCurrentMode; 00068 00069 static enum { 00070 STATE_ENABLED, 00071 STATE_DISABLED, 00072 STATE_NOT_INITIALIZED 00073 } eMBState = STATE_NOT_INITIALIZED; 00074 00075 /* Functions pointer which are initialized in eMBInit( ). Depending on the 00076 * mode (RTU or ASCII) the are set to the correct implementations. 00077 */ 00078 static peMBFrameSend peMBFrameSendCur; 00079 static pvMBFrameStart pvMBFrameStartCur; 00080 static pvMBFrameStop pvMBFrameStopCur; 00081 static peMBFrameReceive peMBFrameReceiveCur; 00082 static pvMBFrameClose pvMBFrameCloseCur; 00083 00084 /* Callback functions required by the porting layer. They are called when 00085 * an external event has happend which includes a timeout or the reception 00086 * or transmission of a character. 00087 */ 00088 BOOL( *pxMBFrameCBByteReceived ) ( void ); 00089 BOOL( *pxMBFrameCBTransmitterEmpty ) ( void ); 00090 BOOL( *pxMBPortCBTimerExpired ) ( void ); 00091 00092 BOOL( *pxMBFrameCBReceiveFSMCur ) ( void ); 00093 BOOL( *pxMBFrameCBTransmitFSMCur ) ( void ); 00094 00095 /* An array of Modbus functions handlers which associates Modbus function 00096 * codes with implementing functions. 00097 */ 00098 static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = { 00099 #if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0 00100 {MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID}, 00101 #endif 00102 #if MB_FUNC_READ_INPUT_ENABLED > 0 00103 {MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister}, 00104 #endif 00105 #if MB_FUNC_READ_HOLDING_ENABLED > 0 00106 {MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister}, 00107 #endif 00108 #if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0 00109 {MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister}, 00110 #endif 00111 #if MB_FUNC_WRITE_HOLDING_ENABLED > 0 00112 {MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister}, 00113 #endif 00114 #if MB_FUNC_READWRITE_HOLDING_ENABLED > 0 00115 {MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister}, 00116 #endif 00117 #if MB_FUNC_READ_COILS_ENABLED > 0 00118 {MB_FUNC_READ_COILS, eMBFuncReadCoils}, 00119 #endif 00120 #if MB_FUNC_WRITE_COIL_ENABLED > 0 00121 {MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil}, 00122 #endif 00123 #if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0 00124 {MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils}, 00125 #endif 00126 #if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0 00127 {MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs}, 00128 #endif 00129 }; 00130 00131 /* ----------------------- Start implementation -----------------------------*/ 00132 eMBErrorCode 00133 eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity ) { 00134 eMBErrorCode eStatus = MB_ENOERR ; 00135 00136 /* check preconditions */ 00137 if ( ( ucSlaveAddress == MB_ADDRESS_BROADCAST ) || 00138 ( ucSlaveAddress < MB_ADDRESS_MIN ) || ( ucSlaveAddress > MB_ADDRESS_MAX ) ) { 00139 eStatus = MB_EINVAL ; 00140 } else { 00141 ucMBAddress = ucSlaveAddress; 00142 00143 switch ( eMode ) { 00144 #if MB_RTU_ENABLED > 0 00145 case MB_RTU : 00146 pvMBFrameStartCur = eMBRTUStart; 00147 pvMBFrameStopCur = eMBRTUStop; 00148 peMBFrameSendCur = eMBRTUSend; 00149 peMBFrameReceiveCur = eMBRTUReceive; 00150 pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL; 00151 pxMBFrameCBByteReceived = xMBRTUReceiveFSM; 00152 pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM; 00153 pxMBPortCBTimerExpired = xMBRTUTimerT35Expired; 00154 00155 eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity ); 00156 break; 00157 #endif 00158 #if MB_ASCII_ENABLED > 0 00159 case MB_ASCII : 00160 pvMBFrameStartCur = eMBASCIIStart; 00161 pvMBFrameStopCur = eMBASCIIStop; 00162 peMBFrameSendCur = eMBASCIISend; 00163 peMBFrameReceiveCur = eMBASCIIReceive; 00164 pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL; 00165 pxMBFrameCBByteReceived = xMBASCIIReceiveFSM; 00166 pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM; 00167 pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired; 00168 00169 eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity ); 00170 break; 00171 #endif 00172 default: 00173 eStatus = MB_EINVAL ; 00174 } 00175 00176 if ( eStatus == MB_ENOERR ) { 00177 if ( !xMBPortEventInit( ) ) { 00178 /* port dependent event module initalization failed. */ 00179 eStatus = MB_EPORTERR ; 00180 } else { 00181 eMBCurrentMode = eMode; 00182 eMBState = STATE_DISABLED; 00183 } 00184 } 00185 } 00186 return eStatus; 00187 } 00188 00189 #if MB_RTU_CUSTOM_ENABLED > 0 00190 eMBErrorCode 00191 eMBRTUCustomInit( UCHAR ucSlaveAddress ) { 00192 eMBErrorCode eStatus = MB_ENOERR ; 00193 ucMBAddress = ucSlaveAddress; 00194 eStatus = eMBRTUCustInit( ucSlaveAddress ); 00195 // if ( ( eStatus = eMBRTUCustInit( ucMBAddress ) ) != MB_ENOERR ) { 00196 eMBState = STATE_DISABLED; 00197 // } else 00198 if ( !xMBPortEventInit( ) ) { 00199 /* Port dependent event module initalization failed. */ 00200 eStatus = MB_EPORTERR ; 00201 } 00202 else { 00203 pvMBFrameStartCur = eMBRTUCustStart; 00204 pvMBFrameStopCur = eMBRTUCustStop; 00205 peMBFrameSendCur = eMBRTUCustSend; 00206 peMBFrameReceiveCur = eMBRTUCustReceive; 00207 pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL; 00208 00209 eMBCurrentMode = MB_RTU_CUSTOM ; 00210 eMBState = STATE_DISABLED; 00211 } 00212 return eStatus; 00213 } 00214 #endif 00215 00216 #if MB_TCP_ENABLED > 0 00217 eMBErrorCode 00218 eMBTCPInit( USHORT ucTCPPort ) { 00219 eMBErrorCode eStatus = MB_ENOERR ; 00220 00221 if ( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR ) { 00222 eMBState = STATE_DISABLED; 00223 } else if ( !xMBPortEventInit( ) ) { 00224 /* Port dependent event module initalization failed. */ 00225 eStatus = MB_EPORTERR ; 00226 } else { 00227 pvMBFrameStartCur = eMBTCPStart; 00228 pvMBFrameStopCur = eMBTCPStop; 00229 peMBFrameReceiveCur = eMBTCPReceive; 00230 peMBFrameSendCur = eMBTCPSend; 00231 pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL; 00232 ucMBAddress = MB_TCP_PSEUDO_ADDRESS; 00233 eMBCurrentMode = MB_TCP ; 00234 eMBState = STATE_DISABLED; 00235 } 00236 return eStatus; 00237 } 00238 #endif 00239 00240 00241 eMBErrorCode 00242 eMBRegisterCB( UCHAR ucFunctionCode, pxMBFunctionHandler pxHandler ) { 00243 int i; 00244 eMBErrorCode eStatus; 00245 00246 if ( ( 0 < ucFunctionCode ) && ( ucFunctionCode <= 127 ) ) { 00247 ENTER_CRITICAL_SECTION( ); 00248 if ( pxHandler != NULL ) { 00249 for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) { 00250 if ( ( xFuncHandlers[i].pxHandler == NULL ) || 00251 ( xFuncHandlers[i].pxHandler == pxHandler ) ) { 00252 xFuncHandlers[i].ucFunctionCode = ucFunctionCode; 00253 xFuncHandlers[i].pxHandler = pxHandler; 00254 break; 00255 } 00256 } 00257 eStatus = ( i != MB_FUNC_HANDLERS_MAX ) ? MB_ENOERR : MB_ENORES ; 00258 } else { 00259 for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) { 00260 if ( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ) { 00261 xFuncHandlers[i].ucFunctionCode = 0; 00262 xFuncHandlers[i].pxHandler = NULL; 00263 break; 00264 } 00265 } 00266 /* Remove can't fail. */ 00267 eStatus = MB_ENOERR ; 00268 } 00269 EXIT_CRITICAL_SECTION( ); 00270 } else { 00271 eStatus = MB_EINVAL ; 00272 } 00273 return eStatus; 00274 } 00275 00276 00277 eMBErrorCode 00278 eMBClose( void ) { 00279 eMBErrorCode eStatus = MB_ENOERR ; 00280 00281 if ( eMBState == STATE_DISABLED ) { 00282 if ( pvMBFrameCloseCur != NULL ) { 00283 pvMBFrameCloseCur( ); 00284 } 00285 } else { 00286 eStatus = MB_EILLSTATE ; 00287 } 00288 return eStatus; 00289 } 00290 00291 eMBErrorCode 00292 eMBEnable( void ) { 00293 eMBErrorCode eStatus = MB_ENOERR ; 00294 00295 if ( eMBState == STATE_DISABLED ) { 00296 /* Activate the protocol stack. */ 00297 pvMBFrameStartCur( ); 00298 eMBState = STATE_ENABLED; 00299 } else { 00300 eStatus = MB_EILLSTATE ; 00301 } 00302 return eStatus; 00303 } 00304 00305 eMBErrorCode 00306 eMBDisable( void ) { 00307 eMBErrorCode eStatus; 00308 00309 if ( eMBState == STATE_ENABLED ) { 00310 pvMBFrameStopCur( ); 00311 eMBState = STATE_DISABLED; 00312 eStatus = MB_ENOERR ; 00313 } else if ( eMBState == STATE_DISABLED ) { 00314 eStatus = MB_ENOERR ; 00315 } else { 00316 eStatus = MB_EILLSTATE ; 00317 } 00318 return eStatus; 00319 } 00320 00321 eMBErrorCode 00322 eMBPoll( void ) { 00323 static UCHAR *ucMBFrame; 00324 static UCHAR ucRcvAddress; 00325 static UCHAR ucFunctionCode; 00326 static USHORT usLength; 00327 static eMBException eException; 00328 00329 int i; 00330 eMBErrorCode eStatus = MB_ENOERR ; 00331 eMBEventType eEvent; 00332 00333 /* Check if the protocol stack is ready. */ 00334 if ( eMBState != STATE_ENABLED ) { 00335 return MB_EILLSTATE ; 00336 } 00337 00338 /* Check if there is a event available. If not return control to caller. 00339 * Otherwise we will handle the event. */ 00340 if ( xMBPortEventGet( &eEvent ) == TRUE ) { 00341 switch ( eEvent ) { 00342 case EV_READY: 00343 break; 00344 00345 case EV_FRAME_RECEIVED: 00346 eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength ); 00347 if ( eStatus == MB_ENOERR ) { 00348 /* Check if the frame is for us. If not ignore the frame. */ 00349 if ( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) ) { 00350 ( void )xMBPortEventPost( EV_EXECUTE ); 00351 } 00352 } 00353 break; 00354 00355 case EV_EXECUTE: 00356 ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF]; 00357 eException = MB_EX_ILLEGAL_FUNCTION; 00358 00359 00360 for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) { 00361 /* No more function handlers registered. Abort. */ 00362 if ( xFuncHandlers[i].ucFunctionCode == 0 ) { 00363 break; 00364 } else if ( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ) { 00365 eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength ); 00366 break; 00367 } 00368 } 00369 00370 /* If the request was not sent to the broadcast address we 00371 * return a reply. */ 00372 if ( ucRcvAddress != MB_ADDRESS_BROADCAST ) { 00373 if ( eException != MB_EX_NONE ) { 00374 /* An exception occured. Build an error frame. */ 00375 usLength = 0; 00376 ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR ); 00377 ucMBFrame[usLength++] = eException; 00378 } 00379 eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength ); 00380 } 00381 break; 00382 00383 case EV_FRAME_SENT: 00384 break; 00385 } 00386 } 00387 return MB_ENOERR ; 00388 }
Generated on Tue Jul 12 2022 20:23:48 by
1.7.2