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
2973// clang-format on
3074
3175/* Sets many bits from a single byte value (all 8 bits of the byte value are
@@ -80,29 +124,17 @@ uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_b
80124/* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */
81125float modbus_get_float_abcd (const uint16_t * src )
82126{
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-
95127 float f ;
128+ uint32_t i ;
96129 uint8_t a , b , c , d ;
97130
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
131+ a = (src [0 ] >> 8 ) & 0xFF ;
132+ b = (src [0 ] >> 0 ) & 0xFF ;
133+ c = (src [1 ] >> 8 ) & 0xFF ;
134+ d = (src [1 ] >> 0 ) & 0xFF ;
102135
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 );
136+ i = (a << 24 ) | (b << 16 ) | (c << 8 ) | (d << 0 );
137+ memcpy (& f , & i , 4 );
106138
107139 return f ;
108140}
@@ -111,16 +143,16 @@ float modbus_get_float_abcd(const uint16_t *src)
111143float modbus_get_float_dcba (const uint16_t * src )
112144{
113145 float f ;
146+ uint32_t i ;
114147 uint8_t a , b , c , d ;
115148
116- d = (src [0 ] >> 8 ) & 0xFF ;
117- c = (src [0 ] >> 0 ) & 0xFF ;
118- b = (src [1 ] >> 8 ) & 0xFF ;
119- a = (src [1 ] >> 0 ) & 0xFF ;
149+ a = (src [0 ] >> 8 ) & 0xFF ;
150+ b = (src [0 ] >> 0 ) & 0xFF ;
151+ c = (src [1 ] >> 8 ) & 0xFF ;
152+ d = (src [1 ] >> 0 ) & 0xFF ;
120153
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 );
154+ i = (d << 24 ) | (c << 16 ) | (b << 8 ) | (a << 0 );
155+ memcpy (& f , & i , 4 );
124156
125157 return f ;
126158}
@@ -129,16 +161,16 @@ float modbus_get_float_dcba(const uint16_t *src)
129161float modbus_get_float_badc (const uint16_t * src )
130162{
131163 float f ;
164+ uint32_t i ;
132165 uint8_t a , b , c , d ;
133166
134- b = (src [0 ] >> 8 ) & 0xFF ;
135- a = (src [0 ] >> 0 ) & 0xFF ;
136- d = (src [1 ] >> 8 ) & 0xFF ;
137- c = (src [1 ] >> 0 ) & 0xFF ;
167+ a = (src [0 ] >> 8 ) & 0xFF ;
168+ b = (src [0 ] >> 0 ) & 0xFF ;
169+ c = (src [1 ] >> 8 ) & 0xFF ;
170+ d = (src [1 ] >> 0 ) & 0xFF ;
138171
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 );
172+ i = (b << 24 ) | (a << 16 ) | (d << 8 ) | (c << 0 );
173+ memcpy (& f , & i , 4 );
142174
143175 return f ;
144176}
@@ -147,88 +179,114 @@ float modbus_get_float_badc(const uint16_t *src)
147179float modbus_get_float_cdab (const uint16_t * src )
148180{
149181 float f ;
182+ uint32_t i ;
150183 uint8_t a , b , c , d ;
151184
152- c = (src [0 ] >> 8 ) & 0xFF ;
153- d = (src [0 ] >> 0 ) & 0xFF ;
154- a = (src [1 ] >> 8 ) & 0xFF ;
155- b = (src [1 ] >> 0 ) & 0xFF ;
185+ a = (src [0 ] >> 8 ) & 0xFF ;
186+ b = (src [0 ] >> 0 ) & 0xFF ;
187+ c = (src [1 ] >> 8 ) & 0xFF ;
188+ d = (src [1 ] >> 0 ) & 0xFF ;
156189
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 );
190+ i = (c << 24 ) | (d << 16 ) | (a << 8 ) | (b << 0 );
191+ memcpy (& f , & i , 4 );
160192
161193 return f ;
162194}
163195
164196/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */
165197float modbus_get_float (const uint16_t * src )
166198{
167- return modbus_get_float_cdab (src );
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 ;
168206}
169207
170208/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
171209void modbus_set_float_abcd (float f , uint16_t * dest )
172210{
173- uint32_t i = * (uint32_t * )(& f );
211+ uint32_t i ;
212+ uint8_t * out = (uint8_t * ) dest ;
174213 uint8_t a , b , c , d ;
175214
215+ memcpy (& i , & f , sizeof (uint32_t ));
176216 a = (i >> 24 ) & 0xFF ;
177217 b = (i >> 16 ) & 0xFF ;
178218 c = (i >> 8 ) & 0xFF ;
179219 d = (i >> 0 ) & 0xFF ;
180220
181- dest [0 ] = (a << 8 ) | b ;
182- dest [1 ] = (c << 8 ) | d ;
221+ out [0 ] = a ;
222+ out [1 ] = b ;
223+ out [2 ] = c ;
224+ out [3 ] = d ;
183225}
184226
185227/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
186228void modbus_set_float_dcba (float f , uint16_t * dest )
187229{
188- uint32_t i = * (uint32_t * )(& f );
230+ uint32_t i ;
231+ uint8_t * out = (uint8_t * ) dest ;
189232 uint8_t a , b , c , d ;
190233
234+ memcpy (& i , & f , sizeof (uint32_t ));
191235 a = (i >> 24 ) & 0xFF ;
192236 b = (i >> 16 ) & 0xFF ;
193237 c = (i >> 8 ) & 0xFF ;
194238 d = (i >> 0 ) & 0xFF ;
195239
196- dest [0 ] = (d << 8 ) | c ;
197- dest [1 ] = (b << 8 ) | a ;
240+ out [0 ] = d ;
241+ out [1 ] = c ;
242+ out [2 ] = b ;
243+ out [3 ] = a ;
198244}
199245
200246/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
201247void modbus_set_float_badc (float f , uint16_t * dest )
202248{
203- uint32_t i = * (uint32_t * )(& f );
249+ uint32_t i ;
250+ uint8_t * out = (uint8_t * ) dest ;
204251 uint8_t a , b , c , d ;
205252
253+ memcpy (& i , & f , sizeof (uint32_t ));
206254 a = (i >> 24 ) & 0xFF ;
207255 b = (i >> 16 ) & 0xFF ;
208256 c = (i >> 8 ) & 0xFF ;
209257 d = (i >> 0 ) & 0xFF ;
210258
211- dest [0 ] = (b << 8 ) | a ;
212- dest [1 ] = (d << 8 ) | c ;
259+ out [0 ] = b ;
260+ out [1 ] = a ;
261+ out [2 ] = d ;
262+ out [3 ] = c ;
213263}
214264
215265/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
216266void modbus_set_float_cdab (float f , uint16_t * dest )
217267{
218- uint32_t i = * (uint32_t * )(& f );
268+ uint32_t i ;
269+ uint8_t * out = (uint8_t * ) dest ;
219270 uint8_t a , b , c , d ;
220271
272+ memcpy (& i , & f , sizeof (uint32_t ));
221273 a = (i >> 24 ) & 0xFF ;
222274 b = (i >> 16 ) & 0xFF ;
223275 c = (i >> 8 ) & 0xFF ;
224276 d = (i >> 0 ) & 0xFF ;
225277
226- dest [0 ] = (c << 8 ) | d ;
227- dest [1 ] = (a << 8 ) | b ;
278+ out [0 ] = c ;
279+ out [1 ] = d ;
280+ out [2 ] = a ;
281+ out [3 ] = b ;
228282}
229283
230284/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
231285void modbus_set_float (float f , uint16_t * dest )
232286{
233- return modbus_set_float_cdab (f , dest );
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 );
234292}
0 commit comments