Skip to content

Commit d0cb19a

Browse files
ghorwinstephane
authored andcommitted
Revert "Fix float endianness issue on big endian architecture." and fix test suite and setter functions.
This reverts commit 49af73d.
1 parent 81bf713 commit d0cb19a

File tree

4 files changed

+73
-136
lines changed

4 files changed

+73
-136
lines changed

src/modbus-data.c

+52-103
Original file line numberDiff line numberDiff line change
@@ -26,50 +26,6 @@
2626

2727
#include "modbus.h"
2828

29-
#if defined(HAVE_BYTESWAP_H)
30-
# include <byteswap.h>
31-
#endif
32-
33-
#if defined(__APPLE__)
34-
# include <libkern/OSByteOrder.h>
35-
# define bswap_16 OSSwapInt16
36-
# define bswap_32 OSSwapInt32
37-
# define bswap_64 OSSwapInt64
38-
#endif
39-
40-
#if defined(__GNUC__)
41-
# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10)
42-
# if GCC_VERSION >= 430
43-
// Since GCC >= 4.30, GCC provides __builtin_bswapXX() alternatives so we switch to them
44-
# undef bswap_32
45-
# define bswap_32 __builtin_bswap32
46-
# endif
47-
# if GCC_VERSION >= 480
48-
# undef bswap_16
49-
# define bswap_16 __builtin_bswap16
50-
# endif
51-
#endif
52-
53-
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
54-
# define bswap_32 _byteswap_ulong
55-
# define bswap_16 _byteswap_ushort
56-
#endif
57-
58-
#if !defined(bswap_16)
59-
# warning "Fallback on C functions for bswap_16"
60-
static inline uint16_t bswap_16(uint16_t x)
61-
{
62-
return (x >> 8) | (x << 8);
63-
}
64-
#endif
65-
66-
#if !defined(bswap_32)
67-
# warning "Fallback on C functions for bswap_32"
68-
static inline uint32_t bswap_32(uint32_t x)
69-
{
70-
return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
71-
}
72-
#endif
7329
// clang-format on
7430

7531
/* Sets many bits from a single byte value (all 8 bits of the byte value are
@@ -128,11 +84,14 @@ float modbus_get_float_abcd(const uint16_t *src)
12884
uint32_t i;
12985
uint8_t a, b, c, d;
13086

131-
a = (src[0] >> 8) & 0xFF;
132-
b = (src[0] >> 0) & 0xFF;
133-
c = (src[1] >> 8) & 0xFF;
134-
d = (src[1] >> 0) & 0xFF;
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
13593

94+
// we assemble 32bit integer always in abcd order via shift operations
13695
i = (a << 24) | (b << 16) | (c << 8) | (d << 0);
13796
memcpy(&f, &i, 4);
13897

@@ -146,12 +105,14 @@ float modbus_get_float_dcba(const uint16_t *src)
146105
uint32_t i;
147106
uint8_t a, b, c, d;
148107

149-
a = (src[0] >> 8) & 0xFF;
150-
b = (src[0] >> 0) & 0xFF;
151-
c = (src[1] >> 8) & 0xFF;
152-
d = (src[1] >> 0) & 0xFF;
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;
153113

154-
i = (d << 24) | (c << 16) | (b << 8) | (a << 0);
114+
// we assemble 32bit integer always in abcd order via shift operations
115+
i = (a << 24) | (b << 16) | (c << 8) | (d << 0);
155116
memcpy(&f, &i, 4);
156117

157118
return f;
@@ -164,12 +125,14 @@ float modbus_get_float_badc(const uint16_t *src)
164125
uint32_t i;
165126
uint8_t a, b, c, d;
166127

167-
a = (src[0] >> 8) & 0xFF;
168-
b = (src[0] >> 0) & 0xFF;
169-
c = (src[1] >> 8) & 0xFF;
170-
d = (src[1] >> 0) & 0xFF;
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;
171133

172-
i = (b << 24) | (a << 16) | (d << 8) | (c << 0);
134+
// we assemble 32bit integer always in abcd order via shift operations
135+
i = (a << 24) | (b << 16) | (c << 8) | (d << 0);
173136
memcpy(&f, &i, 4);
174137

175138
return f;
@@ -182,12 +145,14 @@ float modbus_get_float_cdab(const uint16_t *src)
182145
uint32_t i;
183146
uint8_t a, b, c, d;
184147

185-
a = (src[0] >> 8) & 0xFF;
186-
b = (src[0] >> 0) & 0xFF;
187-
c = (src[1] >> 8) & 0xFF;
188-
d = (src[1] >> 0) & 0xFF;
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;
189153

190-
i = (c << 24) | (d << 16) | (a << 8) | (b << 0);
154+
// we assemble 32bit integer always in abcd order via shift operations
155+
i = (a << 24) | (b << 16) | (c << 8) | (d << 0);
191156
memcpy(&f, &i, 4);
192157

193158
return f;
@@ -196,97 +161,81 @@ float modbus_get_float_cdab(const uint16_t *src)
196161
/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */
197162
float modbus_get_float(const uint16_t *src)
198163
{
199-
float f;
200-
uint32_t i;
201-
202-
i = (((uint32_t) src[1]) << 16) + src[0];
203-
memcpy(&f, &i, sizeof(float));
204-
205-
return f;
164+
return modbus_get_float_cdab(src);
206165
}
207166

208167
/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
209168
void modbus_set_float_abcd(float f, uint16_t *dest)
210169
{
211-
uint32_t i;
212-
uint8_t *out = (uint8_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);
172+
float * fptr = &f;
173+
uint32_t * iptr = (uint32_t *)fptr;
174+
uint32_t i = *iptr;
213175
uint8_t a, b, c, d;
214176

215-
memcpy(&i, &f, sizeof(uint32_t));
216177
a = (i >> 24) & 0xFF;
217178
b = (i >> 16) & 0xFF;
218179
c = (i >> 8) & 0xFF;
219180
d = (i >> 0) & 0xFF;
220181

221-
out[0] = a;
222-
out[1] = b;
223-
out[2] = c;
224-
out[3] = d;
182+
dest[0] = (a << 8) | b;
183+
dest[1] = (c << 8) | d;
225184
}
226185

227186
/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
228187
void modbus_set_float_dcba(float f, uint16_t *dest)
229188
{
230-
uint32_t i;
231-
uint8_t *out = (uint8_t *) dest;
189+
float * fptr = &f;
190+
uint32_t * iptr = (uint32_t *)fptr;
191+
uint32_t i = *iptr;
232192
uint8_t a, b, c, d;
233193

234-
memcpy(&i, &f, sizeof(uint32_t));
235194
a = (i >> 24) & 0xFF;
236195
b = (i >> 16) & 0xFF;
237196
c = (i >> 8) & 0xFF;
238197
d = (i >> 0) & 0xFF;
239198

240-
out[0] = d;
241-
out[1] = c;
242-
out[2] = b;
243-
out[3] = a;
199+
dest[0] = (d << 8) | c;
200+
dest[1] = (b << 8) | a;
244201
}
245202

246203
/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
247204
void modbus_set_float_badc(float f, uint16_t *dest)
248205
{
249-
uint32_t i;
250-
uint8_t *out = (uint8_t *) dest;
206+
float * fptr = &f;
207+
uint32_t * iptr = (uint32_t *)fptr;
208+
uint32_t i = *iptr;
251209
uint8_t a, b, c, d;
252210

253-
memcpy(&i, &f, sizeof(uint32_t));
254211
a = (i >> 24) & 0xFF;
255212
b = (i >> 16) & 0xFF;
256213
c = (i >> 8) & 0xFF;
257214
d = (i >> 0) & 0xFF;
258215

259-
out[0] = b;
260-
out[1] = a;
261-
out[2] = d;
262-
out[3] = c;
216+
dest[0] = (b << 8) | a;
217+
dest[1] = (d << 8) | c;
263218
}
264219

265220
/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
266221
void modbus_set_float_cdab(float f, uint16_t *dest)
267222
{
268-
uint32_t i;
269-
uint8_t *out = (uint8_t *) dest;
223+
float * fptr = &f;
224+
uint32_t * iptr = (uint32_t *)fptr;
225+
uint32_t i = *iptr;
270226
uint8_t a, b, c, d;
271227

272-
memcpy(&i, &f, sizeof(uint32_t));
273228
a = (i >> 24) & 0xFF;
274229
b = (i >> 16) & 0xFF;
275230
c = (i >> 8) & 0xFF;
276231
d = (i >> 0) & 0xFF;
277232

278-
out[0] = c;
279-
out[1] = d;
280-
out[2] = a;
281-
out[3] = b;
233+
dest[0] = (c << 8) | d;
234+
dest[1] = (a << 8) | b;
282235
}
283236

284237
/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
285238
void modbus_set_float(float f, uint16_t *dest)
286239
{
287-
uint32_t i;
288-
289-
memcpy(&i, &f, sizeof(uint32_t));
290-
dest[0] = (uint16_t) i;
291-
dest[1] = (uint16_t) (i >> 16);
240+
modbus_set_float_cdab(f, dest);
292241
}

src/modbus.h

+4
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ extern const unsigned int libmodbus_version_micro;
156156

157157
typedef struct _modbus modbus_t;
158158

159+
/*! Memory layout in tab_xxx arrays is processor-endianness.
160+
When receiving modbus data, it is converted to processor-endianness,
161+
see read_registers().
162+
*/
159163
typedef struct _modbus_mapping_t {
160164
int nb_bits;
161165
int start_bits;

tests/unit-test-client.c

+8-8
Original file line numberDiff line numberDiff line change
@@ -323,30 +323,30 @@ int main(int argc, char *argv[])
323323
/** FLOAT **/
324324
printf("1/4 Set/get float ABCD: ");
325325
modbus_set_float_abcd(UT_REAL, tab_rp_registers);
326-
ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_ABCD_SET, 4),
326+
ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_ABCD, 4),
327327
"FAILED Set float ABCD");
328-
real = modbus_get_float_abcd(UT_IREAL_ABCD_GET);
328+
real = modbus_get_float_abcd(UT_IREAL_ABCD);
329329
ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL);
330330

331331
printf("2/4 Set/get float DCBA: ");
332332
modbus_set_float_dcba(UT_REAL, tab_rp_registers);
333-
ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_DCBA_SET, 4),
333+
ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_DCBA, 4),
334334
"FAILED Set float DCBA");
335-
real = modbus_get_float_dcba(UT_IREAL_DCBA_GET);
335+
real = modbus_get_float_dcba(UT_IREAL_DCBA);
336336
ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL);
337337

338338
printf("3/4 Set/get float BADC: ");
339339
modbus_set_float_badc(UT_REAL, tab_rp_registers);
340-
ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_BADC_SET, 4),
340+
ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_BADC, 4),
341341
"FAILED Set float BADC");
342-
real = modbus_get_float_badc(UT_IREAL_BADC_GET);
342+
real = modbus_get_float_badc(UT_IREAL_BADC);
343343
ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL);
344344

345345
printf("4/4 Set/get float CDAB: ");
346346
modbus_set_float_cdab(UT_REAL, tab_rp_registers);
347-
ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_CDAB_SET, 4),
347+
ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_CDAB, 4),
348348
"FAILED Set float CDAB");
349-
real = modbus_get_float_cdab(UT_IREAL_CDAB_GET);
349+
real = modbus_get_float_cdab(UT_IREAL_CDAB);
350350
ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL);
351351

352352
printf("\nAt this point, error messages doesn't mean the test has failed\n");

tests/unit-test.h.in

+9-25
Original file line numberDiff line numberDiff line change
@@ -77,31 +77,15 @@ const uint16_t UT_INPUT_REGISTERS_TAB[] = { 0x000A };
7777
const float UT_REAL = 123456.00;
7878

7979
/*
80-
* The following arrays assume that 'A' is the MSB,
81-
* and 'D' is the LSB.
82-
* Thus, the following is the case:
83-
* A = 0x47
84-
* B = 0xF1
85-
* C = 0x20
86-
* D = 0x00
87-
*
88-
* There are two sets of arrays: one to test that the setting is correct,
89-
* the other to test that the getting is correct.
90-
* Note that the 'get' values must be constants in processor-endianness,
91-
* as libmodbus will convert all words to processor-endianness as they come in.
80+
* libmodbus will convert all words to processor-endianness as they come in and also converts them
81+
* back to big endian as they are sent out.
82+
* The memory layout in modbus_mapping_t.tab_registers is thus processor-endianess.
83+
* Hence we define the comparison constants to check against the content of modbus_mapping_t.tab_registers
84+
* in terms of 16 bit integer values, that are likewise stored in memory in processor-endianess.
9285
*/
93-
const uint8_t UT_IREAL_ABCD_SET[] = {0x47, 0xF1, 0x20, 0x00};
94-
const uint16_t UT_IREAL_ABCD_GET[] = {0x47F1, 0x2000};
95-
const uint8_t UT_IREAL_DCBA_SET[] = {0x00, 0x20, 0xF1, 0x47};
96-
const uint16_t UT_IREAL_DCBA_GET[] = {0x0020, 0xF147};
97-
const uint8_t UT_IREAL_BADC_SET[] = {0xF1, 0x47, 0x00, 0x20};
98-
const uint16_t UT_IREAL_BADC_GET[] = {0xF147, 0x0020};
99-
const uint8_t UT_IREAL_CDAB_SET[] = {0x20, 0x00, 0x47, 0xF1};
100-
const uint16_t UT_IREAL_CDAB_GET[] = {0x2000, 0x47F1};
101-
102-
/* const uint32_t UT_IREAL_ABCD = 0x47F12000);
103-
const uint32_t UT_IREAL_DCBA = 0x0020F147;
104-
const uint32_t UT_IREAL_BADC = 0xF1470020;
105-
const uint32_t UT_IREAL_CDAB = 0x200047F1;*/
86+
const uint16_t UT_IREAL_ABCD[] = {0x47F1, 0x2000};
87+
const uint16_t UT_IREAL_DCBA[] = {0x0020, 0xF147};
88+
const uint16_t UT_IREAL_BADC[] = {0xF147, 0x0020};
89+
const uint16_t UT_IREAL_CDAB[] = {0x2000, 0x47F1};
10690

10791
#endif /* _UNIT_TEST_H_ */

0 commit comments

Comments
 (0)