modbus_client_pdu.c
Go to the documentation of this file.
1 /**
2  * @file modbus_client_pdu.c
3  * @brief Modbus PDU formatting and parsing
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 1.9.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL MODBUS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "modbus/modbus_client.h"
38 #include "modbus/modbus_debug.h"
39 #include "debug.h"
40 
41 //Check TCP/IP stack configuration
42 #if (MODBUS_CLIENT_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Format Read Coils request
47  * @param[in] context Pointer to the Modbus/TCP client context
48  * @param[in] address Address of the first coil
49  * @param[in] quantity Number of coils
50  * @return Error code
51  **/
52 
54  uint16_t address, uint_t quantity)
55 {
56  size_t length;
57  ModbusReadCoilsReq *request;
58 
59  //Point to the Modbus request PDU
60  request = modbusClientGetRequestPdu(context);
61 
62  //Format Read Coils request
63  request->functionCode = MODBUS_FUNCTION_READ_COILS;
64  request->startingAddr = htons(address);
65  request->quantityOfCoils = htons(quantity);
66 
67  //Compute the length of the request PDU
68  length = sizeof(ModbusReadCoilsReq);
69 
70  //Debug message
71  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
72  //Dump the contents of the PDU for debugging purpose
73  modbusDumpRequestPdu(request, length);
74 
75  //Format MBAP header
76  return modbusClientFormatMbapHeader(context, length);
77 }
78 
79 
80 /**
81  * @brief Format Read Discrete Inputs request
82  * @param[in] context Pointer to the Modbus/TCP client context
83  * @param[in] address Address of the first coil
84  * @param[in] quantity Number of inputs
85  * @return Error code
86  **/
87 
89  uint16_t address, uint_t quantity)
90 {
91  size_t length;
93 
94  //Point to the Modbus request PDU
95  request = modbusClientGetRequestPdu(context);
96 
97  //Format Read Discrete Inputs request
98  request->functionCode = MODBUS_FUNCTION_READ_DISCRETE_INPUTS;
99  request->startingAddr = htons(address);
100  request->quantityOfInputs = htons(quantity);
101 
102  //Compute the length of the request PDU
104 
105  //Debug message
106  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
107  //Dump the contents of the PDU for debugging purpose
108  modbusDumpRequestPdu(request, length);
109 
110  //Format MBAP header
111  return modbusClientFormatMbapHeader(context, length);
112 }
113 
114 
115 /**
116  * @brief Format Read Holding Registers request
117  * @param[in] context Pointer to the Modbus/TCP client context
118  * @param[in] address Starting register address
119  * @param[in] quantity Number of registers
120  * @return Error code
121  **/
122 
124  uint16_t address, uint_t quantity)
125 {
126  size_t length;
127  ModbusReadHoldingRegsReq *request;
128 
129  //Point to the Modbus request PDU
130  request = modbusClientGetRequestPdu(context);
131 
132  //Format Read Holding Registers request
133  request->functionCode = MODBUS_FUNCTION_READ_HOLDING_REGS;
134  request->startingAddr = htons(address);
135  request->quantityOfRegs = htons(quantity);
136 
137  //Compute the length of the request PDU
139 
140  //Debug message
141  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
142  //Dump the contents of the PDU for debugging purpose
143  modbusDumpRequestPdu(request, length);
144 
145  //Format MBAP header
146  return modbusClientFormatMbapHeader(context, length);
147 }
148 
149 
150 /**
151  * @brief Format Read Input Registers request
152  * @param[in] context Pointer to the Modbus/TCP client context
153  * @param[in] address Starting register address
154  * @param[in] quantity Number of registers
155  * @return Error code
156  **/
157 
159  uint16_t address, uint_t quantity)
160 {
161  size_t length;
162  ModbusReadInputRegsReq *request;
163 
164  //Point to the Modbus request PDU
165  request = modbusClientGetRequestPdu(context);
166 
167  //Format Read Input Registers request
168  request->functionCode = MODBUS_FUNCTION_READ_INPUT_REGS;
169  request->startingAddr = htons(address);
170  request->quantityOfRegs = htons(quantity);
171 
172  //Compute the length of the request PDU
173  length = sizeof(ModbusReadInputRegsReq);
174 
175  //Debug message
176  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
177  //Dump the contents of the PDU for debugging purpose
178  modbusDumpRequestPdu(request, length);
179 
180  //Format MBAP header
181  return modbusClientFormatMbapHeader(context, length);
182 }
183 
184 
185 /**
186  * @brief Format Write Single Coil request
187  * @param[in] context Pointer to the Modbus/TCP client context
188  * @param[in] address Address of the coil to be forced
189  * @param[in] value Value of the discrete output
190  * @return Error code
191  **/
192 
194  uint16_t address, bool_t value)
195 {
196  size_t length;
197  ModbusWriteSingleCoilReq *request;
198 
199  //Point to the Modbus request PDU
200  request = modbusClientGetRequestPdu(context);
201 
202  //Format Write Single Coil request
203  request->functionCode = MODBUS_FUNCTION_WRITE_SINGLE_COIL;
204  request->outputAddr = htons(address);
205 
206  //A value of 0xFF00 requests the output to be ON. A value of 0x0000
207  //requests it to be OFF
208  if(value)
209  request->outputValue = HTONS(MODBUS_COIL_STATE_ON);
210  else
211  request->outputValue = HTONS(MODBUS_COIL_STATE_OFF);
212 
213  //Compute the length of the request PDU
215 
216  //Debug message
217  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
218  //Dump the contents of the PDU for debugging purpose
219  modbusDumpRequestPdu(request, length);
220 
221  //Format MBAP header
222  return modbusClientFormatMbapHeader(context, length);
223 }
224 
225 
226 /**
227  * @brief Format Write Single Register request
228  * @param[in] context Pointer to the Modbus/TCP client context
229  * @param[in] address Address of the register to be written
230  * @param[in] value Register value
231  * @return Error code
232  **/
233 
235  uint16_t address, uint16_t value)
236 {
237  size_t length;
238  ModbusWriteSingleRegReq *request;
239 
240  //Point to the Modbus request PDU
241  request = modbusClientGetRequestPdu(context);
242 
243  //Format Write Single Register request
244  request->functionCode = MODBUS_FUNCTION_WRITE_SINGLE_REG;
245  request->regAddr = htons(address);
246  request->regValue = htons(value);
247 
248  //Compute the length of the request PDU
250 
251  //Debug message
252  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
253  //Dump the contents of the PDU for debugging purpose
254  modbusDumpRequestPdu(request, length);
255 
256  //Format MBAP header
257  return modbusClientFormatMbapHeader(context, length);
258 }
259 
260 
261 /**
262  * @brief Format Write Multiple Coils request
263  * @param[in] context Pointer to the Modbus/TCP client context
264  * @param[in] address Address of the first coil to be forced
265  * @param[in] quantity Number of coils
266  * @param[in] value Value of the discrete outputs
267  * @return Error code
268  **/
269 
271  uint16_t address, uint_t quantity, const uint8_t *value)
272 {
273  size_t length;
275 
276  //Point to the Modbus request PDU
277  request = modbusClientGetRequestPdu(context);
278 
279  //Format Write Multiple Coils request
280  request->functionCode = MODBUS_FUNCTION_WRITE_MULTIPLE_COILS;
281  request->startingAddr = htons(address);
282  request->quantityOfOutputs = htons(quantity);
283  request->byteCount = (quantity + 7) / 8;
284 
285  //Copy coil values
286  memcpy(request->outputValue, value, request->byteCount);
287 
288  //Compute the length of the request PDU
289  length = sizeof(ModbusWriteMultipleCoilsReq) + request->byteCount;
290 
291  //Debug message
292  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
293  //Dump the contents of the PDU for debugging purpose
294  modbusDumpRequestPdu(request, length);
295 
296  //Format MBAP header
297  return modbusClientFormatMbapHeader(context, length);
298 }
299 
300 
301 /**
302  * @brief Format Write Multiple Registers request
303  * @param[in] context Pointer to the Modbus/TCP client context
304  * @param[in] address Starting register address
305  * @param[in] quantity Number of registers
306  * @param[in] value Value of the holding registers
307  * @return Error code
308  **/
309 
311  uint16_t address, uint_t quantity, const uint16_t *value)
312 {
313  uint_t i;
314  size_t length;
316 
317  //Point to the Modbus request PDU
318  request = modbusClientGetRequestPdu(context);
319 
320  //Format Write Multiple Registers request
321  request->functionCode = MODBUS_FUNCTION_WRITE_MULTIPLE_REGS;
322  request->startingAddr = htons(address);
323  request->quantityOfRegs = htons(quantity);
324  request->byteCount = quantity * sizeof(uint16_t);
325 
326  //Copy register values
327  for(i = 0; i < quantity; i++)
328  {
329  request->regValue[i] = ntohs(value[i]);
330  }
331 
332  //Compute the length of the request PDU
333  length = sizeof(ModbusWriteMultipleRegsReq) + request->byteCount;
334 
335  //Debug message
336  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
337  //Dump the contents of the PDU for debugging purpose
338  modbusDumpRequestPdu(request, length);
339 
340  //Format MBAP header
341  return modbusClientFormatMbapHeader(context, length);
342 }
343 
344 
345 /**
346  * @brief Format Mask Write Register request
347  * @param[in] context Pointer to the Modbus/TCP client context
348  * @param[in] address Address of the holding register
349  * @param[in] andMask AND bitmask
350  * @param[in] orMask OR bitmask
351  * @return Error code
352  **/
353 
355  uint16_t address, uint16_t andMask, uint16_t orMask)
356 {
357  size_t length;
358  ModbusMaskWriteRegReq *request;
359 
360  //Point to the Modbus request PDU
361  request = modbusClientGetRequestPdu(context);
362 
363  //Format Write Single Register request
364  request->functionCode = MODBUS_FUNCTION_MASK_WRITE_REG;
365  request->referenceAddr = htons(address);
366  request->andMask = htons(andMask);
367  request->orMask = htons(orMask);
368 
369  //Compute the length of the request PDU
370  length = sizeof(ModbusMaskWriteRegReq);
371 
372  //Debug message
373  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
374  //Dump the contents of the PDU for debugging purpose
375  modbusDumpRequestPdu(request, length);
376 
377  //Format MBAP header
378  return modbusClientFormatMbapHeader(context, length);
379 }
380 
381 
382 /**
383  * @brief Format Read/Write Multiple Registers request
384  * @param[in] context Pointer to the Modbus/TCP client context
385  * @param[in] readAddress Address of the first holding registers to be read
386  * @param[in] readQuantity Number of holding registers to be read
387  * @param[in] writeAddress Address of the first holding registers to be written
388  * @param[in] writeQuantity Number of holding registers to be written
389  * @param[in] writeValue Value of the holding registers (write operation)
390  * @return Error code
391  **/
392 
394  uint16_t readAddress, uint16_t readQuantity, uint16_t writeAddress,
395  uint16_t writeQuantity, const uint16_t *writeValue)
396 {
397  uint_t i;
398  size_t length;
400 
401  //Point to the Modbus request PDU
402  request = modbusClientGetRequestPdu(context);
403 
404  //Format Read/Write Multiple Registers request
405  request->functionCode = MODBUS_FUNCTION_READ_WRITE_MULTIPLE_REGS;
406  request->readStartingAddr = htons(readAddress);
407  request->quantityToRead = htons(readQuantity);
408  request->writeStartingAddr = htons(writeAddress);
409  request->quantityToWrite = htons(writeQuantity);
410  request->writeByteCount = writeQuantity * sizeof(uint16_t);
411 
412  //Copy register values
413  for(i = 0; i < writeQuantity; i++)
414  {
415  request->writeRegValue[i] = ntohs(writeValue[i]);
416  }
417 
418  //Compute the length of the request PDU
419  length = sizeof(ModbusReadWriteMultipleRegsReq) + request->writeByteCount;
420 
421  //Debug message
422  TRACE_DEBUG("\r\nModbus Client: Sending Request PDU (%" PRIuSIZE " bytes)...\r\n", length);
423  //Dump the contents of the PDU for debugging purpose
424  modbusDumpRequestPdu(request, length);
425 
426  //Format MBAP header
427  return modbusClientFormatMbapHeader(context, length);
428 }
429 
430 
431 /**
432  * @brief Parse Read Coils response
433  * @param[in] context Pointer to the Modbus/TCP client context
434  * @param[in] quantity Number of coils
435  * @param[out] value Value of the discrete outputs
436  * @return Error code
437  **/
438 
440  uint_t quantity, uint8_t *value)
441 {
442  size_t n;
443  size_t length;
444  ModbusReadCoilsResp *response;
445 
446  //Point to the Modbus response PDU
447  response = modbusClientGetResponsePdu(context, &length);
448 
449  //Malformed PDU?
450  if(length < sizeof(ModbusReadCoilsResp))
451  return ERROR_INVALID_LENGTH;
452 
453  //Compute the length of the data field
454  n = length - sizeof(ModbusReadCoilsResp);
455 
456  //Check function code
457  if(response->functionCode != MODBUS_FUNCTION_READ_COILS)
458  return ERROR_INVALID_RESPONSE;
459 
460  //Check byte count field
461  if(response->byteCount != n || response->byteCount != ((quantity + 7) / 8))
462  return ERROR_INVALID_LENGTH;
463 
464  //Copy coil values
465  memcpy(value, response->coilStatus, response->byteCount);
466 
467  //Successful processing
468  return NO_ERROR;
469 }
470 
471 
472 /**
473  * @brief Parse Discrete Inputs response
474  * @param[in] context Pointer to the Modbus/TCP client context
475  * @param[in] quantity Number of inputs
476  * @param[out] value Value of the discrete inputs
477  * @return Error code
478  **/
479 
481  uint_t quantity, uint8_t *value)
482 {
483  size_t n;
484  size_t length;
486 
487  //Point to the Modbus response PDU
488  response = modbusClientGetResponsePdu(context, &length);
489 
490  //Malformed PDU?
492  return ERROR_INVALID_LENGTH;
493 
494  //Compute the length of the data field
496 
497  //Check function code
498  if(response->functionCode != MODBUS_FUNCTION_READ_DISCRETE_INPUTS)
499  return ERROR_INVALID_RESPONSE;
500 
501  //Check byte count field
502  if(response->byteCount != n || response->byteCount != ((quantity + 7) / 8))
503  return ERROR_INVALID_LENGTH;
504 
505  //Copy discrete input values
506  memcpy(value, response->inputStatus, response->byteCount);
507 
508  //Successful processing
509  return NO_ERROR;
510 }
511 
512 
513 /**
514  * @brief Parse Read Holding Registers response
515  * @param[in] context Pointer to the Modbus/TCP client context
516  * @param[in] quantity Number of registers
517  * @param[out] value Value of the holding registers
518  * @return Error code
519  **/
520 
522  uint_t quantity, uint16_t *value)
523 {
524  uint_t i;
525  size_t n;
526  size_t length;
527  ModbusReadHoldingRegsResp *response;
528 
529  //Point to the Modbus response PDU
530  response = modbusClientGetResponsePdu(context, &length);
531 
532  //Malformed PDU?
533  if(length < sizeof(ModbusReadHoldingRegsResp))
534  return ERROR_INVALID_LENGTH;
535 
536  //Compute the length of the data field
537  n = length - sizeof(ModbusReadHoldingRegsResp);
538 
539  //Check function code
540  if(response->functionCode != MODBUS_FUNCTION_READ_HOLDING_REGS)
541  return ERROR_INVALID_RESPONSE;
542 
543  //Check byte count field
544  if(response->byteCount != n ||
545  response->byteCount != (quantity * sizeof(uint16_t)))
546  {
547  return ERROR_INVALID_LENGTH;
548  }
549 
550  //Copy register values
551  for(i = 0; i < quantity; i++)
552  {
553  value[i] = ntohs(response->regValue[i]);
554  }
555 
556  //Successful processing
557  return NO_ERROR;
558 }
559 
560 
561 /**
562  * @brief Parse Read Input Registers response
563  * @param[in] context Pointer to the Modbus/TCP client context
564  * @param[in] quantity Number of registers
565  * @param[out] value Value of the input registers
566  * @return Error code
567  **/
568 
570  uint_t quantity, uint16_t *value)
571 {
572  uint_t i;
573  size_t n;
574  size_t length;
575  ModbusReadInputRegsResp *response;
576 
577  //Point to the Modbus response PDU
578  response = modbusClientGetResponsePdu(context, &length);
579 
580  //Malformed PDU?
581  if(length < sizeof(ModbusReadInputRegsResp))
582  return ERROR_INVALID_LENGTH;
583 
584  //Compute the length of the data field
585  n = length - sizeof(ModbusReadInputRegsResp);
586 
587  //Check function code
588  if(response->functionCode != MODBUS_FUNCTION_READ_INPUT_REGS)
589  return ERROR_INVALID_RESPONSE;
590 
591  //Check byte count field
592  if(response->byteCount != n ||
593  response->byteCount != (quantity * sizeof(uint16_t)))
594  {
595  return ERROR_INVALID_LENGTH;
596  }
597 
598  //Copy register values
599  for(i = 0; i < quantity; i++)
600  {
601  value[i] = ntohs(response->regValue[i]);
602  }
603 
604  //Successful processing
605  return NO_ERROR;
606 }
607 
608 
609 /**
610  * @brief Parse Write Single Coil response
611  * @param[in] context Pointer to the Modbus/TCP client context
612  * @param[in] address Address of the coil to be forced
613  * @param[in] value Value of the discrete output
614  * @return Error code
615  **/
616 
618  uint16_t address, bool_t value)
619 {
620  size_t length;
621  bool_t referenceValue;
622  ModbusWriteSingleCoilResp *response;
623 
624  //Point to the Modbus response PDU
625  response = modbusClientGetResponsePdu(context, &length);
626 
627  //Malformed PDU?
628  if(length < sizeof(ModbusWriteSingleCoilResp))
629  return ERROR_INVALID_LENGTH;
630 
631  //Check function code
632  if(response->functionCode != MODBUS_FUNCTION_WRITE_SINGLE_COIL)
633  return ERROR_INVALID_RESPONSE;
634 
635  //A value of 0xFF00 requests the output to be ON. A value of 0x0000
636  //requests it to be OFF
637  referenceValue = value ? MODBUS_COIL_STATE_ON : MODBUS_COIL_STATE_OFF;
638 
639  //The normal response is an echo of the request
640  if(ntohs(response->outputAddr) != address ||
641  ntohs(response->outputValue) != referenceValue)
642  {
643  return ERROR_INVALID_RESPONSE;
644  }
645 
646  //Successful processing
647  return NO_ERROR;
648 }
649 
650 
651 /**
652  * @brief Parse Write Single Register response
653  * @param[in] context Pointer to the Modbus/TCP client context
654  * @param[in] address Address of the register to be written
655  * @param[in] value Register value
656  * @return Error code
657  **/
658 
660  uint16_t address, uint16_t value)
661 {
662  size_t length;
663  ModbusWriteSingleRegResp *response;
664 
665  //Point to the Modbus response PDU
666  response = modbusClientGetResponsePdu(context, &length);
667 
668  //Malformed PDU?
669  if(length < sizeof(ModbusWriteSingleRegResp))
670  return ERROR_INVALID_LENGTH;
671 
672  //Check function code
673  if(response->functionCode != MODBUS_FUNCTION_WRITE_SINGLE_REG)
674  return ERROR_INVALID_RESPONSE;
675 
676  //The normal response is an echo of the request
677  if(ntohs(response->regAddr) != address ||
678  ntohs(response->regValue) != value)
679  {
680  return ERROR_INVALID_RESPONSE;
681  }
682 
683  //Successful processing
684  return NO_ERROR;
685 }
686 
687 
688 /**
689  * @brief Parse Write Multiple Coils response
690  * @param[in] context Pointer to the Modbus/TCP client context
691  * @param[in] address Address of the first coil to be forced
692  * @param[in] quantity Number of coils
693  * @return Error code
694  **/
695 
697  uint16_t address, uint_t quantity)
698 {
699  size_t length;
701 
702  //Point to the Modbus response PDU
703  response = modbusClientGetResponsePdu(context, &length);
704 
705  //Malformed PDU?
707  return ERROR_INVALID_LENGTH;
708 
709  //Check function code
710  if(response->functionCode != MODBUS_FUNCTION_WRITE_MULTIPLE_COILS)
711  return ERROR_INVALID_RESPONSE;
712 
713  //The normal response returns the starting address, and quantity of
714  //coils forced
715  if(ntohs(response->startingAddr) != address ||
716  ntohs(response->quantityOfOutputs) != quantity)
717  {
718  return ERROR_INVALID_RESPONSE;
719  }
720 
721  //Successful processing
722  return NO_ERROR;
723 }
724 
725 
726 /**
727  * @brief Parse Write Multiple Registers response
728  * @param[in] context Pointer to the Modbus/TCP client context
729  * @param[in] address Starting register address
730  * @param[in] quantity Number of registers
731  * @return Error code
732  **/
733 
735  uint16_t address, uint_t quantity)
736 {
737  size_t length;
738  ModbusWriteMultipleRegsResp *response;
739 
740  //Point to the Modbus response PDU
741  response = modbusClientGetResponsePdu(context, &length);
742 
743  //Malformed PDU?
744  if(length < sizeof(ModbusWriteMultipleRegsResp))
745  return ERROR_INVALID_LENGTH;
746 
747  //Check function code
748  if(response->functionCode != MODBUS_FUNCTION_WRITE_MULTIPLE_REGS)
749  return ERROR_INVALID_RESPONSE;
750 
751  //The normal response returns the starting address, and quantity of
752  //registers written
753  if(ntohs(response->startingAddr) != address ||
754  ntohs(response->quantityOfRegs) != quantity)
755  {
756  return ERROR_INVALID_RESPONSE;
757  }
758 
759  //Successful processing
760  return NO_ERROR;
761 }
762 
763 
764 /**
765  * @brief Parse Mask Write Register response
766  * @param[in] context Pointer to the Modbus/TCP client context
767  * @param[in] address Address of the holding register
768  * @param[in] andMask AND bitmask
769  * @param[in] orMask OR bitmask
770  * @return Error code
771  **/
772 
774  uint16_t address, uint16_t andMask, uint16_t orMask)
775 {
776  size_t length;
777  ModbusMaskWriteRegResp *response;
778 
779  //Point to the Modbus response PDU
780  response = modbusClientGetResponsePdu(context, &length);
781 
782  //Malformed PDU?
783  if(length < sizeof(ModbusMaskWriteRegResp))
784  return ERROR_INVALID_LENGTH;
785 
786  //Check function code
787  if(response->functionCode != MODBUS_FUNCTION_MASK_WRITE_REG)
788  return ERROR_INVALID_RESPONSE;
789 
790  //The normal response is an echo of the request
791  if(ntohs(response->referenceAddr) != address ||
792  ntohs(response->andMask) != andMask ||
793  ntohs(response->orMask) != orMask)
794  {
795  return ERROR_INVALID_RESPONSE;
796  }
797 
798  //Successful processing
799  return NO_ERROR;
800 }
801 
802 
803 /**
804  * @brief Parse Read/Write Multiple Registers response
805  * @param[in] context Pointer to the Modbus/TCP client context
806  * @param[in] readQuantity Number of holding registers to be read
807  * @param[out] readValue Value of the holding registers
808  * @return Error code
809  **/
810 
812  uint_t readQuantity, uint16_t *readValue)
813 {
814  uint_t i;
815  size_t n;
816  size_t length;
818 
819  //Point to the Modbus response PDU
820  response = modbusClientGetResponsePdu(context, &length);
821 
822  //Malformed PDU?
824  return ERROR_INVALID_LENGTH;
825 
826  //Compute the length of the data field
827  n = length - sizeof(ModbusReadInputRegsResp);
828 
829  //Check function code
830  if(response->functionCode != MODBUS_FUNCTION_READ_WRITE_MULTIPLE_REGS)
831  return ERROR_INVALID_RESPONSE;
832 
833  //Check byte count field
834  if(response->readByteCount != n ||
835  response->readByteCount != (readQuantity * sizeof(uint16_t)))
836  {
837  return ERROR_INVALID_LENGTH;
838  }
839 
840  //Copy register values
841  for(i = 0; i < readQuantity; i++)
842  {
843  readValue[i] = ntohs(response->readRegValue[i]);
844  }
845 
846  //Successful processing
847  return NO_ERROR;
848 }
849 
850 
851 /**
852  * @brief Parse Exception response
853  * @param[in] context Pointer to the Modbus/TCP client context
854  * @return Error code
855  **/
856 
858 {
859  size_t length;
860  ModbusExceptionResp *response;
861 
862  //Point to the Modbus response PDU
863  response = modbusClientGetResponsePdu(context, &length);
864 
865  //Malformed PDU?
866  if(length < sizeof(ModbusExceptionResp))
867  return ERROR_INVALID_LENGTH;
868 
869  //Save exception code
870  context->exceptionCode = (ModbusExceptionCode) response->exceptionCode;
871 
872  //Send a negative confirmation to the user application
874 }
875 
876 #endif
void * modbusClientGetResponsePdu(ModbusClientContext *context, size_t *length)
Retrieve response PDU.
#define htons(value)
Definition: cpu_endian.h:392
error_t modbusDumpRequestPdu(const void *pdu, size_t length)
Dump Modbus request PDU for debugging purpose.
Definition: modbus_debug.c:99
error_t modbusClientParseWriteMultipleRegsResp(ModbusClientContext *context, uint16_t address, uint_t quantity)
Parse Write Multiple Registers response.
Modbus/TCP client.
uint8_t length
Definition: dtls_misc.h:149
__start_packed struct @228 ModbusReadWriteMultipleRegsResp
Read/Write Multiple Registers response PDU.
int bool_t
Definition: compiler_port.h:49
__start_packed struct @222 ModbusWriteMultipleCoilsResp
Write Multiple Coils response PDU.
error_t modbusClientParseReadHoldingRegsResp(ModbusClientContext *context, uint_t quantity, uint16_t *value)
Parse Read Holding Registers response.
error_t modbusClientParseWriteMultipleCoilsResp(ModbusClientContext *context, uint16_t address, uint_t quantity)
Parse Write Multiple Coils response.
uint16_t andMask
__start_packed struct @223 ModbusWriteMultipleRegsReq
Write Multiple Registers request PDU.
error_t modbusClientParseExceptionResp(ModbusClientContext *context)
Parse Exception response.
error_t modbusClientFormatReadWriteMultipleRegsReq(ModbusClientContext *context, uint16_t readAddress, uint16_t readQuantity, uint16_t writeAddress, uint16_t writeQuantity, const uint16_t *writeValue)
Format Read/Write Multiple Registers request.
error_t modbusClientParseWriteSingleCoilResp(ModbusClientContext *context, uint16_t address, bool_t value)
Parse Write Single Coil response.
error_t modbusClientFormatWriteMultipleRegsReq(ModbusClientContext *context, uint16_t address, uint_t quantity, const uint16_t *value)
Format Write Multiple Registers request.
__start_packed struct @229 ModbusExceptionResp
Exception response PDU.
__start_packed struct @217 ModbusWriteSingleCoilReq
Write Single Coil request PDU.
error_t modbusClientFormatMaskWriteRegReq(ModbusClientContext *context, uint16_t address, uint16_t andMask, uint16_t orMask)
Format Mask Write Register request.
__start_packed struct @210 ModbusReadCoilsResp
Read Coils response PDU.
#define ModbusClientContext
Definition: modbus_client.h:81
__start_packed struct @224 ModbusWriteMultipleRegsResp
Write Multiple Registers response PDU.
error_t modbusClientFormatReadCoilsReq(ModbusClientContext *context, uint16_t address, uint_t quantity)
Format Read Coils request.
error_t modbusClientFormatReadInputRegsReq(ModbusClientContext *context, uint16_t address, uint_t quantity)
Format Read Input Registers request.
error_t modbusClientFormatWriteSingleCoilReq(ModbusClientContext *context, uint16_t address, bool_t value)
Format Write Single Coil request.
__start_packed struct @225 ModbusMaskWriteRegReq
Mask Write Register request PDU.
error_t
Error codes.
Definition: error.h:42
__start_packed struct @214 ModbusReadHoldingRegsResp
Read Holding Registers response PDU.
error_t modbusClientParseReadInputRegsResp(ModbusClientContext *context, uint_t quantity, uint16_t *value)
Parse Read Input Registers response.
__start_packed struct @213 ModbusReadHoldingRegsReq
Read Holding Registers request PDU.
__start_packed struct @209 ModbusReadCoilsReq
Read Coils request PDU.
error_t modbusClientParseReadDiscreteInputsResp(ModbusClientContext *context, uint_t quantity, uint8_t *value)
Parse Discrete Inputs response.
error_t modbusClientFormatMbapHeader(ModbusClientContext *context, size_t length)
Format MBAP header.
__start_packed struct @219 ModbusWriteSingleRegReq
Write Single Register request PDU.
__start_packed struct @221 ModbusWriteMultipleCoilsReq
Write Multiple Coils request PDU.
__start_packed struct @227 ModbusReadWriteMultipleRegsReq
Read/Write Multiple Registers request PDU.
__start_packed struct @226 ModbusMaskWriteRegResp
Mask Write Register response PDU.
Modbus PDU formatting and parsing.
__start_packed struct @218 ModbusWriteSingleCoilResp
Write Single Coil response PDU.
#define ntohs(value)
Definition: cpu_endian.h:398
__start_packed struct @211 ModbusReadDiscreteInputsReq
Read Discrete Inputs request PDU.
#define TRACE_DEBUG(...)
Definition: debug.h:106
__start_packed struct @215 ModbusReadInputRegsReq
Read Holding Input request PDU.
uint16_t orMask
Data logging functions for debugging purpose (Modbus/TCP)
#define HTONS(value)
Definition: cpu_endian.h:390
uint8_t n
__start_packed struct @220 ModbusWriteSingleRegResp
Write Single Register response PDU.
void * modbusClientGetRequestPdu(ModbusClientContext *context)
Retrieve request PDU.
error_t modbusClientFormatWriteSingleRegReq(ModbusClientContext *context, uint16_t address, uint16_t value)
Format Write Single Register request.
error_t modbusClientParseReadCoilsResp(ModbusClientContext *context, uint_t quantity, uint8_t *value)
Parse Read Coils response.
error_t modbusClientFormatWriteMultipleCoilsReq(ModbusClientContext *context, uint16_t address, uint_t quantity, const uint8_t *value)
Format Write Multiple Coils request.
__start_packed struct @212 ModbusReadDiscreteInputsResp
Read Discrete Inputs response PDU.
error_t modbusClientFormatReadDiscreteInputsReq(ModbusClientContext *context, uint16_t address, uint_t quantity)
Format Read Discrete Inputs request.
error_t modbusClientParseReadWriteMultipleRegsResp(ModbusClientContext *context, uint_t readQuantity, uint16_t *readValue)
Parse Read/Write Multiple Registers response.
error_t modbusClientParseWriteSingleRegResp(ModbusClientContext *context, uint16_t address, uint16_t value)
Parse Write Single Register response.
Ipv6Addr address
uint8_t value[]
Definition: dtls_misc.h:150
#define PRIuSIZE
Definition: compiler_port.h:78
unsigned int uint_t
Definition: compiler_port.h:45
error_t modbusClientParseMaskWriteRegResp(ModbusClientContext *context, uint16_t address, uint16_t andMask, uint16_t orMask)
Parse Mask Write Register response.
ModbusExceptionCode
Modbus exception codes.
error_t modbusClientFormatReadHoldingRegsReq(ModbusClientContext *context, uint16_t address, uint_t quantity)
Format Read Holding Registers request.
__start_packed struct @216 ModbusReadInputRegsResp
Read Holding Input response PDU.
Helper functions for Modbus/TCP client.
Success.
Definition: error.h:44
Debugging facilities.