upload
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

Endianness.h 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. LUFA Library
  3. Copyright (C) Dean Camera, 2014.
  4. dean [at] fourwalledcubicle [dot] com
  5. www.lufa-lib.org
  6. */
  7. /*
  8. Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
  9. Permission to use, copy, modify, distribute, and sell this
  10. software and its documentation for any purpose is hereby granted
  11. without fee, provided that the above copyright notice appear in
  12. all copies and that both that the copyright notice and this
  13. permission notice and warranty disclaimer appear in supporting
  14. documentation, and that the name of the author not be used in
  15. advertising or publicity pertaining to distribution of the
  16. software without specific, written prior permission.
  17. The author disclaims all warranties with regard to this
  18. software, including all implied warranties of merchantability
  19. and fitness. In no event shall the author be liable for any
  20. special, indirect or consequential damages or any damages
  21. whatsoever resulting from loss of use, data or profits, whether
  22. in an action of contract, negligence or other tortious action,
  23. arising out of or in connection with the use or performance of
  24. this software.
  25. */
  26. /** \file
  27. * \brief Endianness and Byte Ordering macros and functions.
  28. *
  29. * \copydetails Group_Endianness
  30. */
  31. /** \ingroup Group_Endianness
  32. * \defgroup Group_ByteSwapping Byte Reordering
  33. * \brief Macros and functions for forced byte reordering.
  34. */
  35. /** \ingroup Group_Endianness
  36. * \defgroup Group_EndianConversion Endianness Conversion
  37. * \brief Macros and functions for automatic endianness conversion.
  38. */
  39. /** \ingroup Group_Common
  40. * \defgroup Group_Endianness Endianness and Byte Ordering
  41. * \brief Convenience macros and functions relating to byte (re-)ordering
  42. *
  43. * Common library convenience macros and functions relating to byte (re-)ordering.
  44. *
  45. * @{
  46. */
  47. #ifndef __LUFA_ENDIANNESS_H__
  48. #define __LUFA_ENDIANNESS_H__
  49. /* Enable C linkage for C++ Compilers: */
  50. #if defined(__cplusplus)
  51. extern "C" {
  52. #endif
  53. /* Preprocessor Checks: */
  54. #if !defined(__INCLUDE_FROM_COMMON_H)
  55. #error Do not include this file directly. Include LUFA/Common/Common.h instead to gain this functionality.
  56. #endif
  57. #if !(defined(ARCH_BIG_ENDIAN) || defined(ARCH_LITTLE_ENDIAN))
  58. #error ARCH_BIG_ENDIAN or ARCH_LITTLE_ENDIAN not set for the specified architecture.
  59. #endif
  60. /* Public Interface - May be used in end-application: */
  61. /* Macros: */
  62. /** Swaps the byte ordering of a 16-bit value at compile-time. Do not use this macro for swapping byte orderings
  63. * of dynamic values computed at runtime, use \ref SwapEndian_16() instead. The result of this macro can be used
  64. * inside struct or other variable initializers outside of a function, something that is not possible with the
  65. * inline function variant.
  66. *
  67. * \hideinitializer
  68. *
  69. * \ingroup Group_ByteSwapping
  70. *
  71. * \param[in] x 16-bit value whose byte ordering is to be swapped.
  72. *
  73. * \return Input value with the byte ordering reversed.
  74. */
  75. #define SWAPENDIAN_16(x) (uint16_t)((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
  76. /** Swaps the byte ordering of a 32-bit value at compile-time. Do not use this macro for swapping byte orderings
  77. * of dynamic values computed at runtime- use \ref SwapEndian_32() instead. The result of this macro can be used
  78. * inside struct or other variable initializers outside of a function, something that is not possible with the
  79. * inline function variant.
  80. *
  81. * \hideinitializer
  82. *
  83. * \ingroup Group_ByteSwapping
  84. *
  85. * \param[in] x 32-bit value whose byte ordering is to be swapped.
  86. *
  87. * \return Input value with the byte ordering reversed.
  88. */
  89. #define SWAPENDIAN_32(x) (uint32_t)((((x) & 0xFF000000UL) >> 24UL) | (((x) & 0x00FF0000UL) >> 8UL) | \
  90. (((x) & 0x0000FF00UL) << 8UL) | (((x) & 0x000000FFUL) << 24UL))
  91. #if defined(ARCH_BIG_ENDIAN) && !defined(le16_to_cpu)
  92. #define le16_to_cpu(x) SwapEndian_16(x)
  93. #define le32_to_cpu(x) SwapEndian_32(x)
  94. #define be16_to_cpu(x) (x)
  95. #define be32_to_cpu(x) (x)
  96. #define cpu_to_le16(x) SwapEndian_16(x)
  97. #define cpu_to_le32(x) SwapEndian_32(x)
  98. #define cpu_to_be16(x) (x)
  99. #define cpu_to_be32(x) (x)
  100. #define LE16_TO_CPU(x) SWAPENDIAN_16(x)
  101. #define LE32_TO_CPU(x) SWAPENDIAN_32(x)
  102. #define BE16_TO_CPU(x) (x)
  103. #define BE32_TO_CPU(x) (x)
  104. #define CPU_TO_LE16(x) SWAPENDIAN_16(x)
  105. #define CPU_TO_LE32(x) SWAPENDIAN_32(x)
  106. #define CPU_TO_BE16(x) (x)
  107. #define CPU_TO_BE32(x) (x)
  108. #elif !defined(le16_to_cpu)
  109. /** \name Run-time endianness conversion */
  110. //@{
  111. /** Performs a conversion between a Little Endian encoded 16-bit piece of data and the
  112. * Endianness of the currently selected CPU architecture.
  113. *
  114. * On little endian architectures, this macro does nothing.
  115. *
  116. * \note This macro is designed for run-time conversion of data - for compile-time endianness
  117. * conversion, use \ref LE16_TO_CPU instead.
  118. *
  119. * \ingroup Group_EndianConversion
  120. *
  121. * \param[in] x Data to perform the endianness conversion on.
  122. *
  123. * \return Endian corrected version of the input value.
  124. */
  125. #define le16_to_cpu(x) (x)
  126. /** Performs a conversion between a Little Endian encoded 32-bit piece of data and the
  127. * Endianness of the currently selected CPU architecture.
  128. *
  129. * On little endian architectures, this macro does nothing.
  130. *
  131. * \note This macro is designed for run-time conversion of data - for compile-time endianness
  132. * conversion, use \ref LE32_TO_CPU instead.
  133. *
  134. * \ingroup Group_EndianConversion
  135. *
  136. * \param[in] x Data to perform the endianness conversion on.
  137. *
  138. * \return Endian corrected version of the input value.
  139. */
  140. #define le32_to_cpu(x) (x)
  141. /** Performs a conversion between a Big Endian encoded 16-bit piece of data and the
  142. * Endianness of the currently selected CPU architecture.
  143. *
  144. * On big endian architectures, this macro does nothing.
  145. *
  146. * \note This macro is designed for run-time conversion of data - for compile-time endianness
  147. * conversion, use \ref BE16_TO_CPU instead.
  148. *
  149. * \ingroup Group_EndianConversion
  150. *
  151. * \param[in] x Data to perform the endianness conversion on.
  152. *
  153. * \return Endian corrected version of the input value.
  154. */
  155. #define be16_to_cpu(x) SwapEndian_16(x)
  156. /** Performs a conversion between a Big Endian encoded 32-bit piece of data and the
  157. * Endianness of the currently selected CPU architecture.
  158. *
  159. * On big endian architectures, this macro does nothing.
  160. *
  161. * \note This macro is designed for run-time conversion of data - for compile-time endianness
  162. * conversion, use \ref BE32_TO_CPU instead.
  163. *
  164. * \ingroup Group_EndianConversion
  165. *
  166. * \param[in] x Data to perform the endianness conversion on.
  167. *
  168. * \return Endian corrected version of the input value.
  169. */
  170. #define be32_to_cpu(x) SwapEndian_32(x)
  171. /** Performs a conversion on a natively encoded 16-bit piece of data to ensure that it
  172. * is in Little Endian format regardless of the currently selected CPU architecture.
  173. *
  174. * On little endian architectures, this macro does nothing.
  175. *
  176. * \note This macro is designed for run-time conversion of data - for compile-time endianness
  177. * conversion, use \ref CPU_TO_LE16 instead.
  178. *
  179. * \ingroup Group_EndianConversion
  180. *
  181. * \param[in] x Data to perform the endianness conversion on.
  182. *
  183. * \return Endian corrected version of the input value.
  184. */
  185. #define cpu_to_le16(x) (x)
  186. /** Performs a conversion on a natively encoded 32-bit piece of data to ensure that it
  187. * is in Little Endian format regardless of the currently selected CPU architecture.
  188. *
  189. * On little endian architectures, this macro does nothing.
  190. *
  191. * \note This macro is designed for run-time conversion of data - for compile-time endianness
  192. * conversion, use \ref CPU_TO_LE32 instead.
  193. *
  194. * \ingroup Group_EndianConversion
  195. *
  196. * \param[in] x Data to perform the endianness conversion on.
  197. *
  198. * \return Endian corrected version of the input value.
  199. */
  200. #define cpu_to_le32(x) (x)
  201. /** Performs a conversion on a natively encoded 16-bit piece of data to ensure that it
  202. * is in Big Endian format regardless of the currently selected CPU architecture.
  203. *
  204. * On big endian architectures, this macro does nothing.
  205. *
  206. * \note This macro is designed for run-time conversion of data - for compile-time endianness
  207. * conversion, use \ref CPU_TO_BE16 instead.
  208. *
  209. * \ingroup Group_EndianConversion
  210. *
  211. * \param[in] x Data to perform the endianness conversion on.
  212. *
  213. * \return Endian corrected version of the input value.
  214. */
  215. #define cpu_to_be16(x) SwapEndian_16(x)
  216. /** Performs a conversion on a natively encoded 32-bit piece of data to ensure that it
  217. * is in Big Endian format regardless of the currently selected CPU architecture.
  218. *
  219. * On big endian architectures, this macro does nothing.
  220. *
  221. * \note This macro is designed for run-time conversion of data - for compile-time endianness
  222. * conversion, use \ref CPU_TO_BE32 instead.
  223. *
  224. * \ingroup Group_EndianConversion
  225. *
  226. * \param[in] x Data to perform the endianness conversion on.
  227. *
  228. * \return Endian corrected version of the input value.
  229. */
  230. #define cpu_to_be32(x) SwapEndian_32(x)
  231. //@}
  232. /** \name Compile-time endianness conversion */
  233. //@{
  234. /** Performs a conversion between a Little Endian encoded 16-bit piece of data and the
  235. * Endianness of the currently selected CPU architecture.
  236. *
  237. * On little endian architectures, this macro does nothing.
  238. *
  239. * \note This macro is designed for compile-time conversion of data - for run time endianness
  240. * conversion, use \ref le16_to_cpu instead.
  241. *
  242. * \ingroup Group_EndianConversion
  243. *
  244. * \param[in] x Data to perform the endianness conversion on.
  245. *
  246. * \return Endian corrected version of the input value.
  247. */
  248. #define LE16_TO_CPU(x) (x)
  249. /** Performs a conversion between a Little Endian encoded 32-bit piece of data and the
  250. * Endianness of the currently selected CPU architecture.
  251. *
  252. * On little endian architectures, this macro does nothing.
  253. *
  254. * \note This macro is designed for compile-time conversion of data - for run time endianness
  255. * conversion, use \ref le32_to_cpu instead.
  256. *
  257. * \ingroup Group_EndianConversion
  258. *
  259. * \param[in] x Data to perform the endianness conversion on.
  260. *
  261. * \return Endian corrected version of the input value.
  262. */
  263. #define LE32_TO_CPU(x) (x)
  264. /** Performs a conversion between a Big Endian encoded 16-bit piece of data and the
  265. * Endianness of the currently selected CPU architecture.
  266. *
  267. * On big endian architectures, this macro does nothing.
  268. *
  269. * \note This macro is designed for compile-time conversion of data - for run-time endianness
  270. * conversion, use \ref be16_to_cpu instead.
  271. *
  272. * \ingroup Group_EndianConversion
  273. *
  274. * \param[in] x Data to perform the endianness conversion on.
  275. *
  276. * \return Endian corrected version of the input value.
  277. */
  278. #define BE16_TO_CPU(x) SWAPENDIAN_16(x)
  279. /** Performs a conversion between a Big Endian encoded 32-bit piece of data and the
  280. * Endianness of the currently selected CPU architecture.
  281. *
  282. * On big endian architectures, this macro does nothing.
  283. *
  284. * \note This macro is designed for compile-time conversion of data - for run-time endianness
  285. * conversion, use \ref be32_to_cpu instead.
  286. *
  287. * \ingroup Group_EndianConversion
  288. *
  289. * \param[in] x Data to perform the endianness conversion on.
  290. *
  291. * \return Endian corrected version of the input value.
  292. */
  293. #define BE32_TO_CPU(x) SWAPENDIAN_32(x)
  294. /** Performs a conversion on a natively encoded 16-bit piece of data to ensure that it
  295. * is in Little Endian format regardless of the currently selected CPU architecture.
  296. *
  297. * On little endian architectures, this macro does nothing.
  298. *
  299. * \note This macro is designed for compile-time conversion of data - for run-time endianness
  300. * conversion, use \ref cpu_to_le16 instead.
  301. *
  302. * \ingroup Group_EndianConversion
  303. *
  304. * \param[in] x Data to perform the endianness conversion on.
  305. *
  306. * \return Endian corrected version of the input value.
  307. */
  308. #define CPU_TO_LE16(x) (x)
  309. /** Performs a conversion on a natively encoded 32-bit piece of data to ensure that it
  310. * is in Little Endian format regardless of the currently selected CPU architecture.
  311. *
  312. * On little endian architectures, this macro does nothing.
  313. *
  314. * \note This macro is designed for compile-time conversion of data - for run-time endianness
  315. * conversion, use \ref cpu_to_le32 instead.
  316. *
  317. * \ingroup Group_EndianConversion
  318. *
  319. * \param[in] x Data to perform the endianness conversion on.
  320. *
  321. * \return Endian corrected version of the input value.
  322. */
  323. #define CPU_TO_LE32(x) (x)
  324. /** Performs a conversion on a natively encoded 16-bit piece of data to ensure that it
  325. * is in Big Endian format regardless of the currently selected CPU architecture.
  326. *
  327. * On big endian architectures, this macro does nothing.
  328. *
  329. * \note This macro is designed for compile-time conversion of data - for run-time endianness
  330. * conversion, use \ref cpu_to_be16 instead.
  331. *
  332. * \ingroup Group_EndianConversion
  333. *
  334. * \param[in] x Data to perform the endianness conversion on.
  335. *
  336. * \return Endian corrected version of the input value.
  337. */
  338. #define CPU_TO_BE16(x) SWAPENDIAN_16(x)
  339. /** Performs a conversion on a natively encoded 32-bit piece of data to ensure that it
  340. * is in Big Endian format regardless of the currently selected CPU architecture.
  341. *
  342. * On big endian architectures, this macro does nothing.
  343. *
  344. * \note This macro is designed for compile-time conversion of data - for run-time endianness
  345. * conversion, use \ref cpu_to_be32 instead.
  346. *
  347. * \ingroup Group_EndianConversion
  348. *
  349. * \param[in] x Data to perform the endianness conversion on.
  350. *
  351. * \return Endian corrected version of the input value.
  352. */
  353. #define CPU_TO_BE32(x) SWAPENDIAN_32(x)
  354. //! @}
  355. #endif
  356. /* Inline Functions: */
  357. /** Function to reverse the byte ordering of the individual bytes in a 16 bit value.
  358. *
  359. * \ingroup Group_ByteSwapping
  360. *
  361. * \param[in] Word Word of data whose bytes are to be swapped.
  362. *
  363. * \return Input data with the individual bytes reversed.
  364. */
  365. static inline uint16_t SwapEndian_16(const uint16_t Word) ATTR_WARN_UNUSED_RESULT ATTR_CONST;
  366. static inline uint16_t SwapEndian_16(const uint16_t Word)
  367. {
  368. if (GCC_IS_COMPILE_CONST(Word))
  369. return SWAPENDIAN_16(Word);
  370. uint8_t Temp;
  371. union
  372. {
  373. uint16_t Word;
  374. uint8_t Bytes[2];
  375. } Data;
  376. Data.Word = Word;
  377. Temp = Data.Bytes[0];
  378. Data.Bytes[0] = Data.Bytes[1];
  379. Data.Bytes[1] = Temp;
  380. return Data.Word;
  381. }
  382. /** Function to reverse the byte ordering of the individual bytes in a 32 bit value.
  383. *
  384. * \ingroup Group_ByteSwapping
  385. *
  386. * \param[in] DWord Double word of data whose bytes are to be swapped.
  387. *
  388. * \return Input data with the individual bytes reversed.
  389. */
  390. static inline uint32_t SwapEndian_32(const uint32_t DWord) ATTR_WARN_UNUSED_RESULT ATTR_CONST;
  391. static inline uint32_t SwapEndian_32(const uint32_t DWord)
  392. {
  393. if (GCC_IS_COMPILE_CONST(DWord))
  394. return SWAPENDIAN_32(DWord);
  395. uint8_t Temp;
  396. union
  397. {
  398. uint32_t DWord;
  399. uint8_t Bytes[4];
  400. } Data;
  401. Data.DWord = DWord;
  402. Temp = Data.Bytes[0];
  403. Data.Bytes[0] = Data.Bytes[3];
  404. Data.Bytes[3] = Temp;
  405. Temp = Data.Bytes[1];
  406. Data.Bytes[1] = Data.Bytes[2];
  407. Data.Bytes[2] = Temp;
  408. return Data.DWord;
  409. }
  410. /** Function to reverse the byte ordering of the individual bytes in a n byte value.
  411. *
  412. * \ingroup Group_ByteSwapping
  413. *
  414. * \param[in,out] Data Pointer to a number containing an even number of bytes to be reversed.
  415. * \param[in] Length Length of the data in bytes.
  416. *
  417. * \return Input data with the individual bytes reversed.
  418. */
  419. static inline void SwapEndian_n(void* const Data,
  420. uint8_t Length) ATTR_NON_NULL_PTR_ARG(1);
  421. static inline void SwapEndian_n(void* const Data,
  422. uint8_t Length)
  423. {
  424. uint8_t* CurrDataPos = (uint8_t*)Data;
  425. while (Length > 1)
  426. {
  427. uint8_t Temp = *CurrDataPos;
  428. *CurrDataPos = *(CurrDataPos + Length - 1);
  429. *(CurrDataPos + Length - 1) = Temp;
  430. CurrDataPos++;
  431. Length -= 2;
  432. }
  433. }
  434. /* Disable C linkage for C++ Compilers: */
  435. #if defined(__cplusplus)
  436. }
  437. #endif
  438. #endif
  439. /** @} */