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