I have a set of defined macros as follows.
#define ARM_FRONT_REG 1
..............
#define ARM_REAR_REG 10
#define MOTOR_MAIN_REG 1
..............
#define MOTOR_AUX_REG 3
#define MOTOR_REGISTER_ADDRESS(register_offset) \
( \
addr = MOTOR_BASE_ADDR * (1 << BITS_PER_MODULE) + register_offset) \
) \
#define ARM_REGISTER_ADDRESS(register_offset) \
( \
addr = ARM_BASE_ADDR * (1 << BITS_PER_MODULE) + register_offset) \
) \
I am using macros like
ui_address = ARM_BASE_ADDR (ARM_REAR_REG)
ui_address = MOTOR_REGISTER_ADDRESS (MOTOR_MAIN_REG)
I want to restrict macro usage which is mixed with each other. Is there a way of aborting compiling if macros used as following?
ui_address = ARM_BASE_ADDR (MOTOR_MAIN_REG)
ui_address = MOTOR_REGISTER_ADDRESS (ARM_REAR_REG)
PS : I have mentioned macros in brief, But actual macros are as below, which used to perform register reads write to Linux driver from user application.
actual struct :
struct hw_register_struct
{
int log_level;
unsigned int reg_addr;
unsigned int reg_value;
char reg_name [MAX_REG_NAME_LENGTH];
char application_info [APP_INFO_LENGTH];
};
This macro validates the address is correct per module.
#define CHECK_ADDR_SUB_MODULE(module_index, sub_module, sub_module_bits, offset, max_reg_count)
({
unsigned int check_ret = 0;
if(offset >= max_reg_count){
hw_register.reg_addr = 0;
check_ret = 1;
} else {
hw_register.reg_addr = (module_index * (1 << BITS_PER_MODULE) + (1 << sub_module_bits) * (sub_module) + offset);
}
check_ret;
})
This macro assigns the address to the variable in the struct.
#define SEQUENCER_REGISTER_ADDRESS(register_offset)
({
memset((void *)&hw_register, 0, sizeof(struct hw_register_struct));
if(CHECK_ADDR_SUB_MODULE(MODULE_SEQUENCER, 0, register_offset, SEQ_REG_COUNT)){
Logger::Print(ERROR_LEVEL, "Invalid Address | Module : %s | Address : %s", STR(MODULE_SEQUENCER), #register_offset);
}
memcpy(hw_register.reg_name, #register_offset, sizeof(#register_offset));
hw_register.reg_addr;
})
Perform calling the ioctl to Linux driver
#define WRITE_REGISTER_(register_addr, register_value, func, line, log_level_)
{
register_addr;
hw_register.reg_value = register_value;
hw_register.log_level = log_level_;
snprintf(hw_register.application_info, APP_INFO_LENGTH - 1,"%s:%d", func, line);
long ret_ioctl = p_IOCTL->IOCTL<struct hw_register_struct>(IOCTL_WRITE, hw_register);
if(unlikely(ret_ioctl != 0))
{
Logger::Print(ERROR_LEVEL, "IOCTL WRITE_REGISTER Failed | Reg: %u, Reg Name [ %s ]", hw_register.reg_addr, hw_register.reg_name);
}
}
#define WRITE_REGISTER_INFO(register_addr, register_value) WRITE_REGISTER_(register_addr, register_value, __func__, __LINE__, KERN_INFO_LEVEL)
In your case, one thing you can do is have the macros taking arguments adding a name prefix to the argument passed. E.g.:
#define ARM_REGISTER_ADDRESS(register_offset) \
( \
addr = ARM_BASE_ADDR * (1 << BITS_PER_MODULE) + ARM_##register_offset) \
)
The ##
will concatenate ARM_ and the argument passed to the macro. Then you can use it as:
ui_address = ARM_BASE_ADDR (REAR_REG);
And
ui_address = ARM_BASE_ADDR (MAIN_REG);
Would fail because ARM_MAIN_REG doesn't exist (in your case).
But I don't think typechecking even using enums will solve your issue (at least, I am not aware of a compiler option to allow it).