Cast functions into function pointers in c program
I'm trying to understand the software for a tire pressure monitoring system, but I don't know much about the C language. One of the header files has definitions like this:
#define TPMS_RESET gu16AddressToFn = u16fnDALLinkFmw(gu8Derivative, FN_RESET);\
((void(*)(void))(gu16AddressToFn))
/* UINT8 TPMS_READ_VOLTAGE(UINT16 *u16UUMA) */
#define TPMS_READ_VOLTAGE ((UINT8(*)(UINT16*))(u16fnDALLinkFmw(gu8Derivative, FN_READ_VOLT)))
/* UINT8 TPMS_COMP_VOLTAGE(UINT8 *u8CompVoltage, *UINT16 u16UUMA) */
#define TPMS_COMP_VOLTAGE ((UINT8(*)(UINT8*, UINT16*))(u16fnDALLinkFmw(gu8Derivative, FN_COMP_V)))
/* UINT8 TPMS_READ_TEMPERATURE(UINT16 *u16UUMA) */
#define TPMS_READ_TEMPERATURE ((UINT8(*)(UINT16*))(u16fnDALLinkFmw(gu8Derivative, FN_READ_T)))
/* UINT8 TPMS_COMP_TEMPERATURE(UINT8 *u8Temp, UINT16 *u16UUMA) */
#define TPMS_COMP_TEMPERATURE ((UINT8(*)(UINT8*, UINT16*))(u16fnDALLinkFmw(gu8Derivative, FN_COMP_T)))
/* UINT8 TPMS_READ_PRESSURE(UINT16 *u16UUMA, UINT8 u8Avg) */
#define TPMS_READ_PRESSURE ((UINT8(*)(UINT16*, UINT8))(u16fnDALLinkFmw(gu8Derivative, FN_READ_P)))
/* UINT8 TPMS_COMP_PRESSURE(UINT16 *u16CompPressure, UINT16 *u16UUMA) */
#define TPMS_COMP_PRESSURE ((UINT8(*)(UINT16*, UINT16*))(u16fnDALLinkFmw(gu8Derivative, FN_COMP_P)))
/* UINT8 TPMS_READ_ACCEL_X(UINT16 *u16UUMA, UINT8 u8Avg, UINT8 u8FiltSelect, UINT8 u8DynamicOffset) */
#define TPMS_READ_ACCEL_X ((UINT8(*)(UINT16*, UINT8, UINT8, UINT8))(u16fnDALLinkFmw(gu8Derivative, FN_READ_X)))
/* UINT8 TPMS_READ_ACCEL_Z(UINT16 *u16UUMA, UINT8 u8Avg, UINT8 u8FiltSelect, UINT8 u8DynamicOffset) */
#define TPMS_READ_ACCEL_Z ((UINT8(*)(UINT16*, UINT8, UINT8, UINT8))(u16fnDALLinkFmw(gu8Derivative, FN_READ_Z)))
I don't understand this trick in other functions. Do you have an idea?
source to share
Casting function pointers is a way of converting non-C firmware memory addresses into valid function declarations in C. This is usually done in embedded systems when you access firmware functions (possibly written in languages ββor non-C assembly) without the firmware API exposed like API C.
For example, in your case, the firmware provides a list of addresses for the firmware functions in gu8Derivative
(the table of transition to the firmware code). Using u16fnDALLinkFmw(gu8Derivative, X)
, you can get the function jump address X
in firmware, which is equivalent to a function pointer in C. Now, since the function declaration in firmware is not known directly in C, it is provided as a function pointer with an accompanying comment describing the API of the corresponding firmware function.
This NXP community post gives more details on this exact firmware you are trying to use.
source to share
Macros that you represent is ultimately defined in terms of function (likely) or maybe another macro (unlikely) u16fnDALLinkFmw()
. I believe this is a function. However, you are not quite sure what is happening here: the code in the macro replacement texts does not perform this function; rather, they discard the return value.
What seems to be happening here is a variation on dynamic dispatch. The macros ensure that each desired function is searched in a specified table using offset / id, and since the lookup functions for different identifiers may have different signatures, the macros map the returned function pointer to a function pointer type of the correct signature.
You would use it something like this:
uint16_t argument = 1;
uint8_t result = TPMS_READ_VOLTAGE(&argument);
source to share