blob: e7fbb0389f2fe49ec53b27cc0b963202ca1655d2 [file] [log] [blame]
Brad Bishop0f291cc2019-09-01 15:16:57 -04001From: =?utf-8?b?IlNaIExpbiAo5p6X5LiK5pm6KSI=?= <szlin@debian.org>
2Date: Wed, 19 Dec 2018 10:24:47 +0800
3Subject: Fix float endianness issue on big endian arch
4
5It converts float values depending on what order they come in.
6
7This patch was modified from rm5248 [1]
8
9[1] https://github.com/synexxus/libmodbus/commit/a511768e7fe7ec52d7bae1d9ae04e33f87a59627
10
11---
Patrick Williams520786c2023-06-25 16:20:36 -050012Upstream-Status: Pending
13
Brad Bishop0f291cc2019-09-01 15:16:57 -040014 src/modbus-data.c | 110 ++++++++++++++++++++++++++++++++++++++---------
15 tests/unit-test-client.c | 22 ++++++----
16 tests/unit-test.h.in | 41 ++++++++++++++++--
17 3 files changed, 141 insertions(+), 32 deletions(-)
18
19diff --git a/src/modbus-data.c b/src/modbus-data.c
20index 902b8c6..7a744fa 100644
21--- a/src/modbus-data.c
22+++ b/src/modbus-data.c
23@@ -119,9 +119,18 @@ float modbus_get_float_abcd(const uint16_t *src)
24 {
25 float f;
26 uint32_t i;
27+ uint8_t a, b, c, d;
28
29- i = ntohl(((uint32_t)src[0] << 16) + src[1]);
30- memcpy(&f, &i, sizeof(float));
31+ a = (src[0] >> 8) & 0xFF;
32+ b = (src[0] >> 0) & 0xFF;
33+ c = (src[1] >> 8) & 0xFF;
34+ d = (src[1] >> 0) & 0xFF;
35+
36+ i = (a << 24) |
37+ (b << 16) |
38+ (c << 8) |
39+ (d << 0);
40+ memcpy(&f, &i, 4);
41
42 return f;
43 }
44@@ -131,9 +140,18 @@ float modbus_get_float_dcba(const uint16_t *src)
45 {
46 float f;
47 uint32_t i;
48+ uint8_t a, b, c, d;
49
50- i = ntohl(bswap_32((((uint32_t)src[0]) << 16) + src[1]));
51- memcpy(&f, &i, sizeof(float));
52+ a = (src[0] >> 8) & 0xFF;
53+ b = (src[0] >> 0) & 0xFF;
54+ c = (src[1] >> 8) & 0xFF;
55+ d = (src[1] >> 0) & 0xFF;
56+
57+ i = (d << 24) |
58+ (c << 16) |
59+ (b << 8) |
60+ (a << 0);
61+ memcpy(&f, &i, 4);
62
63 return f;
64 }
65@@ -143,9 +161,18 @@ float modbus_get_float_badc(const uint16_t *src)
66 {
67 float f;
68 uint32_t i;
69+ uint8_t a, b, c, d;
70
71- i = ntohl((uint32_t)(bswap_16(src[0]) << 16) + bswap_16(src[1]));
72- memcpy(&f, &i, sizeof(float));
73+ a = (src[0] >> 8) & 0xFF;
74+ b = (src[0] >> 0) & 0xFF;
75+ c = (src[1] >> 8) & 0xFF;
76+ d = (src[1] >> 0) & 0xFF;
77+
78+ i = (b << 24) |
79+ (a << 16) |
80+ (d << 8) |
81+ (c << 0);
82+ memcpy(&f, &i, 4);
83
84 return f;
85 }
86@@ -155,9 +182,18 @@ float modbus_get_float_cdab(const uint16_t *src)
87 {
88 float f;
89 uint32_t i;
90+ uint8_t a, b, c, d;
91
92- i = ntohl((((uint32_t)src[1]) << 16) + src[0]);
93- memcpy(&f, &i, sizeof(float));
94+ a = (src[0] >> 8) & 0xFF;
95+ b = (src[0] >> 0) & 0xFF;
96+ c = (src[1] >> 8) & 0xFF;
97+ d = (src[1] >> 0) & 0xFF;
98+
99+ i = (c << 24) |
100+ (d << 16) |
101+ (a << 8) |
102+ (b << 0);
103+ memcpy(&f, &i, 4);
104
105 return f;
106 }
107@@ -172,50 +208,84 @@ float modbus_get_float(const uint16_t *src)
108 memcpy(&f, &i, sizeof(float));
109
110 return f;
111+
112 }
113
114 /* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
115 void modbus_set_float_abcd(float f, uint16_t *dest)
116 {
117 uint32_t i;
118+ uint8_t *out = (uint8_t*) dest;
119+ uint8_t a, b, c, d;
120
121 memcpy(&i, &f, sizeof(uint32_t));
122- i = htonl(i);
123- dest[0] = (uint16_t)(i >> 16);
124- dest[1] = (uint16_t)i;
125+ a = (i >> 24) & 0xFF;
126+ b = (i >> 16) & 0xFF;
127+ c = (i >> 8) & 0xFF;
128+ d = (i >> 0) & 0xFF;
129+
130+ out[0] = a;
131+ out[1] = b;
132+ out[2] = c;
133+ out[3] = d;
134 }
135
136 /* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
137 void modbus_set_float_dcba(float f, uint16_t *dest)
138 {
139 uint32_t i;
140+ uint8_t *out = (uint8_t*) dest;
141+ uint8_t a, b, c, d;
142
143 memcpy(&i, &f, sizeof(uint32_t));
144- i = bswap_32(htonl(i));
145- dest[0] = (uint16_t)(i >> 16);
146- dest[1] = (uint16_t)i;
147+ a = (i >> 24) & 0xFF;
148+ b = (i >> 16) & 0xFF;
149+ c = (i >> 8) & 0xFF;
150+ d = (i >> 0) & 0xFF;
151+
152+ out[0] = d;
153+ out[1] = c;
154+ out[2] = b;
155+ out[3] = a;
156+
157 }
158
159 /* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
160 void modbus_set_float_badc(float f, uint16_t *dest)
161 {
162 uint32_t i;
163+ uint8_t *out = (uint8_t*) dest;
164+ uint8_t a, b, c, d;
165
166 memcpy(&i, &f, sizeof(uint32_t));
167- i = htonl(i);
168- dest[0] = (uint16_t)bswap_16(i >> 16);
169- dest[1] = (uint16_t)bswap_16(i & 0xFFFF);
170+ a = (i >> 24) & 0xFF;
171+ b = (i >> 16) & 0xFF;
172+ c = (i >> 8) & 0xFF;
173+ d = (i >> 0) & 0xFF;
174+
175+ out[0] = b;
176+ out[1] = a;
177+ out[2] = d;
178+ out[3] = c;
179 }
180
181 /* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
182 void modbus_set_float_cdab(float f, uint16_t *dest)
183 {
184 uint32_t i;
185+ uint8_t *out = (uint8_t*) dest;
186+ uint8_t a, b, c, d;
187
188 memcpy(&i, &f, sizeof(uint32_t));
189- i = htonl(i);
190- dest[0] = (uint16_t)i;
191- dest[1] = (uint16_t)(i >> 16);
192+ a = (i >> 24) & 0xFF;
193+ b = (i >> 16) & 0xFF;
194+ c = (i >> 8) & 0xFF;
195+ d = (i >> 0) & 0xFF;
196+
197+ out[0] = c;
198+ out[1] = d;
199+ out[2] = a;
200+ out[3] = b;
201 }
202
203 /* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
204diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c
205index 3e315f4..3fccf3e 100644
206--- a/tests/unit-test-client.c
207+++ b/tests/unit-test-client.c
208@@ -27,6 +27,7 @@ int send_crafted_request(modbus_t *ctx, int function,
209 uint16_t max_value, uint16_t bytes,
210 int backend_length, int backend_offset);
211 int equal_dword(uint16_t *tab_reg, const uint32_t value);
212+int is_memory_equal(const void *s1, const void *s2, size_t size);
213
214 #define BUG_REPORT(_cond, _format, _args ...) \
215 printf("\nLine %d: assertion error for '%s': " _format "\n", __LINE__, # _cond, ## _args)
216@@ -40,6 +41,11 @@ int equal_dword(uint16_t *tab_reg, const uint32_t value);
217 } \
218 };
219
220+int is_memory_equal(const void *s1, const void *s2, size_t size)
221+{
222+ return (memcmp(s1, s2, size) == 0);
223+}
224+
225 int equal_dword(uint16_t *tab_reg, const uint32_t value) {
226 return ((tab_reg[0] == (value >> 16)) && (tab_reg[1] == (value & 0xFFFF)));
227 }
228@@ -286,26 +292,26 @@ int main(int argc, char *argv[])
229 /** FLOAT **/
230 printf("1/4 Set/get float ABCD: ");
231 modbus_set_float_abcd(UT_REAL, tab_rp_registers);
232- ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_ABCD), "FAILED Set float ABCD");
233- real = modbus_get_float_abcd(tab_rp_registers);
234+ ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_ABCD_SET, 4), "FAILED Set float ABCD");
235+ real = modbus_get_float_abcd(UT_IREAL_ABCD_GET);
236 ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL);
237
238 printf("2/4 Set/get float DCBA: ");
239 modbus_set_float_dcba(UT_REAL, tab_rp_registers);
240- ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_DCBA), "FAILED Set float DCBA");
241- real = modbus_get_float_dcba(tab_rp_registers);
242+ ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_DCBA_SET, 4), "FAILED Set float DCBA");
243+ real = modbus_get_float_dcba(UT_IREAL_DCBA_GET);
244 ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL);
245
246 printf("3/4 Set/get float BADC: ");
247 modbus_set_float_badc(UT_REAL, tab_rp_registers);
248- ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_BADC), "FAILED Set float BADC");
249- real = modbus_get_float_badc(tab_rp_registers);
250+ ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_BADC_SET, 4), "FAILED Set float BADC");
251+ real = modbus_get_float_badc(UT_IREAL_BADC_GET);
252 ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL);
253
254 printf("4/4 Set/get float CDAB: ");
255 modbus_set_float_cdab(UT_REAL, tab_rp_registers);
256- ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_CDAB), "FAILED Set float CDAB");
257- real = modbus_get_float_cdab(tab_rp_registers);
258+ ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_CDAB_SET, 4), "FAILED Set float CDAB");
259+ real = modbus_get_float_cdab(UT_IREAL_CDAB_GET);
260 ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL);
261
262 printf("\nAt this point, error messages doesn't mean the test has failed\n");
263diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in
264index dca826f..4ffa254 100644
265--- a/tests/unit-test.h.in
266+++ b/tests/unit-test.h.in
267@@ -56,12 +56,45 @@ const uint16_t UT_INPUT_REGISTERS_ADDRESS = 0x108;
268 const uint16_t UT_INPUT_REGISTERS_NB = 0x1;
269 const uint16_t UT_INPUT_REGISTERS_TAB[] = { 0x000A };
270
271+/*
272+ * This float value is 0x47F12000 (in big-endian format).
273+ * In Little-endian(intel) format, it will be stored in memory as follows:
274+ * 0x00 0x20 0xF1 0x47
275+ *
276+ * You can check this with the following code:
277+
278+ float fl = UT_REAL;
279+ uint8_t *inmem = (uint8_t*)&fl;
280+ int x;
281+ for(x = 0; x < 4; x++){
282+ printf("0x%02X ", inmem[ x ]);
283+ }
284+ printf("\n");
285+ */
286 const float UT_REAL = 123456.00;
287
288-const uint32_t UT_IREAL_ABCD = 0x0020F147;
289-const uint32_t UT_IREAL_DCBA = 0x47F12000;
290-const uint32_t UT_IREAL_BADC = 0x200047F1;
291-const uint32_t UT_IREAL_CDAB = 0xF1470020;
292+/*
293+ * The following arrays assume that 'A' is the MSB,
294+ * and 'D' is the LSB.
295+ * Thus, the following is the case:
296+ * A = 0x47
297+ * B = 0xF1
298+ * C = 0x20
299+ * D = 0x00
300+ *
301+ * There are two sets of arrays: one to test that the setting is correct,
302+ * the other to test that the getting is correct.
303+ * Note that the 'get' values must be constants in processor-endianness,
304+ * as libmodbus will convert all words to processor-endianness as they come in.
305+ */
306+const uint8_t UT_IREAL_ABCD_SET[] = {0x47, 0xF1, 0x20, 0x00};
307+const uint16_t UT_IREAL_ABCD_GET[] = {0x47F1, 0x2000};
308+const uint8_t UT_IREAL_DCBA_SET[] = {0x00, 0x20, 0xF1, 0x47};
309+const uint16_t UT_IREAL_DCBA_GET[] = {0x0020, 0xF147};
310+const uint8_t UT_IREAL_BADC_SET[] = {0xF1, 0x47, 0x00, 0x20};
311+const uint16_t UT_IREAL_BADC_GET[] = {0xF147, 0x0020};
312+const uint8_t UT_IREAL_CDAB_SET[] = {0x20, 0x00, 0x47, 0xF1};
313+const uint16_t UT_IREAL_CDAB_GET[] = {0x2000, 0x47F1};
314
315 /* const uint32_t UT_IREAL_ABCD = 0x47F12000);
316 const uint32_t UT_IREAL_DCBA = 0x0020F147;