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
54  uint8_t exceptionCode;
55 
56  // ReadCoils = 0x01
57  union ReadCoils {
59  uint16_t startAddress;
60  uint16_t quantityOfCoils;
61  };
62 
64  uint8_t byteCount;
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
86  uint16_t getCount() const
87  {
88  return byteCount * 8;
89  }
90  };
91 
94  };
96 
97  // ReadDiscreteInputs = 0x02
100  uint16_t startAddress;
102  };
103 
105  uint8_t byteCount;
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
127  uint16_t getCount() const
128  {
129  return byteCount * 8;
130  }
131  };
132 
135  };
137 
138  // 16-bit access
139  // Common format for reading input/holding registers
142  uint16_t startAddress;
144  };
145 
147  static constexpr uint16_t MaxRegisters{250 / 2};
148  uint8_t byteCount;
149  uint16_t values[MaxRegisters];
150 
151  void setCount(uint16_t count)
152  {
153  byteCount = std::min(count, MaxRegisters) * 2;
154  }
155 
156  uint16_t getCount() const
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 
180  uint16_t outputAddress;
182  };
183 
184  using Response = Request;
185 
188  };
190 
191  // WriteSingleRegister = 0x06,
194  uint16_t address;
195  uint16_t value;
196  };
197 
198  using Response = Request;
199 
202  };
204 
205  // ReadExceptionStatus = 0x07,
208  uint8_t outputData;
209  };
210 
212  };
214 
215  // GetComEventCounter = 0x0b,
218  uint16_t status;
219  uint16_t eventCount;
220  };
221 
223  };
225 
226  // GetComEventLog = 0x0c,
229  static constexpr uint16_t MaxEvents{64};
230  uint8_t byteCount;
231  uint16_t status;
232  uint16_t eventCount;
233  uint16_t messageCount;
234  uint8_t events[MaxEvents];
235 
236  void setEventCount(uint16_t count)
237  {
238  eventCount = std::min(count, MaxEvents);
239  byteCount = 7 + eventCount;
240  }
241  };
242 
244  };
246 
247  // WriteMultipleCoils = 0x0f,
250  uint16_t startAddress;
252  uint8_t byteCount;
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 
271  uint16_t startAddress;
273  };
274 
277  };
279 
280  // WriteMultipleRegisters = 0x10,
283  static constexpr uint16_t MaxRegisters{123};
284  uint16_t startAddress;
286  uint8_t byteCount;
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 
297  uint16_t startAddress;
299  };
300 
303  };
305 
306  // ReportServerId = 0x11,
309  enum RunStatus : uint8_t {
310  runstatus_off = 0x00,
311  runstatus_on = 0xFF,
312  };
313 
314  uint8_t byteCount;
315  uint8_t serverId;
317  uint8_t data[248];
318 
319  void setCount(uint8_t dataSize)
320  {
321  byteCount = 2 + dataSize;
322  }
323 
324  uint8_t getCount() const
325  {
326  return byteCount - 2;
327  }
328  };
329 
331  };
333 
334  // MaskWriteRegister = 0x16,
337  uint16_t address;
338  uint16_t andMask;
339  uint16_t orMask;
340  };
341  using Response = Request;
342 
345  };
347 
348  // ReadWriteMultipleRegisters = 0x17,
351  static constexpr uint16_t MaxWriteRegisters{121};
352  uint16_t readAddress;
353  uint16_t quantityToRead;
354  uint16_t writeAddress;
355  uint16_t quantityToWrite;
356  uint8_t writeByteCount;
357  uint16_t writeValues[MaxWriteRegisters];
358 
359  void setWriteCount(uint16_t count)
360  {
361  quantityToWrite = std::min(count, MaxWriteRegisters);
362  writeByteCount = quantityToWrite * 2;
363  }
364  };
366  static constexpr uint16_t MaxReadRegisters{125};
367  uint8_t byteCount;
368  uint16_t values[MaxReadRegisters];
369 
370  void setCount(uint16_t count)
371  {
372  byteCount = count * 2;
373  }
374 
375  uint16_t getCount() const
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;
400  data.exceptionCode = uint8_t(exception);
401  }
402 
403  bool exceptionFlag() const
404  {
405  return functionCode & 0x80;
406  }
407 
409  {
411  }
412 
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 
439  uint8_t functionCode;
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
#define ATTR_PACKED
Definition: PDU.h:27
Definition: ADU.h:26
Function
Definition: IOControl/include/IO/Modbus/Function.h:45
Exception
Modbus exception codes returned in response packets.
Definition: Exception.h:29
@ Success
No exception, transaction completed normally.
uint8_t byteCount
Calculated.
Definition: PDU.h:230
uint16_t messageCount
Definition: PDU.h:233
uint16_t eventCount
Definition: PDU.h:232
void setEventCount(uint16_t count)
Definition: PDU.h:236
uint16_t quantityOfCoils
Definition: PDU.h:60
uint16_t startAddress
Definition: PDU.h:59
uint8_t byteCount
Use setCount()
Definition: PDU.h:64
void setCoil(uint16_t coil, bool value)
Definition: PDU.h:68
bool getCoil(uint16_t coil)
Definition: PDU.h:75
uint16_t getCount() const
Definition: PDU.h:86
void setCount(uint16_t count)
Definition: PDU.h:80
uint16_t quantityOfInputs
Definition: PDU.h:101
uint16_t getCount() const
Definition: PDU.h:127
bool getInput(uint16_t input)
Definition: PDU.h:116
uint8_t byteCount
Calculated.
Definition: PDU.h:105
void setCount(uint16_t count)
Definition: PDU.h:121
void setInput(uint16_t input, bool value)
Definition: PDU.h:109
uint16_t startAddress
Definition: PDU.h:142
uint16_t quantityOfRegisters
Definition: PDU.h:143
uint8_t byteCount
Calculated.
Definition: PDU.h:148
uint16_t getCount() const
Definition: PDU.h:156
void setCount(uint16_t count)
Definition: PDU.h:151
void setWriteCount(uint16_t count)
Definition: PDU.h:359
uint8_t writeByteCount
Calculated.
Definition: PDU.h:356
void setCount(uint16_t count)
Definition: PDU.h:370
uint16_t getCount() const
Definition: PDU.h:375
void setCount(uint8_t dataSize)
Definition: PDU.h:319
uint8_t getCount() const
Definition: PDU.h:324
RunStatus runStatus
Definition: PDU.h:316
uint8_t byteCount
Calculated.
Definition: PDU.h:252
void setCount(uint16_t count)
Definition: PDU.h:263
uint16_t quantityOfOutputs
Definition: PDU.h:251
void setCoil(uint16_t coil, bool state)
Definition: PDU.h:256
uint16_t quantityOfOutputs
Definition: PDU.h:272
void setCount(uint16_t count)
Definition: PDU.h:289
uint8_t byteCount
Calculated.
Definition: PDU.h:286
uint16_t outputAddress
Definition: PDU.h:180
Protocol Data Unit.
Definition: PDU.h:45
bool exceptionFlag() const
Definition: PDU.h:403
size_t getRequestSize() const
Definition: PDU.h:426
Data data
Definition: PDU.h:440
void swapResponseByteOrder()
void setException(Exception exception)
Definition: PDU.h:397
void swapRequestByteOrder()
void setFunction(Function function)
Definition: PDU.h:392
Exception exception() const
Definition: PDU.h:408
size_t getResponseSize() const
Definition: PDU.h:431
uint8_t functionCode
Definition: PDU.h:439
Response response
Definition: PDU.h:222
Response response
Definition: PDU.h:243
Request request
Definition: PDU.h:343
Response response
Definition: PDU.h:344
Response response
Definition: PDU.h:93
Request request
Definition: PDU.h:92
Response response
Definition: PDU.h:134
Request request
Definition: PDU.h:133
Response response
Definition: PDU.h:211
Response response
Definition: PDU.h:163
Request request
Definition: PDU.h:162
Response response
Definition: PDU.h:330
Request request
Definition: PDU.h:275
Response response
Definition: PDU.h:276
Response response
Definition: PDU.h:302
Request request
Definition: PDU.h:301
Response response
Definition: PDU.h:187
Request request
Definition: PDU.h:186
Response response
Definition: PDU.h:201
Request request
Definition: PDU.h:200
Definition: PDU.h:52
ReadCoils readCoils
Definition: PDU.h:95
ReadRegisters readInputRegisters
Definition: PDU.h:170
WriteSingleRegister writeSingleRegister
Definition: PDU.h:203
MaskWriteRegister maskWriteRegister
Definition: PDU.h:346
uint8_t exceptionCode
Definition: PDU.h:54
ReportServerId reportServerId
Definition: PDU.h:332
ReadExceptionStatus readExceptionStatus
Definition: PDU.h:213
ReadDiscreteInputs readDiscreteInputs
Definition: PDU.h:136
ReadWriteMultipleRegisters readWriteMultipleRegisters
Definition: PDU.h:384
WriteMultipleCoils writeMultipleCoils
Definition: PDU.h:278
ReadRegisters readHoldingRegisters
Definition: PDU.h:167
GetComEventLog getComEventLog
Definition: PDU.h:245
WriteSingleCoil writeSingleCoil
Definition: PDU.h:189
GetComEventCounter getComEventCounter
Definition: PDU.h:224
WriteMultipleRegisters writeMultipleRegisters
Definition: PDU.h:304