• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Jacajack / liblightmodbus / 18621134393

29 Jan 2025 09:02PM UTC coverage: 94.253% (-0.3%) from 94.509%
18621134393

push

github

Jacajack
Explicit initialization of variables

6 of 6 new or added lines in 2 files covered. (100.0%)

2 existing lines in 1 file now uncovered.

574 of 609 relevant lines covered (94.25%)

204.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.44
/include/lightmodbus/base.h
1
#ifndef LIGHTMODBUS_BASE_H
2
#define LIGHTMODBUS_BASE_H
3

4
#include <stdint.h>
5

6
/**
7
        \file base.h
8
        \brief Common types and functions (header)
9
*/
10

11
/**
12
        \def LIGHTMOBBUS_WARN_UNUSED
13
        \brief Wrapper for a compiler attribute to warn if the result of a function is not used.
14
        
15
        This macro can be used to check if all ModbusErrors coming from library
16
        functions are handled properly.
17
*/
18
#ifndef LIGHTMODBUS_WARN_UNUSED
19
#define LIGHTMODBUS_WARN_UNUSED __attribute__((warn_unused_result))
20
#endif
21

22
/**
23
        \def LIGHTMOBBUS_ALWAYS_INLINE
24
        \brief Wrapper for a compiler attribute causing a function to be always inlined.
25
        
26
        Using this attribute may help to reduce binary size in some cases.
27
*/
28
#ifndef LIGHTMODBUS_ALWAYS_INLINE
29
#define LIGHTMODBUS_ALWAYS_INLINE __attribute__((always_inline))
30
#endif
31

32
#define MODBUS_PDU_MIN 1   //!< Minimum length of a PDU
33
#define MODBUS_PDU_MAX 253 //!< Maximum length of a PDU
34

35
#define MODBUS_RTU_ADU_MIN     4   //!< Minimum length of ADU in Modbus RTU
36
#define MODBUS_RTU_ADU_MAX     256 //!< Maximum length of ADU in Modbus RTU
37
#define MODBUS_RTU_ADU_PADDING 3   //!< Number of extra bytes added to the PDU in Modbus RTU
38
#define MODBUS_RTU_PDU_OFFSET  1   //!< Offset of PDU relative to the frame beginning in Modbus RTU
39

40
#define MODBUS_TCP_ADU_MIN     8   //!< Minimum length of ADU in Modbus TCP
41
#define MODBUS_TCP_ADU_MAX     260 //!< Maximum length of ADU in Modbus TCP
42
#define MODBUS_TCP_ADU_PADDING 7   //!< Number of extra bytes added to the PDU in Modbus TCP
43
#define MODBUS_TCP_PDU_OFFSET  7   //!< Offset of PDU relative to the frame beginning in Modbus TCP
44

45
/**
46
        \def LIGHTMODBUS_RET_ERROR
47
        \brief Return type for library functions returning ModbusErrorInfo that should be handled properly.
48
*/
49
#define LIGHTMODBUS_RET_ERROR LIGHTMODBUS_WARN_UNUSED ModbusErrorInfo
50

51
/**
52
        \def MODBUS_ERROR_SOURCE_GENERAL
53
        \brief General library error - can be caused by providing an incorrect argument
54
        or a internal library error.
55
*/
56
#define MODBUS_ERROR_SOURCE_GENERAL  0u
57

58
/**
59
        \def MODBUS_ERROR_SOURCE_REQUEST
60
        \brief The request frame contains errors.
61
*/
62
#define MODBUS_ERROR_SOURCE_REQUEST  1u
63

64
/**
65
        \def MODBUS_ERROR_SOURCE_RESPONSE
66
        \brief The response frame contains errors.
67
*/
68
#define MODBUS_ERROR_SOURCE_RESPONSE 2u
69

70
/**
71
        \def MODBUS_ERROR_SOURCE_RESERVED
72
        \brief Reserved for future use.
73
*/
74
#define MODBUS_ERROR_SOURCE_RESERVED 3u
75

76
/**
77
        \def MODBUS_MAKE_ERROR(source, error)
78
        \brief Constructs a ModbusErrorInfo object from a ModbusErrorCode and a `MODBUS_ERROR_SOURCE_*` macro
79
*/
80
#define MODBUS_MAKE_ERROR(s, e) ((ModbusErrorInfo){.source = (s), .error = (e)})
81

82
/**
83
        \def MODBUS_NO_ERROR()
84
        \brief Construcs a ModbusErrorInfo object for which `modbusIsOK()` is guaranteed to return true.
85
*/
86
#define MODBUS_NO_ERROR() MODBUS_MAKE_ERROR(MODBUS_ERROR_SOURCE_GENERAL, MODBUS_OK)
87

88
/**
89
        \def MODBUS_GENERAL_ERROR(e)
90
        \brief Constructs a ModbusErrorInfo where source is set to `MODBUS_ERROR_SOURCE_GENERAL` and 
91
        the error code is set to `MODBUS_ERROR_##e`.
92
*/
93
#define MODBUS_GENERAL_ERROR(e) MODBUS_MAKE_ERROR(MODBUS_ERROR_SOURCE_GENERAL, (MODBUS_ERROR_##e))
94

95
/**
96
        \def MODBUS_REQUEST_ERROR(e)
97
        \brief Constructs a ModbusErrorInfo where source is set to `MODBUS_ERROR_SOURCE_REQUESTL` and 
98
        the error code is set to `MODBUS_ERROR_##e`.
99
*/
100
#define MODBUS_REQUEST_ERROR(e) MODBUS_MAKE_ERROR(MODBUS_ERROR_SOURCE_REQUEST, (MODBUS_ERROR_##e))
101

102
/**
103
        \def MODBUS_RESPONSE_ERROR(e)
104
        \brief Constructs a ModbusErrorInfo where source is set to `MODBUS_ERROR_SOURCE_RESPONSE` and 
105
        the error code is set to `MODBUS_ERROR_##e`.
106
*/
107
#define MODBUS_RESPONSE_ERROR(e) MODBUS_MAKE_ERROR(MODBUS_ERROR_SOURCE_RESPONSE, (MODBUS_ERROR_##e))
108

109
/**
110
        \brief Richer error represenation - source and type of error
111

112
        \see ModbusError
113
        \see modbusIsOk()
114
        \see modbusGetGeneralError()
115
        \see modbusGetRequestError()
116
        \see modbusGetResponseError()
117
        \see modbusGetErrorSource()
118
        \see modbusGetErrorCode()
119

120
        \warning You should not be accessing `source` and `error` directly.
121
        The internal implementation of this struct may change in future releases.
122
        For this reason, please use modbusGetGeneralError(), modbusGetRequestError(),
123
        modbusGetResponseError(), modbusGetErrorSource() and modbusIsOk() instead.
124
*/
125
typedef struct ModbusErrorInfo
126
{
127
        unsigned int source : 2; //!< Source of the error (e.g. MODBUS_ERROR_SOURCE_REQUEST)
128
        unsigned int error  : 6; //!< Contains ModbusError
129
} ModbusErrorInfo;
130

131
/**
132
        \brief Represtents different kinds of errors.
133

134
        \see ModbusErrorInfo
135
*/
136
typedef enum ModbusError
137
{
138
        /**
139
                \brief No error
140

141
                Returned when everything is fine.
142
        */
143
        MODBUS_OK = 0,
144

145
        /**
146
                \brief Same as MODBUS_OK
147
        */
148
        MODBUS_ERROR_OK = 0,
149
        
150
        /**
151
                \brief Invalid frame length
152

153
                 - The provided frame is either too long or too short
154
                 - The data length declared in frame does not match the actual frame length
155
        */
156
        MODBUS_ERROR_LENGTH,
157
        
158
        /**
159
                \brief Memory allocation error
160

161
                The allocator has failed to allocate requested amount of memory or free it.
162
        */
163
        MODBUS_ERROR_ALLOC,
164

165
        /**
166
                \brief Invalid function
167
        */
168
        MODBUS_ERROR_FUNCTION,
169

170
        /**
171
                \brief Invalid register count
172

173
                Provided register count is 0 or exceeds maximum allowed value.
174
        */
175
        MODBUS_ERROR_COUNT,
176

177
        /**
178
                \brief Invalid index value
179
        */
180
        MODBUS_ERROR_INDEX,
181

182
        /**
183
                \brief Invalid register value
184
        */
185
        MODBUS_ERROR_VALUE,
186

187
        /**
188
                \brief Invalid register range
189

190
                Returned when accessing `count` registers starting at `index` would cause
191
                a 16-bit unsigned int overflow.
192
        */
193
        MODBUS_ERROR_RANGE,
194

195
        /**
196
                \brief CRC invalid
197
                \note Only in Modbus RTU
198
        */
199
        MODBUS_ERROR_CRC,
200

201
        /**
202
                \brief Invalid protocol ID (nonzero)
203
                \note Only in Modbus TCP
204
        */
205
        MODBUS_ERROR_BAD_PROTOCOL,
206

207
        /**
208
                \brief Mismatched transaction ID
209
                \note Only in Modbus TCP
210
                
211
                The transaction identifier in the response does not match the one in the request frame.
212
        */
213
        MODBUS_ERROR_BAD_TRANSACTION,
214

215
        /**
216
                \brief Invalid slave address
217
        */
218
        MODBUS_ERROR_ADDRESS,
219

220
        /**
221
                \brief Other error
222
        */
223
        MODBUS_ERROR_OTHER,
224
} ModbusError;
225

226
/**
227
        \brief Represents a Modbus exception code
228
*/
229
typedef enum ModbusExceptionCode
230
{
231
        MODBUS_EXCEP_NONE = 0,
232
        MODBUS_EXCEP_ILLEGAL_FUNCTION = 1, //!< Illegal function code
233
        MODBUS_EXCEP_ILLEGAL_ADDRESS = 2,  //!< Illegal data address
234
        MODBUS_EXCEP_ILLEGAL_VALUE = 3,    //!< Illegal data value
235
        MODBUS_EXCEP_SLAVE_FAILURE = 4,    //!< Slave could not process the request
236
        MODBUS_EXCEP_ACK = 5,              //!< Acknowledge
237
        MODBUS_EXCEP_NACK = 7              //!< Negative acknowledge
238
} ModbusExceptionCode;
239

240
/**
241
        \brief Represents different Modbus data types
242
*/
243
typedef enum ModbusDataType
244
{
245
        MODBUS_HOLDING_REGISTER = 1, //!< Holding register
246
        MODBUS_INPUT_REGISTER = 2,   //!< Input register
247
        MODBUS_COIL = 4,             //!< Coil
248
        MODBUS_DISCRETE_INPUT = 8    //!< Discrete input
249
} ModbusDataType;
250

251
// Forward declaration for ModbusBuffer
252
struct ModbusBuffer;
253

254
/**
255
        \brief Pointer to a memory allocator function
256

257
        Please refer to \ref allocators for more information regarding custom allocator functions.
258
*/
259
typedef ModbusError (*ModbusAllocator)(
260
        struct ModbusBuffer *buffer,
261
        uint16_t size,
262
        void *context);
263

264
/**
265
        \brief Stores a Modbus frame
266

267
        \see modbusBufferInit()
268
        \see modbusBufferDestroy()
269
        \see modbusBufferModePDU()
270
        \see modbusBufferModeRTU()
271
        \see modbusBufferModeTCP()
272
        \see modbusBufferAllocateADU()
273
        \see modbusBufferFree()
274
*/
275
typedef struct ModbusBuffer
276
{
277
        //! Pointer to the allocator function
278
        ModbusAllocator allocator;
279

280
        uint8_t *data;      //!< Pointer to the frame buffer
281
        uint8_t *pdu;       //!< A pointer to the PDU section of the frame
282
        uint16_t length;    //!< Length of the entire frame (PDU size + padding)
283

284
        uint8_t padding;    //!< Number of extra bytes surrounding the PDU
285
        uint8_t pduOffset;  //!< PDU offset relative to the beginning of the frame
286
} ModbusBuffer;
287

288
LIGHTMODBUS_WARN_UNUSED ModbusError modbusDefaultAllocator(
289
        ModbusBuffer *buffer,
290
        uint16_t size,
291
        void *context);
292

293
LIGHTMODBUS_RET_ERROR modbusBufferInit(ModbusBuffer *buffer, ModbusAllocator allocator);
294
void modbusBufferDestroy(ModbusBuffer *buffer, void *context);
295
LIGHTMODBUS_WARN_UNUSED ModbusError modbusBufferAllocateADU(ModbusBuffer *buffer, uint16_t pduSize, void *context);
296
void modbusBufferFree(ModbusBuffer *buffer, void *context);
297

298
uint16_t modbusCRC(const uint8_t *data, uint16_t length);
299

300
/**
301
        \brief Prepares buffer to only store a Modbus PDU
302
*/
303
static inline void modbusBufferModePDU(ModbusBuffer *buffer)
87✔
304
{
305
        buffer->padding = 0;
87✔
306
        buffer->pduOffset = 0;
87✔
307
}
87✔
308

309
/**
310
        \brief Prepares buffer to store a Modbus RTU message
311
*/
312
static inline void modbusBufferModeRTU(ModbusBuffer *buffer)
22✔
313
{
314
        buffer->padding = MODBUS_RTU_ADU_PADDING;
22✔
315
        buffer->pduOffset = MODBUS_RTU_PDU_OFFSET;
22✔
316
}
22✔
317

318
/**
319
        \brief Prepares buffer to store a Modbus TCP message
320
*/
321
static inline void modbusBufferModeTCP(ModbusBuffer *buffer)
8✔
322
{
323
        buffer->padding = MODBUS_TCP_ADU_PADDING;
8✔
324
        buffer->pduOffset = MODBUS_TCP_PDU_OFFSET;
8✔
325
}
8✔
326

327
/**
328
        \brief Reads n-th bit from an array
329
        \param mask A pointer to the array
330
        \param n Number of the bit to be read
331
        \returns The bit value
332
*/
333
LIGHTMODBUS_WARN_UNUSED static inline uint8_t modbusMaskRead(const uint8_t *mask, uint16_t n)
4,029✔
334
{
335
        return (mask[n >> 3] & (1 << (n & 7))) != 0;
4,029✔
336
}
337

338
/**
339
        \brief Writes n-th bit in an array
340
        \param mask A pointer to the array
341
        \param n Number of the bit to write
342
        \param value Bit value to be written
343
*/
344
static inline void modbusMaskWrite(uint8_t *mask, uint16_t n, uint8_t value)
4,036✔
345
{
346
        if (value)
4,036✔
347
                mask[n >> 3] |= (1 << (n & 7));
14✔
348
        else
349
                mask[n >> 3] &= ~(1 << (n & 7));
4,022✔
350
}
4,036✔
351

352
/**
353
        \brief Returns number of bytes necessary to hold given number of bits
354
        \param n Number of bits
355
        \returns Number of bytes requred to hold n bits
356
*/
357
LIGHTMODBUS_WARN_UNUSED static inline uint16_t modbusBitsToBytes(uint16_t n)
27✔
358
{
359
        return (n + 7) >> 3;
27✔
360
}
361

362
/**
363
        \brief Safely reads a little-endian 16-bit word from provided pointer
364
*/
365
LIGHTMODBUS_WARN_UNUSED static inline uint16_t modbusRLE(const uint8_t *p)
26✔
366
{
367
        uint8_t lo = *p;
26✔
368
        uint8_t hi = *(p + 1);
26✔
369
        return (uint16_t) lo | ((uint16_t) hi << 8);
26✔
370
}
371

372
/**
373
        \brief Safely writes a little-endian 16-bit word to provided pointer
374
*/
375
static inline uint16_t modbusWLE(uint8_t *p, uint16_t val)
17✔
376
{
377
        *p = val & 0xff;
17✔
378
        *(p + 1) = val >> 8;
17✔
379
        return val;
17✔
380
}
381

382
/**
383
        \brief Safely reads a big-endian 16-bit word from provided pointer
384
*/
385
LIGHTMODBUS_WARN_UNUSED static inline uint16_t modbusRBE(const uint8_t *p)
757✔
386
{
387
        uint8_t lo = *(p + 1);
757✔
388
        uint8_t hi = *p;
757✔
389
        return (uint16_t) lo | ((uint16_t) hi << 8);
757✔
390
}
391

392
/**
393
        \brief Safely writes a big-endian 16-bit word to provided pointer
394
*/
395
static inline uint16_t modbusWBE(uint8_t *p, uint16_t val)
666✔
396
{
397
        *p = val >> 8;
666✔
398
        *(p + 1) = val & 0xff;
666✔
399
        return val;
666✔
400
}
401

402
/**
403
        \brief Checks whether provided address range causes an `uint16_t` overflow
404
        \param index index of the first register in the range
405
        \param count number of registers in the range
406
        \returns true if the range causes an overflow
407
*/
408
static inline uint8_t modbusCheckRangeU16(uint16_t index, uint16_t count)
93✔
409
{
410
        // return (uint16_t)(index + count - 1) < index;
411
        return index > UINT16_MAX - count + 1;
93✔
412
}
413

414
/**
415
        \brief Returns uint8_t describing error source of ModbusErrorInfo
416
        \returns error source
417

418
        \see MODBUS_ERROR_SOURCE_GENERAL
419
        \see MODBUS_ERROR_SOURCE_REQUEST
420
        \see MODBUS_ERROR_SOURCE_REQUEST
421
*/
422
LIGHTMODBUS_WARN_UNUSED static inline uint8_t modbusGetErrorSource(ModbusErrorInfo err)
875✔
423
{
424
        return err.source;
875✔
425
}
426

427
/**
428
        \brief Returns ModbusError contained in ModbusErrorInfo
429
        \returns MdobusError contained in ModbusErrorInfo
430
*/
431
LIGHTMODBUS_WARN_UNUSED static inline ModbusError modbusGetErrorCode(ModbusErrorInfo err)
788✔
432
{
433
        return (ModbusError) err.error;
788✔
434
}
435

436
/**
437
        \brief Checks if ModbusErrorInfo contains an error
438
        \returns true if ModbusErrorInfo contains an error
439

440
        \see MODBUS_NO_ERROR()
441
*/
442
LIGHTMODBUS_WARN_UNUSED static inline uint8_t modbusIsOk(ModbusErrorInfo err)
495✔
443
{
444
        return modbusGetErrorSource(err) == MODBUS_ERROR_SOURCE_GENERAL && modbusGetErrorCode(err) == MODBUS_OK;
495✔
445
}
446

447
/**
448
        \brief Returns general error from ModbusErrorInfo
449
        \returns ModbusError if ModbusErrorInfo contains an error from MODBUS_ERROR_SOURCE_GENERAL
450
        \returns MODBUS_OK otherwise
451
*/
452
LIGHTMODBUS_WARN_UNUSED static inline ModbusError modbusGetGeneralError(ModbusErrorInfo err)
453
{
454
        return err.source == MODBUS_ERROR_SOURCE_GENERAL ? modbusGetErrorCode(err) : MODBUS_OK;
455
}
456

457
/**
458
        \brief Returns request error from ModbusErrorInfo
459
        \returns ModbusError if ModbusErrorInfo contains an error from MODBUS_ERROR_SOURCE_REQUEST
460
        \returns MODBUS_OK otherwise
461
*/
462
LIGHTMODBUS_WARN_UNUSED static inline ModbusError modbusGetRequestError(ModbusErrorInfo err)
463
{
464
        return err.source == MODBUS_ERROR_SOURCE_REQUEST ? modbusGetErrorCode(err) : MODBUS_OK;
465
}
466

467
/**
468
        \brief Returns response error from ModbusErrorInfo
469
        \returns ModbusError if ModbusErrorInfo contains an error from MODBUS_ERROR_SOURCE_RESPONSE
470
        \returns MODBUS_OK otherwise
471
*/
472
LIGHTMODBUS_WARN_UNUSED static inline ModbusError modbusGetResponseError(ModbusErrorInfo err)
473
{
474
        return err.source == MODBUS_ERROR_SOURCE_RESPONSE ? modbusGetErrorCode(err) : MODBUS_OK;
475
}
476

477
/**
478
        \brief Unpacks data from a Modbus RTU frame and optionally checks CRC
479
        \param frame Pointer to the frame data
480
        \param length Length of the frame (valid range: 4 - 256)
481
        \param checkCRC Controls whether the CRC of the frame should be checked
482
        \param pdu Output: pointer to the PDU
483
        \param pduLength Output: length of the PDU
484
        \param address Output: Slave address
485
        \returns MODBUS_OK on success
486
        \returns MODBUS_ERROR_LENGTH if the length of the frame is invalid
487
        \returns MODBUS_ERROR_CRC if the CRC is incorrect
488
*/
489
LIGHTMODBUS_WARN_UNUSED LIGHTMODBUS_ALWAYS_INLINE static inline ModbusError modbusUnpackRTU(
490
        const uint8_t *frame,
491
        uint16_t length,
492
        uint8_t checkCRC,
493
        const uint8_t **pdu,
494
        uint16_t *pduLength,
495
        uint8_t *address)
496
{
497
        // Check length
498
        if (length < MODBUS_RTU_ADU_MIN || length > MODBUS_RTU_ADU_MAX)
29✔
499
                return MODBUS_ERROR_LENGTH;
3✔
500

501
        // Extract address
502
        *address = frame[0];
26✔
503

504
        // Check CRC
505
        if (checkCRC && modbusCRC(frame, length - 2) != modbusRLE(frame + length - 2))
26✔
506
                return MODBUS_ERROR_CRC;
5✔
507

508
        *pdu = frame + MODBUS_RTU_PDU_OFFSET;
21✔
509
        *pduLength = length - MODBUS_RTU_ADU_PADDING;
21✔
510

511
        return MODBUS_OK;
21✔
512
}
513

514
/**
515
        \brief Sets up address and CRC in a Modbus RTU frame
516
        \param frame Pointer to the frame data
517
        \param length Length of the frame (valid range: 4 - 256)
518
        \param address Address of the slave
519
        \returns MODBUS_OK on success
520
        \returns MODBUS_ERROR_LENGTH if the length of the frame is invalid
521
*/
522
LIGHTMODBUS_WARN_UNUSED LIGHTMODBUS_ALWAYS_INLINE static inline ModbusError modbusPackRTU(
523
        uint8_t *frame,
524
        uint16_t length,
525
        uint8_t address)
526
{
527
        // Check length
528
        if (length < MODBUS_RTU_ADU_MIN || length > MODBUS_RTU_ADU_MAX)
17✔
UNCOV
529
                return MODBUS_ERROR_LENGTH;
×
530

531
        // Write address
532
        frame[0] = address;
17✔
533

534
        // Compute and write CRC
535
        modbusWLE(&frame[length - 2], modbusCRC(frame, length - 2));
17✔
536
        
537
        return MODBUS_OK;
17✔
538
}
539

540
/**
541
        \brief Unpacks data from a Modbus TCP frame
542
        \param frame Pointer to the frame data
543
        \param length Length of the frame (valid range: 8 - 260)
544
        \param pdu Output: pointer to the PDU
545
        \param pduLength Output: length of the PDU
546
        \param transactionID Output: TCP transaction ID
547
        \param unitID Output: Slave unit ID
548
        \returns MODBUS_OK on success
549
        \returns MODBUS_ERROR_LENGTH if the length of the frame is invalid or if
550
                the length declared inside the frame does not match the actual frame length
551
        \returns MODBUS_ERROR_BAD_PROTOCOL if the protocol ID declared in frame is not 0
552
*/
553
LIGHTMODBUS_WARN_UNUSED LIGHTMODBUS_ALWAYS_INLINE static inline ModbusError modbusUnpackTCP(
554
        const uint8_t *frame,
555
        uint16_t length,
556
        const uint8_t **pdu,
557
        uint16_t *pduLength,
558
        uint16_t *transactionID,
559
        uint8_t *unitID)
560
{
561
        // Check length
562
        if (length < MODBUS_TCP_ADU_MIN || length > MODBUS_TCP_ADU_MAX)
25✔
563
                return MODBUS_ERROR_LENGTH;
3✔
564

565
        // Discard non-Modbus messages
566
        uint16_t protocolID = modbusRBE(&frame[2]);
22✔
567
        if (protocolID != 0)
22✔
568
                return MODBUS_ERROR_BAD_PROTOCOL;
3✔
569

570
        // Length mismatch
571
        uint16_t messageLength = modbusRBE(&frame[4]);
19✔
572
        if (messageLength != length - 6)
19✔
573
                return MODBUS_ERROR_LENGTH;
3✔
574

575
        *transactionID = modbusRBE(&frame[0]);
16✔
576
        *unitID = frame[6];
16✔
577
        *pdu = frame + MODBUS_TCP_PDU_OFFSET;
16✔
578
        *pduLength = length - MODBUS_TCP_ADU_PADDING;
16✔
579

580
        return MODBUS_OK;
16✔
581
}
582

583
/**
584
        \brief Sets up the MBAP header in a Modbus TCP frame
585
        \param frame Pointer to the frame data
586
        \param length Length of the frame (valid range: 8 - 260)
587
        \param transactionID TCP transaction ID
588
        \param unitID Slave unit ID
589
        \returns MODBUS_OK on success
590
        \returns MODBUS_ERROR_LENGTH if the length of the frame is invalid
591
*/
592
LIGHTMODBUS_WARN_UNUSED LIGHTMODBUS_ALWAYS_INLINE static inline ModbusError modbusPackTCP(
593
        uint8_t *frame,
594
        uint16_t length,
595
        uint16_t transactionID,
596
        uint8_t unitID)
597
{
598
        // Check length
599
        if (length < MODBUS_TCP_ADU_MIN || length > MODBUS_TCP_ADU_MAX)
10✔
UNCOV
600
                return MODBUS_ERROR_LENGTH;
×
601

602
        modbusWBE(&frame[0], transactionID);
10✔
603
        modbusWBE(&frame[2], 0);
10✔
604
        modbusWBE(&frame[4], length - 6);
10✔
605
        frame[6] = unitID;
10✔
606
        return MODBUS_OK;
10✔
607
}
608

609
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc