1 /*
2  * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
3  * Copyright (C) 2013 Armink <armink.ztl@gmail.com>
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: mbfuncholding_m.c,v 1.60 2013/09/02 14:13:40 Armink Add Master Functions  Exp $
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 //#include "mb.h"
40 #include "mb_m.h"
41 #include "mbframe.h"
42 #include "mbproto.h"
43 #include "mbconfig.h"
44 
45 /* ----------------------- Defines ------------------------------------------*/
46 #define MB_PDU_REQ_READ_ADDR_OFF                ( MB_PDU_DATA_OFF + 0 )
47 #define MB_PDU_REQ_READ_REGCNT_OFF              ( MB_PDU_DATA_OFF + 2 )
48 #define MB_PDU_REQ_READ_SIZE                    ( 4 )
49 #define MB_PDU_FUNC_READ_REGCNT_MAX             ( 0x007D )
50 #define MB_PDU_FUNC_READ_BYTECNT_OFF            ( MB_PDU_DATA_OFF + 0 )
51 #define MB_PDU_FUNC_READ_VALUES_OFF             ( MB_PDU_DATA_OFF + 1 )
52 #define MB_PDU_FUNC_READ_SIZE_MIN               ( 1 )
53 
54 #define MB_PDU_REQ_WRITE_ADDR_OFF               ( MB_PDU_DATA_OFF + 0)
55 #define MB_PDU_REQ_WRITE_VALUE_OFF              ( MB_PDU_DATA_OFF + 2 )
56 #define MB_PDU_REQ_WRITE_SIZE                   ( 4 )
57 #define MB_PDU_FUNC_WRITE_ADDR_OFF              ( MB_PDU_DATA_OFF + 0)
58 #define MB_PDU_FUNC_WRITE_VALUE_OFF             ( MB_PDU_DATA_OFF + 2 )
59 #define MB_PDU_FUNC_WRITE_SIZE                  ( 4 )
60 
61 #define MB_PDU_REQ_WRITE_MUL_ADDR_OFF           ( MB_PDU_DATA_OFF + 0 )
62 #define MB_PDU_REQ_WRITE_MUL_REGCNT_OFF         ( MB_PDU_DATA_OFF + 2 )
63 #define MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF        ( MB_PDU_DATA_OFF + 4 )
64 #define MB_PDU_REQ_WRITE_MUL_VALUES_OFF         ( MB_PDU_DATA_OFF + 5 )
65 #define MB_PDU_REQ_WRITE_MUL_SIZE_MIN           ( 5 )
66 #define MB_PDU_REQ_WRITE_MUL_REGCNT_MAX         ( 0x0078 )
67 #define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF          ( MB_PDU_DATA_OFF + 0 )
68 #define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF        ( MB_PDU_DATA_OFF + 2 )
69 #define MB_PDU_FUNC_WRITE_MUL_SIZE              ( 4 )
70 
71 #define MB_PDU_REQ_READWRITE_READ_ADDR_OFF      ( MB_PDU_DATA_OFF + 0 )
72 #define MB_PDU_REQ_READWRITE_READ_REGCNT_OFF    ( MB_PDU_DATA_OFF + 2 )
73 #define MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF     ( MB_PDU_DATA_OFF + 4 )
74 #define MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF   ( MB_PDU_DATA_OFF + 6 )
75 #define MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF  ( MB_PDU_DATA_OFF + 8 )
76 #define MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF   ( MB_PDU_DATA_OFF + 9 )
77 #define MB_PDU_REQ_READWRITE_SIZE_MIN           ( 9 )
78 #define MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF  ( MB_PDU_DATA_OFF + 0 )
79 #define MB_PDU_FUNC_READWRITE_READ_VALUES_OFF   ( MB_PDU_DATA_OFF + 1 )
80 #define MB_PDU_FUNC_READWRITE_SIZE_MIN          ( 1 )
81 
82 /* ----------------------- Static functions ---------------------------------*/
83 eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
84 
85 /* ----------------------- Start implementation -----------------------------*/
86 #if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
87 
88 #if MB_FUNC_WRITE_HOLDING_ENABLED
89 
90 /**
91  * This function will request write holding register.
92  *
93  * @param ucSndAddr salve address
94  * @param usRegAddr register start address
95  * @param usRegData register data to be written
96  * @param lTimeOut timeout (-1 will waiting forever)
97  *
98  * @return error code
99  */
100 eMBMasterReqErrCode
eMBMasterReqWriteHoldingRegister(UCHAR ucSndAddr,USHORT usRegAddr,USHORT usRegData,LONG lTimeOut)101 eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut )
102 {
103     UCHAR                 *ucMBFrame;
104     eMBMasterReqErrCode    eErrStatus = MB_MRE_NO_ERR;
105 
106     if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
107     else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
108     else
109     {
110         vMBMasterGetPDUSndBuf(&ucMBFrame);
111         vMBMasterSetDestAddress(ucSndAddr);
112         ucMBFrame[MB_PDU_FUNC_OFF]                = MB_FUNC_WRITE_REGISTER;
113         ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF]      = usRegAddr >> 8;
114         ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1]  = usRegAddr;
115         ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF]     = usRegData >> 8;
116         ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData ;
117         vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
118         ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
119         eErrStatus = eMBMasterWaitRequestFinish( );
120     }
121     return eErrStatus;
122 }
123 
124 eMBException
eMBMasterFuncWriteHoldingRegister(UCHAR * pucFrame,USHORT * usLen)125 eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
126 {
127     USHORT          usRegAddress;
128     eMBException    eStatus = MB_EX_NONE;
129     eMBErrorCode    eRegStatus;
130 
131     if( *usLen == ( MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_SIZE ) )
132     {
133         usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
134         usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
135         usRegAddress++;
136 
137         /* Make callback to update the value. */
138         eRegStatus = eMBMasterRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
139                                       usRegAddress, 1, MB_REG_WRITE );
140 
141         /* If an error occured convert it into a Modbus exception. */
142         if( eRegStatus != MB_ENOERR )
143         {
144             eStatus = prveMBError2Exception( eRegStatus );
145         }
146     }
147     else
148     {
149         /* Can't be a valid request because the length is incorrect. */
150         eStatus = MB_EX_ILLEGAL_DATA_VALUE;
151     }
152     return eStatus;
153 }
154 #endif
155 
156 #if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
157 
158 /**
159  * This function will request write multiple holding register.
160  *
161  * @param ucSndAddr salve address
162  * @param usRegAddr register start address
163  * @param usNRegs register total number
164  * @param pusDataBuffer data to be written
165  * @param lTimeOut timeout (-1 will waiting forever)
166  *
167  * @return error code
168  */
169 eMBMasterReqErrCode
eMBMasterReqWriteMultipleHoldingRegister(UCHAR ucSndAddr,USHORT usRegAddr,USHORT usNRegs,USHORT * pusDataBuffer,LONG lTimeOut)170 eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
171         USHORT usRegAddr, USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut )
172 {
173     UCHAR                 *ucMBFrame;
174     USHORT                 usRegIndex = 0;
175     eMBMasterReqErrCode    eErrStatus = MB_MRE_NO_ERR;
176 
177     if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
178     else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
179     else
180     {
181         vMBMasterGetPDUSndBuf(&ucMBFrame);
182         vMBMasterSetDestAddress(ucSndAddr);
183         ucMBFrame[MB_PDU_FUNC_OFF]                     = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
184         ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF]       = usRegAddr >> 8;
185         ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1]   = usRegAddr;
186         ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF]     = usNRegs >> 8;
187         ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] = usNRegs ;
188         ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF]    = usNRegs * 2;
189         ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF;
190         while( usNRegs > usRegIndex)
191         {
192             *ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
193             *ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
194         }
195         vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs );
196         ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
197         eErrStatus = eMBMasterWaitRequestFinish( );
198     }
199     return eErrStatus;
200 }
201 
202 eMBException
eMBMasterFuncWriteMultipleHoldingRegister(UCHAR * pucFrame,USHORT * usLen)203 eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
204 {
205     UCHAR          *ucMBFrame;
206     USHORT          usRegAddress;
207     USHORT          usRegCount;
208     UCHAR           ucRegByteCount;
209 
210     eMBException    eStatus = MB_EX_NONE;
211     eMBErrorCode    eRegStatus;
212 
213     /* If this request is broadcast, the *usLen is not need check. */
214     if( ( *usLen == MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_MUL_SIZE ) || xMBMasterRequestIsBroadcast() )
215     {
216         vMBMasterGetPDUSndBuf(&ucMBFrame);
217         usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] << 8 );
218         usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] );
219         usRegAddress++;
220 
221         usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] << 8 );
222         usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] );
223 
224         ucRegByteCount = ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF];
225 
226         if( ucRegByteCount == 2 * usRegCount )
227         {
228             /* Make callback to update the register values. */
229             eRegStatus = eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
230                                  usRegAddress, usRegCount, MB_REG_WRITE );
231 
232             /* If an error occured convert it into a Modbus exception. */
233             if( eRegStatus != MB_ENOERR )
234             {
235                 eStatus = prveMBError2Exception( eRegStatus );
236             }
237         }
238         else
239         {
240             eStatus = MB_EX_ILLEGAL_DATA_VALUE;
241         }
242     }
243     else
244     {
245         /* Can't be a valid request because the length is incorrect. */
246         eStatus = MB_EX_ILLEGAL_DATA_VALUE;
247     }
248     return eStatus;
249 }
250 #endif
251 
252 #if MB_FUNC_READ_HOLDING_ENABLED > 0
253 
254 /**
255  * This function will request read holding register.
256  *
257  * @param ucSndAddr salve address
258  * @param usRegAddr register start address
259  * @param usNRegs register total number
260  * @param lTimeOut timeout (-1 will waiting forever)
261  *
262  * @return error code
263  */
264 eMBMasterReqErrCode
eMBMasterReqReadHoldingRegister(UCHAR ucSndAddr,USHORT usRegAddr,USHORT usNRegs,LONG lTimeOut)265 eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut )
266 {
267     UCHAR                 *ucMBFrame;
268     eMBMasterReqErrCode    eErrStatus = MB_MRE_NO_ERR;
269 
270     if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
271     else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
272     else
273     {
274         vMBMasterGetPDUSndBuf(&ucMBFrame);
275         vMBMasterSetDestAddress(ucSndAddr);
276         ucMBFrame[MB_PDU_FUNC_OFF]                = MB_FUNC_READ_HOLDING_REGISTER;
277         ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF]       = usRegAddr >> 8;
278         ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1]   = usRegAddr;
279         ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF]     = usNRegs >> 8;
280         ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
281         vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
282         ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
283         eErrStatus = eMBMasterWaitRequestFinish( );
284     }
285     return eErrStatus;
286 }
287 
288 eMBException
eMBMasterFuncReadHoldingRegister(UCHAR * pucFrame,USHORT * usLen)289 eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
290 {
291     UCHAR          *ucMBFrame;
292     USHORT          usRegAddress;
293     USHORT          usRegCount;
294 
295     eMBException    eStatus = MB_EX_NONE;
296     eMBErrorCode    eRegStatus;
297 
298     /* If this request is broadcast, and it's read mode. This request don't need execute. */
299     if ( xMBMasterRequestIsBroadcast() )
300     {
301         eStatus = MB_EX_NONE;
302     }
303     else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
304     {
305         vMBMasterGetPDUSndBuf(&ucMBFrame);
306         usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
307         usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
308         usRegAddress++;
309 
310         usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
311         usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] );
312 
313         /* Check if the number of registers to read is valid. If not
314          * return Modbus illegal data value exception.
315          */
316         if( ( usRegCount >= 1 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
317         {
318             /* Make callback to fill the buffer. */
319             eRegStatus = eMBMasterRegHoldingCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount, MB_REG_READ );
320             /* If an error occured convert it into a Modbus exception. */
321             if( eRegStatus != MB_ENOERR )
322             {
323                 eStatus = prveMBError2Exception( eRegStatus );
324             }
325         }
326         else
327         {
328             eStatus = MB_EX_ILLEGAL_DATA_VALUE;
329         }
330     }
331     else
332     {
333         /* Can't be a valid request because the length is incorrect. */
334         eStatus = MB_EX_ILLEGAL_DATA_VALUE;
335     }
336     return eStatus;
337 }
338 
339 #endif
340 
341 #if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
342 
343 /**
344  * This function will request read and write holding register.
345  *
346  * @param ucSndAddr salve address
347  * @param usReadRegAddr read register start address
348  * @param usNReadRegs read register total number
349  * @param pusDataBuffer data to be written
350  * @param usWriteRegAddr write register start address
351  * @param usNWriteRegs write register total number
352  * @param lTimeOut timeout (-1 will waiting forever)
353  *
354  * @return error code
355  */
356 eMBMasterReqErrCode
eMBMasterReqReadWriteMultipleHoldingRegister(UCHAR ucSndAddr,USHORT usReadRegAddr,USHORT usNReadRegs,USHORT * pusDataBuffer,USHORT usWriteRegAddr,USHORT usNWriteRegs,LONG lTimeOut)357 eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
358         USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer,
359         USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut )
360 {
361     UCHAR                 *ucMBFrame;
362     USHORT                 usRegIndex = 0;
363     eMBMasterReqErrCode    eErrStatus = MB_MRE_NO_ERR;
364 
365     if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
366     else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
367     else
368     {
369         vMBMasterGetPDUSndBuf(&ucMBFrame);
370         vMBMasterSetDestAddress(ucSndAddr);
371         ucMBFrame[MB_PDU_FUNC_OFF]                           = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
372         ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF]        = usReadRegAddr >> 8;
373         ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1]    = usReadRegAddr;
374         ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF]      = usNReadRegs >> 8;
375         ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1]  = usNReadRegs ;
376         ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF]       = usWriteRegAddr >> 8;
377         ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1]   = usWriteRegAddr;
378         ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF]     = usNWriteRegs >> 8;
379         ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] = usNWriteRegs ;
380         ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF]    = usNWriteRegs * 2;
381         ucMBFrame += MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF;
382         while( usNWriteRegs > usRegIndex)
383         {
384             *ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
385             *ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
386         }
387         vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs );
388         ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
389         eErrStatus = eMBMasterWaitRequestFinish( );
390     }
391     return eErrStatus;
392 }
393 
394 eMBException
eMBMasterFuncReadWriteMultipleHoldingRegister(UCHAR * pucFrame,USHORT * usLen)395 eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
396 {
397     USHORT          usRegReadAddress;
398     USHORT          usRegReadCount;
399     USHORT          usRegWriteAddress;
400     USHORT          usRegWriteCount;
401     UCHAR          *ucMBFrame;
402 
403     eMBException    eStatus = MB_EX_NONE;
404     eMBErrorCode    eRegStatus;
405 
406     /* If this request is broadcast, and it's read mode. This request don't need execute. */
407     if ( xMBMasterRequestIsBroadcast() )
408     {
409         eStatus = MB_EX_NONE;
410     }
411     else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READWRITE_SIZE_MIN )
412     {
413         vMBMasterGetPDUSndBuf(&ucMBFrame);
414         usRegReadAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] << 8U );
415         usRegReadAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] );
416         usRegReadAddress++;
417 
418         usRegReadCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] << 8U );
419         usRegReadCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] );
420 
421         usRegWriteAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] << 8U );
422         usRegWriteAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] );
423         usRegWriteAddress++;
424 
425         usRegWriteCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] << 8U );
426         usRegWriteCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] );
427 
428         if( ( 2 * usRegReadCount ) == pucFrame[MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF] )
429         {
430             /* Make callback to update the register values. */
431             eRegStatus = eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF],
432                                            usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
433 
434             if( eRegStatus == MB_ENOERR )
435             {
436                 /* Make the read callback. */
437                 eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF],
438                                               usRegReadAddress, usRegReadCount, MB_REG_READ);
439             }
440             if( eRegStatus != MB_ENOERR )
441             {
442                 eStatus = prveMBError2Exception( eRegStatus );
443             }
444         }
445         else
446         {
447             eStatus = MB_EX_ILLEGAL_DATA_VALUE;
448         }
449     }
450     return eStatus;
451 }
452 
453 #endif
454 #endif // #if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
455