I am writing some C code that is for a microcontroller and have come across a curious couple of statements in some generated drivers for a peripheral I am using. Seemingly, a function uint8_t gapm_reset_req_handler (void) is supposed to reset a handler and return a status. The function is seemingly failing in its purpose, which surprises me as it seems simple enough. The relevant code I would like to ask about is this function and that INTERFACE_UNPACK_UINT8 line.
uint8_t gapm_reset_req_handler (void) {
uint8_t u8Operation, u8Status;
INTERFACE_MSG_INIT(GAPM_RESET_CMD, TASK_GAPM);
INTERFACE_PACK_ARG_UINT8(GAPM_RESET);
INTERFACE_SEND_WAIT(GAPM_CMP_EVT, TASK_GAPM);
INTERFACE_UNPACK_UINT8(&u8Operation);
INTERFACE_UNPACK_UINT8(&u8Status);
INTERFACE_MSG_DONE();
if(u8Operation!=GAPM_RESET)
return AT_BLE_FAILURE;
return u8Status;}
These INTERFACE messages are defined in another file, and I am a bit lost at what exactly is supposed to be accomplished by the generated code regarding the use of the double underscore on the ptr variable. Does anyone have any intuition as to what is going on? To me, it looks like some operation on the value that is passed to it but the use of the double underscore confuses me as I thought that was just for macros. Any thoughts are greatly appreciated!
Specific line
#define INTERFACE_UNPACK_UINT8(ptr)\
*ptr = *__ptr
Full Definition of INTERFACE Code:
#ifndef __INTERFACE_H__
#define __INTERFACE_H__
#include "event.h"
#define INTERFACE_HDR_LENGTH 9
#define INTERFACE_API_PKT_ID 0x05
#define INTERFACE_SEND_BUF_MAX 600
#define INTERFACE_RCV_BUFF_LEN 500
extern uint8_t interface_send_msg[INTERFACE_SEND_BUF_MAX];
void platform_send_lock_aquire(void);
void platform_send_lock_release(void);
#define INTERFACE_MSG_INIT(msg_id, dest_id) \
do{\
uint8_t* __ptr = interface_send_msg;\
uint16_t __len;\
platform_send_lock_aquire();\
*__ptr = (INTERFACE_API_PKT_ID);\
*__ptr = ((msg_id) & 0x00FF );\
*__ptr = (((msg_id)>>8) & 0x00FF );\
*__ptr = ((dest_id) & 0x00FF );\
*__ptr = (((dest_id)>>8) & 0x00FF );\
*__ptr = ((TASK_EXTERN) & 0x00FF );\
*__ptr = (((TASK_EXTERN)>>8) & 0x00FF );\
__ptr = 2
#define INTERFACE_PACK_ARG_UINT8(arg)\
*__ptr = (arg)
#define INTERFACE_PACK_ARG_UINT16(arg)\
*__ptr = ((arg) & 0x00FF);\
*__ptr = (((arg) >> 8) & 0x00FF)
#define INTERFACE_PACK_ARG_UINT32(arg) \
*__ptr = (uint8_t)((arg) & 0x00FF );\
*__ptr = (uint8_t)(( (arg) >> 8) & 0x00FF) ;\
*__ptr = (uint8_t)(( (arg) >> 16) & 0x00FF);\
*__ptr = (uint8_t)(( (arg) >> 24) & 0x00FF)
#define INTERFACE_PACK_ARG_BLOCK(ptr,len)\
memcpy(__ptr, ptr, len);\
__ptr = len
#define INTERFACE_PACK_ARG_DUMMY(len)\
__ptr = len
#define INTERFACE_PACK_LEN()\
__len = __ptr - &interface_send_msg[INTERFACE_HDR_LENGTH];\
interface_send_msg[7] = ((__len) & 0x00FF );\
interface_send_msg[8] = (((__len)>>8) & 0x00FF);\
__len = INTERFACE_HDR_LENGTH;
#define INTERFACE_SEND_NO_WAIT()\
INTERFACE_PACK_LEN();\
interface_send(interface_send_msg, __len)
#define INTERFACE_SEND_WAIT(msg, src)\
watched_event.msg_id = msg;\
watched_event.src_id = src;\
INTERFACE_PACK_LEN();\
interface_send(interface_send_msg, __len);\
if(platform_cmd_cmpl_wait()){return AT_BLE_FAILURE;}\
__ptr = watched_event.params;\
#define INTERFACE_MSG_DONE()\
platform_send_lock_release();\
}while(0)
#define INTERFACE_UNPACK_INIT(ptr)\
do{\
uint8_t* __ptr = (uint8_t*)(ptr);\
#define INTERFACE_UNPACK_UINT8(ptr)\
*ptr = *__ptr
#define INTERFACE_UNPACK_UINT16(ptr)\
*ptr = (uint16_t)__ptr[0]\
| ((uint16_t)__ptr[1] << 8);\
__ptr = 2
#define INTERFACE_UNPACK_UINT32(ptr)\
*ptr = (uint32_t)__ptr[0] \
| ((uint32_t)__ptr[1] << 8) \
| ((uint32_t)__ptr[2] << 16)\
| ((uint32_t)__ptr[3] << 24);\
__ptr = 4
#define INTERFACE_UNPACK_BLOCK(ptr, len)\
memcpy(ptr, __ptr, len);\
__ptr = len
#define INTERFACE_UNPACK_SKIP(len)\
__ptr = (len)
#define INTERFACE_UNPACK_DONE()\
}while(0)
void interface_send(uint8_t* msg, uint16_t u16TxLen);
#endif /* HCI_H_ */
CodePudding user response:
*ptr = *__ptr
is simply a byte copy followed by increasing the source pointer by one. __ptr
is a local variable declared inside one of the macros then re-used in the other macros.
Notably, it is bad practice to use identifiers starting with underscore and particularly with two underscore or one underscore an upper case letter. These are reserved for the compiler and standard lib, and the lib you post does not appear to belong to either. So there is reason to believe it was badly designed.
The following function-like macro nightmare confirms this - this is some horrible code with non-existent type safety and massive potential for undefined behavior upon bitwise arithmetic with signed numbers. People used to write macro crap like this before function inlining became industry standard back in the 1980s-1990s. Although stdint.h was introduced in 1999 so more likely they were just incompetent.
As for what the code does, it is much simpler than it looks. There's just various macros for shoveling data from one data type to another, apparently part of some protocol encoding/decoding. They also seem to make various assumptions about endianess that aren't portable.
Please never use or trust code provided to you by some silicon vendor. They have a very long tradition of employing the absolutely worst programmers in the world. If someone wrote microcontroller code like this in a normal company, they would get fired immediately. Similarly, don't trust the average open source barf posted on Github either.