1 /** @file
2  *  @brief Byte order helpers.
3  */
4 
5 /*
6  * Copyright (c) 2015-2016, Intel Corporation.
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 #ifndef ZEPHYR_INCLUDE_SYS_BYTEORDER_H_
12 #define ZEPHYR_INCLUDE_SYS_BYTEORDER_H_
13 
14 #include <zephyr/types.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include <zephyr/sys/__assert.h>
18 #include <zephyr/sys/util_macro.h>
19 #include <zephyr/toolchain.h>
20 
21 #define BSWAP_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
22 #define BSWAP_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \
23 				   (((x)) & 0xff00) | \
24 				   (((x) & 0xff) << 16)))
25 #define BSWAP_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \
26 				   (((x) >> 8) & 0xff00) | \
27 				   (((x) & 0xff00) << 8) | \
28 				   (((x) & 0xff) << 24)))
29 #define BSWAP_40(x) ((uint64_t) ((((x) >> 32) & 0xff) | \
30 				   (((x) >> 16) & 0xff00) | \
31 				   (((x)) & 0xff0000) | \
32 				   (((x) & 0xff00) << 16) | \
33 				   (((x) & 0xff) << 32)))
34 #define BSWAP_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \
35 				   (((x) >> 24) & 0xff00) | \
36 				   (((x) >> 8) & 0xff0000) | \
37 				   (((x) & 0xff0000) << 8) | \
38 				   (((x) & 0xff00) << 24) | \
39 				   (((x) & 0xff) << 40)))
40 #define BSWAP_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \
41 				   (((x) >> 40) & 0xff00) | \
42 				   (((x) >> 24) & 0xff0000) | \
43 				   (((x) >> 8) & 0xff000000) | \
44 				   (((x) & 0xff000000) << 8) | \
45 				   (((x) & 0xff0000) << 24) | \
46 				   (((x) & 0xff00) << 40) | \
47 				   (((x) & 0xff) << 56)))
48 
49 /** @def sys_le16_to_cpu
50  *  @brief Convert 16-bit integer from little-endian to host endianness.
51  *
52  *  @param val 16-bit integer in little-endian format.
53  *
54  *  @return 16-bit integer in host endianness.
55  */
56 
57 /** @def sys_cpu_to_le16
58  *  @brief Convert 16-bit integer from host endianness to little-endian.
59  *
60  *  @param val 16-bit integer in host endianness.
61  *
62  *  @return 16-bit integer in little-endian format.
63  */
64 
65 /** @def sys_le24_to_cpu
66  *  @brief Convert 24-bit integer from little-endian to host endianness.
67  *
68  *  @param val 24-bit integer in little-endian format.
69  *
70  *  @return 24-bit integer in host endianness.
71  */
72 
73 /** @def sys_cpu_to_le24
74  *  @brief Convert 24-bit integer from host endianness to little-endian.
75  *
76  *  @param val 24-bit integer in host endianness.
77  *
78  *  @return 24-bit integer in little-endian format.
79  */
80 
81 /** @def sys_le32_to_cpu
82  *  @brief Convert 32-bit integer from little-endian to host endianness.
83  *
84  *  @param val 32-bit integer in little-endian format.
85  *
86  *  @return 32-bit integer in host endianness.
87  */
88 
89 /** @def sys_cpu_to_le32
90  *  @brief Convert 32-bit integer from host endianness to little-endian.
91  *
92  *  @param val 32-bit integer in host endianness.
93  *
94  *  @return 32-bit integer in little-endian format.
95  */
96 
97 /** @def sys_le48_to_cpu
98  *  @brief Convert 48-bit integer from little-endian to host endianness.
99  *
100  *  @param val 48-bit integer in little-endian format.
101  *
102  *  @return 48-bit integer in host endianness.
103  */
104 
105 /** @def sys_cpu_to_le48
106  *  @brief Convert 48-bit integer from host endianness to little-endian.
107  *
108  *  @param val 48-bit integer in host endianness.
109  *
110  *  @return 48-bit integer in little-endian format.
111  */
112 
113 /** @def sys_be16_to_cpu
114  *  @brief Convert 16-bit integer from big-endian to host endianness.
115  *
116  *  @param val 16-bit integer in big-endian format.
117  *
118  *  @return 16-bit integer in host endianness.
119  */
120 
121 /** @def sys_cpu_to_be16
122  *  @brief Convert 16-bit integer from host endianness to big-endian.
123  *
124  *  @param val 16-bit integer in host endianness.
125  *
126  *  @return 16-bit integer in big-endian format.
127  */
128 
129 /** @def sys_be24_to_cpu
130  *  @brief Convert 24-bit integer from big-endian to host endianness.
131  *
132  *  @param val 24-bit integer in big-endian format.
133  *
134  *  @return 24-bit integer in host endianness.
135  */
136 
137 /** @def sys_cpu_to_be24
138  *  @brief Convert 24-bit integer from host endianness to big-endian.
139  *
140  *  @param val 24-bit integer in host endianness.
141  *
142  *  @return 24-bit integer in big-endian format.
143  */
144 
145 /** @def sys_be32_to_cpu
146  *  @brief Convert 32-bit integer from big-endian to host endianness.
147  *
148  *  @param val 32-bit integer in big-endian format.
149  *
150  *  @return 32-bit integer in host endianness.
151  */
152 
153 /** @def sys_cpu_to_be32
154  *  @brief Convert 32-bit integer from host endianness to big-endian.
155  *
156  *  @param val 32-bit integer in host endianness.
157  *
158  *  @return 32-bit integer in big-endian format.
159  */
160 
161 /** @def sys_be48_to_cpu
162  *  @brief Convert 48-bit integer from big-endian to host endianness.
163  *
164  *  @param val 48-bit integer in big-endian format.
165  *
166  *  @return 48-bit integer in host endianness.
167  */
168 
169 /** @def sys_cpu_to_be48
170  *  @brief Convert 48-bit integer from host endianness to big-endian.
171  *
172  *  @param val 48-bit integer in host endianness.
173  *
174  *  @return 48-bit integer in big-endian format.
175  */
176 
177 /** @def sys_uint16_to_array
178  *  @brief Convert 16-bit unsigned integer to byte array.
179  *
180  *  @details Byte order aware macro to treat an unsigned integer
181  *           as an array, rather than an integer literal. For example,
182  *           `0x0123` would be converted to `{0x01, 0x23}` for big endian
183  *           machines, and `{0x23, 0x01}` for little endian machines.
184  *
185  *  @param val 16-bit unsigned integer.
186  *
187  *  @return 16-bit unsigned integer as byte array.
188  */
189 
190 /** @def sys_uint32_to_array
191  *  @brief Convert 32-bit unsigned integer to byte array.
192  *
193  *  @details Byte order aware macro to treat an unsigned integer
194  *           as an array, rather than an integer literal. For example,
195  *           `0x01234567` would be converted to `{0x01, 0x23, 0x45, 0x67}`
196  *           for big endian machines, and `{0x67, 0x45, 0x23, 0x01}` for
197  *           little endian machines.
198  *
199  *  @param val 32-bit unsigned integer.
200  *
201  *  @return 32-bit unsigned integer as byte array.
202  */
203 
204 /** @def sys_uint64_to_array
205  *  @brief Convert 64-bit unsigned integer to byte array.
206  *
207  *  @details Byte order aware macro to treat an unsigned integer
208  *           as an array, rather than an integer literal. For example,
209  *           `0x0123456789abcdef` would be converted to
210  *           `{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}`
211  *           for big endian machines, and
212  *           `{0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01}` for
213  *           little endian machines.
214  *
215  *  @param val 64-bit unsigned integer.
216  *
217  *  @return 64-bit unsigned integer as byte array.
218  */
219 
220 #ifdef CONFIG_LITTLE_ENDIAN
221 #define sys_le16_to_cpu(val) (val)
222 #define sys_cpu_to_le16(val) (val)
223 #define sys_le24_to_cpu(val) (val)
224 #define sys_cpu_to_le24(val) (val)
225 #define sys_le32_to_cpu(val) (val)
226 #define sys_cpu_to_le32(val) (val)
227 #define sys_le40_to_cpu(val) (val)
228 #define sys_cpu_to_le40(val) (val)
229 #define sys_le48_to_cpu(val) (val)
230 #define sys_cpu_to_le48(val) (val)
231 #define sys_le64_to_cpu(val) (val)
232 #define sys_cpu_to_le64(val) (val)
233 #define sys_be16_to_cpu(val) BSWAP_16(val)
234 #define sys_cpu_to_be16(val) BSWAP_16(val)
235 #define sys_be24_to_cpu(val) BSWAP_24(val)
236 #define sys_cpu_to_be24(val) BSWAP_24(val)
237 #define sys_be32_to_cpu(val) BSWAP_32(val)
238 #define sys_cpu_to_be32(val) BSWAP_32(val)
239 #define sys_be40_to_cpu(val) BSWAP_40(val)
240 #define sys_cpu_to_be40(val) BSWAP_40(val)
241 #define sys_be48_to_cpu(val) BSWAP_48(val)
242 #define sys_cpu_to_be48(val) BSWAP_48(val)
243 #define sys_be64_to_cpu(val) BSWAP_64(val)
244 #define sys_cpu_to_be64(val) BSWAP_64(val)
245 
246 #define sys_uint16_to_array(val) {		\
247 	((val) & 0xff),				\
248 	(((val) >> 8) & 0xff)}
249 
250 #define sys_uint32_to_array(val) {		\
251 	((val) & 0xff),				\
252 	(((val) >> 8) & 0xff),			\
253 	(((val) >> 16) & 0xff),			\
254 	(((val) >> 24) & 0xff)}
255 
256 #define sys_uint64_to_array(val) {		\
257 	((val) & 0xff),				\
258 	(((val) >> 8) & 0xff),			\
259 	(((val) >> 16) & 0xff),			\
260 	(((val) >> 24) & 0xff),			\
261 	(((val) >> 32) & 0xff),			\
262 	(((val) >> 40) & 0xff),			\
263 	(((val) >> 48) & 0xff),			\
264 	(((val) >> 56) & 0xff)}
265 
266 #else
267 #define sys_le16_to_cpu(val) BSWAP_16(val)
268 #define sys_cpu_to_le16(val) BSWAP_16(val)
269 #define sys_le24_to_cpu(val) BSWAP_24(val)
270 #define sys_cpu_to_le24(val) BSWAP_24(val)
271 #define sys_le32_to_cpu(val) BSWAP_32(val)
272 #define sys_cpu_to_le32(val) BSWAP_32(val)
273 #define sys_le40_to_cpu(val) BSWAP_40(val)
274 #define sys_cpu_to_le40(val) BSWAP_40(val)
275 #define sys_le48_to_cpu(val) BSWAP_48(val)
276 #define sys_cpu_to_le48(val) BSWAP_48(val)
277 #define sys_le64_to_cpu(val) BSWAP_64(val)
278 #define sys_cpu_to_le64(val) BSWAP_64(val)
279 #define sys_be16_to_cpu(val) (val)
280 #define sys_cpu_to_be16(val) (val)
281 #define sys_be24_to_cpu(val) (val)
282 #define sys_cpu_to_be24(val) (val)
283 #define sys_be32_to_cpu(val) (val)
284 #define sys_cpu_to_be32(val) (val)
285 #define sys_be40_to_cpu(val) (val)
286 #define sys_cpu_to_be40(val) (val)
287 #define sys_be48_to_cpu(val) (val)
288 #define sys_cpu_to_be48(val) (val)
289 #define sys_be64_to_cpu(val) (val)
290 #define sys_cpu_to_be64(val) (val)
291 
292 #define sys_uint16_to_array(val) {		\
293 	(((val) >> 8) & 0xff),			\
294 	((val) & 0xff)}
295 
296 #define sys_uint32_to_array(val) {		\
297 	(((val) >> 24) & 0xff),			\
298 	(((val) >> 16) & 0xff),			\
299 	(((val) >> 8) & 0xff),			\
300 	((val) & 0xff)}
301 
302 #define sys_uint64_to_array(val) {		\
303 	(((val) >> 56) & 0xff),			\
304 	(((val) >> 48) & 0xff),			\
305 	(((val) >> 40) & 0xff),			\
306 	(((val) >> 32) & 0xff),			\
307 	(((val) >> 24) & 0xff),			\
308 	(((val) >> 16) & 0xff),			\
309 	(((val) >> 8) & 0xff),			\
310 	((val) & 0xff)}
311 
312 #endif
313 
314 /**
315  *  @brief Put a 16-bit integer as big-endian to arbitrary location.
316  *
317  *  Put a 16-bit integer, originally in host endianness, to a
318  *  potentially unaligned memory location in big-endian format.
319  *
320  *  @param val 16-bit integer in host endianness.
321  *  @param dst Destination memory address to store the result.
322  */
sys_put_be16(uint16_t val,uint8_t dst[2])323 static inline void sys_put_be16(uint16_t val, uint8_t dst[2])
324 {
325 	dst[0] = val >> 8;
326 	dst[1] = val;
327 }
328 
329 /**
330  *  @brief Put a 24-bit integer as big-endian to arbitrary location.
331  *
332  *  Put a 24-bit integer, originally in host endianness, to a
333  *  potentially unaligned memory location in big-endian format.
334  *
335  *  @param val 24-bit integer in host endianness.
336  *  @param dst Destination memory address to store the result.
337  */
sys_put_be24(uint32_t val,uint8_t dst[3])338 static inline void sys_put_be24(uint32_t val, uint8_t dst[3])
339 {
340 	dst[0] = val >> 16;
341 	sys_put_be16(val, &dst[1]);
342 }
343 
344 /**
345  *  @brief Put a 32-bit integer as big-endian to arbitrary location.
346  *
347  *  Put a 32-bit integer, originally in host endianness, to a
348  *  potentially unaligned memory location in big-endian format.
349  *
350  *  @param val 32-bit integer in host endianness.
351  *  @param dst Destination memory address to store the result.
352  */
sys_put_be32(uint32_t val,uint8_t dst[4])353 static inline void sys_put_be32(uint32_t val, uint8_t dst[4])
354 {
355 	sys_put_be16(val >> 16, dst);
356 	sys_put_be16(val, &dst[2]);
357 }
358 /**
359  *  @brief Put a 40-bit integer as big-endian to arbitrary location.
360  *
361  *  Put a 40-bit integer, originally in host endianness, to a
362  *  potentially unaligned memory location in big-endian format.
363  *
364  *  @param val 40-bit integer in host endianness.
365  *  @param dst Destination memory address to store the result.
366  */
sys_put_be40(uint64_t val,uint8_t dst[5])367 static inline void sys_put_be40(uint64_t val, uint8_t dst[5])
368 {
369 	dst[0] = val >> 32;
370 	sys_put_be32(val, &dst[1]);
371 }
372 
373 /**
374  *  @brief Put a 48-bit integer as big-endian to arbitrary location.
375  *
376  *  Put a 48-bit integer, originally in host endianness, to a
377  *  potentially unaligned memory location in big-endian format.
378  *
379  *  @param val 48-bit integer in host endianness.
380  *  @param dst Destination memory address to store the result.
381  */
sys_put_be48(uint64_t val,uint8_t dst[6])382 static inline void sys_put_be48(uint64_t val, uint8_t dst[6])
383 {
384 	sys_put_be16(val >> 32, dst);
385 	sys_put_be32(val, &dst[2]);
386 }
387 
388 /**
389  *  @brief Put a 64-bit integer as big-endian to arbitrary location.
390  *
391  *  Put a 64-bit integer, originally in host endianness, to a
392  *  potentially unaligned memory location in big-endian format.
393  *
394  *  @param val 64-bit integer in host endianness.
395  *  @param dst Destination memory address to store the result.
396  */
sys_put_be64(uint64_t val,uint8_t dst[8])397 static inline void sys_put_be64(uint64_t val, uint8_t dst[8])
398 {
399 	sys_put_be32(val >> 32, dst);
400 	sys_put_be32(val, &dst[4]);
401 }
402 
403 /**
404  *  @brief Put a 16-bit integer as little-endian to arbitrary location.
405  *
406  *  Put a 16-bit integer, originally in host endianness, to a
407  *  potentially unaligned memory location in little-endian format.
408  *
409  *  @param val 16-bit integer in host endianness.
410  *  @param dst Destination memory address to store the result.
411  */
sys_put_le16(uint16_t val,uint8_t dst[2])412 static inline void sys_put_le16(uint16_t val, uint8_t dst[2])
413 {
414 	dst[0] = val;
415 	dst[1] = val >> 8;
416 }
417 
418 /**
419  *  @brief Put a 24-bit integer as little-endian to arbitrary location.
420  *
421  *  Put a 24-bit integer, originally in host endianness, to a
422  *  potentially unaligned memory location in little-endian format.
423  *
424  *  @param val 24-bit integer in host endianness.
425  *  @param dst Destination memory address to store the result.
426  */
sys_put_le24(uint32_t val,uint8_t dst[3])427 static inline void sys_put_le24(uint32_t val, uint8_t dst[3])
428 {
429 	sys_put_le16(val, dst);
430 	dst[2] = val >> 16;
431 }
432 
433 /**
434  *  @brief Put a 32-bit integer as little-endian to arbitrary location.
435  *
436  *  Put a 32-bit integer, originally in host endianness, to a
437  *  potentially unaligned memory location in little-endian format.
438  *
439  *  @param val 32-bit integer in host endianness.
440  *  @param dst Destination memory address to store the result.
441  */
sys_put_le32(uint32_t val,uint8_t dst[4])442 static inline void sys_put_le32(uint32_t val, uint8_t dst[4])
443 {
444 	sys_put_le16(val, dst);
445 	sys_put_le16(val >> 16, &dst[2]);
446 }
447 
448 /**
449  *  @brief Put a 40-bit integer as little-endian to arbitrary location.
450  *
451  *  Put a 40-bit integer, originally in host endianness, to a
452  *  potentially unaligned memory location in little-endian format.
453  *
454  *  @param val 40-bit integer in host endianness.
455  *  @param dst Destination memory address to store the result.
456  */
sys_put_le40(uint64_t val,uint8_t dst[5])457 static inline void sys_put_le40(uint64_t val, uint8_t dst[5])
458 {
459 	sys_put_le32(val, dst);
460 	dst[4] = val >> 32;
461 }
462 
463 /**
464  *  @brief Put a 48-bit integer as little-endian to arbitrary location.
465  *
466  *  Put a 48-bit integer, originally in host endianness, to a
467  *  potentially unaligned memory location in little-endian format.
468  *
469  *  @param val 48-bit integer in host endianness.
470  *  @param dst Destination memory address to store the result.
471  */
sys_put_le48(uint64_t val,uint8_t dst[6])472 static inline void sys_put_le48(uint64_t val, uint8_t dst[6])
473 {
474 	sys_put_le32(val, dst);
475 	sys_put_le16(val >> 32, &dst[4]);
476 }
477 
478 /**
479  *  @brief Put a 64-bit integer as little-endian to arbitrary location.
480  *
481  *  Put a 64-bit integer, originally in host endianness, to a
482  *  potentially unaligned memory location in little-endian format.
483  *
484  *  @param val 64-bit integer in host endianness.
485  *  @param dst Destination memory address to store the result.
486  */
sys_put_le64(uint64_t val,uint8_t dst[8])487 static inline void sys_put_le64(uint64_t val, uint8_t dst[8])
488 {
489 	sys_put_le32(val, dst);
490 	sys_put_le32(val >> 32, &dst[4]);
491 }
492 
493 /**
494  *  @brief Get a 16-bit integer stored in big-endian format.
495  *
496  *  Get a 16-bit integer, stored in big-endian format in a potentially
497  *  unaligned memory location, and convert it to the host endianness.
498  *
499  *  @param src Location of the big-endian 16-bit integer to get.
500  *
501  *  @return 16-bit integer in host endianness.
502  */
sys_get_be16(const uint8_t src[2])503 static inline uint16_t sys_get_be16(const uint8_t src[2])
504 {
505 	return ((uint16_t)src[0] << 8) | src[1];
506 }
507 
508 /**
509  *  @brief Get a 24-bit integer stored in big-endian format.
510  *
511  *  Get a 24-bit integer, stored in big-endian format in a potentially
512  *  unaligned memory location, and convert it to the host endianness.
513  *
514  *  @param src Location of the big-endian 24-bit integer to get.
515  *
516  *  @return 24-bit integer in host endianness.
517  */
sys_get_be24(const uint8_t src[3])518 static inline uint32_t sys_get_be24(const uint8_t src[3])
519 {
520 	return ((uint32_t)src[0] << 16) | sys_get_be16(&src[1]);
521 }
522 
523 /**
524  *  @brief Get a 32-bit integer stored in big-endian format.
525  *
526  *  Get a 32-bit integer, stored in big-endian format in a potentially
527  *  unaligned memory location, and convert it to the host endianness.
528  *
529  *  @param src Location of the big-endian 32-bit integer to get.
530  *
531  *  @return 32-bit integer in host endianness.
532  */
sys_get_be32(const uint8_t src[4])533 static inline uint32_t sys_get_be32(const uint8_t src[4])
534 {
535 	return ((uint32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
536 }
537 
538 /**
539  *  @brief Get a 40-bit integer stored in big-endian format.
540  *
541  *  Get a 40-bit integer, stored in big-endian format in a potentially
542  *  unaligned memory location, and convert it to the host endianness.
543  *
544  *  @param src Location of the big-endian 40-bit integer to get.
545  *
546  *  @return 40-bit integer in host endianness.
547  */
sys_get_be40(const uint8_t src[5])548 static inline uint64_t sys_get_be40(const uint8_t src[5])
549 {
550 	return ((uint64_t)sys_get_be32(&src[0]) << 8) | src[4];
551 }
552 
553 /**
554  *  @brief Get a 48-bit integer stored in big-endian format.
555  *
556  *  Get a 48-bit integer, stored in big-endian format in a potentially
557  *  unaligned memory location, and convert it to the host endianness.
558  *
559  *  @param src Location of the big-endian 48-bit integer to get.
560  *
561  *  @return 48-bit integer in host endianness.
562  */
sys_get_be48(const uint8_t src[6])563 static inline uint64_t sys_get_be48(const uint8_t src[6])
564 {
565 	return ((uint64_t)sys_get_be32(&src[0]) << 16) | sys_get_be16(&src[4]);
566 }
567 
568 /**
569  *  @brief Get a 64-bit integer stored in big-endian format.
570  *
571  *  Get a 64-bit integer, stored in big-endian format in a potentially
572  *  unaligned memory location, and convert it to the host endianness.
573  *
574  *  @param src Location of the big-endian 64-bit integer to get.
575  *
576  *  @return 64-bit integer in host endianness.
577  */
sys_get_be64(const uint8_t src[8])578 static inline uint64_t sys_get_be64(const uint8_t src[8])
579 {
580 	return ((uint64_t)sys_get_be32(&src[0]) << 32) | sys_get_be32(&src[4]);
581 }
582 
583 /**
584  *  @brief Get a 16-bit integer stored in little-endian format.
585  *
586  *  Get a 16-bit integer, stored in little-endian format in a potentially
587  *  unaligned memory location, and convert it to the host endianness.
588  *
589  *  @param src Location of the little-endian 16-bit integer to get.
590  *
591  *  @return 16-bit integer in host endianness.
592  */
sys_get_le16(const uint8_t src[2])593 static inline uint16_t sys_get_le16(const uint8_t src[2])
594 {
595 	return ((uint16_t)src[1] << 8) | src[0];
596 }
597 
598 /**
599  *  @brief Get a 24-bit integer stored in little-endian format.
600  *
601  *  Get a 24-bit integer, stored in little-endian format in a potentially
602  *  unaligned memory location, and convert it to the host endianness.
603  *
604  *  @param src Location of the little-endian 24-bit integer to get.
605  *
606  *  @return 24-bit integer in host endianness.
607  */
sys_get_le24(const uint8_t src[3])608 static inline uint32_t sys_get_le24(const uint8_t src[3])
609 {
610 	return ((uint32_t)src[2] << 16) | sys_get_le16(&src[0]);
611 }
612 
613 /**
614  *  @brief Get a 32-bit integer stored in little-endian format.
615  *
616  *  Get a 32-bit integer, stored in little-endian format in a potentially
617  *  unaligned memory location, and convert it to the host endianness.
618  *
619  *  @param src Location of the little-endian 32-bit integer to get.
620  *
621  *  @return 32-bit integer in host endianness.
622  */
sys_get_le32(const uint8_t src[4])623 static inline uint32_t sys_get_le32(const uint8_t src[4])
624 {
625 	return ((uint32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
626 }
627 
628 /**
629  *  @brief Get a 40-bit integer stored in little-endian format.
630  *
631  *  Get a 40-bit integer, stored in little-endian format in a potentially
632  *  unaligned memory location, and convert it to the host endianness.
633  *
634  *  @param src Location of the little-endian 40-bit integer to get.
635  *
636  *  @return 40-bit integer in host endianness.
637  */
sys_get_le40(const uint8_t src[5])638 static inline uint64_t sys_get_le40(const uint8_t src[5])
639 {
640 	return ((uint64_t)sys_get_le32(&src[1]) << 8) | src[0];
641 }
642 
643 /**
644  *  @brief Get a 48-bit integer stored in little-endian format.
645  *
646  *  Get a 48-bit integer, stored in little-endian format in a potentially
647  *  unaligned memory location, and convert it to the host endianness.
648  *
649  *  @param src Location of the little-endian 48-bit integer to get.
650  *
651  *  @return 48-bit integer in host endianness.
652  */
sys_get_le48(const uint8_t src[6])653 static inline uint64_t sys_get_le48(const uint8_t src[6])
654 {
655 	return ((uint64_t)sys_get_le32(&src[2]) << 16) | sys_get_le16(&src[0]);
656 }
657 
658 /**
659  *  @brief Get a 64-bit integer stored in little-endian format.
660  *
661  *  Get a 64-bit integer, stored in little-endian format in a potentially
662  *  unaligned memory location, and convert it to the host endianness.
663  *
664  *  @param src Location of the little-endian 64-bit integer to get.
665  *
666  *  @return 64-bit integer in host endianness.
667  */
sys_get_le64(const uint8_t src[8])668 static inline uint64_t sys_get_le64(const uint8_t src[8])
669 {
670 	return ((uint64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
671 }
672 
673 /**
674  * @brief Swap one buffer content into another
675  *
676  * Copy the content of src buffer into dst buffer in reversed order,
677  * i.e.: src[n] will be put in dst[end-n]
678  * Where n is an index and 'end' the last index in both arrays.
679  * The 2 memory pointers must be pointing to different areas, and have
680  * a minimum size of given length.
681  *
682  * @param dst A valid pointer on a memory area where to copy the data in
683  * @param src A valid pointer on a memory area where to copy the data from
684  * @param length Size of both dst and src memory areas
685  */
sys_memcpy_swap(void * dst,const void * src,size_t length)686 static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
687 {
688 	uint8_t *pdst = (uint8_t *)dst;
689 	const uint8_t *psrc = (const uint8_t *)src;
690 
691 	__ASSERT(((psrc < pdst && (psrc + length) <= pdst) ||
692 		  (psrc > pdst && (pdst + length) <= psrc)),
693 		 "Source and destination buffers must not overlap");
694 
695 	psrc += length - 1;
696 
697 	for (; length > 0; length--) {
698 		*pdst++ = *psrc--;
699 	}
700 }
701 
702 /**
703  * @brief Swap buffer content
704  *
705  * In-place memory swap, where final content will be reversed.
706  * I.e.: buf[n] will be put in buf[end-n]
707  * Where n is an index and 'end' the last index of buf.
708  *
709  * @param buf A valid pointer on a memory area to swap
710  * @param length Size of buf memory area
711  */
sys_mem_swap(void * buf,size_t length)712 static inline void sys_mem_swap(void *buf, size_t length)
713 {
714 	size_t i;
715 
716 	for (i = 0; i < (length/2); i++) {
717 		uint8_t tmp = ((uint8_t *)buf)[i];
718 
719 		((uint8_t *)buf)[i] = ((uint8_t *)buf)[length - 1 - i];
720 		((uint8_t *)buf)[length - 1 - i] = tmp;
721 	}
722 }
723 
724 /**
725  *  @brief Convert buffer from little-endian to host endianness.
726  *
727  * @param buf A valid pointer on a memory area to convert from little-endian to host endianness.
728  * @param length Size of buf memory area
729  */
sys_le_to_cpu(void * buf,size_t length)730 static inline void sys_le_to_cpu(void *buf, size_t length)
731 {
732 	if (IS_ENABLED(CONFIG_BIG_ENDIAN)) {
733 		sys_mem_swap(buf, length);
734 	}
735 }
736 
737 /**
738  *  @brief Convert buffer from host endianness to little-endian.
739  *
740  * @param buf A valid pointer on a memory area to convert from host endianness to little-endian.
741  * @param length Size of buf memory area
742  */
sys_cpu_to_le(void * buf,size_t length)743 static inline void sys_cpu_to_le(void *buf, size_t length)
744 {
745 	if (IS_ENABLED(CONFIG_BIG_ENDIAN)) {
746 		sys_mem_swap(buf, length);
747 	}
748 }
749 
750 /**
751  *  @brief Convert buffer from big-endian to host endianness.
752  *
753  * @param buf A valid pointer on a memory area to convert from big-endian to host endianness.
754  * @param length Size of buf memory area
755  */
sys_be_to_cpu(void * buf,size_t length)756 static inline void sys_be_to_cpu(void *buf, size_t length)
757 {
758 	if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
759 		sys_mem_swap(buf, length);
760 	}
761 }
762 
763 /**
764  *  @brief Convert buffer from host endianness to big-endian.
765  *
766  * @param buf A valid pointer on a memory area to convert from host endianness to big-endian.
767  * @param length Size of buf memory area
768  */
sys_cpu_to_be(void * buf,size_t length)769 static inline void sys_cpu_to_be(void *buf, size_t length)
770 {
771 	if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
772 		sys_mem_swap(buf, length);
773 	}
774 }
775 
776 /**
777  *  @brief Put a buffer as little-endian to arbitrary location.
778  *
779  *  Put a buffer originally in host endianness, to a
780  *  potentially unaligned memory location in little-endian format.
781  *
782  * @param dst A valid pointer on a memory area where to copy the data in
783  * @param src A valid pointer on a memory area where to copy the data from
784  * @param length Size of both dst and src memory areas
785  */
sys_put_le(void * dst,const void * src,size_t length)786 static inline void sys_put_le(void *dst, const void *src, size_t length)
787 {
788 	if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
789 		(void)memcpy(dst, src, length);
790 	} else {
791 		sys_memcpy_swap(dst, src, length);
792 	}
793 }
794 
795 /**
796  *  @brief Put a buffer as big-endian to arbitrary location.
797  *
798  *  Put a buffer originally in host endianness, to a
799  *  potentially unaligned memory location in big-endian format.
800  *
801  * @param dst A valid pointer on a memory area where to copy the data in
802  * @param src A valid pointer on a memory area where to copy the data from
803  * @param length Size of both dst and src memory areas
804  */
sys_put_be(void * dst,const void * src,size_t length)805 static inline void sys_put_be(void *dst, const void *src, size_t length)
806 {
807 	if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
808 		sys_memcpy_swap(dst, src, length);
809 	} else {
810 		(void)memcpy(dst, src, length);
811 	}
812 }
813 
814 /**
815  *  @brief Get a buffer stored in little-endian format.
816  *
817  *  Get a buffer, stored in little-endian format in a potentially
818  *  unaligned memory location, and convert it to the host endianness.
819  *
820  * @param dst A valid pointer on a memory area where to copy the data in
821  * @param src A valid pointer on a memory area where to copy the data from
822  * @param length Size of both dst and src memory areas
823  */
sys_get_le(void * dst,const void * src,size_t length)824 static inline void sys_get_le(void *dst, const void *src, size_t length)
825 {
826 	if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
827 		(void)memcpy(dst, src, length);
828 	} else {
829 		sys_memcpy_swap(dst, src, length);
830 	}
831 }
832 
833 /**
834  *  @brief Get a buffer stored in big-endian format.
835  *
836  *  Get a buffer, stored in big-endian format in a potentially
837  *  unaligned memory location, and convert it to the host endianness.
838  *
839  * @param dst A valid pointer on a memory area where to copy the data in
840  * @param src A valid pointer on a memory area where to copy the data from
841  * @param length Size of both dst and src memory areas
842  */
sys_get_be(void * dst,const void * src,size_t length)843 static inline void sys_get_be(void *dst, const void *src, size_t length)
844 {
845 	if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
846 		sys_memcpy_swap(dst, src, length);
847 	} else {
848 		(void)memcpy(dst, src, length);
849 	}
850 }
851 
852 #endif /* ZEPHYR_INCLUDE_SYS_BYTEORDER_H_ */
853