2 * Copyright © Stéphane Raimbault <stephane.raimbault@gmail.com>
4 * SPDX-License-Identifier: LGPL-2.1-or-later
20 # include <winsock2.h>
22 # include <arpa/inet.h>
31 /* Sets many bits from a single byte value (all 8 bits of the byte value are
33 void modbus_set_bits_from_byte(uint8_t *dest
, int idx
, const uint8_t value
)
37 for (i
= 0; i
< 8; i
++) {
38 dest
[idx
+ i
] = (value
& (1 << i
)) ? 1 : 0;
42 /* Sets many bits from a table of bytes (only the bits between idx and
43 idx + nb_bits are set) */
44 void modbus_set_bits_from_bytes(uint8_t *dest
,
47 const uint8_t *tab_byte
)
52 for (i
= idx
; i
< idx
+ nb_bits
; i
++) {
53 dest
[i
] = tab_byte
[(i
- idx
) / 8] & (1 << shift
) ? 1 : 0;
54 /* gcc doesn't like: shift = (++shift) % 8; */
60 /* Gets the byte value from many bits.
61 To obtain a full byte, set nb_bits to 8. */
62 uint8_t modbus_get_byte_from_bits(const uint8_t *src
, int idx
, unsigned int nb_bits
)
68 /* Assert is ignored if NDEBUG is set */
73 for (i
= 0; i
< nb_bits
; i
++) {
74 value
|= (src
[idx
+ i
] << i
);
80 /* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */
81 float modbus_get_float_abcd(const uint16_t *src
)
87 // Mind: src contains 16-bit numbers in processor-endianness, hence
88 // we use shift operations and do not access memory directly
89 a
= (src
[0] >> 8) & 0xFF; // high byte of first word
90 b
= (src
[0] >> 0) & 0xFF; // low byte of first word
91 c
= (src
[1] >> 8) & 0xFF; // high byte of second word
92 d
= (src
[1] >> 0) & 0xFF; // low byte of second word
94 // we assemble 32bit integer always in abcd order via shift operations
95 i
= (a
<< 24) | (b
<< 16) | (c
<< 8) | (d
<< 0);
101 /* Get a float from 4 bytes (Modbus) in inversed format (DCBA) */
102 float modbus_get_float_dcba(const uint16_t *src
)
108 // byte order is defined when reading from src: dcba
109 d
= (src
[0] >> 8) & 0xFF;
110 c
= (src
[0] >> 0) & 0xFF;
111 b
= (src
[1] >> 8) & 0xFF;
112 a
= (src
[1] >> 0) & 0xFF;
114 // we assemble 32bit integer always in abcd order via shift operations
115 i
= (a
<< 24) | (b
<< 16) | (c
<< 8) | (d
<< 0);
121 /* Get a float from 4 bytes (Modbus) with swapped bytes (BADC) */
122 float modbus_get_float_badc(const uint16_t *src
)
128 // byte order is defined when reading from src: badc
129 b
= (src
[0] >> 8) & 0xFF;
130 a
= (src
[0] >> 0) & 0xFF;
131 d
= (src
[1] >> 8) & 0xFF;
132 c
= (src
[1] >> 0) & 0xFF;
134 // we assemble 32bit integer always in abcd order via shift operations
135 i
= (a
<< 24) | (b
<< 16) | (c
<< 8) | (d
<< 0);
141 /* Get a float from 4 bytes (Modbus) with swapped words (CDAB) */
142 float modbus_get_float_cdab(const uint16_t *src
)
148 // byte order is defined when reading from src: cdab
149 c
= (src
[0] >> 8) & 0xFF;
150 d
= (src
[0] >> 0) & 0xFF;
151 a
= (src
[1] >> 8) & 0xFF;
152 b
= (src
[1] >> 0) & 0xFF;
154 // we assemble 32bit integer always in abcd order via shift operations
155 i
= (a
<< 24) | (b
<< 16) | (c
<< 8) | (d
<< 0);
161 /* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */
162 float modbus_get_float(const uint16_t *src
)
164 return modbus_get_float_cdab(src
);
167 /* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
168 void modbus_set_float_abcd(float f
, uint16_t *dest
)
170 // The straight-forward type conversion won't work because of type-punned pointer aliasing warning
171 // uint32_t i = *(uint32_t*)(&f);
173 uint32_t * iptr
= (uint32_t *)fptr
;
177 a
= (i
>> 24) & 0xFF;
178 b
= (i
>> 16) & 0xFF;
182 dest
[0] = (a
<< 8) | b
;
183 dest
[1] = (c
<< 8) | d
;
186 /* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
187 void modbus_set_float_dcba(float f
, uint16_t *dest
)
190 uint32_t * iptr
= (uint32_t *)fptr
;
194 a
= (i
>> 24) & 0xFF;
195 b
= (i
>> 16) & 0xFF;
199 dest
[0] = (d
<< 8) | c
;
200 dest
[1] = (b
<< 8) | a
;
203 /* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
204 void modbus_set_float_badc(float f
, uint16_t *dest
)
207 uint32_t * iptr
= (uint32_t *)fptr
;
211 a
= (i
>> 24) & 0xFF;
212 b
= (i
>> 16) & 0xFF;
216 dest
[0] = (b
<< 8) | a
;
217 dest
[1] = (d
<< 8) | c
;
220 /* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
221 void modbus_set_float_cdab(float f
, uint16_t *dest
)
224 uint32_t * iptr
= (uint32_t *)fptr
;
228 a
= (i
>> 24) & 0xFF;
229 b
= (i
>> 16) & 0xFF;
233 dest
[0] = (c
<< 8) | d
;
234 dest
[1] = (a
<< 8) | b
;
237 /* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
238 void modbus_set_float(float f
, uint16_t *dest
)
240 modbus_set_float_cdab(f
, dest
);