-
Notifications
You must be signed in to change notification settings - Fork 164
Expand file tree
/
Copy pathModbusMessage.h
More file actions
216 lines (166 loc) · 8.39 KB
/
Copy pathModbusMessage.h
File metadata and controls
216 lines (166 loc) · 8.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// =================================================================================================
// eModbus: Copyright 2020 by Michael Harwerth, Bert Melis and the contributors to eModbus
// MIT license - see license.md for details
// =================================================================================================
#ifndef _MODBUS_MESSAGE_H
#define _MODBUS_MESSAGE_H
#include "ModbusTypeDefs.h"
#include "ModbusError.h"
#include <type_traits>
#include <vector>
using Modbus::Error;
using Modbus::FCType;
using Modbus::FCT;
using std::vector;
class ModbusMessage {
public:
// Default empty message Constructor - optionally takes expected size of MM_data
explicit ModbusMessage(uint16_t dataLen = 0);
// Special message Constructor - takes a std::vector<uint8_t>
explicit ModbusMessage(std::vector<uint8_t> s);
// Message constructors - internally setMessage() is called
// WARNING: if parameters are invalid, message will _NOT_ be set up!
template <typename... Args>
ModbusMessage(uint8_t serverID, uint8_t functionCode, Args&&... args) { // NOLINT
Error e = SUCCESS;
if ((e = setMessage(serverID, functionCode, std::forward<Args>(args) ...)) != SUCCESS) {
printError(__FILE__, __LINE__, e, serverID, functionCode);
}
}
// Destructor
~ModbusMessage();
// Assignment operator
ModbusMessage& operator=(const ModbusMessage& m);
// Copy constructor
ModbusMessage(const ModbusMessage& m);
#ifndef NO_MOVE
// Move constructor
ModbusMessage(ModbusMessage&& m);
// Move assignment
ModbusMessage& operator=(ModbusMessage&& m);
#endif
// Comparison operators
bool operator==(const ModbusMessage& m);
bool operator!=(const ModbusMessage& m);
operator bool();
// Exposed methods of std::vector
const uint8_t *data(); // address of MM_data
uint16_t size(); // used length in MM_data
uint8_t operator[](uint16_t index) const; // provide restricted operator[] interface
void push_back(const uint8_t& val); // add a byte at the end of MM_data
void clear(); // delete message contents
uint16_t resize(uint16_t newSize); // resize MM_data
// provide iterator interface on MM_data
typedef std::vector<uint8_t>::const_iterator const_iterator;
const_iterator begin() const { return MM_data.begin(); }
const_iterator end() const { return MM_data.end(); }
// Add append() for two ModbusMessages or a std::vector<uint8_t> to be appended
void append(ModbusMessage& m);
void append(std::vector<uint8_t>& m);
// Modbus data extraction
uint8_t getServerID() const; // returns Server ID or 0 if MM_data is shorter than 3
uint8_t getFunctionCode() const; // returns FC or 0 if MM_data is shorter than 3
Error getError() const; // getError() - returns error code (MM_data[2], if MM_data[1] > 0x7F, else SUCCESS)
// Modbus data manipulation
void setServerID(uint8_t serverID); // Change server ID
void setFunctionCode(uint8_t FC); // Change function code
// add() variant to copy a buffer into MM_data. Returns updated size
uint16_t add(const uint8_t *arrayOfBytes, uint16_t count);
// add() - add a single data element MSB first to MM_data. Returns updated size
template <class T> uint16_t add(T v) {
uint16_t sz = sizeof(T); // Size of value to be added
// Copy it MSB first
while (sz) {
sz--;
MM_data.push_back((v >> (sz << 3)) & 0xFF);
}
// Return updated size (logical length of message so far)
return MM_data.size();
}
// Template function to extend add(A) to add(A, B, C, ...)
template <class T, class... Args>
typename std::enable_if<!std::is_pointer<T>::value, uint16_t>::type
add(T v, Args... args) {
add(v);
return add(args...);
}
// get() - read a byte array of a given size into a vector<uint8_t>. Returns updated index
uint16_t get(uint16_t index, vector<uint8_t>& v, uint8_t count) const;
// get() - recursion stopper for template function below
inline uint16_t get(uint16_t index) const { return index; }
// Template function to extend getOne(index, A&) to get(index, A&, B&, C&, ...)
template <class T, class... Args>
typename std::enable_if<!std::is_pointer<T>::value, uint16_t>::type
get(uint16_t index, T& v, Args&... args) const {
uint16_t pos = getOne(index, v);
return get(pos, args...);
}
// add() variant for vectors of uint8_t
uint16_t add(vector<uint8_t> v);
// add() variants for float and double values
uint16_t add(float v, int swapRules = 0);
uint16_t add(double v, int swapRules = 0);
// get() variants for float and double values
uint16_t get(uint16_t index, float& v, int swapRules = 0) const;
uint16_t get(uint16_t index, double& v, int swapRules = 0) const;
// Message generation methods
// 1. no additional parameter (FCs 0x07, 0x0b, 0x0c, 0x11)
Error setMessage(uint8_t serverID, uint8_t functionCode);
// 2. one uint16_t parameter (FC 0x18)
Error setMessage(uint8_t serverID, uint8_t functionCode, uint16_t p1);
// 3. two uint16_t parameters (FC 0x01, 0x02, 0x03, 0x04, 0x05, 0x06)
Error setMessage(uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2);
// 4. three uint16_t parameters (FC 0x16)
Error setMessage(uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint16_t p3);
// 5. two uint16_t parameters, a uint8_t length byte and a uint8_t* pointer to array of words (FC 0x10)
Error setMessage(uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint8_t count, uint16_t *arrayOfWords);
// 6. two uint16_t parameters, a uint8_t length byte and a uint16_t* pointer to array of bytes (FC 0x0f)
Error setMessage(uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint8_t count, uint8_t *arrayOfBytes);
// 7. generic constructor for preformatted data ==> count is counting bytes!
Error setMessage(uint8_t serverID, uint8_t functionCode, uint16_t count, uint8_t *arrayOfBytes);
// 8. error response
Error setError(uint8_t serverID, uint8_t functionCode, Error errorCode);
protected:
// Data validation methods - used by the above!
// 0. serverID and function code - used by all of the below
static Error checkServerFC(uint8_t serverID, uint8_t functionCode);
// 1. no additional parameter (FCs 0x07, 0x0b, 0x0c, 0x11)
static Error checkData(uint8_t serverID, uint8_t functionCode);
// 2. one uint16_t parameter (FC 0x18)
static Error checkData(uint8_t serverID, uint8_t functionCode, uint16_t p1);
// 3. two uint16_t parameters (FC 0x01, 0x02, 0x03, 0x04, 0x05, 0x06)
static Error checkData(uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2);
// 4. three uint16_t parameters (FC 0x16)
static Error checkData(uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint16_t p3);
// 5. two uint16_t parameters, a uint8_t length byte and a uint8_t* pointer to array of words (FC 0x10)
static Error checkData(uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint8_t count, uint16_t *arrayOfWords);
// 6. two uint16_t parameters, a uint8_t length byte and a uint16_t* pointer to array of bytes (FC 0x0f)
static Error checkData(uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint8_t count, uint8_t *arrayOfBytes);
// 7. generic constructor for preformatted data ==> count is counting bytes!
static Error checkData(uint8_t serverID, uint8_t functionCode, uint16_t count, uint8_t *arrayOfBytes);
// Error output in case a message constructor will fail
static void printError(const char *file, int lineNo, Error e, uint8_t serverID, uint8_t functionCode);
std::vector<uint8_t> MM_data; // Message data buffer
static uint8_t floatOrder[sizeof(float)]; // order of bytes in a float variable
static uint8_t doubleOrder[sizeof(double)]; // order of bytes in a double variable
static uint8_t determineFloatOrder();
static uint8_t determineDoubleOrder();
static float swapFloat(float& f, int swapRule);
static double swapDouble(double& f, int swapRule);
// getOne() - read a MSB-first value starting at byte index. Returns updated index
template <typename T> uint16_t getOne(uint16_t index, T& retval) const {
uint16_t sz = sizeof(retval); // Size of value to be read
retval = 0; // return value
// Will it fit?
if (index <= MM_data.size() - sz) {
// Yes. Copy it MSB first
while (sz) {
sz--;
retval <<= 8;
retval |= MM_data[index++];
}
}
return index;
}
};
#endif