PDU.h
Go to the documentation of this file.
1 
20 #pragma once
21 
22 #include "Exception.h"
23 #include "Function.h"
24 
25 namespace IO::Modbus
26 {
27 #define ATTR_PACKED __attribute__((aligned(1), packed))
28 
45 struct PDU {
46  /*
47  * Data is packed as some fields are misaligned.
48  *
49  * MODBUS sends 16-bit values MSB first, so appropriate byte-swapping is handled by the driver.
50  * Other than that, the data is un-modified.
51  */
52  union Data {
53  // For exception response
55 
56  // ReadCoils = 0x01
57  union ReadCoils {
61  };
62 
65  uint8_t coilStatus[250];
66  static constexpr uint16_t MaxCoils{sizeof(coilStatus) * 8};
67 
68  void setCoil(uint16_t coil, bool value)
69  {
70  if(coil < MaxCoils) {
71  setBit(coilStatus, coil, value);
72  }
73  }
74 
75  bool getCoil(uint16_t coil)
76  {
77  return getBit(coilStatus, coil);
78  }
79 
80  void setCount(uint16_t count)
81  {
82  byteCount = (count + 7) / 8;
83  }
84 
85  // This figure may be larger than the actual coil count
87  {
88  return byteCount * 8;
89  }
90  };
91 
94  };
96 
97  // ReadDiscreteInputs = 0x02
102  };
103 
106  uint8_t inputStatus[250];
107  static constexpr uint16_t MaxInputs{sizeof(inputStatus) * 8};
108 
109  void setInput(uint16_t input, bool value)
110  {
111  if(input < MaxInputs) {
112  setBit(inputStatus, input, value);
113  }
114  }
115 
116  bool getInput(uint16_t input)
117  {
118  return getBit(inputStatus, input);
119  }
120 
121  void setCount(uint16_t count)
122  {
123  byteCount = (count + 7) / 8;
124  }
125 
126  // This figure may be larger than the actual input count
128  {
129  return byteCount * 8;
130  }
131  };
132 
135  };
137 
138  // 16-bit access
139  // Common format for reading input/holding registers
144  };
145 
147  static constexpr uint16_t MaxRegisters{250 / 2};
149  uint16_t values[MaxRegisters];
150 
151  void setCount(uint16_t count)
152  {
153  byteCount = std::min(count, MaxRegisters) * 2;
154  }
155 
157  {
158  return byteCount / 2;
159  }
160  };
161 
164  };
165 
166  // ReadHoldingRegisters = 0x03,
168 
169  // ReadInputRegisters = 0x04,
171 
172  // WriteSingleCoil = 0x05,
175  enum State : uint16_t {
176  state_off = 0x0000,
177  state_on = 0xFF00,
178  };
179 
182  };
183 
184  using Response = Request;
185 
188  };
190 
191  // WriteSingleRegister = 0x06,
196  };
197 
198  using Response = Request;
199 
202  };
204 
205  // ReadExceptionStatus = 0x07,
209  };
210 
212  };
214 
215  // GetComEventCounter = 0x0b,
220  };
221 
223  };
225 
226  // GetComEventLog = 0x0c,
229  static constexpr uint16_t MaxEvents{64};
234  uint8_t events[MaxEvents];
235 
237  {
238  eventCount = std::min(count, MaxEvents);
239  byteCount = 7 + eventCount;
240  }
241  };
242 
244  };
246 
247  // WriteMultipleCoils = 0x0f,
253  uint8_t values[246];
254  static constexpr uint16_t MaxCoils{sizeof(values) * 8};
255 
256  void setCoil(uint16_t coil, bool state)
257  {
258  if(coil < MaxCoils) {
259  setBit(values, coil, state);
260  }
261  }
262 
263  void setCount(uint16_t count)
264  {
265  quantityOfOutputs = std::min(count, MaxCoils);
266  byteCount = (quantityOfOutputs + 7) / 8;
267  }
268  };
269 
273  };
274 
277  };
279 
280  // WriteMultipleRegisters = 0x10,
283  static constexpr uint16_t MaxRegisters{123};
287  uint16_t values[MaxRegisters];
288 
289  void setCount(uint16_t count)
290  {
291  quantityOfRegisters = std::min(count, MaxRegisters);
292  byteCount = quantityOfRegisters * 2;
293  }
294  };
295 
299  };
300 
303  };
305 
306  // ReportServerId = 0x11,
310  runstatus_off = 0x00,
311  runstatus_on = 0xFF,
312  };
313 
317  uint8_t data[248];
318 
319  void setCount(uint8_t dataSize)
320  {
321  byteCount = 2 + dataSize;
322  }
323 
325  {
326  return byteCount - 2;
327  }
328  };
329 
331  };
333 
334  // MaskWriteRegister = 0x16,
340  };
341  using Response = Request;
342 
345  };
347 
348  // ReadWriteMultipleRegisters = 0x17,
351  static constexpr uint16_t MaxWriteRegisters{121};
357  uint16_t writeValues[MaxWriteRegisters];
358 
360  {
361  quantityToWrite = std::min(count, MaxWriteRegisters);
362  writeByteCount = quantityToWrite * 2;
363  }
364  };
366  static constexpr uint16_t MaxReadRegisters{125};
368  uint16_t values[MaxReadRegisters];
369 
370  void setCount(uint16_t count)
371  {
372  byteCount = count * 2;
373  }
374 
376  {
377  return byteCount / 2;
378  }
379  };
380 
383  };
385  };
386 
387  Function function() const
388  {
389  return Function(functionCode & 0x7f);
390  }
391 
392  void setFunction(Function function)
393  {
394  functionCode = uint8_t(function);
395  }
396 
398  {
399  functionCode |= 0x80;
401  }
402 
403  bool exceptionFlag() const
404  {
405  return functionCode & 0x80;
406  }
407 
409  {
411  }
412 
417  void swapRequestByteOrder();
418  void swapResponseByteOrder();
426  size_t getRequestSize() const
427  {
428  return 1 + getRequestDataSize(); // function + data
429  }
430 
431  size_t getResponseSize() const
432  {
433  return 1 + getResponseDataSize(); // function + data
434  }
437  /* Structure content */
438 
441 
442 private:
443  size_t getRequestDataSize() const;
444  size_t getResponseDataSize() const;
445 
446  static void setBit(uint8_t* values, uint16_t number, bool state)
447  {
448  uint8_t mask = 1 << (number % 8);
449  if(state) {
450  values[number / 8] |= mask;
451  } else {
452  values[number / 8] &= ~mask;
453  }
454  }
455 
456  static bool getBit(uint8_t* values, uint16_t number)
457  {
458  uint8_t mask = 1 << (number % 8);
459  return (values[number / 8] & mask) ? true : false;
460  }
461 };
462 
463 static_assert(offsetof(PDU, data) == 1, "PDU alignment error");
464 
465 } // namespace IO::Modbus
Function
Definition: IOControl/include/IO/Modbus/Function.h:45
Response response
Definition: PDU.h:134
void setInput(uint16_t input, bool value)
Definition: PDU.h:109
WriteSingleCoil writeSingleCoil
Definition: PDU.h:189
void setCount(uint16_t count)
Definition: PDU.h:80
WriteMultipleCoils writeMultipleCoils
Definition: PDU.h:278
uint16_t getCount() const
Definition: PDU.h:127
Request request
Definition: PDU.h:162
Request request
Definition: PDU.h:92
uint8_t byteCount
Calculated.
Definition: PDU.h:286
ReadWriteMultipleRegisters readWriteMultipleRegisters
Definition: PDU.h:384
uint16_t startAddress
Definition: PDU.h:142
uint8_t byteCount
Calculated.
Definition: PDU.h:148
Response response
Definition: PDU.h:330
Response response
Definition: PDU.h:201
void setFunction(Function function)
Definition: PDU.h:392
uint8_t getCount() const
Definition: PDU.h:324
Request request
Definition: PDU.h:186
bool getCoil(uint16_t coil)
Definition: PDU.h:75
void setCount(uint16_t count)
Definition: PDU.h:121
Protocol Data Unit.
Definition: PDU.h:45
WriteMultipleRegisters writeMultipleRegisters
Definition: PDU.h:304
ReportServerId reportServerId
Definition: PDU.h:332
RunStatus runStatus
Definition: PDU.h:316
uint16_t quantityOfOutputs
Definition: PDU.h:272
bool exceptionFlag() const
Definition: PDU.h:403
Response response
Definition: PDU.h:344
WriteSingleRegister writeSingleRegister
Definition: PDU.h:203
uint8_t functionCode
Definition: PDU.h:439
Request request
Definition: PDU.h:301
Response response
Definition: PDU.h:302
ReadExceptionStatus readExceptionStatus
Definition: PDU.h:213
void setWriteCount(uint16_t count)
Definition: PDU.h:359
ReadRegisters readInputRegisters
Definition: PDU.h:170
uint8_t byteCount
Calculated.
Definition: PDU.h:230
Exception
Modbus exception codes returned in response packets.
Definition: Exception.h:29
bool getInput(uint16_t input)
Definition: PDU.h:116
uint16_t getCount() const
Definition: PDU.h:86
void setCount(uint16_t count)
Definition: PDU.h:263
uint8_t writeByteCount
Calculated.
Definition: PDU.h:356
Response response
Definition: PDU.h:163
uint16_t quantityOfRegisters
Definition: PDU.h:143
void setCount(uint8_t dataSize)
Definition: PDU.h:319
ReadCoils readCoils
Definition: PDU.h:95
void setCoil(uint16_t coil, bool value)
Definition: PDU.h:68
void setCount(uint16_t count)
Definition: PDU.h:289
Response response
Definition: PDU.h:276
ReadRegisters readHoldingRegisters
Definition: PDU.h:167
Request request
Definition: PDU.h:343
uint8_t byteCount
Use setCount()
Definition: PDU.h:64
uint16_t startAddress
Definition: PDU.h:59
Definition: PDU.h:52
uint16_t getCount() const
Definition: PDU.h:156
GetComEventLog getComEventLog
Definition: PDU.h:245
Exception exception() const
Definition: PDU.h:408
Response response
Definition: PDU.h:93
uint8_t byteCount
Calculated.
Definition: PDU.h:105
uint16_t quantityOfCoils
Definition: PDU.h:60
void swapRequestByteOrder()
size_t getRequestSize() const
Definition: PDU.h:426
uint16_t eventCount
Definition: PDU.h:232
ReadDiscreteInputs readDiscreteInputs
Definition: PDU.h:136
void setEventCount(uint16_t count)
Definition: PDU.h:236
void setCount(uint16_t count)
Definition: PDU.h:370
size_t getResponseSize() const
Definition: PDU.h:431
void swapResponseByteOrder()
uint8_t byteCount
Calculated.
Definition: PDU.h:252
Response response
Definition: PDU.h:187
void setCoil(uint16_t coil, bool state)
Definition: PDU.h:256
Request request
Definition: PDU.h:275
Response response
Definition: PDU.h:211
@ Success
No exception, transaction completed normally.
uint16_t messageCount
Definition: PDU.h:233
MaskWriteRegister maskWriteRegister
Definition: PDU.h:346
uint16_t outputAddress
Definition: PDU.h:180
void setCount(uint16_t count)
Definition: PDU.h:151
void setException(Exception exception)
Definition: PDU.h:397
Definition: ADU.h:25
#define ATTR_PACKED
Definition: PDU.h:27
Response response
Definition: PDU.h:243
Request request
Definition: PDU.h:133
uint16_t quantityOfOutputs
Definition: PDU.h:251
uint8_t exceptionCode
Definition: PDU.h:54
uint16_t quantityOfInputs
Definition: PDU.h:101
Request request
Definition: PDU.h:200
GetComEventCounter getComEventCounter
Definition: PDU.h:224
uint16_t getCount() const
Definition: PDU.h:375
Data data
Definition: PDU.h:440
Response response
Definition: PDU.h:222