sw k
/
Modbus
a
Fork of Modbus by
Embed:
(wiki syntax)
Show/hide line numbers
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 23:11:12 by 1.7.2