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
@@ -124,17 +80,29 @@ uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_b
12480/* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */
12581float modbus_get_float_abcd (const uint16_t * src )
12682{
83+ /* Suppose the modbus byte stream contained the 32-bit float 0x10203040 - abcd.
84+ On big endian systems, the memory starting at src contains two 16-bit registers 0x1020 and 0x3040
85+ On little endian system, the 16-bit registers memory holds 0x2010 and 0x4030
86+
87+ To convert the data to float32 on big-endian we only need to cast the pointer and we are done.
88+ On little endian systems, we need to swap the bytes in each word again and then assemble
89+ an integer via shift operations and finally cast to float32.
90+
91+ A portable way is to retrieve low and high bytes of both words using shift operations, then assemble
92+ the 32-bit integer.
93+ */
94+
12795 float f ;
128- uint32_t i ;
12996 uint8_t a , b , c , d ;
13097
131- a = (src [0 ] >> 8 ) & 0xFF ;
132- b = (src [0 ] >> 0 ) & 0xFF ;
133- c = (src [1 ] >> 8 ) & 0xFF ;
134- d = (src [1 ] >> 0 ) & 0xFF ;
98+ a = (src [0 ] >> 8 ) & 0xFF ; // high byte if first word
99+ b = (src [0 ] >> 0 ) & 0xFF ; // low byte if first word
100+ c = (src [1 ] >> 8 ) & 0xFF ; // high byte if second word
101+ d = (src [1 ] >> 0 ) & 0xFF ; // low byte if second word
135102
136- i = (a << 24 ) | (b << 16 ) | (c << 8 ) | (d << 0 );
137- memcpy (& f , & i , 4 );
103+ // assemble in memory location of float
104+ // from right to left: get address of float, interpret as address to uint32, dereference and write uint32
105+ * (uint32_t * )& f = (a << 24 ) | (b << 16 ) | (c << 8 ) | (d << 0 );
138106
139107 return f ;
140108}
@@ -143,16 +111,16 @@ float modbus_get_float_abcd(const uint16_t *src)
143111float modbus_get_float_dcba (const uint16_t * src )
144112{
145113 float f ;
146- uint32_t i ;
147114 uint8_t a , b , c , d ;
148115
149- a = (src [0 ] >> 8 ) & 0xFF ;
150- b = (src [0 ] >> 0 ) & 0xFF ;
151- c = (src [1 ] >> 8 ) & 0xFF ;
152- d = (src [1 ] >> 0 ) & 0xFF ;
116+ d = (src [0 ] >> 8 ) & 0xFF ;
117+ c = (src [0 ] >> 0 ) & 0xFF ;
118+ b = (src [1 ] >> 8 ) & 0xFF ;
119+ a = (src [1 ] >> 0 ) & 0xFF ;
153120
154- i = (d << 24 ) | (c << 16 ) | (b << 8 ) | (a << 0 );
155- memcpy (& f , & i , 4 );
121+ // assemble in memory location of float
122+ // from right to left: get address of float, interpret as address to uint32, dereference and write uint32
123+ * (uint32_t * )& f = (a << 24 ) | (b << 16 ) | (c << 8 ) | (d << 0 );
156124
157125 return f ;
158126}
@@ -161,16 +129,16 @@ float modbus_get_float_dcba(const uint16_t *src)
161129float modbus_get_float_badc (const uint16_t * src )
162130{
163131 float f ;
164- uint32_t i ;
165132 uint8_t a , b , c , d ;
166133
167- a = (src [0 ] >> 8 ) & 0xFF ;
168- b = (src [0 ] >> 0 ) & 0xFF ;
169- c = (src [1 ] >> 8 ) & 0xFF ;
170- d = (src [1 ] >> 0 ) & 0xFF ;
134+ b = (src [0 ] >> 8 ) & 0xFF ;
135+ a = (src [0 ] >> 0 ) & 0xFF ;
136+ d = (src [1 ] >> 8 ) & 0xFF ;
137+ c = (src [1 ] >> 0 ) & 0xFF ;
171138
172- i = (b << 24 ) | (a << 16 ) | (d << 8 ) | (c << 0 );
173- memcpy (& f , & i , 4 );
139+ // assemble in memory location of float
140+ // from right to left: get address of float, interpret as address to uint32, dereference and write uint32
141+ * (uint32_t * )& f = (a << 24 ) | (b << 16 ) | (c << 8 ) | (d << 0 );
174142
175143 return f ;
176144}
@@ -179,114 +147,88 @@ float modbus_get_float_badc(const uint16_t *src)
179147float modbus_get_float_cdab (const uint16_t * src )
180148{
181149 float f ;
182- uint32_t i ;
183150 uint8_t a , b , c , d ;
184151
185- a = (src [0 ] >> 8 ) & 0xFF ;
186- b = (src [0 ] >> 0 ) & 0xFF ;
187- c = (src [1 ] >> 8 ) & 0xFF ;
188- d = (src [1 ] >> 0 ) & 0xFF ;
152+ c = (src [0 ] >> 8 ) & 0xFF ;
153+ d = (src [0 ] >> 0 ) & 0xFF ;
154+ a = (src [1 ] >> 8 ) & 0xFF ;
155+ b = (src [1 ] >> 0 ) & 0xFF ;
189156
190- i = (c << 24 ) | (d << 16 ) | (a << 8 ) | (b << 0 );
191- memcpy (& f , & i , 4 );
157+ // assemble in memory location of float
158+ // from right to left: get address of float, interpret as address to uint32, dereference and write uint32
159+ * (uint32_t * )& f = (a << 24 ) | (b << 16 ) | (c << 8 ) | (d << 0 );
192160
193161 return f ;
194162}
195163
196164/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */
197165float modbus_get_float (const uint16_t * src )
198166{
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 ;
167+ return modbus_get_float_cdab (src );
206168}
207169
208170/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
209171void modbus_set_float_abcd (float f , uint16_t * dest )
210172{
211- uint32_t i ;
212- uint8_t * out = (uint8_t * ) dest ;
173+ uint32_t i = * (uint32_t * )(& f );
213174 uint8_t a , b , c , d ;
214175
215- memcpy (& i , & f , sizeof (uint32_t ));
216176 a = (i >> 24 ) & 0xFF ;
217177 b = (i >> 16 ) & 0xFF ;
218178 c = (i >> 8 ) & 0xFF ;
219179 d = (i >> 0 ) & 0xFF ;
220180
221- out [0 ] = a ;
222- out [1 ] = b ;
223- out [2 ] = c ;
224- out [3 ] = d ;
181+ dest [0 ] = (a << 8 ) | b ;
182+ dest [1 ] = (c << 8 ) | d ;
225183}
226184
227185/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
228186void modbus_set_float_dcba (float f , uint16_t * dest )
229187{
230- uint32_t i ;
231- uint8_t * out = (uint8_t * ) dest ;
188+ uint32_t i = * (uint32_t * )(& f );
232189 uint8_t a , b , c , d ;
233190
234- memcpy (& i , & f , sizeof (uint32_t ));
235191 a = (i >> 24 ) & 0xFF ;
236192 b = (i >> 16 ) & 0xFF ;
237193 c = (i >> 8 ) & 0xFF ;
238194 d = (i >> 0 ) & 0xFF ;
239195
240- out [0 ] = d ;
241- out [1 ] = c ;
242- out [2 ] = b ;
243- out [3 ] = a ;
196+ dest [0 ] = (d << 8 ) | c ;
197+ dest [1 ] = (b << 8 ) | a ;
244198}
245199
246200/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
247201void modbus_set_float_badc (float f , uint16_t * dest )
248202{
249- uint32_t i ;
250- uint8_t * out = (uint8_t * ) dest ;
203+ uint32_t i = * (uint32_t * )(& f );
251204 uint8_t a , b , c , d ;
252205
253- memcpy (& i , & f , sizeof (uint32_t ));
254206 a = (i >> 24 ) & 0xFF ;
255207 b = (i >> 16 ) & 0xFF ;
256208 c = (i >> 8 ) & 0xFF ;
257209 d = (i >> 0 ) & 0xFF ;
258210
259- out [0 ] = b ;
260- out [1 ] = a ;
261- out [2 ] = d ;
262- out [3 ] = c ;
211+ dest [0 ] = (b << 8 ) | a ;
212+ dest [1 ] = (d << 8 ) | c ;
263213}
264214
265215/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
266216void modbus_set_float_cdab (float f , uint16_t * dest )
267217{
268- uint32_t i ;
269- uint8_t * out = (uint8_t * ) dest ;
218+ uint32_t i = * (uint32_t * )(& f );
270219 uint8_t a , b , c , d ;
271220
272- memcpy (& i , & f , sizeof (uint32_t ));
273221 a = (i >> 24 ) & 0xFF ;
274222 b = (i >> 16 ) & 0xFF ;
275223 c = (i >> 8 ) & 0xFF ;
276224 d = (i >> 0 ) & 0xFF ;
277225
278- out [0 ] = c ;
279- out [1 ] = d ;
280- out [2 ] = a ;
281- out [3 ] = b ;
226+ dest [0 ] = (c << 8 ) | d ;
227+ dest [1 ] = (a << 8 ) | b ;
282228}
283229
284230/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
285231void modbus_set_float (float f , uint16_t * dest )
286232{
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 );
233+ return modbus_set_float_cdab (f , dest );
292234}
0 commit comments