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