How to separate #defined arguments in C - c

I'm working on an embedded project and I have all the ports and pins defined like this:
#define SENSOR_1 gpioPortA,15
Is there a way to extract just the integer without creating a new #define?
So far I used a typedef and assigned the pin value from the #define like so:
typedef struct
{
GPIO_Port_TypeDef port;
uint8_t pin;
}sensor_t;
sensor_t sensor1 = {SENSOR_1};
/* Now sensor1.pin is the pin value */
but I want to pass the pin to a switch case and I can only use constant values for that and I'd rather avoid using an if statement.
Is there a way to pass the pin to a switch case without a new #define?

Short answer is no.
You could however use sensor1.pin when needed but not in case of switch statement as switch does not support variables there. In this case use if-else statement.
Or do it like this:
#define SENSOR_1_PIN 10
#define SENSOR_1 my_port,SENSOR_1_PIN
and then in switch you use SENSOR_1_PIN in case part.
switch (condition) {
case SENSOR_1_PIN:
//Do stuff
break;
//....
}
Just to remind again as it was posted in first comment on your question. Doing that is very dangerous.
Most proper way would be to do it like this:
#define SENSOR_1_PORT GPIOB
#define SENSOR_1_PIN 15
//If structure order changes here, you may lead to wrong data interpretation
sensor_t sensor1 = {SENSOR_1_PORT, SENSOR_1_PIN};
If you are C99 compliant, you may do it even more safer like this:
//If structure order changes here, your data are still properly assigned to fields
sensor_t sensor1 = {.port = SENSOR_1_PORT, .pin = SENSOR_1_PIN};

You can define a macro to extract the value from your definition.
#define GET_SECOND(x, y) y
#define PIN_VALUE(x) GET_SECOND(x)
switch (pin) {
case PIN_VALUE(SENSOR_1):
/* ... */
break;
}
PIN_VALUE must allow SENSOR_1 to be expanded via helper macro so that the second part can be extracted.

The proper solution at this point is to re-design the definitions into something that makes more sense, or alternatively create new constants.
As a last resort, if you are stuck with these macros, you can parse them in the following way:
#include <stdio.h>
#include <stdint.h>
typedef int GPIO_Port_TypeDef; // whatever type this happens to be
typedef struct
{
GPIO_Port_TypeDef port;
uint8_t pin;
}sensor_t;
#define GET_FIELD(field,...) (sensor_t){__VA_ARGS__}.field
#define SENSOR_1 gpioPortA,15
int main (void)
{
int gpioPortA = 1;
printf("%d %d", GET_FIELD(port, SENSOR_1), GET_FIELD(pin, SENSOR_1));
}
The type-generic version would be:
#define GET_FIELD(type, field, ...) (type){__VA_ARGS__}.field
...
printf("%d %d", GET_FIELD(sensor_t, port, SENSOR_1), GET_FIELD(sensor_t, pin, SENSOR_1));
This scales variably no matter how many fields there are. This is however not recommended practice. Macros in general, and variadic macros in particular, should be avoided.
As for how to use run-time variables in case - you can't. Use an if-else if statement instead.

What about inserting a define inside a define ? Instead of directly adding 15, you could make a define holding 15 and insert it elsewhere.
E.g:
#define SENSORVAL 15
#define SENSOR_1 gpioPortA,SENSORVAL
typedef struct
{
GPIO_Port_TypeDef port;
uint8_t pin;
}sensor_t;
sensor_t sensor1 = {SENSOR_1};
/* Now sensor1.pin is the pin value */

Related

Creating iterable list of register in embedded C

I have been programming with python java and c++, which all have list objects predefined. I'm now working on a microcontroller in C embedded, but objects such as lists and functions such as printf simply don't exist.
What I am trying to do is the following. I have multiple registers which I attach to defines. I want to put all my defines in a list I can access.
#include <stdlib.h>
#include <stdio.h>
#include <xc.h>
#define KP_ROW1 LATBbits.LATB0
#define KP_ROW2 LATBbits.LATB1
#define KP_ROW3 LATBbits.LATB2
#define KP_ROW4 LATBbits.LATB3
#define KP_COL1 LATBbits.LATB4
#define KP_COL2 LATBbits.LATB5
#define KP_COL3 LATBbits.LATB6
#define KP_COL4 LATBbits.LATB7
KP_ROW = [KP_ROW1, KP_ROW2, KP_ROW3, KP_ROW4]; //error on this line
KP_COL = [KP_COL1, KP_COL2, KP_COL3, KP_COL4]; //error
for(int i=0;i<4;i++)
{
if (KP_COL[i] == 1){return 1;}
}
Since I have no previous experience in C embedded, I assumed that google could help me, but it seems that all the solutions I find need the good understanding of struct and the fabrication of really complex functions.
The reasons for this is that I will have maybe 100 pins and I don,t want to make "if" statements for each, I want to iterate throughout a list. I'm using a PIC18F with the XC8 compiler.
I'm asking for advice. How would you do it? Is there a faster, simpler way than making your own list class?
It's quite hard to understand what is desired here. I understand that you wish to read the values of 100 register in your program. You have to know their addresses. Then, you can create a series of macros:
#define REG1 0xabcd
#define REG2 0x1234
...
or whichever addresses. Then, create more macros to access the values directly:
#define REG1_VAL (*(volatile uint8_t *) REG1)
#define REG2_VAL (*(volatile uint8_t *) REG2)
...
Then you can write assignments such as REG1_VAL = 1 or tests such as REG1_VAL == 1. Otherwise, you can create macros that access their values through their addresses:
#define READ(reg) (*(volatile uint8_t *) reg)
Usage of the above to obtain a register value is then:
READ(REG1);
You could then allocate an array of 100 elements:
volatile uint8_t regs[100] = {REG1, REG2, ..., REG100};
and iterate through that array:
for (i = 0; i < 100; i ++) {
if (READ(regs[i]) == 1) {
...
}
}
Hope this helps you!
Note: These macros would need fine tuning to avoid subtle errors, but I hope they are still useful to illustrate what I mean.
I found the answer!
It was not working because I was trying to get the adress of the bit instead of the register.... my bad. It should rather be:
#define KP_ROW LATB
And then add some bitmasks to write the pins I want.
Sorry for this beginner's error!

C macros: Conditional code based on parameter value?

Is there a cleaner/simpler way to do this?
The below works OK, but I think it's ugly - I'd like a solution that doesn't need a separate #define for every possible invalid value passed as "port".
#define _port_A_config_digital(mask) // do nothing; this port is always digital
#define _port_B_config_digital(mask) AD1PCFGSET = (mask)
#define _port_C_config_digital(mask)
#define _port_D_config_digital(mask)
#define _port_E_config_digital(mask)
#define _port_F_config_digital(mask)
#define _port_G_config_digital(mask)
#define _port_H_config_digital(mask)
#define _port_I_config_digital(mask)
#define _port_J_config_digital(mask)
#define _port_K_config_digital(mask)
#define ConfigDigitalBits(port, mask) _port_##port##_config_digital(mask)
If "port" is anything other than B, I want a null statement.
I'd like to get rid of all the #defines other than the one that does something.
I want to do this because on this MCU all ports other than B are always digital and there's nothing to be done.
But calling ConfigDigitalBits() ought to be a valid thing to do for any port.
You could do something like
#define CONFIG_DIGITAL_BITS(PORT, MASK) \
do { if (PORT == 'B') AD1PCFGSET = (MASK); } while (0)
and trust (or check by reading the assembly) your compiler to evaluate the if condition at compile-time. That is,
CONFIG_DIGITAL_BITS('B', 0x42);
would generate code for only
AD1PCFGSET = 0x42;
and
CONFIG_DIGITAL_BITS('A', 0x42);
would generate no code at all.
The proposed code above has the problem that it ignores errors. For example,
CONFIG_DIGITAL_BITS('Z', 0x42);
would happily compile although there is no port Z. You could assert on this but this will only catch the error at run-time.
Once you got to this, consider getting rid of the macro at whole and use an inline function instead that will also permit constant propagation.
inline void
config_digital_bits(const char port, const unsigned mask)
{
assert(port >= 'A' && port <= 'K');
if (port == 'B')
AD1PCFGSET = mask;
}

Array in #define

I am trying to achieve something like this:
#define MACRO(x) {PORTB=0,PORTC=0,PORTD=0}
MACRO(0); //This would get replaced by PORTB=0;
MACRO(1); //PORTC=0;
MACRO(2); //PORTD=0;
I want to create a "macro array". I would pass in an index to it and it would return the right code.
Is this possible?
EDIT:
If it helps, PORTB, PORTC and PORTD are all #defines.
It can be done using the preprocessor, but it is arguably ugly.
#define MACRO_CASE0 PORTB = 0
#define MACRO_CASE1 PORTC = 0
#define MACRO_CASE2 PORTD = 0
#define MACRO(X) MACRO_CASE##X
Also have a look at the Boost.Preprocessor library. (It works for both C and C++.)
Update: After the discussion with Jonathan Leffler (see below) I feel an obligation to update the answer with an exhortation for new C programmers not to abuse the (powerful but dirty) technique shown above.
If you – as the OP requested – want to pass in an index to it and it would return the right code, then you'll need to resort to preprocessor programming. However, if all you want to do is execute different code based on some condition and want this to have no run-time overhead if the condition is a compile-time constant, then the following approach is not only much cleaner but also more flexible as it allows passing run-time values too.
/* '#include' this definition in any file where you want to use it. */
static inline void
do_the_right_thing(const int selector)
{
switch (selector)
{
case 0:
PORTB = 0;
break;
case 1:
PORTC = 0;
break;
case 2:
PORTD = 0;
break;
default:
assert(!"cannot do the right thing: invalid selector");
}
}
Now, in your code, if you write
do_the_right_thing(1); /* selector is a compile-time constant */
a decent compiler with appropriate optimizations enabled will generate no overhead compared to using a macro. However, you can also write
do_the_right_thing(rand() % 3); /* selector is a run-time expression */
and the compiler will insert some fast switching code to select the appropriate operation at run-time.
This would do the task, but it doesn't extend or generalize very gracefully:
#define MACRO(x) (((x) == 0) ? PORTB=0 : ((x) == 1) ? PORTC=0 : PORTD=0)

compile-time struct size check, error out if odd

Is there any possible way to make the compiler bail out if the sizeof (struct Astruct) is uneven?
Background information:
We have a 16-bit microprocessor which will give processor alignment errors if a 16-bit value is mis-aligned. That might happen in the following scenario:
typedef struct
{
U8BIT u8BitValue1;
U8BIT u8BitValue2;
U8BIT u8BitValue3;
} unevenAmountOf8BitValues;
typedef struct
{
U16BIT u16BitValue1;
U16BIT u16BitValue2;
} my16BitValues;
#define U8BIT_COUNT 3
#define U16BIT_COUNT 2
typedef struct
{
unevenAmountOf8BitValues u8BitValues;
my16BitValues u16BitValues;
} valuesCombined;
typedef union
{
valuesCombined myValues;
U8BIT buffer[sizeof(valuesCombined)];
struct
{
U8BIT bufferU8[U8BIT_COUNT];
U16BIT bufferU16[U16BIT_COUNT]; /* <<-- missalignment */
} valuesPerType;
} myValuesInRamAndRom
What we do now is counting the amount of U8BIT/U16BIT/U32BIT values (well, keeping track of the amount using excel) manually and putting that in the U(8/16/32)BIT_COUNT define and then the following:
#if U8BIT_COUNT % 2 == 1
#error The number of U8BIT parameters need to be even, add a dummy
#endif
Keeping track of the amount of U8-/U16-/U32BIT values is pretty error prone and we've had quite some moments that we were thinking "hey, it ain't working", an hour or what later, oh! Darn, forgot to adjust the amount of values define.
A preferred method would be to use the sizeof operator, however that can't be used in the error checking, which I would really like to keep.
So is there anyway to use the sizeof operator and to keep some form of error checking that the amount of U8BIT values must be even?
Combined solution by Lundin and Aaron McDaid:
#define COMPILE_TIME_ASSERT(expr) {typedef U8BIT COMP_TIME_ASSERT[((!!(expr))*2-1)];}
With a C11 compiler, use:
static_assert (sizeof(the struct) % 2 == 0,
"Misaligned");
With older compilers, you can use dirty tricks like
#define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0];
...
COMPILE_TIME_ASSERT(sizeof(the_struct) % 2 == 0);
The real solution to your specific problem might however be to ensure that struct padding is enabled. You shouldn't get any misalignments then.
It's possible, using a trick that's also being used in the Linux kernel:
#define BUILD_BUG_OR_ZERO(e) (sizeof(struct{ int:-!!(e);}))
#define ENSURE_EVEN_SIZE(e) BUILD_BUG_OR_ZERO(sizeof(e) % 2 == 1)
struct uneven{
char a,b,c;
};
struct even{
char a,b,c,d;
};
int main(){
ENSURE_EVEN_SIZE(struct even);
/* compiler error: */
ENSURE_EVEN_SIZE(struct uneven);
}
If sizeof(e) % 2 == 1 is true, the bitfield int:-!!(e) would have a negative size, which is forbidden. (Ideone)
Here is the version which allows using same assertion macro multiple times in the same
file.
/*
General purpose static assert.
Works in/out -side of scope:
STATIC_ASSERT(sizeof(long)==8);
int main()
{
STATIC_ASSERT(sizeof(int)==4);
}
*/
#define STATIC_ASSERT(X) STATIC_ASSERT2(X,__LINE__)
/*
These macros are required by STATIC_ASSERT to make token pasting work.
Not really useful by themselves.
*/
#define STATIC_ASSERT2(X,L) STATIC_ASSERT3(X,L)
#define STATIC_ASSERT3(X,L) STATIC_ASSERT_MSG(X,at_line_##L)
/*
Static assertion with special error message.
Note: It depends on compiler whether message is visible or not!
STATIC_ASSERT_MSG(sizeof(long)==8, long_is_not_eight_bytes);
*/
#define STATIC_ASSERT_MSG(COND,MSG) \
typedef char static_assertion_##MSG[(!!(COND))*2-1]

Best way to define offsets via C preprocessor

I would like to define a macro that will help me to auto generate offsets. Something like this:
#define MEM_OFFSET(name, size) ...
MEM_OFFSET(param1, 1);
MEM_OFFSET(param2, 2);
MEM_OFFSET(param3, 4);
MEM_OFFSET(param4, 1);
should generate the following code:
const int param1_offset = 0;
const int param2_offset = 1;
const int param3_offset = 3;
const int param4_offset = 7;
or
enum {
param1_offset = 0,
param2_offset = 1,
param3_offset = 3,
param4_offset = 7,
}
or even (not possible using C-preprocessor only for sure, but who knows ;)
#define param1_offset 0
#define param2_offset 1
#define param3_offset 3
#define param4_offset 7
Is it possible to do without running external awk/bash/... scripts?
I'm using Keil C51
It seems I've found a solution with enum:
#define MEM_OFFSET(name, size) \
name ## _offset, \
___tmp__ ## name = name ## _offset + size - 1, // allocate right bound offset and introduce a gap to force compiler to use next available offset
enum {
MEM_OFFSET(param1, 1)
MEM_OFFSET(param2, 2)
MEM_OFFSET(param3, 4)
MEM_OFFSET(param4, 1)
};
In the comments to your post you mention that you're managing an EEPROM memory map, so this answer relates to managing memory offsets rather than answering your specific question.
One way to manage EEPROM memory is with the use of a packed struct. ie, one where there is no space between each of the elements. The struct is never instantiated, it is only used for offset calculations.
typedef struct {
uint8_t param1;
#ifdef FEATURE_ENABLED
uint16_t param2;
#endif
uint8_t param3;
} __packed eeprom_memory_layout_t;
You could then use code like the following to determine the offset of each element as needed(untested). This uses the offsetof stddef macro.
uint16_t read_param3(void) {
uint8_t buf;
eeprom_memory_layout_t * ee;
/* eeprom_read(offset, size, buf) */
eeprom_read(offsetof(eeprom_memory_layout_t, param3), sizeof(ee->param3), &buf);
return buf;
}
Note that the struct is never instantiated. Using a struct like this makes it easy to see your memory map at a glance, and macros can easily be used to abstract away the calls to offsetof and sizeof during access.
If you want to create several structures based on some preprocessor declarations, you could do something like:
#define OFFSET_FOREACH(MODIFIER) \
MODIFIER(1) \
MODIFIER(2) \
MODIFIER(3) \
MODIFIER(4)
#define OFFSET_MODIFIER_ENUM(NUM) param##NUM##_offset,
enum
{
OFFSET_FOREACH(OFFSET_MODIFIER_ENUM)
};
The preprocessor would then produce the following code:
enum
{
param1_offset,
param2_offset,
param3_offset,
param4_offset,
}
I'm sure somebody will figure a nice preprocessor trick to compute the offset values with the sum of its predecessors :)
If you are doing this in C code, you have to keep in mind that const int declarations do not declare constants in C. To declare a named constant you have to use either enum or #define.
If you need int constants specifically, then enum will work well, although I the auto-generation part might be tricky in any case. Off the top of my head I can only come up with something as ugly as
#define MEM_OFFSET_BEGIN(name, size)\
enum {\
name##_OFFSET = 0,\
name##_SIZE__ = size,
#define MEM_OFFSET(name, size, prev_name)\
name##_OFFSET = prev_name##_OFFSET + prev_name##_SIZE__,\
name##_SIZE__ = size,
#define MEM_OFFSET_END()\
};
and then
MEM_OFFSET_BEGIN(param1, 1)
MEM_OFFSET(param2, 2, param1)
MEM_OFFSET(param3, 4, param2)
MEM_OFFSET(param4, 1, param3)
MEM_OFFSET_END()
Needless to say, the fact that it requires the next offset declaration to refer to the previous offset declaration by name defeats most of the purpose of this construct.
Try something like:
#define OFFSET(x) offsetof(struct {\
char param1[1], param2[2], param3[4], param4[1];\
},x)
Then you can use OFFSET(param1), etc. and it's even an integer constant expression.

Resources