Trouble defining macros in C - Initializer element is not constant - c

I'm programming for the Game Boy Advance and I need to have a list of memory locations for each area(a bunch of RAM and ROM).
However, while defining the macros in a header file, the compiler pointed out that on one macro, error: initializer element is not constant.
Here is my full header file(approx. 90 lines) that I borrowed from Tonc:
#ifndef TOOLBOX_H
#define TOOLBOX_H
// === (from tonc_types.h) ============================================
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef u16 COLOR;
#define INLINE static inline
// === (from tonc_memmap.h) ===========================================
#define MEM_IO 0x04000000
#define MEM_VRAM 0x06000000
#define GAMEPAK_RAM 0x0E000000
#define REG_DISPCNT *((volatile u32*)(MEM_IO+0x0000))
#define REG_VCOUNT *(volatile u16*)(MEM_IO+0x0006) // vertical count
// === (from tonc_memdef.h) ===========================================
// --- REG_DISPCNT defines ---
#define DCNT_MODE0 0x0000
#define DCNT_MODE1 0x0001
#define DCNT_MODE2 0x0002
#define DCNT_MODE3 0x0003
#define DCNT_MODE4 0x0004
#define DCNT_MODE5 0x0005
// layers
#define DCNT_BG0 0x0100
#define DCNT_BG1 0x0200
#define DCNT_BG2 0x0400
#define DCNT_BG3 0x0800
#define DCNT_OBJ 0x1000
#define save_mem ((u8*)GAMEPAK_RAM) //<- Error here
// === (from tonc_video.h) ============================================
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 160
#define vid_mem ((u16*)MEM_VRAM) //But not here
INLINE void m3_plot(int x, int y, COLOR clr)
{ vid_mem[y*SCREEN_WIDTH+x]= clr; }
#define CLR_BLACK 0x0000
#define CLR_RED 0x001F
#define CLR_LIME 0x03E0
#define CLR_YELLOW 0x03FF
#define CLR_BLUE 0x7C00
#define CLR_MAG 0x7C1F
#define CLR_CYAN 0x7FE0
#define CLR_WHITE 0x7FFF
INLINE int CLAMP(int val, int min, int max)
{
if(val >= max)
{
val = max - 1;
}
else if(val < min)
{
val = min;
}
else
{
return val;
}
return val;
}
INLINE COLOR RGB15(u32 red, u32 green, u32 blue)
{ return red | (green<<5) | (blue<<10); }
INLINE u16 * get_RGB(COLOR clr)
{
u16 red, green, blue;
red = clr & 31;
green = (clr >> 5) & 31;
blue = clr >> 10;
static u16 rgb[3];
rgb[0] = red; rgb[1] = green; rgb[2] = blue;
return rgb;
}
INLINE void vid_vsync()
{
while(REG_VCOUNT >= 160); // wait till VDraw
while(REG_VCOUNT < 160); // wait till VBlank
}
#endif // TOOLBOX_H
However, I did not have these two lines in my code originally:
#define GAMEPAK_RAM 0x0E000000
and
#define save_mem ((u8*)GAMEPAK_RAM)
If you noticed, I purposely defined save_mem almost exactly like vid_mem except that I needed to cast it to u8 because that RAM could only read/write 8 bits at a time.
Then I thought that if there were errors, then both lines should have errors. However, only the save_mem got caught with error: initializer element is not constant. (I personally commented out the save_mem line to see if vid_mem would have that problem.)
Also, I was already in the middle of programming my game for the GBA and I had already used vid_mem many times, so this puzzles me even more.
I am wondering why this is occurring and how to fix it.(Pretty sure my compiler is fine)
Thanks in advance.
EDIT:
Here is the code where I use the save_mem macro:
#include "toolbox.h"
u8 played = save_mem[0];
u8 coins = save_mem[1] | (save_mem[2] << 8) | (save_mem[3] << 16) |
(save_mem[4] < 24);
void get_coins()
{
coins = save_mem[1] | (save_mem[2] << 8) | (save_mem[3] << 16) |
(save_mem[4] < 24);
}
void save_coins(int amount)
{
save_mem[1] = (amount & 255);
save_mem[2] = ((amount >> 8) & 255);
save_mem[3] = ((amount >> 16) & 255);
save_mem[4] = ((amount >> 24) & 255);
}
void set_played()
{
save_mem[0] = 1;
}

I could only reproduce your problem by doing
u8 played = save_mem[0];
outside of any function. This is not an error in your define, but an error in the above line. The way the error was presented is really misleading.
Anyway, the error happens because the line above will require the program to load contents from memory, and as you expect, there is no way for the compiler to know what will be in this memory at compile time, and global variable initializations only accept constants. You should move this line of code inside a function.
The code I used to test:
#ifndef TOOLBOX_H
#define TOOLBOX_H
// === (from tonc_types.h) ============================================
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef u16 COLOR;
#define INLINE static inline
// === (from tonc_memmap.h) ===========================================
#define MEM_IO 0x04000000
#define MEM_VRAM 0x06000000
#define GAMEPAK_RAM 0x0E000000
#define REG_DISPCNT *((volatile u32*)(MEM_IO+0x0000))
#define REG_VCOUNT *(volatile u16*)(MEM_IO+0x0006) // vertical count
// === (from tonc_memdef.h) ===========================================
// --- REG_DISPCNT defines ---
#define DCNT_MODE0 0x0000
#define DCNT_MODE1 0x0001
#define DCNT_MODE2 0x0002
#define DCNT_MODE3 0x0003
#define DCNT_MODE4 0x0004
#define DCNT_MODE5 0x0005
// layers
#define DCNT_BG0 0x0100
#define DCNT_BG1 0x0200
#define DCNT_BG2 0x0400
#define DCNT_BG3 0x0800
#define DCNT_OBJ 0x1000
#define save_mem ((u8*)GAMEPAK_RAM) //<- Error here
// === (from tonc_video.h) ============================================
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 160
#define vid_mem ((u16*)MEM_VRAM) //But not here
INLINE void m3_plot(int x, int y, COLOR clr)
{ vid_mem[y*SCREEN_WIDTH+x]= clr; }
#define CLR_BLACK 0x0000
#define CLR_RED 0x001F
#define CLR_LIME 0x03E0
#define CLR_YELLOW 0x03FF
#define CLR_BLUE 0x7C00
#define CLR_MAG 0x7C1F
#define CLR_CYAN 0x7FE0
#define CLR_WHITE 0x7FFF
INLINE int CLAMP(int val, int min, int max)
{
if(val >= max)
{
val = max - 1;
}
else if(val < min)
{
val = min;
}
else
{
return val;
}
return val;
}
INLINE COLOR RGB15(u32 red, u32 green, u32 blue)
{ return red | (green<<5) | (blue<<10); }
INLINE u16 * get_RGB(COLOR clr)
{
u16 red, green, blue;
red = clr & 31;
green = (clr >> 5) & 31;
blue = clr >> 10;
static u16 rgb[3];
rgb[0] = red; rgb[1] = green; rgb[2] = blue;
return rgb;
}
INLINE void vid_vsync()
{
while(REG_VCOUNT >= 160); // wait till VDraw
while(REG_VCOUNT < 160); // wait till VBlank
}
#endif // TOOLBOX_H
/*void bob(){*/
u8 played = save_mem[0];
/*}*/
To compile I copied from your screenshot:
arm-none-eabi-gcc -mthumb-interwork -mthumb -O2 test.c -c
but added -c to avoid link(since there is no main function).

Related

Is this the right way to access function?

I am currently using "STM32F429I-DISC1" with joystick. I am trying to draw something on the LCD screen and using joystick move this object. My drawing is working fine, but I have the error: " void value not ignored as it ought to be".
This two lines have problems...
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4);
Can someone please tell me, how I can fix this error?
And why I see this error?
Main.c
#include "stm32f429i_discovery_lcd.h"
#define CTRL_REG_IN3 0b00011000
#define CTRL_REG_IN4 0b00100000
SemaphoreHandle_t xMutex;
Joystick_data xy;
void vTaskFunction1(void *pvParameters) {
uint16_t localX;
uint16_t localY;
for(;;) {
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4);
xSemaphoreTake( xMutex, portMAX_DELAY );
xy.x = localX;
xy.y = localY;
xSemaphoreGive( xMutex );
HAL_Delay(10);
}
}
void vTaskFunction2(void *pvParameters) {
uint32_t xCoord = 240/2;
uint32_t yCoord = 320/2;
uint8_t reads = 0;
uint8_t ballRadius = 5;
uint16_t xLimitMin = ballRadius+25;
uint16_t xLimitMax = 240-ballRadius-25;
uint16_t yLimitMin = ballRadius+25;
uint16_t yLimitMax = 320-ballRadius-25;
for(;;) {
xSemaphoreTake( xMutex, portMAX_DELAY );
if (xy.x > 3000 && !(xCoord < xLimitMin))
xCoord -= 5;
if (xy.x < 1000 && !(xCoord > xLimitMax))
xCoord += 5;
if (xy.y > 3000 && !(yCoord < yLimitMin))
yCoord -= 5;
if (xy.y < 1000 && !(yCoord > yLimitMax))
yCoord += 5;
reads++;
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_DrawCircle(xCoord, yCoord, ballRadius);
BSP_LCD_FillCircle(xCoord, yCoord, ballRadius);
xSemaphoreGive(xMutex);
HAL_Delay(20);
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI4_Init();
MX_TIM1_Init();
MX_USART1_UART_Init();
// LCD Things
BSP_LCD_Init();
BSP_LCD_LayerDefaultInit(1, LCD_FRAME_BUFFER);
BSP_LCD_SelectLayer(1);
BSP_LCD_SetBackColor(LCD_COLOR_WHITE); // Vali meelepärane värv
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_SetTextColor(LCD_COLOR_DARKBLUE); // Vali meelepärane värv
MX_FREERTOS_Init();
if ( xMutex == NULL )
{
xMutex = xSemaphoreCreateMutex();
if ( ( xMutex ) != NULL )
xSemaphoreGive( ( xMutex ) );
}
xTaskCreate(vTaskFunction1, "Task 1", 100, NULL, 1, NULL);
xTaskCreate(vTaskFunction2, "Task 2", 100, NULL, 1, NULL);
vTaskStartScheduler();
osKernelStart();
while (1)
{
}
}
Read joystick function (joystick.c)
#include <stdio.h>
#include <main.h>
#include "gpio.h"
#include "spi.h"
#define READ_SLAVE_OPERATION 0b10000000
#define READ_INCR_SLAVE_OPERATION 0b11000000
#define WRITE_SLAVE_OPERATION 0b00000000
#define CTRL_REG_IN3 0b00000011
#define CTRL_REG_IN4 0b00000100
#define OUT_X_L 0x28
#define OUT_X_H 0x29
#define OUT_Y_L 0x2A
#define OUT_Y_H 0x2B
#define OUT_Z_L 0x2C
#define OUT_Z_H 0x2D
#define JOY_CS_LOW() HAL_GPIO_WritePin(JOY_CS_GPIO_PORT, JOY_CS_PIN, 0)
#define JOY_CS_HIGH() HAL_GPIO_WritePin(JOY_CS_GPIO_PORT, JOY_CS_PIN, 1)
#define JOY_CS_GPIO_PORT GPIOC
#define JOY_CS_PIN GPIO_PIN_13
int16_t Joy_ReadXY(uint8_t reg1){
uint8_t pTxData1[2] = {reg1, 0};
uint8_t pRxData1[2] = {0, 0};
JOY_CS_LOW();
HAL_SPI_TransmitReceive(&hspi4, pTxData1, pRxData1, 2, HAL_MAX_DELAY);
JOY_CS_HIGH();
return pRxData1[0] << 8 | pRxData1[1];
}
Here, in Main.c, you call the function before telling the compiler about what parameters and what return value types it has.
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4)
That confused the compiler and it starts "guessing" about them.
Guessing that it is a void-returning function, the compiler then complains that you are expecting a return value from a function which does return void i.e. nothing.
The returned void should be ignored, instead of attempting to write it to a variable. At least that is what the compiler thinks...
To fix it, you should explain to the compiler that there is a function elsewhere, with name, parameters and return value type. That is done by providing the prototype
int16_t Joy_ReadXY(uint8_t reg1);
It needs to be done before the function body in which the the extern function is first called. (And you already confirmed in comments that it fixes the described problem in your code.)
Note that for the other shown functions this is not needed, because they are defined (with head and body) before they are called.
Similar for other functions, which have their prototype provided in the header you include early on.
Actually, putting the prototype of your function into a header and including that similarily would be the best way to solve this.

C macro's argument limiting by argument prefix

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).
If you need to do it in preprocessor, you could use a tag with the variables and then concatenate it with a unique name that will expand to the result, something along:
#define MOTOR_BASE_ADDR 1
#define BITS_PER_MODULE 2
#define ARM_FRONT_REG (ARM, 1)
#define ARM_REAR_REG (ARM, 10)
#define MOTOR_MAIN_REG (MOTOR, 1)
#define MOTOR_AUX_REG (MOTOR, 3)
#define MOTOR_UNIQUE_STRING(x) x
#define MOTOR_ONLY(a, b) a##_UNIQUE_STRING(b)
#define MOTOR_REGISTER_ADDRESS(register_offset) \
( MOTOR_BASE_ADDR * (1 << BITS_PER_MODULE) + MOTOR_ONLY register_offset )
#define ARM_UNIQUE_STRING_FDASDFSAFDA(x) x
#define ARM_ONLY(a, b) a##_UNIQUE_STRING_FDASDFSAFDA(b)
#define ARM_REGISTER_ADDRESS(register_offset) \
( ARM_BASE_ADDR * (1 << BITS_PER_MODULE) + ARM_ONLY register_offset )
int main() {
MOTOR_REGISTER_ADDRESS(MOTOR_MAIN_REG); // all fine
MOTOR_REGISTER_ADDRESS(ARM_FRONT_REG); // error - sytnax error or ARM_UNIQUE_STRING undeclared
}
Picking a unique tag name and unique string will essentially work as a protecting against strange names. You could pick more unique name for the functions.
You could use actual proper types and use an actual function depending that one structure type can't be converted to another:
struct arm_register { long v; };
static const struct arm_register ARM_FRONT_REG = {1};
struct motor_register { long v; };
static const struct motor_register MOTOR_MAIN_REG = {1};
#define MOTOR_BASE_ADDR 1
#define BITS_PER_MODULE 2
static inline long MOTOR_REGISTER_ADDRESS(struct motor_register register_offset) {
return MOTOR_BASE_ADDR * (1 << BITS_PER_MODULE) + register_offset.v;
}
int main() {
MOTOR_REGISTER_ADDRESS(MOTOR_MAIN_REG); // all fine
MOTOR_REGISTER_ADDRESS(ARM_FRONT_REG); // error - incompatible type
}
# or with _Generic:
#define MOTOR_REGISTER_ADDRESS_2(x) \
_Generic((x), struct motor_register: MOTOR_BASE_ADDR * (1 << BITS_PER_MODULE) + x.v)
static const int a = MOTOR_REGISTER_ADDRESS_2(MOTOR_MAIN_REG); // all fine
static const int b = MOTOR_REGISTER_ADDRESS_2(ARM_FRONT_REG); // error - _Generic can't be chosen

Convert endianness of integer fields in struct using macros

Consider the following struct and functions
typedef struct __attribute__((__packed__)) req_file {
uint32_t start_pos;
uint32_t byte_count;
uint16_t name_len;
} req_file;
void req_file_hton(req_file *d){
d->name_len = htons(d->name_len);
d->start_pos = htonl(d->start_pos);
d->byte_count = htonl(d->byte_count);
}
void req_file_ntoh(req_file *d){
d->name_len = ntohs(d->name_len);
d->start_pos = ntohl(d->start_pos);
d->byte_count = ntohl(d->byte_count);
}
The above code is tedious to write for a lot of structs with many fields. I would like to configure the name and the fields of the struct once, and have the functions struct_name_hton and struct_name_ntoh generated for me. I have tried to play with x macros a little but had bad luck. A portable C preprocessor solution will be highly appreciated (not C++).
Well, that's easy.
#include <stdint.h>
#include <arpa/inet.h>
/* the NETSTRUCT library ------------------------------- */
// for uint32_t
#define NETSTRUCT_dec_uint32_t(n) uint32_t n;
#define NETSTRUCT_hton_uint32_t(n) t->n = htonl(t->n);
#define NETSTRUCT_ntoh_uint32_t(n) t->n = ntohl(t->n);
// for uint16_t
#define NETSTRUCT_dec_uint16_t(n) uint16_t n;
#define NETSTRUCT_hton_uint16_t(n) t->n = htons(t->n);
#define NETSTRUCT_ntoh_uint16_t(n) t->n = ntohs(t->n);
// dec hton ntoh switch
#define NETSTRUCT_dec(type, name) NETSTRUCT_dec_##type(name)
#define NETSTRUCT_hton(type, name) NETSTRUCT_hton_##type(name)
#define NETSTRUCT_ntoh(type, name) NETSTRUCT_ntoh_##type(name)
// calls NETSTRUCT_mod
#define NETSTRUCT1(mod, a) NETSTRUCT_##mod a
#define NETSTRUCT2(mod, a, ...) NETSTRUCT1(mod, a) NETSTRUCT1(mod, __VA_ARGS__)
#define NETSTRUCT3(mod, a, ...) NETSTRUCT1(mod, a) NETSTRUCT2(mod, __VA_ARGS__)
#define NETSTRUCT4(mod, a, ...) NETSTRUCT1(mod, a) NETSTRUCT3(mod, __VA_ARGS__)
// TO DO: all up to NETSTRUCT64
// variadic macro overload
#define NETSTRUCT_GET(_1,_2,_3,_4,NAME,...) NAME
// Overlads VA_ARGS with specified mod
#define NETSTRUCT_IN(mod, ...) \
NETSTRUCT_GET(__VA_ARGS__, NETSTRUCT4, NETSTRUCT3, NETSTRUCT2, NETSTRUCT1) \
(mod, __VA_ARGS__)
// entrypoint of out library
#define NETSTRUCT(name, ...) \
\
struct name { \
NETSTRUCT_IN(dec, __VA_ARGS__) \
} __attribute__((__packed__)); \
\
void name##_hton(struct name *t) { \
NETSTRUCT_IN(hton, __VA_ARGS__) \
} \
\
void name##_ntoh(struct name *t) { \
NETSTRUCT_IN(ntoh, __VA_ARGS__) \
}
/* -------------------------------------------------------- */
// adding custom type
#define NETSTRUCT_dec_uint8_t_arr_8(n) uint8_t n[8];
#define NETSTRUCT_hton_uint8_t_arr_8(n) do{}while(0);
#define NETSTRUCT_ntoh_uint8_t_arr_8(n) do{}while(0);
NETSTRUCT(reg_file,
(uint32_t, start_pos),
(uint32_t, byte_count),
(uint16_t, name_len),
(uint8_t_arr_8, example_custom_array)
);
int main() {
struct reg_file t;
reg_file_hton(&t);
reg_file_ntoh(&t);
}
I have written the mactos so it's easy to add another function, most probably void name##serialize(char *in) and void name##deserialize(const char *out). The design can be slightly refactored so that type callbacks NETSTRUCT_dec_* take two or even unknown number of arguments with ex. NETSTRUCT(name, (type_callback_suffix, (arguments, arguments2))).
#edit added custom array type example and some lines order changing.
IMHO, you should use a raw buffer for input / output. This is by far more portable (and safer) than guessing the way a compiler will order the fields or the structure on each system.
In addition, this would allow you to pack/unpack data without worrying about byte order or memory alignment.
The macros in this example code were extracted from the facil.io framework header:
/** Reads an unaligned network ordered byte stream to a 16 bit number. */
#define fio_str2u16(c) \
((uint16_t)(((uint16_t)(((uint8_t *)(c))[0]) << 8) | \
(uint16_t)(((uint8_t *)(c))[1])))
/** Reads an unaligned network ordered byte stream to a 32 bit number. */
#define fio_str2u32(c) \
((uint32_t)(((uint32_t)(((uint8_t *)(c))[0]) << 24) | \
((uint32_t)(((uint8_t *)(c))[1]) << 16) | \
((uint32_t)(((uint8_t *)(c))[2]) << 8) | \
(uint32_t)(((uint8_t *)(c))[3])))
/** Writes a local 16 bit number to an unaligned buffer in network order. */
#define fio_u2str16(buffer, i) \
do { \
((uint8_t *)(buffer))[0] = ((uint16_t)(i) >> 8) & 0xFF; \
((uint8_t *)(buffer))[1] = ((uint16_t)(i)) & 0xFF; \
} while (0);
/** Writes a local 32 bit number to an unaligned buffer in network order. */
#define fio_u2str32(buffer, i) \
do { \
((uint8_t *)(buffer))[0] = ((uint32_t)(i) >> 24) & 0xFF; \
((uint8_t *)(buffer))[1] = ((uint32_t)(i) >> 16) & 0xFF; \
((uint8_t *)(buffer))[2] = ((uint32_t)(i) >> 8) & 0xFF; \
((uint8_t *)(buffer))[3] = ((uint32_t)(i)) & 0xFF; \
} while (0);
void req_file_read(req_file *d, unsigned char * buffer){
d->byte_count = fio_str2u32(buffer);
d->start_pos = fio_str2u32(buffer + 4);
d->name_len = fio_str2u16(buffer + 8);
}
void req_file_write(unsigned char * buffer, req_file *d){
fio_u2str32(buffer, d->byte_count);
fio_u2str32(buffer + 4, d->start_pos);
fio_u2str16(buffer + 8, d->name_len);
}
This makes it far easier to handle unaligned memory access as well as network byte ordering on any system. The binary based math makes this both portable and space efficient.
EDIT (X-macros)
As per the comments and concerns raised by Lightness Races in Orbit, here's a header file with X-macros that could be used to automatically create X_read / X_write inline functions.
The downside of serialization is that the byte offset for the raw buffer should be provided when declaring the struct using the macros.
In this example, the same header is included a number of times with different results. Also, the read/write functions don't have to be inlined, it's just an example.
Here's the header:
/* note there's NO include guard in the header file */
#ifndef H__FACIL_IO_MACROS
#define H__FACIL_IO_MACROS
/** Reads an unaligned network ordered byte stream to a 16 bit number. */
#define fio_str2u16(c) \
((uint16_t)(((uint16_t)(((uint8_t *)(c))[0]) << 8) | \
(uint16_t)(((uint8_t *)(c))[1])))
/** Reads an unaligned network ordered byte stream to a 32 bit number. */
#define fio_str2u32(c) \
((uint32_t)(((uint32_t)(((uint8_t *)(c))[0]) << 24) | \
((uint32_t)(((uint8_t *)(c))[1]) << 16) | \
((uint32_t)(((uint8_t *)(c))[2]) << 8) | \
(uint32_t)(((uint8_t *)(c))[3])))
/** Writes a local 16 bit number to an unaligned buffer in network order. */
#define fio_u2str16(buffer, i) \
do { \
((uint8_t *)(buffer))[0] = ((uint16_t)(i) >> 8) & 0xFF; \
((uint8_t *)(buffer))[1] = ((uint16_t)(i)) & 0xFF; \
} while (0);
/** Writes a local 32 bit number to an unaligned buffer in network order. */
#define fio_u2str32(buffer, i) \
do { \
((uint8_t *)(buffer))[0] = ((uint32_t)(i) >> 24) & 0xFF; \
((uint8_t *)(buffer))[1] = ((uint32_t)(i) >> 16) & 0xFF; \
((uint8_t *)(buffer))[2] = ((uint32_t)(i) >> 8) & 0xFF; \
((uint8_t *)(buffer))[3] = ((uint32_t)(i)) & 0xFF; \
} while (0);
/* convert SERIAL_STRUCT_NAME to actual name */
#define SERIAL_STRUCT_MAKE(struct_name) SERIAL_STRUCT_MAKE2(struct_name)
#endif
#if SERIALIZE_TYPE /* create the type */
#undef SERIALIZE_TYPE
#undef SERIAL_STRUCT_FIELD
#define SERIAL_STRUCT_FIELD(name, bits, pos) uint##bits##_t name
#undef SERIAL_STRUCT_MAKE2
#define SERIAL_STRUCT_MAKE2(struct_name) \
typedef struct { \
SERIAL_STRUCT_FIELDS; \
} struct_name##_s;
/* perform macros */
SERIAL_STRUCT_MAKE(SERIAL_STRUCT_NAME)
#elif SERIALIZE_READ /* create reader function */
#undef SERIALIZE_READ
#undef SERIAL_STRUCT_FIELD
#define SERIAL_STRUCT_FIELD(name, bits, pos) \
dest->name = fio_str2u##bits((src + (pos)))
#undef SERIAL_STRUCT_MAKE2
#define SERIAL_STRUCT_MAKE2(struct_name) \
inline static void struct_name_read(struct_name##_s *dest, \
unsigned char *src) { \
SERIAL_STRUCT_FIELDS; \
}
/* perform macros */
SERIAL_STRUCT_MAKE(SERIAL_STRUCT_NAME)
#elif SERIALIZE_WRITE /* create writer function */
#undef SERIALIZE_WRITE
#undef SERIAL_STRUCT_FIELD
#define SERIAL_STRUCT_FIELD(name, bits, pos) \
fio_u2str##bits((dest + (pos)), src->name)
#undef SERIAL_STRUCT_MAKE2
#define SERIAL_STRUCT_MAKE2(struct_name) \
inline static void struct_name##_write(unsigned char *dest, \
struct_name##_s *src) { \
SERIAL_STRUCT_FIELDS; \
}
/* perform macros */
SERIAL_STRUCT_MAKE(SERIAL_STRUCT_NAME)
#endif
In the implementation file, the information might look like this (again, the inline approach could be altered):
/* will produce req_file_s as the struct name, but you can change that */
#define SERIAL_STRUCT_NAME req_file
#define SERIAL_STRUCT_FIELDS \
SERIAL_STRUCT_FIELD(start_pos, 32, 0); \
SERIAL_STRUCT_FIELD(byte_count, 32, 4); \
SERIAL_STRUCT_FIELD(name_len, 16, 8)
#define SERIALIZE_TYPE 1
#include "serialize.h"
#define SERIALIZE_READ 1
#include "serialize.h"
#define SERIALIZE_WRITE 1
#include "serialize.h"
This could be adjusted so SERIALIZE_TYPE also declares the functions (without defining them), and the functions aren't inlined (so only the implementation file includes the header 3 times per type.
You could adapt Antony Polukhin's magic_get library, to be able to convert any (arbitrary) structure into a different byte order - just like it can now print any arbitrary structure to an ostream.
xmacros work. The trick is to use token pasting and aliasing of the functions depending on the type:
#define htonuint32_t htonl
#define htonuint16_t htons
#define ntohuint32_t ntohl
#define ntohuint16_t ntohl
#define DEF_FIELDS \
DEF_FIELD(uint32_t,start_pos); \
DEF_FIELD(uint32_t,byte_count); \
DEF_FIELD(uint16_t,name_len)
#define DEF_FIELD(t,v) t v
typedef struct __attribute__((__packed__)) req_file {
DEF_FIELDS;
} req_file;
#undef DEF_FIELD
#define DEF_FIELD(t,v) d->v = hton##t(d->v)
void req_file_hton(req_file *d) {
DEF_FIELDS;
}
#undef DEF_FIELD
#define DEF_FIELD(t,v) d->v = ntoh##t(d->v)
void req_file_hton(req_file *d) {
DEF_FIELDS;
}
pre-processed code (reformatted for clearer display):
typedef struct __attribute__((__packed__)) req_file {
uint32_t start_pos;
uint32_t byte_count;
uint16_t name_len;
} req_file;
void req_file_hton(req_file *d) {
d->start_pos = htonl(d->start_pos);
d->byte_count = htonl(d->byte_count);
d->name_len = htons(d->name_len);
}
void req_file_hton(req_file *d) {
d->start_pos = ntohl(d->start_pos);
d->byte_count = ntohl(d->byte_count);
d->name_len = ntohl(d->name_len);
}
If you have more than one structure, you can complexify the macro system to be able to generate all the structs & functions. Example with 2 different structures:
#define htonuint32_t htonl
#define htonuint16_t htons
#define ntohuint32_t ntohl
#define ntohuint16_t ntohl
#define DEF_FIELDS_req_file \
DEF_FIELD(uint32_t,start_pos); \
DEF_FIELD(uint32_t,byte_count); \
DEF_FIELD(uint16_t,name_len)
#define DEF_FIELDS_other_file \
DEF_FIELD(uint32_t,foo_pos); \
DEF_FIELD(uint32_t,char_count); \
DEF_FIELD(uint16_t,bar_len)
#define STRUCT_DEF(s) \
START_DECL(s) \
DEF_FIELDS_##s; \
END_DECL(s)
#define START_DECL(s) typedef struct __attribute__((__packed__)) s {
#define END_DECL(s) } s
#define DEF_FIELD(t,v) t v
STRUCT_DEF(req_file);
STRUCT_DEF(other_file);
#undef DEF_FIELD
#undef START_DECL
#undef END_DECL
#define DEF_FIELD(t,v) d->v = hton##t(d->v)
#define START_DECL(s) void s##_hton(s *d) {
#define END_DECL(s) }
STRUCT_DEF(req_file);
STRUCT_DEF(other_file);
#undef DEF_FIELD
#undef START_DECL
#define DEF_FIELD(t,v) d->v = ntoh##t(d->v)
#define START_DECL(s) void s##_ntoh(s *d) {
STRUCT_DEF(req_file);
STRUCT_DEF(other_file);
result:
typedef struct __attribute__((__packed__)) req_file { uint32_t start_pos; uint32_t byte_count; uint16_t name_len; } req_file;
typedef struct __attribute__((__packed__)) other_file { uint32_t foo_pos; uint32_t char_count; uint16_t bar_len; } other_file;
void req_file_hton(req_file *d) { d->start_pos = htonl(d->start_pos); d->byte_count = htonl(d->byte_count); d->name_len = htons(d->name_len); };
void other_file_hton(other_file *d) { d->foo_pos = htonl(d->foo_pos); d->char_count = htonl(d->char_count); d->bar_len = htons(d->bar_len); };
void req_file_ntoh(req_file *d) { d->start_pos = ntohl(d->start_pos); d->byte_count = ntohl(d->byte_count); d->name_len = ntohl(d->name_len); };
void other_file_ntoh(other_file *d) { d->foo_pos = ntohl(d->foo_pos); d->char_count = ntohl(d->char_count); d->bar_len = ntohl(d->bar_len); };

Using Switch With MACROS

I am trying to simulate Switch statement using macros in my Header file (.h) .
I have some predefined macros:
#define MULTIPLY_BY_1 1
#define MULTIPLY_BY_10 2
#define MULTIPLY_BY_100 3
#define MULTIPLY_BY_1000 4
#define CHOSEN_FACTOR MULTIPLY_BY_100
I have a const result that takes a value according to CHOSEN_FACTOR (The user will define this macro). I am in the header file and I want to "simulate" the switch statement like this:
switch(CHOSEN_VALUE)
{
case MULTIPLY_BY_1:
const uint16_t result = 5;
break;
case MULTIPLY_BY_10:
const uint16_t result = 50;
break;
case MULTIPLY_BY_100:
const uint16_t result = 500;
break;
case MULTIPLY_BY_1000:
const uint16_t result = 50000;
break;
default:
break;
}
EDIT:
In the source file (.c), I want to use result like this:
uint16_t foo(void)
{
uint16_t myFoo = getMyFooValue();
return result * myFoo;
}
Is there any macros-based-solution to so ? Is there a more optimised approach to get the same result ?
Like in this answer suggests, i would suggest you to use enum for getting the selected value and based on the selection with the enum type, return the macro that you have specified. To do that, you can create a function and get the correct macro as shown below.
typedef enum {
MULTIPLY_BY_1
MULTIPLY_BY_10
MULTIPLY_BY_100
MULTIPLY_BY_1000
}multiplier_t;
uint16_t foo(multiplier_t multiplier)
{
switch (multiplier) {
case MULTIPLY_BY_1:
return 1;
case MULTIPLY_BY_10:
return 2;
case MULTIPLY_BY_100:
return 3;
case MULTIPLY_BY_1000:
return 4;
}
return 0; // just in case no code matches
}
Hope this helps you.
Assuming I understand what you're asking for, I think you're looking for something like this:
#define INIT_FACTOR(var, value) \
#ifdef CHOSEN_FACTOR \
#if CHOSEN_FACTOR == MULTIPLY_BY_1 \
const uint16_t var = value \
#elif CHOSEN_FACTOR == MULTIPLY_BY_10 \
const uint16_t var = value * 10 \
#elif CHOSEN_FACTOR == MULTIPLY_BY_100 \
const uint16_t var = value * 100 \
#elif CHOSEN_FACTOR == MULTIPLY_BY_1000 \
const uint16_t var = value * 1000 \
#endif \
#else \
const uint16_t var = value \
#endif
This will define a macro named INIT_FACTOR that takes two arguments, the name of the variable to define and the starting value. You'd add it in the body of your code as
INIT_FACTOR(result, 5);
and then, if CHOSEN_FACTOR is MULTIPLY_BY_100, that line would expand to
const uint16_t result = 5 * 100;
If CHOSEN_FACTOR is not defined, that line expands to
const uint16_t result = 5;
Remember that macro substitution happens at compile time, not run time. If you want a run time solution, this isn't it.
Selection in the preprocessor can be done by using a helper macro to expand a parameter and then pasting it with a token to kludge a look-up table:
#include <stdio.h>
int main(void)
{
#define MULTIPLY_BY_1 1
#define MULTIPLY_BY_10 2
#define MULTIPLY_BY_100 3
#define MULTIPLY_BY_1000 4
#define CHOSEN_FACTOR MULTIPLY_BY_100
#define Foo1 1
#define Foo2 10
#define Foo3 100
#define Foo4 1000
#define FooHelper(x) Foo##x
#define Foo(x) FooHelper(x)
printf("%d\n", Foo(CHOSEN_FACTOR));
}
Preprocessor abuse of this sort should be generally avoided and likely is not needed for the actual problem that motivated this question.
Thank you all for your answers. I was looking for a specific solution and I guess I found it.
#define MULTIPLY_BY_1 0
#define MULTIPLY_BY_10 1
#define MULTIPLY_BY_100 2
#define MULTIPLY_BY_1000 3
const struct
{
uint8_t index;
uint16_t value;
}myArray[] = {
{MULTIPLY_BY_1, 1},
{MULTIPLY_BY_10, 10},
{MULTIPLY_BY_100, 100},
{MULTIPLY_BY_1000, 1000}
};
#define CHOSEN_VALUE MULTIPLY_BY_10
const uint16_t result = myArray[CHOSEN_VALUE].value;
void foo(void)
{
printf("%d", result); // 10
}

'BMSerial' does not name a type

This is what I see every time I compile the software:
Every time I try to compile this code with the Arduino IDE, it generates this error.
This code is for the RTK1 tracked robot. and I'm trying to control it by PS3 controller.
I'm pretty new tote whole Arduino board and compiler, as well as C++. so any help would be much appreciated.
#include <BMSerial.h>
#include <BMPS2.h>
#define DEBUG
//#define LIPO
#define SWAPMOTORS
#define LTRIG 8
#define RTRIG 8
#define RATE 40
#define IN1 4
#define IN2 2
#define IN3 9
#define IN4 7
#define EN1 6
#define EN2 5
#define LEDA 8
#define LEDB 10
#define BUTTONA 18
#define BUTTONB 19
#define BATT 15
#define ISENA 16
#define ISENB 17
#define DEADZONE 20
int currentlpwm;
int currentrpwm;
int targetlpwm;
int targetrpwm;
long currentafilter;
long currentbfilter;
#define filter_update(filter,input,rate) (filter = filter - (filter >> rate) + input) >> rate;
BMSerial sensor(13,13);
BMPS2 ps2x(11,100);
long lastalarm;
long lastalarmcheck;
int lipolow;
int lipoverylow;
int lipocritical;
boolean autonomous;
void setup() {
#ifdef DEBUG
Serial.begin(625000);
#endif
digitalWrite(LEDB,HIGH);
lipolow = false;
lipoverylow = false;
lipocritical = false;
lastalarm = millis();
lastalarmcheck = millis();
autonomous = false;
sensor.begin(38400);
// put your setup code here, to run once:
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
pinMode(IN3,OUTPUT);
pinMode(IN4,OUTPUT);
pinMode(EN1,OUTPUT);
pinMode(EN2,OUTPUT);
pinMode(LEDA,OUTPUT);
pinMode(LEDB,OUTPUT);
pinMode(BUTTONA,INPUT);
pinMode(BUTTONB,INPUT);
digitalWrite(IN1,LOW);
digitalWrite(IN2,LOW);
digitalWrite(IN3,LOW);
digitalWrite(IN4,LOW);
tone(3,750,100);
delay(100);
tone(3,1000,100);
delay(100);
tone(3,1250,100);
delay(100);
}
boolean CheckLipo()
{
long time = millis() - lastalarm;
if(lipocritical>=10){
//Lipo protection
tone(3,500,250);
delay(250);
tone(3,800,250);
delay(250);
return true;
}
else if(lipoverylow>=10){
//Lipo protection
if(time>1000){
lastalarm=millis();
tone(3,500,100);
delay(100);
}
}
else if(lipolow>=10){
//Lipo protection
if(time>3000){
lastalarm=millis();
tone(3,500,100);
delay(100);
}
}
if((millis()-lastalarmcheck)>100){
lastalarmcheck=millis();
int voltage = (long)analogRead(BATT)*1500/1024;
if(voltage<700){
lipolow++;
if(lipolow>10)
lipolow=10;
}
else
lipolow=0;
if(voltage<650){
lipoverylow++;
if(lipoverylow>10)
lipoverylow=10;
}
else
lipoverylow=0;
if(voltage<620) //Orion will auto cutoff servo use at this level but there is still approx 100ma draw from all electronics
lipocritical++; //once triggered always triggered
else
lipocritical=0;
}
return false;
}
void loop() {
#ifdef LIPO
if(CheckLipo()){
digitalWrite(IN1,LOW);
digitalWrite(IN2,LOW);
digitalWrite(IN3,LOW);
digitalWrite(IN4,LOW);
return; //Battery too low to do anything.
}
#endif
if(ps2x.isUpdated()){
if(ps2x.buttonPressed(PSB_RED)){
if(autonomous)
autonomous=false;
else
autonomous=true;
}
int RY,LY;
if(autonomous){
sensor.listen();
sensor.println("#AB");
unsigned char rstate = sensor.readhex(10000);
unsigned char lstate = sensor.readhex(10000);
}
else{
delay(20);
RY = ps2x.analog(PSS_RY);
LY = ps2x.analog(PSS_LY);
if(RY>-DEADZONE && RY<DEADZONE)
RY=0;
if(RY<-127)
RY=-127;
if(LY>-DEADZONE && LY<DEADZONE)
LY=0;
if(LY<-127)
LY=-127;
}
setlpwm(LY);
setrpwm(RY);
}
}
void setrpwm(int pwm)
{
targetrpwm = pwm;
if(currentrpwm<targetrpwm){
currentrpwm+=RATE;
if(currentrpwm>targetrpwm)
currentrpwm=targetrpwm;
}
if(currentrpwm>targetrpwm){
currentrpwm-=RATE;
if(currentrpwm<targetrpwm)
currentrpwm=targetrpwm;
}
#ifdef SWAPMOTORS
SetPWM2(currentrpwm);
#else
SetPWM1(currentrpwm);
#endif
}
void setlpwm(int pwm)
{
targetlpwm = pwm;
if(currentlpwm<targetlpwm){
currentlpwm+=RATE;
if(currentlpwm>targetlpwm)
currentlpwm=targetlpwm;
}
if(currentlpwm>targetlpwm){
currentlpwm-=RATE;
if(currentlpwm<targetlpwm)
currentlpwm=targetlpwm;
}
#ifdef SWAPMOTORS
SetPWM1(currentlpwm);
#else
SetPWM2(currentlpwm);
#endif
}
void SetPWM1(int pwm)
{
if(pwm>0){
digitalWrite(IN1,HIGH);
digitalWrite(IN2,LOW);
}
if(pwm<0){
digitalWrite(IN1,LOW);
digitalWrite(IN2,HIGH);
}
if(pwm==0){
digitalWrite(IN1,LOW);
digitalWrite(IN2,LOW);
}
analogWrite(EN1,abs(pwm*2));
}
void SetPWM2(int pwm)
{
if(pwm>0){
digitalWrite(IN3,HIGH);
digitalWrite(IN4,LOW);
}
if(pwm<0){
digitalWrite(IN3,LOW);
digitalWrite(IN4,HIGH);
}
if(pwm==0){
digitalWrite(IN3,LOW);
digitalWrite(IN4,LOW);
}
analogWrite(EN2,abs(pwm*2));
}
Simple things first: Unless it has changed recently (or is different on Windows than on OSX), you need to have your libraries in Arduino -> Libraries folder (or within your sketch folder but that is generally not a good practice with 3rd party libs).
I can't tell for sure from your screenshot but it doesn't look like you have them there. If that is the case, not sure why the #include statement doesn't throw and error.

Resources