Check and convert endianness of a variable in embedded systems - TCP/IP , BLE, etc
Gurajapu Raja Sumant
Embedded systems software developer using C/C++ for products such as PTC HVAC,EV chargers, etc. ISO26262,UDS, OBD.
If we break down the storage of data in variables, then the least that we could think of would be bytes or 8 bits (Yes, I know there is a concept of bit fields in structs.??but anyways, I am considering int8_t is the smallest known datatype.)
Endianness is a concept which comes into picture when we are dealing with multi byte data such as uint32_t (4 bytes), float, char arr[4] , etc.
Has it ever occurred to you that you had to check the endian ness of a variable during runtime in an embedded system? This is quite a significant concept in embedded systems especially when one is using concepts of SPI/UART/I2C or TCP/IP!
In?big-endian (PowerPC, SPARC, and Internet), the 32-bit value x01234567 is stored as four bytes 0x01, 0x23, 0x45, 0x67, while on?little-endian (Intel x86 and ARM below 3), it will be stored in reverse order : 0x67 , 0x45, 0x23 , 0x01. This is what the definition of endian ness is. ARM processors were little endians. Current generation ARM processors are bi-endian.
Now when I say internet, it is all tcp/ip sockets. Communication between a host server and a client takes place as exchange of bytes. It is to be noted that these bytes are transmitted as big endian!
However, detection and conversion from one another is easy and simple. Here are a few resources available to do so -
Detection: [Pointers at it again! ]
int n = 1;
if(*(char *)&n == 1)
{
cout<<“Little Endian”<<endl;
}
Conversion:
If your system is little endian, then you will have to perform some special byte operations to inter convert them to meaningful data. There are special macros htonl, htons, ntohl, ntohs – to convert values between host and network byte order
#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
#define htons(A) (A)
#define htonl(A) (A)
#define ntohs(A) (A)
#define ntohl(A) (A)
#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
#define htons(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
(((uint16_t)(A) & 0x00ff) << 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 ntohs htons
# define ntohl htonl
#else
#error "Must define one of BIG_ENDIAN or LITTLE_ENDIAN"
#endif
The linux man page describes these as:
领英推荐
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
Description
The htonl() function converts the unsigned integer hostlong from host byte order to network byte order.
The htons() function converts the unsigned short integer hostshort from host byte order to network byte order.
The ntohl() function converts the unsigned integer netlong from network byte order to host byte order.
The ntohs() function converts the unsigned short integer netshort from network byte order to host byte order.
On the i386 the host byte order is Least Significant Byte first, whereas the network byte order, as used on the Internet, is Most Significant Byte first.
Bluetooth low energy is a concept where any embedded developer can get easily confused.
GATT fields are always (or at least should always be) little-endian. This is discussed in the Bluetooth Core Spec.
From v4.2 of the spec, Vol 3, Part G (which covers GATT), page 523:
2.4 Profile Fundamentals
? Multi-octet fields within the GATT Profile shall be sent least significant octet first (little endian). Recently I was very confused on why such a thing needs to be implemented. I thought it was the job of the mobile app developer to do the conversion but it turns out that it is one of the firmware engineer!
Be very careful reading this spec because there are pieces that are in network order (big-endian), but GATT attributes are always supposed to be in little-endian.
It is very much possible to take things for granted before transmitting data via BLE GATT profile. Hence it is advised to convert your variables that you would like to transmit.