xref: /nrf52832-nimble/rt-thread/components/net/freemodbus/modbus/mb_m.c (revision 104654410c56c573564690304ae786df310c91fc)
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
eMBMasterInit(eMBMode eMode,UCHAR ucPort,ULONG ulBaudRate,eMBParity eParity)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
eMBMasterClose(void)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
eMBMasterEnable(void)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
eMBMasterDisable(void)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
eMBMasterPoll(void)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.*/
xMBMasterGetCBRunInMasterMode(void)374 BOOL xMBMasterGetCBRunInMasterMode( void )
375 {
376 	return xMBRunInMasterMode;
377 }
378 /* Set whether the Modbus Master is run in master mode.*/
vMBMasterSetCBRunInMasterMode(BOOL IsMasterMode)379 void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode )
380 {
381 	xMBRunInMasterMode = IsMasterMode;
382 }
383 /* Get Modbus Master send destination address. */
ucMBMasterGetDestAddress(void)384 UCHAR ucMBMasterGetDestAddress( void )
385 {
386 	return ucMBMasterDestAddress;
387 }
388 /* Set Modbus Master send destination address. */
vMBMasterSetDestAddress(UCHAR Address)389 void vMBMasterSetDestAddress( UCHAR Address )
390 {
391 	ucMBMasterDestAddress = Address;
392 }
393 /* Get Modbus Master current error event type. */
eMBMasterGetErrorType(void)394 eMBMasterErrorEventType eMBMasterGetErrorType( void )
395 {
396 	return eMBMasterCurErrorType;
397 }
398 /* Set Modbus Master current error event type. */
vMBMasterSetErrorType(eMBMasterErrorEventType errorType)399 void vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
400 {
401 	eMBMasterCurErrorType = errorType;
402 }
403 
404 
405 
406 #endif
407