mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-26 23:11:19 +01:00
Merge pull request #1699 from Kijewski/issue-1586
core: Provide functions for different byte orders
This commit is contained in:
commit
42f96b0d60
314
core/include/byteorder.h
Normal file
314
core/include/byteorder.h
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright (C) 2014 René Kijewski
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup core_util
|
||||
* @{
|
||||
*
|
||||
* @file byteorder.h
|
||||
* @brief Functions to work with different byte orders.
|
||||
*
|
||||
* @author René Kijewski <rene.kijewski@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef BYTEORDER_H_
|
||||
#define BYTEORDER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* ******************************* INTERFACE ******************************* */
|
||||
|
||||
|
||||
/**
|
||||
* @brief A 16 bit integer in little endian.
|
||||
* @details This is a wrapper around an uint16_t to catch missing conversions
|
||||
* between different byte orders at compile time.
|
||||
*/
|
||||
typedef union __attribute__((packed)) {
|
||||
uint8_t u8[2];
|
||||
uint16_t u16;
|
||||
} le_uint16_t;
|
||||
|
||||
/**
|
||||
* @brief A 32 bit integer in little endian.
|
||||
* @details This is a wrapper around an uint32_t to catch missing conversions
|
||||
* between different byte orders at compile time.
|
||||
*/
|
||||
typedef union __attribute__((packed)) {
|
||||
uint8_t u8[4];
|
||||
uint16_t u16[2];
|
||||
uint32_t u32;
|
||||
le_uint16_t l16[2];
|
||||
} le_uint32_t;
|
||||
|
||||
/**
|
||||
* @brief A 64 bit integer in little endian.
|
||||
* @details This is a wrapper around an uint64_t to catch missing conversions
|
||||
* between different byte orders at compile time.
|
||||
*/
|
||||
typedef union __attribute__((packed)) {
|
||||
uint8_t u8[8];
|
||||
uint16_t u16[4];
|
||||
uint32_t u32[2];
|
||||
uint64_t u64;
|
||||
le_uint16_t l16[4];
|
||||
le_uint32_t l32[2];
|
||||
} le_uint64_t;
|
||||
|
||||
/**
|
||||
* @brief A 16 bit integer in big endian aka network byte order.
|
||||
* @details This is a wrapper around an uint16_t to catch missing conversions
|
||||
* between different byte orders at compile time.
|
||||
*/
|
||||
typedef union __attribute__((packed)) {
|
||||
uint8_t u8[2];
|
||||
uint16_t u16;
|
||||
} be_uint16_t;
|
||||
|
||||
/**
|
||||
* @brief A 32 bit integer in big endian aka network byte order.
|
||||
* @details This is a wrapper around an uint32_t to catch missing conversions
|
||||
* between different byte orders at compile time.
|
||||
*/
|
||||
typedef union __attribute__((packed)) {
|
||||
uint8_t u8[4];
|
||||
uint16_t u16[2];
|
||||
uint32_t u32;
|
||||
be_uint16_t b16[2];
|
||||
} be_uint32_t;
|
||||
|
||||
/**
|
||||
* @brief A 64 bit integer in big endian aka network byte order.
|
||||
* @details This is a wrapper around an uint64_t to catch missing conversions
|
||||
* between different byte orders at compile time.
|
||||
*/
|
||||
typedef union __attribute__((packed)) {
|
||||
uint8_t u8[8];
|
||||
uint16_t u16[4];
|
||||
uint32_t u32[2];
|
||||
uint64_t u64;
|
||||
be_uint16_t b16[4];
|
||||
be_uint32_t b32[2];
|
||||
} be_uint64_t;
|
||||
|
||||
typedef be_uint16_t network_uint16_t;
|
||||
typedef be_uint32_t network_uint32_t;
|
||||
typedef be_uint64_t network_uint64_t;
|
||||
|
||||
/**
|
||||
* @brief Convert from little endian to big endian, 16 bit.
|
||||
* @param[in] v The integer in little endian.
|
||||
* @returns `v` converted to big endian.
|
||||
*/
|
||||
static inline be_uint16_t byteorder_ltobs(le_uint16_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from little endian to big endian, 32 bit.
|
||||
* @param[in] v The integer in little endian.
|
||||
* @returns `v` converted to big endian.
|
||||
*/
|
||||
static inline be_uint32_t byteorder_ltobl(le_uint32_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from little endian to big endian, 64 bit.
|
||||
* @param[in] v The integer in little endian.
|
||||
* @returns `v` converted to big endian.
|
||||
*/
|
||||
static inline be_uint64_t byteorder_ltobll(le_uint64_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from big endian to little endian, 16 bit.
|
||||
* @param[in] v The integer in big endian.
|
||||
* @returns `v` converted to little endian.
|
||||
*/
|
||||
static inline le_uint16_t byteorder_btols(be_uint16_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from big endian to little endian, 32 bit.
|
||||
* @param[in] v The integer in big endian.
|
||||
* @returns `v` converted to little endian.
|
||||
*/
|
||||
static inline le_uint32_t byteorder_btoll(be_uint32_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from big endian to little endian, 64 bit.
|
||||
* @param[in] v The integer in big endian.
|
||||
* @returns `v` converted to little endian.
|
||||
*/
|
||||
static inline le_uint64_t byteorder_btolll(be_uint64_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from host byte order to network byte order, 16 bit.
|
||||
* @param[in] v The integer in host byte order.
|
||||
* @returns `v` converted to network byte order.
|
||||
*/
|
||||
static inline network_uint16_t byteorder_htons(uint16_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from host byte order to network byte order, 32 bit.
|
||||
* @param[in] v The integer in host byte order.
|
||||
* @returns `v` converted to network byte order.
|
||||
*/
|
||||
static inline network_uint32_t byteorder_htonl(uint32_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from host byte order to network byte order, 64 bit.
|
||||
* @param[in] v The integer in host byte order.
|
||||
* @returns `v` converted to network byte order.
|
||||
*/
|
||||
static inline network_uint64_t byteorder_htonll(uint64_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from network byte order to host byte order, 16 bit.
|
||||
* @param[in] v The integer in network byte order.
|
||||
* @returns `v` converted to host byte order.
|
||||
*/
|
||||
static inline uint16_t byteorder_ntohs(network_uint16_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from network byte order to host byte order, 32 bit.
|
||||
* @param[in] v The integer in network byte order.
|
||||
* @returns `v` converted to host byte order.
|
||||
*/
|
||||
static inline uint32_t byteorder_ntohl(network_uint32_t v);
|
||||
|
||||
/**
|
||||
* @brief Convert from network byte order to host byte order, 64 bit.
|
||||
* @param[in] v The integer in network byte order.
|
||||
* @returns `v` converted to host byte order.
|
||||
*/
|
||||
static inline uint64_t byteorder_ntohll(network_uint64_t v);
|
||||
|
||||
/**
|
||||
* @brief Swap byte order, 16 bit.
|
||||
* @param[in] v The integer to swap.
|
||||
* @returns The swapped integer.
|
||||
*/
|
||||
static inline uint16_t byteorder_swaps(uint16_t v);
|
||||
|
||||
/**
|
||||
* @brief Swap byte order, 32 bit.
|
||||
* @param[in] v The integer to swap.
|
||||
* @returns The swapped integer.
|
||||
*/
|
||||
static inline uint32_t byteorder_swapl(uint32_t v);
|
||||
|
||||
/**
|
||||
* @brief Swap byte order, 64 bit.
|
||||
* @param[in] v The integer to swap.
|
||||
* @returns The swapped integer.
|
||||
*/
|
||||
static inline uint64_t byteorder_swapll(uint64_t v);
|
||||
|
||||
|
||||
/* **************************** IMPLEMENTATION ***************************** */
|
||||
|
||||
|
||||
uint16_t byteorder_swaps(uint16_t v)
|
||||
{
|
||||
#ifndef MODULE_MSP430_COMMON
|
||||
return __builtin_bswap16(v);
|
||||
#else
|
||||
network_uint16_t result = { .u16 = v };
|
||||
uint8_t tmp = result.u8[0];
|
||||
result.u8[0] = result.u8[1];
|
||||
result.u8[1] = tmp;
|
||||
return result.u16;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t byteorder_swapl(uint32_t v)
|
||||
{
|
||||
return __builtin_bswap32(v);
|
||||
}
|
||||
|
||||
uint64_t byteorder_swapll(uint64_t v)
|
||||
{
|
||||
return __builtin_bswap64(v);
|
||||
}
|
||||
|
||||
be_uint16_t byteorder_ltobs(le_uint16_t v)
|
||||
{
|
||||
be_uint16_t result = { .u16 = byteorder_swaps(v.u16) };
|
||||
return result;
|
||||
}
|
||||
|
||||
be_uint32_t byteorder_ltobl(le_uint32_t v)
|
||||
{
|
||||
be_uint32_t result = { .u32 = byteorder_swapl(v.u32) };
|
||||
return result;
|
||||
}
|
||||
|
||||
be_uint64_t byteorder_ltobll(le_uint64_t v)
|
||||
{
|
||||
be_uint64_t result = { .u64 = byteorder_swapll(v.u64) };
|
||||
return result;
|
||||
}
|
||||
|
||||
le_uint16_t byteorder_btols(be_uint16_t v)
|
||||
{
|
||||
le_uint16_t result = { .u16 = byteorder_swaps(v.u16) };
|
||||
return result;
|
||||
}
|
||||
|
||||
le_uint32_t byteorder_btoll(be_uint32_t v)
|
||||
{
|
||||
le_uint32_t result = { .u32 = byteorder_swapl(v.u32) };
|
||||
return result;
|
||||
}
|
||||
|
||||
le_uint64_t byteorder_btolll(be_uint64_t v)
|
||||
{
|
||||
le_uint64_t result = { .u64 = byteorder_swapll(v.u64) };
|
||||
return result;
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define _byteorder_swap(V, T) (byteorder_swap##T((V)))
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define _byteorder_swap(V, T) (V)
|
||||
#else
|
||||
# error "Byte order is neither little nor big!"
|
||||
#endif
|
||||
|
||||
network_uint16_t byteorder_htons(uint16_t v)
|
||||
{
|
||||
network_uint16_t result = { .u16 = _byteorder_swap(v, s) };
|
||||
return result;
|
||||
}
|
||||
|
||||
network_uint32_t byteorder_htonl(uint32_t v)
|
||||
{
|
||||
network_uint32_t result = { .u32 = _byteorder_swap(v, l) };
|
||||
return result;
|
||||
}
|
||||
|
||||
network_uint64_t byteorder_htonll(uint64_t v)
|
||||
{
|
||||
network_uint64_t result = { .u64 = _byteorder_swap(v, ll) };
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t byteorder_ntohs(network_uint16_t v)
|
||||
{
|
||||
return _byteorder_swap(v.u16, s);
|
||||
}
|
||||
|
||||
uint32_t byteorder_ntohl(network_uint32_t v)
|
||||
{
|
||||
return _byteorder_swap(v.u32, l);
|
||||
}
|
||||
|
||||
uint64_t byteorder_ntohll(network_uint64_t v)
|
||||
{
|
||||
return _byteorder_swap(v.u64, ll);
|
||||
}
|
||||
|
||||
#endif /* BYTEORDER_H_ */
|
||||
/** @} */
|
||||
@ -27,23 +27,39 @@
|
||||
#include "clang_compat.h"
|
||||
#endif
|
||||
|
||||
#include "byteorder.h"
|
||||
|
||||
#define BITSET(var,pos) ((var) & (1<<(pos)))
|
||||
#define HTONS(a) ((((uint16_t) (a) >> 8) & 0xff) | ((((uint16_t) (a)) & 0xff) << 8))
|
||||
#define HTONL(a) ((((uint32_t) (a) & 0xff000000) >> 24) | \
|
||||
(((uint32_t) (a) & 0x00ff0000) >> 8) | \
|
||||
(((uint32_t) (a) & 0x0000ff00) << 8) | \
|
||||
(((uint32_t) (a) & 0x000000ff) << 24))
|
||||
#define HTONLL(a) ((((uint64_t) (a) & 0xff00000000000000) >> 56) | \
|
||||
(((uint64_t) (a) & 0x00ff000000000000) >> 40) | \
|
||||
(((uint64_t) (a) & 0x0000ff0000000000) >> 24) | \
|
||||
(((uint64_t) (a) & 0x000000ff00000000) >> 8) | \
|
||||
(((uint64_t) (a) & 0x00000000ff000000) << 8) | \
|
||||
(((uint64_t) (a) & 0x0000000000ff0000) << 24) | \
|
||||
(((uint64_t) (a) & 0x000000000000ff00) << 40) | \
|
||||
(((uint64_t) (a) & 0x00000000000000ff) << 56))
|
||||
#define NTOHS HTONS
|
||||
#define NTOHL HTONL
|
||||
#define NTOHLL HTONLL
|
||||
|
||||
static inline uint16_t HTONS(uint16_t a)
|
||||
{
|
||||
return byteorder_htons(a).u16;
|
||||
}
|
||||
|
||||
static inline uint32_t HTONL(uint32_t a)
|
||||
{
|
||||
return byteorder_htonl(a).u32;
|
||||
}
|
||||
|
||||
static inline uint64_t HTONLL(uint64_t a)
|
||||
{
|
||||
return byteorder_htonll(a).u64;
|
||||
}
|
||||
|
||||
static inline uint16_t NTOHS(uint16_t a)
|
||||
{
|
||||
return byteorder_ntohs(*(network_uint16_t *) &a);
|
||||
}
|
||||
|
||||
static inline uint32_t NTOHL(uint32_t a)
|
||||
{
|
||||
return byteorder_ntohl(*(network_uint32_t *) &a);
|
||||
}
|
||||
|
||||
static inline uint64_t NTOHLL(uint64_t a)
|
||||
{
|
||||
return byteorder_ntohll(*(network_uint64_t *) &a);
|
||||
}
|
||||
|
||||
#define CMP_IPV6_ADDR(a, b) (memcmp(a, b, 16))
|
||||
|
||||
|
||||
97
tests/unittests/tests-core/tests-core-byteorder.c
Normal file
97
tests/unittests/tests-core/tests-core-byteorder.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2014 René Kijewski
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
#include "embUnit/embUnit.h"
|
||||
|
||||
#include "byteorder.h"
|
||||
|
||||
#include "tests-core.h"
|
||||
|
||||
static void test_byteorder_little_to_big_16(void)
|
||||
{
|
||||
le_uint16_t little = { .u8 = { 0x12, 0x34 } };
|
||||
be_uint16_t big = { .u8 = { 0x34, 0x12 } };
|
||||
TEST_ASSERT_EQUAL_INT(big.u16, byteorder_ltobs(little).u16);
|
||||
}
|
||||
|
||||
static void test_byteorder_big_to_little_16(void)
|
||||
{
|
||||
le_uint16_t little = { .u8 = { 0x12, 0x34 } };
|
||||
be_uint16_t big = { .u8 = { 0x34, 0x12 } };
|
||||
TEST_ASSERT_EQUAL_INT(little.u16, byteorder_btols(big).u16);
|
||||
}
|
||||
|
||||
static void test_byteorder_little_to_big_32(void)
|
||||
{
|
||||
le_uint32_t little = { .u8 = { 0x12, 0x34, 0x56, 0x78 } };
|
||||
be_uint32_t big = { .u8 = { 0x78, 0x56, 0x34, 0x12 } };
|
||||
TEST_ASSERT_EQUAL_INT(big.u32, byteorder_ltobl(little).u32);
|
||||
}
|
||||
|
||||
static void test_byteorder_big_to_little_32(void)
|
||||
{
|
||||
le_uint32_t little = { .u8 = { 0x12, 0x34, 0x56, 0x78 } };
|
||||
be_uint32_t big = { .u8 = { 0x78, 0x56, 0x34, 0x12 } };
|
||||
TEST_ASSERT_EQUAL_INT(little.u32, byteorder_btoll(big).u32);
|
||||
}
|
||||
|
||||
static void test_byteorder_little_to_big_64(void)
|
||||
{
|
||||
le_uint64_t little = { .u8 = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
|
||||
be_uint64_t big = { .u8 = { 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12 } };
|
||||
TEST_ASSERT_EQUAL_INT(big.u64, byteorder_ltobll(little).u64);
|
||||
}
|
||||
|
||||
static void test_byteorder_big_to_little_64(void)
|
||||
{
|
||||
le_uint64_t little = { .u8 = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
|
||||
be_uint64_t big = { .u8 = { 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12 } };
|
||||
TEST_ASSERT_EQUAL_INT(little.u64, byteorder_btolll(big).u64);
|
||||
}
|
||||
|
||||
static void test_byteorder_host_to_network_16(void)
|
||||
{
|
||||
static const uint16_t host = 0x1234;
|
||||
network_uint16_t network = { .u8 = { 0x12, 0x34 } };
|
||||
TEST_ASSERT_EQUAL_INT(network.u16, byteorder_htons(host).u16);
|
||||
TEST_ASSERT_EQUAL_INT(host, byteorder_ntohs(network));
|
||||
}
|
||||
|
||||
static void test_byteorder_host_to_network_32(void)
|
||||
{
|
||||
static const uint32_t host = 0x12345678ul;
|
||||
network_uint32_t network = { .u8 = { 0x12, 0x34, 0x56, 0x78 } };
|
||||
TEST_ASSERT_EQUAL_INT(network.u32, byteorder_htonl(host).u32);
|
||||
TEST_ASSERT_EQUAL_INT(host, byteorder_ntohl(network));
|
||||
}
|
||||
|
||||
static void test_byteorder_host_to_network_64(void)
|
||||
{
|
||||
static const uint64_t host = 0x123456789abcdef0ull;
|
||||
network_uint64_t network = { .u8 = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
|
||||
TEST_ASSERT_EQUAL_INT(network.u64, byteorder_htonll(host).u64);
|
||||
TEST_ASSERT_EQUAL_INT(host, byteorder_ntohll(network));
|
||||
}
|
||||
|
||||
Test *tests_core_byteorder_tests(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
new_TestFixture(test_byteorder_little_to_big_16),
|
||||
new_TestFixture(test_byteorder_big_to_little_16),
|
||||
new_TestFixture(test_byteorder_little_to_big_32),
|
||||
new_TestFixture(test_byteorder_big_to_little_32),
|
||||
new_TestFixture(test_byteorder_little_to_big_64),
|
||||
new_TestFixture(test_byteorder_big_to_little_64),
|
||||
new_TestFixture(test_byteorder_host_to_network_16),
|
||||
new_TestFixture(test_byteorder_host_to_network_32),
|
||||
new_TestFixture(test_byteorder_host_to_network_64),
|
||||
};
|
||||
|
||||
EMB_UNIT_TESTCALLER(core_byteorder_tests, NULL, NULL, fixtures);
|
||||
return (Test *)&core_byteorder_tests;
|
||||
}
|
||||
@ -16,4 +16,5 @@ void tests_core(void)
|
||||
TESTS_RUN(tests_core_clist_tests());
|
||||
TESTS_RUN(tests_core_lifo_tests());
|
||||
TESTS_RUN(tests_core_priority_queue_tests());
|
||||
TESTS_RUN(tests_core_byteorder_tests());
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
void tests_core(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests atomic.h
|
||||
* @brief Generates tests for atomic.h
|
||||
*
|
||||
* @return embUnit tests if successful, NULL if not.
|
||||
*/
|
||||
@ -40,32 +40,39 @@ Test *tests_core_atomic_tests(void);
|
||||
Test *tests_core_bitarithm_tests(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests cib.h
|
||||
* @brief Generates tests for cib.h
|
||||
*
|
||||
* @return embUnit tests if successful, NULL if not.
|
||||
*/
|
||||
Test *tests_core_cib_tests(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests clist.h
|
||||
* @brief Generates tests for clist.h
|
||||
*
|
||||
* @return embUnit tests if successful, NULL if not.
|
||||
*/
|
||||
Test *tests_core_clist_tests(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests lifo.h
|
||||
* @brief Generates tests for lifo.h
|
||||
*
|
||||
* @return embUnit tests if successful, NULL if not.
|
||||
*/
|
||||
Test *tests_core_lifo_tests(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests priority_queue.h
|
||||
* @brief Generates tests for priority_queue.h
|
||||
*
|
||||
* @return embUnit tests if successful, NULL if not.
|
||||
*/
|
||||
Test *tests_core_priority_queue_tests(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests for byteorder.h
|
||||
*
|
||||
* @return embUnit tests if successful, NULL if not.
|
||||
*/
|
||||
Test *tests_core_byteorder_tests(void);
|
||||
|
||||
#endif /* __TESTS_CORE_H_ */
|
||||
/** @} */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user