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 __BYTEORDER_H__
12 #define __BYTEORDER_H__
13 
14 #include <ble_types/types.h>
15 #include <stddef.h>
16 #include <misc/__assert.h>
17 
18 /* Internal helpers only used by the sys_* APIs further below */
19 #define __bswap_16(x) ((u16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
20 #define __bswap_24(x) ((bt_u32_t) ((((x) >> 16) & 0xff) | \
21 				   (((x)) & 0xff00) | \
22 				   (((x) & 0xff) << 16)))
23 #define __bswap_32(x) ((bt_u32_t) ((((x) >> 24) & 0xff) | \
24 				   (((x) >> 8) & 0xff00) | \
25 				   (((x) & 0xff00) << 8) | \
26 				   (((x) & 0xff) << 24)))
27 #define __bswap_48(x) ((u64_t) ((((x) >> 40) & 0xff) | \
28 				   (((x) >> 24) & 0xff00) | \
29 				   (((x) >> 8) & 0xff0000) | \
30 				   (((x) & 0xff0000) << 8) | \
31 				   (((x) & 0xff00) << 24) | \
32 				   (((x) & 0xff) << 40)))
33 #define __bswap_64(x) ((u64_t) ((((x) >> 56) & 0xff) | \
34 				   (((x) >> 40) & 0xff00) | \
35 				   (((x) >> 24) & 0xff0000) | \
36 				   (((x) >> 8) & 0xff000000) | \
37 				   (((x) & 0xff000000) << 8) | \
38 				   (((x) & 0xff0000) << 24) | \
39 				   (((x) & 0xff00) << 40) | \
40 				   (((x) & 0xff) << 56)))
41 
42 /** @def sys_le16_to_cpu
43  *  @brief Convert 16-bit integer from little-endian to host endianness.
44  *
45  *  @param val 16-bit integer in little-endian format.
46  *
47  *  @return 16-bit integer in host endianness.
48  */
49 
50 /** @def sys_cpu_to_le16
51  *  @brief Convert 16-bit integer from host endianness to little-endian.
52  *
53  *  @param val 16-bit integer in host endianness.
54  *
55  *  @return 16-bit integer in little-endian format.
56  */
57 
58 /** @def sys_le24_to_cpu
59  *  @brief Convert 24-bit integer from little-endian to host endianness.
60  *
61  *  @param val 24-bit integer in little-endian format.
62  *
63  *  @return 24-bit integer in host endianness.
64  */
65 
66 /** @def sys_cpu_to_le24
67  *  @brief Convert 24-bit integer from host endianness to little-endian.
68  *
69  *  @param val 24-bit integer in host endianness.
70  *
71  *  @return 24-bit integer in little-endian format.
72  */
73 
74 /** @def sys_le32_to_cpu
75  *  @brief Convert 32-bit integer from little-endian to host endianness.
76  *
77  *  @param val 32-bit integer in little-endian format.
78  *
79  *  @return 32-bit integer in host endianness.
80  */
81 
82 /** @def sys_cpu_to_le32
83  *  @brief Convert 32-bit integer from host endianness to little-endian.
84  *
85  *  @param val 32-bit integer in host endianness.
86  *
87  *  @return 32-bit integer in little-endian format.
88  */
89 
90 /** @def sys_le48_to_cpu
91  *  @brief Convert 48-bit integer from little-endian to host endianness.
92  *
93  *  @param val 48-bit integer in little-endian format.
94  *
95  *  @return 48-bit integer in host endianness.
96  */
97 
98 /** @def sys_cpu_to_le48
99  *  @brief Convert 48-bit integer from host endianness to little-endian.
100  *
101  *  @param val 48-bit integer in host endianness.
102  *
103  *  @return 48-bit integer in little-endian format.
104  */
105 
106 /** @def sys_be16_to_cpu
107  *  @brief Convert 16-bit integer from big-endian to host endianness.
108  *
109  *  @param val 16-bit integer in big-endian format.
110  *
111  *  @return 16-bit integer in host endianness.
112  */
113 
114 /** @def sys_cpu_to_be16
115  *  @brief Convert 16-bit integer from host endianness to big-endian.
116  *
117  *  @param val 16-bit integer in host endianness.
118  *
119  *  @return 16-bit integer in big-endian format.
120  */
121 
122 /** @def sys_be24_to_cpu
123  *  @brief Convert 24-bit integer from big-endian to host endianness.
124  *
125  *  @param val 24-bit integer in big-endian format.
126  *
127  *  @return 24-bit integer in host endianness.
128  */
129 
130 /** @def sys_cpu_to_be24
131  *  @brief Convert 24-bit integer from host endianness to big-endian.
132  *
133  *  @param val 24-bit integer in host endianness.
134  *
135  *  @return 24-bit integer in big-endian format.
136  */
137 
138 /** @def sys_be32_to_cpu
139  *  @brief Convert 32-bit integer from big-endian to host endianness.
140  *
141  *  @param val 32-bit integer in big-endian format.
142  *
143  *  @return 32-bit integer in host endianness.
144  */
145 
146 /** @def sys_cpu_to_be32
147  *  @brief Convert 32-bit integer from host endianness to big-endian.
148  *
149  *  @param val 32-bit integer in host endianness.
150  *
151  *  @return 32-bit integer in big-endian format.
152  */
153 
154 /** @def sys_be48_to_cpu
155  *  @brief Convert 48-bit integer from big-endian to host endianness.
156  *
157  *  @param val 48-bit integer in big-endian format.
158  *
159  *  @return 48-bit integer in host endianness.
160  */
161 
162 /** @def sys_cpu_to_be48
163  *  @brief Convert 48-bit integer from host endianness to big-endian.
164  *
165  *  @param val 48-bit integer in host endianness.
166  *
167  *  @return 48-bit integer in big-endian format.
168  */
169 
170 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
171 #define sys_le16_to_cpu(val) (val)
172 #define sys_cpu_to_le16(val) (val)
173 #define sys_le24_to_cpu(val) (val)
174 #define sys_cpu_to_le24(val) (val)
175 #define sys_le32_to_cpu(val) (val)
176 #define sys_cpu_to_le32(val) (val)
177 #define sys_le48_to_cpu(val) (val)
178 #define sys_cpu_to_le48(val) (val)
179 #define sys_le64_to_cpu(val) (val)
180 #define sys_cpu_to_le64(val) (val)
181 #define sys_be16_to_cpu(val) __bswap_16(val)
182 #define sys_cpu_to_be16(val) __bswap_16(val)
183 #define sys_be24_to_cpu(val) __bswap_24(val)
184 #define sys_cpu_to_be24(val) __bswap_24(val)
185 #define sys_be32_to_cpu(val) __bswap_32(val)
186 #define sys_cpu_to_be32(val) __bswap_32(val)
187 #define sys_be48_to_cpu(val) __bswap_48(val)
188 #define sys_cpu_to_be48(val) __bswap_48(val)
189 #define sys_be64_to_cpu(val) __bswap_64(val)
190 #define sys_cpu_to_be64(val) __bswap_64(val)
191 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
192 #define sys_le16_to_cpu(val) __bswap_16(val)
193 #define sys_cpu_to_le16(val) __bswap_16(val)
194 #define sys_le24_to_cpu(val) __bswap_24(val)
195 #define sys_cpu_to_le24(val) __bswap_24(val)
196 #define sys_le32_to_cpu(val) __bswap_32(val)
197 #define sys_cpu_to_le32(val) __bswap_32(val)
198 #define sys_le48_to_cpu(val) __bswap_48(val)
199 #define sys_cpu_to_le48(val) __bswap_48(val)
200 #define sys_le64_to_cpu(val) __bswap_64(val)
201 #define sys_cpu_to_le64(val) __bswap_64(val)
202 #define sys_be16_to_cpu(val) (val)
203 #define sys_cpu_to_be16(val) (val)
204 #define sys_be24_to_cpu(val) (val)
205 #define sys_cpu_to_be24(val) (val)
206 #define sys_be32_to_cpu(val) (val)
207 #define sys_cpu_to_be32(val) (val)
208 #define sys_be48_to_cpu(val) (val)
209 #define sys_cpu_to_be48(val) (val)
210 #define sys_be64_to_cpu(val) (val)
211 #define sys_cpu_to_be64(val) (val)
212 #else
213 #error "Unknown byte order"
214 #endif
215 
216 /**
217  *  @brief Put a 16-bit integer as big-endian to arbitrary location.
218  *
219  *  Put a 16-bit integer, originally in host endianness, to a
220  *  potentially unaligned memory location in big-endian format.
221  *
222  *  @param val 16-bit integer in host endianness.
223  *  @param dst Destination memory address to store the result.
224  */
sys_put_be16(u16_t val,u8_t dst[2])225 static inline void sys_put_be16(u16_t val, u8_t dst[2])
226 {
227 	dst[0] = val >> 8;
228 	dst[1] = val;
229 }
230 
231 /**
232  *  @brief Put a 24-bit integer as big-endian to arbitrary location.
233  *
234  *  Put a 24-bit integer, originally in host endianness, to a
235  *  potentially unaligned memory location in big-endian format.
236  *
237  *  @param val 24-bit integer in host endianness.
238  *  @param dst Destination memory address to store the result.
239  */
sys_put_be24(bt_u32_t val,u8_t dst[3])240 static inline void sys_put_be24(bt_u32_t val, u8_t dst[3])
241 {
242 	dst[0] = val >> 16;
243 	sys_put_be16(val, &dst[1]);
244 }
245 
246 /**
247  *  @brief Put a 32-bit integer as big-endian to arbitrary location.
248  *
249  *  Put a 32-bit integer, originally in host endianness, to a
250  *  potentially unaligned memory location in big-endian format.
251  *
252  *  @param val 32-bit integer in host endianness.
253  *  @param dst Destination memory address to store the result.
254  */
sys_put_be32(bt_u32_t val,u8_t dst[4])255 static inline void sys_put_be32(bt_u32_t val, u8_t dst[4])
256 {
257 	sys_put_be16(val >> 16, dst);
258 	sys_put_be16(val, &dst[2]);
259 }
260 
261 /**
262  *  @brief Put a 48-bit integer as big-endian to arbitrary location.
263  *
264  *  Put a 48-bit integer, originally in host endianness, to a
265  *  potentially unaligned memory location in big-endian format.
266  *
267  *  @param val 48-bit integer in host endianness.
268  *  @param dst Destination memory address to store the result.
269  */
sys_put_be48(u64_t val,u8_t dst[6])270 static inline void sys_put_be48(u64_t val, u8_t dst[6])
271 {
272 	sys_put_be16(val >> 32, dst);
273 	sys_put_be32(val, &dst[2]);
274 }
275 
276 /**
277  *  @brief Put a 64-bit integer as big-endian to arbitrary location.
278  *
279  *  Put a 64-bit integer, originally in host endianness, to a
280  *  potentially unaligned memory location in big-endian format.
281  *
282  *  @param val 64-bit integer in host endianness.
283  *  @param dst Destination memory address to store the result.
284  */
sys_put_be64(u64_t val,u8_t dst[8])285 static inline void sys_put_be64(u64_t val, u8_t dst[8])
286 {
287 	sys_put_be32(val >> 32, dst);
288 	sys_put_be32(val, &dst[4]);
289 }
290 
291 /**
292  *  @brief Put a 16-bit integer as little-endian to arbitrary location.
293  *
294  *  Put a 16-bit integer, originally in host endianness, to a
295  *  potentially unaligned memory location in little-endian format.
296  *
297  *  @param val 16-bit integer in host endianness.
298  *  @param dst Destination memory address to store the result.
299  */
sys_put_le16(u16_t val,u8_t dst[2])300 static inline void sys_put_le16(u16_t val, u8_t dst[2])
301 {
302 	dst[0] = val;
303 	dst[1] = val >> 8;
304 }
305 
306 /**
307  *  @brief Put a 24-bit integer as little-endian to arbitrary location.
308  *
309  *  Put a 24-bit integer, originally in host endianness, to a
310  *  potentially unaligned memory location in littel-endian format.
311  *
312  *  @param val 24-bit integer in host endianness.
313  *  @param dst Destination memory address to store the result.
314  */
sys_put_le24(bt_u32_t val,u8_t dst[3])315 static inline void sys_put_le24(bt_u32_t val, u8_t dst[3])
316 {
317 	sys_put_le16(val, dst);
318 	dst[2] = val >> 16;
319 }
320 
321 /**
322  *  @brief Put a 32-bit integer as little-endian to arbitrary location.
323  *
324  *  Put a 32-bit integer, originally in host endianness, to a
325  *  potentially unaligned memory location in little-endian format.
326  *
327  *  @param val 32-bit integer in host endianness.
328  *  @param dst Destination memory address to store the result.
329  */
sys_put_le32(bt_u32_t val,u8_t dst[4])330 static inline void sys_put_le32(bt_u32_t val, u8_t dst[4])
331 {
332 	sys_put_le16(val, dst);
333 	sys_put_le16(val >> 16, &dst[2]);
334 }
335 
336 /**
337  *  @brief Put a 48-bit integer as little-endian to arbitrary location.
338  *
339  *  Put a 48-bit integer, originally in host endianness, to a
340  *  potentially unaligned memory location in little-endian format.
341  *
342  *  @param val 48-bit integer in host endianness.
343  *  @param dst Destination memory address to store the result.
344  */
sys_put_le48(u64_t val,u8_t dst[6])345 static inline void sys_put_le48(u64_t val, u8_t dst[6])
346 {
347 	sys_put_le32(val, dst);
348 	sys_put_le16(val >> 32, &dst[4]);
349 }
350 
351 /**
352  *  @brief Put a 64-bit integer as little-endian to arbitrary location.
353  *
354  *  Put a 64-bit integer, originally in host endianness, to a
355  *  potentially unaligned memory location in little-endian format.
356  *
357  *  @param val 64-bit integer in host endianness.
358  *  @param dst Destination memory address to store the result.
359  */
sys_put_le64(u64_t val,u8_t dst[8])360 static inline void sys_put_le64(u64_t val, u8_t dst[8])
361 {
362 	sys_put_le32(val, dst);
363 	sys_put_le32(val >> 32, &dst[4]);
364 }
365 
366 /**
367  *  @brief Get a 16-bit integer stored in big-endian format.
368  *
369  *  Get a 16-bit integer, stored in big-endian format in a potentially
370  *  unaligned memory location, and convert it to the host endianness.
371  *
372  *  @param src Location of the big-endian 16-bit integer to get.
373  *
374  *  @return 16-bit integer in host endianness.
375  */
sys_get_be16(const u8_t src[2])376 static inline u16_t sys_get_be16(const u8_t src[2])
377 {
378 	return ((u16_t)src[0] << 8) | src[1];
379 }
380 
381 /**
382  *  @brief Get a 24-bit integer stored in big-endian format.
383  *
384  *  Get a 24-bit integer, stored in big-endian format in a potentially
385  *  unaligned memory location, and convert it to the host endianness.
386  *
387  *  @param src Location of the big-endian 24-bit integer to get.
388  *
389  *  @return 24-bit integer in host endianness.
390  */
sys_get_be24(const u8_t src[3])391 static inline bt_u32_t sys_get_be24(const u8_t src[3])
392 {
393 	return ((bt_u32_t)src[0] << 16) | sys_get_be16(&src[1]);
394 }
395 
396 /**
397  *  @brief Get a 32-bit integer stored in big-endian format.
398  *
399  *  Get a 32-bit integer, stored in big-endian format in a potentially
400  *  unaligned memory location, and convert it to the host endianness.
401  *
402  *  @param src Location of the big-endian 32-bit integer to get.
403  *
404  *  @return 32-bit integer in host endianness.
405  */
sys_get_be32(const u8_t src[4])406 static inline bt_u32_t sys_get_be32(const u8_t src[4])
407 {
408 	return ((bt_u32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
409 }
410 
411 /**
412  *  @brief Get a 48-bit integer stored in big-endian format.
413  *
414  *  Get a 48-bit integer, stored in big-endian format in a potentially
415  *  unaligned memory location, and convert it to the host endianness.
416  *
417  *  @param src Location of the big-endian 48-bit integer to get.
418  *
419  *  @return 48-bit integer in host endianness.
420  */
sys_get_be48(const u8_t src[6])421 static inline u64_t sys_get_be48(const u8_t src[6])
422 {
423 	return ((u64_t)sys_get_be32(&src[0]) << 32) | sys_get_be16(&src[4]);
424 }
425 
426 /**
427  *  @brief Get a 64-bit integer stored in big-endian format.
428  *
429  *  Get a 64-bit integer, stored in big-endian format in a potentially
430  *  unaligned memory location, and convert it to the host endianness.
431  *
432  *  @param src Location of the big-endian 64-bit integer to get.
433  *
434  *  @return 64-bit integer in host endianness.
435  */
sys_get_be64(const u8_t src[8])436 static inline u64_t sys_get_be64(const u8_t src[8])
437 {
438 	return ((u64_t)sys_get_be32(&src[0]) << 32) | sys_get_be32(&src[4]);
439 }
440 
441 /**
442  *  @brief Get a 16-bit integer stored in little-endian format.
443  *
444  *  Get a 16-bit integer, stored in little-endian format in a potentially
445  *  unaligned memory location, and convert it to the host endianness.
446  *
447  *  @param src Location of the little-endian 16-bit integer to get.
448  *
449  *  @return 16-bit integer in host endianness.
450  */
sys_get_le16(const u8_t src[2])451 static inline u16_t sys_get_le16(const u8_t src[2])
452 {
453 	return ((u16_t)src[1] << 8) | src[0];
454 }
455 
456 /**
457  *  @brief Get a 24-bit integer stored in big-endian format.
458  *
459  *  Get a 24-bit integer, stored in big-endian format in a potentially
460  *  unaligned memory location, and convert it to the host endianness.
461  *
462  *  @param src Location of the big-endian 24-bit integer to get.
463  *
464  *  @return 24-bit integer in host endianness.
465  */
sys_get_le24(const u8_t src[3])466 static inline bt_u32_t sys_get_le24(const u8_t src[3])
467 {
468 	return ((bt_u32_t)src[2] << 16) | sys_get_le16(&src[0]);
469 }
470 
471 /**
472  *  @brief Get a 32-bit integer stored in little-endian format.
473  *
474  *  Get a 32-bit integer, stored in little-endian format in a potentially
475  *  unaligned memory location, and convert it to the host endianness.
476  *
477  *  @param src Location of the little-endian 32-bit integer to get.
478  *
479  *  @return 32-bit integer in host endianness.
480  */
sys_get_le32(const u8_t src[4])481 static inline bt_u32_t sys_get_le32(const u8_t src[4])
482 {
483 	return ((bt_u32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
484 }
485 
486 /**
487  *  @brief Get a 48-bit integer stored in little-endian format.
488  *
489  *  Get a 48-bit integer, stored in little-endian format in a potentially
490  *  unaligned memory location, and convert it to the host endianness.
491  *
492  *  @param src Location of the little-endian 48-bit integer to get.
493  *
494  *  @return 48-bit integer in host endianness.
495  */
sys_get_le48(const u8_t src[6])496 static inline u64_t sys_get_le48(const u8_t src[6])
497 {
498 	return ((u64_t)sys_get_le32(&src[2]) << 32) | sys_get_le16(&src[0]);
499 }
500 
501 /**
502  *  @brief Get a 64-bit integer stored in little-endian format.
503  *
504  *  Get a 64-bit integer, stored in little-endian format in a potentially
505  *  unaligned memory location, and convert it to the host endianness.
506  *
507  *  @param src Location of the little-endian 64-bit integer to get.
508  *
509  *  @return 64-bit integer in host endianness.
510  */
sys_get_le64(const u8_t src[8])511 static inline u64_t sys_get_le64(const u8_t src[8])
512 {
513 	return ((u64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
514 }
515 
516 /**
517  * @brief Swap one buffer content into another
518  *
519  * Copy the content of src buffer into dst buffer in reversed order,
520  * i.e.: src[n] will be put in dst[end-n]
521  * Where n is an index and 'end' the last index in both arrays.
522  * The 2 memory pointers must be pointing to different areas, and have
523  * a minimum size of given length.
524  *
525  * @param dst A valid pointer on a memory area where to copy the data in
526  * @param src A valid pointer on a memory area where to copy the data from
527  * @param length Size of both dst and src memory areas
528  */
sys_memcpy_swap(void * dst,const void * src,size_t length)529 static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
530 {
531 	u8_t *pdst = (u8_t *)dst;
532 	const u8_t *psrc = (const u8_t *)src;
533 
534 	__ASSERT(((psrc < pdst && (psrc + length) <= pdst) ||
535 		  (psrc > pdst && (pdst + length) <= psrc)),
536 		 "Source and destination buffers must not overlap");
537 
538 	psrc += length - 1;
539 
540 	for (; length > 0; length--) {
541 		*pdst++ = *psrc--;
542 	}
543 }
544 
545 /**
546  * @brief Swap buffer content
547  *
548  * In-place memory swap, where final content will be reversed.
549  * I.e.: buf[n] will be put in buf[end-n]
550  * Where n is an index and 'end' the last index of buf.
551  *
552  * @param buf A valid pointer on a memory area to swap
553  * @param length Size of buf memory area
554  */
sys_mem_swap(void * buf,size_t length)555 static inline void sys_mem_swap(void *buf, size_t length)
556 {
557 	size_t i;
558 
559 	for (i = 0; i < (length/2); i++) {
560 		u8_t tmp = ((u8_t *)buf)[i];
561 
562 		((u8_t *)buf)[i] = ((u8_t *)buf)[length - 1 - i];
563 		((u8_t *)buf)[length - 1 - i] = tmp;
564 	}
565 }
566 
567 #endif /* __BYTEORDER_H__ */
568