1 /* 2 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU. 3 * Copyright (C) 2013 Armink <[email protected]> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * File: $Id: mbrtu_m.c,v 1.60 2013/08/20 11:18:10 Armink Add Master Functions $ 29 */ 30 31 /* ----------------------- System includes ----------------------------------*/ 32 #include "stdlib.h" 33 #include "string.h" 34 35 /* ----------------------- Platform includes --------------------------------*/ 36 #include "port.h" 37 38 /* ----------------------- Modbus includes ----------------------------------*/ 39 40 #include "mb.h" 41 #include "mb_m.h" 42 #include "mbconfig.h" 43 #include "mbframe.h" 44 #include "mbproto.h" 45 #include "mbfunc.h" 46 47 #include "mbport.h" 48 #if MB_MASTER_RTU_ENABLED == 1 49 #include "mbrtu.h" 50 #endif 51 #if MB_MASTER_ASCII_ENABLED == 1 52 #include "mbascii.h" 53 #endif 54 #if MB_MASTER_TCP_ENABLED == 1 55 #include "mbtcp.h" 56 #endif 57 58 #if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 59 60 #ifndef MB_PORT_HAS_CLOSE 61 #define MB_PORT_HAS_CLOSE 0 62 #endif 63 64 /* ----------------------- Static variables ---------------------------------*/ 65 66 static UCHAR ucMBMasterDestAddress; 67 static BOOL xMBRunInMasterMode = FALSE; 68 static eMBMasterErrorEventType eMBMasterCurErrorType; 69 70 static enum 71 { 72 STATE_ENABLED, 73 STATE_DISABLED, 74 STATE_NOT_INITIALIZED 75 } eMBState = STATE_NOT_INITIALIZED; 76 77 /* Functions pointer which are initialized in eMBInit( ). Depending on the 78 * mode (RTU or ASCII) the are set to the correct implementations. 79 * Using for Modbus Master,Add by Armink 20130813 80 */ 81 static peMBFrameSend peMBMasterFrameSendCur; 82 static pvMBFrameStart pvMBMasterFrameStartCur; 83 static pvMBFrameStop pvMBMasterFrameStopCur; 84 static peMBFrameReceive peMBMasterFrameReceiveCur; 85 static pvMBFrameClose pvMBMasterFrameCloseCur; 86 87 /* Callback functions required by the porting layer. They are called when 88 * an external event has happend which includes a timeout or the reception 89 * or transmission of a character. 90 * Using for Modbus Master,Add by Armink 20130813 91 */ 92 BOOL( *pxMBMasterFrameCBByteReceived ) ( void ); 93 BOOL( *pxMBMasterFrameCBTransmitterEmpty ) ( void ); 94 BOOL( *pxMBMasterPortCBTimerExpired ) ( void ); 95 96 BOOL( *pxMBMasterFrameCBReceiveFSMCur ) ( void ); 97 BOOL( *pxMBMasterFrameCBTransmitFSMCur ) ( void ); 98 99 /* An array of Modbus functions handlers which associates Modbus function 100 * codes with implementing functions. 101 */ 102 static xMBFunctionHandler xMasterFuncHandlers[MB_FUNC_HANDLERS_MAX] = { 103 #if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0 104 //TODO Add Master function define 105 {MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID}, 106 #endif 107 #if MB_FUNC_READ_INPUT_ENABLED > 0 108 {MB_FUNC_READ_INPUT_REGISTER, eMBMasterFuncReadInputRegister}, 109 #endif 110 #if MB_FUNC_READ_HOLDING_ENABLED > 0 111 {MB_FUNC_READ_HOLDING_REGISTER, eMBMasterFuncReadHoldingRegister}, 112 #endif 113 #if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0 114 {MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBMasterFuncWriteMultipleHoldingRegister}, 115 #endif 116 #if MB_FUNC_WRITE_HOLDING_ENABLED > 0 117 {MB_FUNC_WRITE_REGISTER, eMBMasterFuncWriteHoldingRegister}, 118 #endif 119 #if MB_FUNC_READWRITE_HOLDING_ENABLED > 0 120 {MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBMasterFuncReadWriteMultipleHoldingRegister}, 121 #endif 122 #if MB_FUNC_READ_COILS_ENABLED > 0 123 {MB_FUNC_READ_COILS, eMBMasterFuncReadCoils}, 124 #endif 125 #if MB_FUNC_WRITE_COIL_ENABLED > 0 126 {MB_FUNC_WRITE_SINGLE_COIL, eMBMasterFuncWriteCoil}, 127 #endif 128 #if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0 129 {MB_FUNC_WRITE_MULTIPLE_COILS, eMBMasterFuncWriteMultipleCoils}, 130 #endif 131 #if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0 132 {MB_FUNC_READ_DISCRETE_INPUTS, eMBMasterFuncReadDiscreteInputs}, 133 #endif 134 }; 135 136 /* ----------------------- Start implementation -----------------------------*/ 137 eMBErrorCode 138 eMBMasterInit( eMBMode eMode, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity ) 139 { 140 eMBErrorCode eStatus = MB_ENOERR; 141 142 switch (eMode) 143 { 144 #if MB_MASTER_RTU_ENABLED > 0 145 case MB_RTU: 146 pvMBMasterFrameStartCur = eMBMasterRTUStart; 147 pvMBMasterFrameStopCur = eMBMasterRTUStop; 148 peMBMasterFrameSendCur = eMBMasterRTUSend; 149 peMBMasterFrameReceiveCur = eMBMasterRTUReceive; 150 pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL; 151 pxMBMasterFrameCBByteReceived = xMBMasterRTUReceiveFSM; 152 pxMBMasterFrameCBTransmitterEmpty = xMBMasterRTUTransmitFSM; 153 pxMBMasterPortCBTimerExpired = xMBMasterRTUTimerExpired; 154 155 eStatus = eMBMasterRTUInit(ucPort, ulBaudRate, eParity); 156 break; 157 #endif 158 #if MB_MASTER_ASCII_ENABLED > 0 159 case MB_ASCII: 160 pvMBMasterFrameStartCur = eMBMasterASCIIStart; 161 pvMBMasterFrameStopCur = eMBMasterASCIIStop; 162 peMBMasterFrameSendCur = eMBMasterASCIISend; 163 peMBMasterFrameReceiveCur = eMBMasterASCIIReceive; 164 pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL; 165 pxMBMasterFrameCBByteReceived = xMBMasterASCIIReceiveFSM; 166 pxMBMasterFrameCBTransmitterEmpty = xMBMasterASCIITransmitFSM; 167 pxMBMasterPortCBTimerExpired = xMBMasterASCIITimerT1SExpired; 168 169 eStatus = eMBMasterASCIIInit(ucPort, ulBaudRate, eParity ); 170 break; 171 #endif 172 default: 173 eStatus = MB_EINVAL; 174 break; 175 } 176 177 if (eStatus == MB_ENOERR) 178 { 179 if (!xMBMasterPortEventInit()) 180 { 181 /* port dependent event module initalization failed. */ 182 eStatus = MB_EPORTERR; 183 } 184 else 185 { 186 eMBState = STATE_DISABLED; 187 } 188 /* initialize the OS resource for modbus master. */ 189 vMBMasterOsResInit(); 190 } 191 return eStatus; 192 } 193 194 eMBErrorCode 195 eMBMasterClose( void ) 196 { 197 eMBErrorCode eStatus = MB_ENOERR; 198 199 if( eMBState == STATE_DISABLED ) 200 { 201 if( pvMBMasterFrameCloseCur != NULL ) 202 { 203 pvMBMasterFrameCloseCur( ); 204 } 205 } 206 else 207 { 208 eStatus = MB_EILLSTATE; 209 } 210 return eStatus; 211 } 212 213 eMBErrorCode 214 eMBMasterEnable( void ) 215 { 216 eMBErrorCode eStatus = MB_ENOERR; 217 218 if( eMBState == STATE_DISABLED ) 219 { 220 /* Activate the protocol stack. */ 221 pvMBMasterFrameStartCur( ); 222 eMBState = STATE_ENABLED; 223 } 224 else 225 { 226 eStatus = MB_EILLSTATE; 227 } 228 return eStatus; 229 } 230 231 eMBErrorCode 232 eMBMasterDisable( void ) 233 { 234 eMBErrorCode eStatus; 235 236 if( eMBState == STATE_ENABLED ) 237 { 238 pvMBMasterFrameStopCur( ); 239 eMBState = STATE_DISABLED; 240 eStatus = MB_ENOERR; 241 } 242 else if( eMBState == STATE_DISABLED ) 243 { 244 eStatus = MB_ENOERR; 245 } 246 else 247 { 248 eStatus = MB_EILLSTATE; 249 } 250 return eStatus; 251 } 252 253 eMBErrorCode 254 eMBMasterPoll( void ) 255 { 256 static UCHAR *ucMBFrame; 257 static UCHAR ucRcvAddress; 258 static UCHAR ucFunctionCode; 259 static USHORT usLength; 260 static eMBException eException; 261 262 int i , j; 263 eMBErrorCode eStatus = MB_ENOERR; 264 eMBMasterEventType eEvent; 265 eMBMasterErrorEventType errorType; 266 267 /* Check if the protocol stack is ready. */ 268 if( eMBState != STATE_ENABLED ) 269 { 270 return MB_EILLSTATE; 271 } 272 273 /* Check if there is a event available. If not return control to caller. 274 * Otherwise we will handle the event. */ 275 if( xMBMasterPortEventGet( &eEvent ) == TRUE ) 276 { 277 switch ( eEvent ) 278 { 279 case EV_MASTER_READY: 280 break; 281 282 case EV_MASTER_FRAME_RECEIVED: 283 eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength ); 284 /* Check if the frame is for us. If not ,send an error process event. */ 285 if ( ( eStatus == MB_ENOERR ) && ( ucRcvAddress == ucMBMasterGetDestAddress() ) ) 286 { 287 ( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE ); 288 } 289 else 290 { 291 vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA); 292 ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); 293 } 294 break; 295 296 case EV_MASTER_EXECUTE: 297 ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF]; 298 eException = MB_EX_ILLEGAL_FUNCTION; 299 /* If receive frame has exception .The receive function code highest bit is 1.*/ 300 if(ucFunctionCode >> 7) { 301 eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF]; 302 } 303 else 304 { 305 for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++) 306 { 307 /* No more function handlers registered. Abort. */ 308 if (xMasterFuncHandlers[i].ucFunctionCode == 0) { 309 break; 310 } 311 else if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) { 312 vMBMasterSetCBRunInMasterMode(TRUE); 313 /* If master request is broadcast, 314 * the master need execute function for all slave. 315 */ 316 if ( xMBMasterRequestIsBroadcast() ) { 317 usLength = usMBMasterGetPDUSndLength(); 318 for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++){ 319 vMBMasterSetDestAddress(j); 320 eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength); 321 } 322 } 323 else { 324 eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength); 325 } 326 vMBMasterSetCBRunInMasterMode(FALSE); 327 break; 328 } 329 } 330 } 331 /* If master has exception ,Master will send error process.Otherwise the Master is idle.*/ 332 if (eException != MB_EX_NONE) { 333 vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION); 334 ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); 335 } 336 else { 337 vMBMasterCBRequestScuuess( ); 338 vMBMasterRunResRelease( ); 339 } 340 break; 341 342 case EV_MASTER_FRAME_SENT: 343 /* Master is busy now. */ 344 vMBMasterGetPDUSndBuf( &ucMBFrame ); 345 eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() ); 346 break; 347 348 case EV_MASTER_ERROR_PROCESS: 349 /* Execute specified error process callback function. */ 350 errorType = eMBMasterGetErrorType(); 351 vMBMasterGetPDUSndBuf( &ucMBFrame ); 352 switch (errorType) { 353 case EV_ERROR_RESPOND_TIMEOUT: 354 vMBMasterErrorCBRespondTimeout(ucMBMasterGetDestAddress(), 355 ucMBFrame, usMBMasterGetPDUSndLength()); 356 break; 357 case EV_ERROR_RECEIVE_DATA: 358 vMBMasterErrorCBReceiveData(ucMBMasterGetDestAddress(), 359 ucMBFrame, usMBMasterGetPDUSndLength()); 360 break; 361 case EV_ERROR_EXECUTE_FUNCTION: 362 vMBMasterErrorCBExecuteFunction(ucMBMasterGetDestAddress(), 363 ucMBFrame, usMBMasterGetPDUSndLength()); 364 break; 365 } 366 vMBMasterRunResRelease(); 367 break; 368 } 369 } 370 return MB_ENOERR; 371 } 372 373 /* Get whether the Modbus Master is run in master mode.*/ 374 BOOL xMBMasterGetCBRunInMasterMode( void ) 375 { 376 return xMBRunInMasterMode; 377 } 378 /* Set whether the Modbus Master is run in master mode.*/ 379 void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode ) 380 { 381 xMBRunInMasterMode = IsMasterMode; 382 } 383 /* Get Modbus Master send destination address. */ 384 UCHAR ucMBMasterGetDestAddress( void ) 385 { 386 return ucMBMasterDestAddress; 387 } 388 /* Set Modbus Master send destination address. */ 389 void vMBMasterSetDestAddress( UCHAR Address ) 390 { 391 ucMBMasterDestAddress = Address; 392 } 393 /* Get Modbus Master current error event type. */ 394 eMBMasterErrorEventType eMBMasterGetErrorType( void ) 395 { 396 return eMBMasterCurErrorType; 397 } 398 /* Set Modbus Master current error event type. */ 399 void vMBMasterSetErrorType( eMBMasterErrorEventType errorType ) 400 { 401 eMBMasterCurErrorType = errorType; 402 } 403 404 405 406 #endif 407