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