let's say I have a couple of hardware registers which are defined within an enum:
typedef enum registers
{
REG1 = 0,
REG2 = 1,
REG3 = 2,
REG4 = 4,
REG5 = 6,
REG6 = 8,
REG_MAX,
}
I have default values for these registers(actually not decided in which way to define them, #define, array or enum...):
// This is just conceptual, not really an enum, array or #define :)
typedef enum values
{
VALUE_REG1 = A,
VALUE_REG2 = B,
VALUE_REG3 = C,
VALUE_REG4 = 53,
VALUE_REG5 = 88,
VALUE_REG6 = 24,
MAX_NUM_REG_VALUES
}
I have a function which can read the hardware registers:
uint8 readRegs(uint8 regaddr);
Now I would like to loop through registers
, and on each element call the readRegs()
function and compare it to the enum regvalues
. It looks like:
registers regs;
reg_values values;
uint8 readfromregs;
for (regs = REG1; regs <= REG_MAX; regs++)
{
readfromregs = readRegs(regs);
for (values = VALUE_REG1; reg_values <= MAX_NUM_REG_VALUES; reg_values++)
{
if (readfromregs != values)
{
// Value not correct
}
else
{
// value correct
}
}
}
This will not work because it's not possible to iterate in enum in this way. Does anybody have a better solution? How to define the construct enum reg_values
?
The enum registers must be fix (this can not be changes to array).
you can iterate the elements like: for(int i=Bar; i<=Last; i++) { ... } Note that this exposes the really-just-an-int nature of a C enum. In particular, you can see that a C enum doesn't really provide type safety, as you can use an int in place of an enum value and vice versa.
To iterate through an enumeration, you can move it into an array using the GetValues method. You could also iterate through an enumeration using a For... Each statement, using the GetNames or GetValues method to extract the string or numeric value.
Can you loop through an enum C ++? Yes. It iterates over an std::initializer_list<Item>.
A typedef is a mechanism for declaring an alternative name for a type. An enumerated type is an integer type with an associated set of symbolic constants representing the valid values of that type.
I'd probably define a struct
struct RegInfo
{
registers number;
values defaultValue;
}
Then I would create an array matching the register number to the default value
struct RegInfo registerInfo[] =
{
{ REG1, VALUE_REG1 },
{ REG2, VALUE_REG2 },
{ REG3, VALUE_REG3 },
{ REG4, VALUE_REG4 },
{ REG5, VALUE_REG5 },
{ REG6, VALUE_REG6 },
};
Now to iterate the registers:
for (int i = 0 ; i < sizeof registerInfo / sizeof(RegInfo) ; ++i)
{
values value = readFromReg( registerInfo[i].number);
if (value != registerInfo[i].defaultValue)
{
// Not the default
}
}
If you want an inner loop foe each value, same trick except the array can be directly of the values
values allValues[] = { VALUE_REG1, Value_REG2, ... , VALUE_REG6 };
There is a risk that you'll forget to put new values/registers in the relevant array, but that's what unit testing is for.
REG_MAX
will be 9
and MAX_NUM_REG_VALUES
will be 25
so you can't use those. You'll have to enumerate the constants in a different way.
Based on the struct solution in another answer by @JeremyP, you could use a 3rd enum for the actual indices:
typedef enum
{
REG_INDEX1 = REG1,
REG_INDEX2 = REG2,
REG_INDEX3 = REG3,
REG_INDEX4 = REG4,
REG_INDEX5 = REG5,
REG_INDEX6 = REG6,
REG_INDEX_N // number of registers
} reg_index;
This enables some ways to improve data integrity:
struct RegInfo registerInfo[] =
{
[REG_INDEX1] = { REG1, VALUE_REG1 },
[REG_INDEX2] = { REG2, VALUE_REG2 },
[REG_INDEX3] = { REG3, VALUE_REG3 },
[REG_INDEX4] = { REG4, VALUE_REG4 },
[REG_INDEX5] = { REG5, VALUE_REG5 },
[REG_INDEX6] = { REG6, VALUE_REG6 },
};
_Static_assert(sizeof(registerInfo)/sizeof(*registerInfo) == REG_INDEX_N,
"Enum not in sync with array initializer");
This is the solution I would recommend.
If you are very pedantic with data integrity and want to avoid code repetition, there is also some evil macro magic you can use. Namely "X macros" that come at the expense of severely reduced readability:
// whatever A, B and C is supposed to be
#define A 10
#define B 11
#define C 12
#define REG_LIST \
X(0, A) \
X(1, B) \
X(2, C) \
X(4, 53) \
X(6, 88) \
X(8, 24) \
int main (void)
{
// iterate through the value pairs:
#define X(reg, val) printf("reg: %d val:%.2d\n", reg, val);
REG_LIST
#undef X
}
Similarly, you can use X macros to create the enums:
typedef enum // create REG1, REG2, REG4 etc
{
#define X(key, val) REG##key = key,
REG_LIST
#undef X
} registers;
typedef enum // create VALUE_REG1, VALUE_REG2, VALUE_REG4 etc
{
#define X(key, val) VALUE_REG##key = val,
REG_LIST
#undef X
} values;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With