liblightmodbus 3.0
A lightweight, header-only, hardware-agnostic Modbus RTU/TCP library
Loading...
Searching...
No Matches
master_func.impl.h
Go to the documentation of this file.
1#ifndef LIGHTMODBUS_MASTER_FUNC_IMPL_H
2#define LIGHTMODBUS_MASTER_FUNC_IMPL_H
3
4#include "master_func.h"
5#include "master.h"
6
29 ModbusMaster *status,
30 uint8_t address,
31 uint8_t function,
32 const uint8_t *requestPDU,
33 uint8_t requestLength,
34 const uint8_t *responsePDU,
35 uint8_t responseLength)
36{
37 // Check if lengths are ok
38 if (requestLength != 5) return MODBUS_REQUEST_ERROR(LENGTH);
39 if (responseLength < 3) return MODBUS_RESPONSE_ERROR(LENGTH);
40
41 // Determine data type
42 uint8_t bits;
43 uint16_t maxCount;
44 ModbusDataType datatype;
45 switch (function)
46 {
47 case 1:
48 datatype = MODBUS_COIL;
49 maxCount = 2000;
50 bits = 1;
51 break;
52
53 case 2:
54 datatype = MODBUS_DISCRETE_INPUT;
55 maxCount = 2000;
56 bits = 1;
57 break;
58
59 case 3:
60 datatype = MODBUS_HOLDING_REGISTER;
61 maxCount = 125;
62 bits = 16;
63 break;
64
65 case 4:
66 datatype = MODBUS_INPUT_REGISTER;
67 maxCount = 125;
68 bits = 16;
69 break;
70
71 default:
72 return MODBUS_GENERAL_ERROR(FUNCTION);
73 }
74
75 uint16_t index = modbusRBE(&requestPDU[1]);
76 uint16_t count = modbusRBE(&requestPDU[3]);
77
78 // Check count
79 if (count == 0 || count > maxCount)
80 return MODBUS_REQUEST_ERROR(COUNT);
81
82 // Address range check
83 if (modbusCheckRangeU16(index, count))
84 return MODBUS_REQUEST_ERROR(RANGE);
85
86 // Based on the request, calculate expected data size
87 uint8_t expected = (bits == 16) ? (count << 1) : modbusBitsToBytes(count);
88
89 // Check if declared data size matches
90 // and if response length is valid
91 if (responsePDU[1] != expected || responseLength != expected + 2)
92 return MODBUS_RESPONSE_ERROR(LENGTH);
93
94 // Prepare callback args
96 .type = datatype,
97 .index = 0,
98 .value = 0,
99 .function = function,
100 .address = address,
101 };
102
103 // And finally read the data from the response
104 for (uint16_t i = 0; i < count; i++)
105 {
106 cargs.index = index + i;
107 if (bits == 1)
108 cargs.value = modbusMaskRead(&responsePDU[2], i);
109 else
110 cargs.value = modbusRBE(&responsePDU[2 + (i << 1)]);
111
112 status->dataCallback(status, &cargs);
113 }
114
115 return MODBUS_NO_ERROR();
116}
117
133 ModbusMaster *status,
134 uint8_t address,
135 uint8_t function,
136 const uint8_t *requestPDU,
137 uint8_t requestLength,
138 const uint8_t *responsePDU,
139 uint8_t responseLength)
140{
141 // Check if lengths are ok
142 if (requestLength != 5) return MODBUS_REQUEST_ERROR(LENGTH);
143 if (responseLength != 5) return MODBUS_RESPONSE_ERROR(LENGTH);
144
145 // Verify index
146 if (modbusRBE(&requestPDU[1]) != modbusRBE(&responsePDU[1]))
147 return MODBUS_RESPONSE_ERROR(INDEX);
148
149 // Verify value
150 if (modbusRBE(&requestPDU[3]) != modbusRBE(&responsePDU[3]))
151 return MODBUS_RESPONSE_ERROR(VALUE);
152
153 return MODBUS_NO_ERROR();
154}
155
173 ModbusMaster *status,
174 uint8_t address,
175 uint8_t function,
176 const uint8_t *requestPDU,
177 uint8_t requestLength,
178 const uint8_t *responsePDU,
179 uint8_t responseLength)
180{
181 // Check if lengths are ok
182 if (requestLength < 7) return MODBUS_REQUEST_ERROR(LENGTH);
183 if (responseLength != 5) return MODBUS_RESPONSE_ERROR(LENGTH);
184
185 uint16_t index = modbusRBE(&requestPDU[1]);
186 uint16_t count = modbusRBE(&requestPDU[3]);
187
188 // Check if index is the same in the response
189 if (index != modbusRBE(&responsePDU[1]))
190 return MODBUS_RESPONSE_ERROR(INDEX);
191
192 // Check if count is the same
193 if (count != modbusRBE(&responsePDU[3]))
194 return MODBUS_RESPONSE_ERROR(COUNT);
195
196 // Verify count in the request
197 uint16_t maxCount = (function == 15) ? 1968 : 123;
198 if (count == 0 || count > maxCount)
199 return MODBUS_REQUEST_ERROR(COUNT);
200
201 // Verify if the request length is correct
202 uint16_t expected = function == 15 ? modbusBitsToBytes(count) : (count << 1);
203 if (requestLength != expected + 6)
204 return MODBUS_REQUEST_ERROR(LENGTH);
205
206 // Verify register range
207 if (modbusCheckRangeU16(index, count))
208 return MODBUS_REQUEST_ERROR(RANGE);
209
210 return MODBUS_NO_ERROR();
211}
212
227 ModbusMaster *status,
228 uint8_t address,
229 uint8_t function,
230 const uint8_t *requestPDU,
231 uint8_t requestLength,
232 const uint8_t *responsePDU,
233 uint8_t responseLength)
234{
235 // Check lengths
236 if (requestLength != 7) return MODBUS_REQUEST_ERROR(LENGTH);
237 if (responseLength != 7) return MODBUS_RESPONSE_ERROR(LENGTH);;
238
239 // The response should be identical to the request
240 uint8_t ok = 1;
241 for (uint8_t i = 0; ok && i < 7; i++)
242 ok = ok && (responsePDU[i] == requestPDU[i]);
243
244 if (!ok) return MODBUS_RESPONSE_ERROR(OTHER);
245
246 return MODBUS_NO_ERROR();
247}
248
262 ModbusMaster *status,
263 uint8_t function,
264 uint16_t index,
265 uint16_t count)
266{
267 uint16_t maxCount;
268 switch (function)
269 {
270 case 1:
271 case 2:
272 maxCount = 2000;
273 break;
274
275 case 3:
276 case 4:
277 maxCount = 125;
278 break;
279
280 default:
281 return MODBUS_GENERAL_ERROR(FUNCTION);
282 }
283
284 // Check count
285 if (count == 0 || count > maxCount)
286 return MODBUS_GENERAL_ERROR(COUNT);
287
288 // Address range check
289 if (modbusCheckRangeU16(index, count))
290 return MODBUS_GENERAL_ERROR(RANGE);
291
292 if (modbusMasterAllocateRequest(status, 5))
293 return MODBUS_GENERAL_ERROR(ALLOC);
294
295 status->request.pdu[0] = function;
296 modbusWBE(&status->request.pdu[1], index);
297 modbusWBE(&status->request.pdu[3], count);
298
299 return MODBUS_NO_ERROR();
300}
301
312 ModbusMaster *status,
313 uint8_t function,
314 uint16_t index,
315 uint16_t value)
316{
317 if (function != 5 && function != 6)
318 return MODBUS_GENERAL_ERROR(FUNCTION);
319
320 // Write coils using proper value
321 if (function == 5)
322 value = value ? 0xff00 : 0;
323
324 if (modbusMasterAllocateRequest(status, 5))
325 return MODBUS_GENERAL_ERROR(ALLOC);
326
327 status->request.pdu[0] = function;
328 modbusWBE(&status->request.pdu[1], index);
329 modbusWBE(&status->request.pdu[3], value);
330
331 return MODBUS_NO_ERROR();
332}
333
345 ModbusMaster *status,
346 uint16_t index,
347 uint16_t count,
348 const uint8_t *values)
349{
350 // Check count
351 if (count == 0 || count > 1968)
352 return MODBUS_GENERAL_ERROR(COUNT);
353
354 // Address range check
355 if (modbusCheckRangeU16(index, count))
356 return MODBUS_GENERAL_ERROR(RANGE);
357
358 uint8_t dataLength = modbusBitsToBytes(count);
359
360 if (modbusMasterAllocateRequest(status, 6 + dataLength))
361 return MODBUS_GENERAL_ERROR(ALLOC);
362
363 // Number of full bytes and remaining bits
364 uint8_t n = count >> 3;
365 uint8_t r = count & 7;
366
367 // Copy n full bytes
368 for (uint8_t i = 0; i < n; i++)
369 status->request.pdu[6 + i] = values[i];
370
371 // Copy remaining bits
372 if (r)
373 {
374 status->request.pdu[6 + n] = 0;
375 for (uint8_t i = 0; i < r; i++)
377 &status->request.pdu[6 + n],
378 i,
379 modbusMaskRead(values + n, i));
380 }
381
382 status->request.pdu[0] = 15;
383 modbusWBE(&status->request.pdu[1], index);
384 modbusWBE(&status->request.pdu[3], count);
385 status->request.pdu[5] = dataLength;
386
387 return MODBUS_NO_ERROR();
388}
389
401 ModbusMaster *status,
402 uint16_t index,
403 uint16_t count,
404 const uint16_t *values)
405{
406 // Check count
407 if (count == 0 || count > 123)
408 return MODBUS_GENERAL_ERROR(COUNT);
409
410 // Addresss range check
411 if (modbusCheckRangeU16(index, count))
412 return MODBUS_GENERAL_ERROR(RANGE);
413
414 uint8_t dataLength = count << 1;
415
416 if (modbusMasterAllocateRequest(status, 6 + dataLength))
417 return MODBUS_GENERAL_ERROR(ALLOC);
418
419 // Copy register values
420 for (uint8_t i = 0; i < (uint8_t)count; i++)
421 modbusWBE(&status->request.pdu[6 + (i << 1)], values[i]);
422
423 status->request.pdu[0] = 16;
424 modbusWBE(&status->request.pdu[1], index);
425 modbusWBE(&status->request.pdu[3], count);
426 status->request.pdu[5] = dataLength;
427 return MODBUS_NO_ERROR();
428}
429
439 ModbusMaster *status,
440 uint16_t index,
441 uint16_t andmask,
442 uint16_t ormask)
443{
444 if (modbusMasterAllocateRequest(status, 7))
445 return MODBUS_GENERAL_ERROR(ALLOC);
446
447 status->request.pdu[0] = 22;
448 modbusWBE(&status->request.pdu[1], index);
449 modbusWBE(&status->request.pdu[3], andmask);
450 modbusWBE(&status->request.pdu[5], ormask);
451
452 return MODBUS_NO_ERROR();
453}
454
455#endif
#define MODBUS_REQUEST_ERROR(e)
Constructs a ModbusErrorInfo where source is set to MODBUS_ERROR_SOURCE_REQUESTL and the error code i...
Definition base.h:100
#define MODBUS_RESPONSE_ERROR(e)
Constructs a ModbusErrorInfo where source is set to MODBUS_ERROR_SOURCE_RESPONSE and the error code i...
Definition base.h:107
ModbusDataType
Represents different Modbus data types.
Definition base.h:244
@ MODBUS_DISCRETE_INPUT
Discrete input.
Definition base.h:248
@ MODBUS_HOLDING_REGISTER
Holding register.
Definition base.h:245
@ MODBUS_INPUT_REGISTER
Input register.
Definition base.h:246
@ MODBUS_COIL
Coil.
Definition base.h:247
#define MODBUS_NO_ERROR()
Construcs a ModbusErrorInfo object for which modbusIsOK() is guaranteed to return true.
Definition base.h:86
static void modbusMaskWrite(uint8_t *mask, uint16_t n, uint8_t value)
Writes n-th bit in an array.
Definition base.h:344
static uint8_t modbusCheckRangeU16(uint16_t index, uint16_t count)
Checks whether provided address range causes an uint16_t overflow.
Definition base.h:408
static uint16_t modbusWBE(uint8_t *p, uint16_t val)
Safely writes a big-endian 16-bit word to provided pointer.
Definition base.h:395
#define LIGHTMODBUS_RET_ERROR
Return type for library functions returning ModbusErrorInfo that should be handled properly.
Definition base.h:49
#define MODBUS_GENERAL_ERROR(e)
Constructs a ModbusErrorInfo where source is set to MODBUS_ERROR_SOURCE_GENERAL and the error code is...
Definition base.h:93
static uint16_t modbusRBE(const uint8_t *p)
Safely reads a big-endian 16-bit word from provided pointer.
Definition base.h:385
static uint16_t modbusBitsToBytes(uint16_t n)
Returns number of bytes necessary to hold given number of bits.
Definition base.h:357
static uint8_t modbusMaskRead(const uint8_t *mask, uint16_t n)
Reads n-th bit from an array.
Definition base.h:333
Master's types and basic functions (header)
static ModbusError modbusMasterAllocateRequest(ModbusMaster *status, uint16_t pduSize)
Allocates memory for the request frame.
Definition master.h:162
Master's functions for building requests and parsing responses (header)
ModbusErrorInfo modbusParseResponse1516(ModbusMaster *status, uint8_t address, uint8_t function, const uint8_t *requestPDU, uint8_t requestLength, const uint8_t *responsePDU, uint8_t responseLength)
Parses response to requests 15 and 16 (write mutliple regsiters/coils)
Definition master_func.impl.h:172
ModbusErrorInfo modbusParseResponse0506(ModbusMaster *status, uint8_t address, uint8_t function, const uint8_t *requestPDU, uint8_t requestLength, const uint8_t *responsePDU, uint8_t responseLength)
Parses response to requests 05 and 06.
Definition master_func.impl.h:132
ModbusErrorInfo modbusBuildRequest0506(ModbusMaster *status, uint8_t function, uint16_t index, uint16_t value)
Write single coil/holding register.
Definition master_func.impl.h:311
ModbusErrorInfo modbusBuildRequest22(ModbusMaster *status, uint16_t index, uint16_t andmask, uint16_t ormask)
Mask write register request.
Definition master_func.impl.h:438
ModbusErrorInfo modbusParseResponse22(ModbusMaster *status, uint8_t address, uint8_t function, const uint8_t *requestPDU, uint8_t requestLength, const uint8_t *responsePDU, uint8_t responseLength)
Parses response to request 22.
Definition master_func.impl.h:226
ModbusErrorInfo modbusBuildRequest16(ModbusMaster *status, uint16_t index, uint16_t count, const uint16_t *values)
Write multiple holding registers.
Definition master_func.impl.h:400
ModbusErrorInfo modbusBuildRequest01020304(ModbusMaster *status, uint8_t function, uint16_t index, uint16_t count)
Read mutiple coils/discrete inputs/holding registers/input registers.
Definition master_func.impl.h:261
ModbusErrorInfo modbusParseResponse01020304(ModbusMaster *status, uint8_t address, uint8_t function, const uint8_t *requestPDU, uint8_t requestLength, const uint8_t *responsePDU, uint8_t responseLength)
Parses response to requests 01, 02, 03 and 04.
Definition master_func.impl.h:28
ModbusErrorInfo modbusBuildRequest15(ModbusMaster *status, uint16_t index, uint16_t count, const uint8_t *values)
Write multiple coils.
Definition master_func.impl.h:344
uint8_t * pdu
A pointer to the PDU section of the frame.
Definition base.h:281
Arguments for the data callback.
Definition master.h:40
uint16_t value
Value of the register.
Definition master.h:43
uint16_t index
Index of the register.
Definition master.h:42
ModbusDataType type
Type of Modbus register.
Definition master.h:41
Master device status.
Definition master.h:73
ModbusDataCallback dataCallback
A pointer to data callback (required)
Definition master.h:74
ModbusBuffer request
Stores master's request for slave.
Definition master.h:81