#include "SFBTypes.h"
Go to the source code of this file.
Defines | |
#define | REGISTER_OFFSET(baseAddress, byteOffset) (*((uv32 *) (((u32)(baseAddress))+(byteOffset)))) |
Access a 32 bit H/W register. | |
#define | B36_1(a) B36_CONST_##a |
A length 1 base 36 constant. | |
#define | B36_2(a, b) (B36_1(a)*36u+B36_1(b)) |
A length 2 base 36 constant. | |
#define | B36_3(a, b, c) (B36_2(a,b)*36u+B36_1(c)) |
A length 3 base 36 constant. | |
#define | B36_4(a, b, c, d) (B36_3(a,b,c)*36u+B36_1(d)) |
A length 4 base 36 constant. | |
#define | B36_5(a, b, c, d, e) (B36_4(a,b,c,d)*36u+B36_1(e)) |
A length 5 base 36 constant. | |
#define | B36_6(a, b, c, d, e, f) (B36_5(a,b,c,d,e)*36u+B36_1(f)) |
A length 6 base 36 constant. | |
#define | B36_7(a, b, c, d, e, f, g) (B36_6(a,b,c,d,e,f)*36u+B36_1(g)) |
A length 7 base 36 constant. | |
#define | IN_BODYRAM __attribute__((section (".bodyram"))) |
#define | IN_TALKRAM __attribute__((section (".talkram"))) |
#define | IN_FASTRAM __attribute__((section (".fastram"))) |
#define | IN_BODYRAM_BSS __attribute__((section (".bss.bodyram"))) |
#define | IN_TALKRAM_BSS __attribute__((section (".bss.talkram"))) |
#define | IN_FASTRAM_BSS __attribute__((section (".bss.fastram"))) |
Bit Operations | |
These macros generally expect u32 operands, though some may work on smaller types | |
#define | SET_BIT(value, bitNum) ((value) |= (1<<(bitNum))) |
Set bit bitNum in value. | |
#define | CLEAR_BIT(value, bitNum) ((value) &= ~(1<<(bitNum))) |
Clear bit bitNum in value. | |
#define | GET_BIT(value, bitNum) (((value)>>(bitNum))&1) |
Access bit bitNum in value. | |
#define | TEST_BIT(value, bitNum) ((value)&(1<<(bitNum))) |
Check if bit bitNum in value is set. | |
#define | BIT_PAIR_AT_POSITION(bits, newValue, position) ((bits) = ((bits)&(~(3<<(position))))|((newValue)<<(position))) |
Set a consecutive pair of bits in bits, located at position, to value newValue. | |
Small Constant Array Maps | |
#define | MAP4BY2(a, b, c, d) ((((((((u8) d)<<2)|(c))<<2)|(b))<<2)|(a)) |
Encode 4 numbers each 2 bits long, see MAP3BY3 for background. | |
#define | GET_MAP4BY2(map, idx) (((map)>>((idx)<<1))&0x3) |
Access the values encoded by MAP4BY2. | |
#define | MAP4BY4(a, b, c, d) ((((((((u16) d)<<4)|(c))<<4)|(b))<<4)|(a)) |
Encode 4 numbers each 4 bits long, see MAP3BY3 for background. | |
#define | GET_MAP4BY4(map, idx) (((map)>>((idx)<<2))&0xf) |
Access the values encoded by MAP4BY4. | |
#define | MAP4BY8(a, b, c, d) ((((((((u32) d)<<8)|(c))<<8)|(b))<<8)|(a)) |
Encode 4 numbers each 8 bits long, see MAP3BY3 for background. | |
#define | GET_MAP4BY8(map, idx) (((map)>>((idx)<<3))&0xff) |
Access the values encoded by MAP4BY8. | |
#define | MAP3BY3(a, b, c) ((((((u16) c)<<3)|(b))<<3)|(a)) |
Encode 3 numbers each 3 bits long. | |
#define | GET_MAP3BY3(map, idx) (((map)>>((idx)*3))&0x7) |
Access the values encoded by MAP3BY3. | |
#define | BLINK_MAP(red, green, blue) MAP3BY3(blue,green,red) |
Use a MAP3BY3 to encode a 'blink code' of red, green, and blue flash counts. | |
#define | GET_BLINK_MAP_COLOR(code, color) GET_MAP3BY3(code,2-(color)) |
Access the color flash counts encoded by BLINK_MAP. | |
Fast u32 Comparisons Handling Rollover | |
#define | IS_EARLIER(a, b) ((((u32)(a))-((u32)(b))) > 0x80000000UL) |
Functions like millis() and micros() can be tricky to use robustly. | |
#define | IS_LATER_OR_EQUAL(a, b) ((((u32)(a))-((u32)(b))) < 0x80000000UL) |
a after or same as b, with wraparound; see IS_EARLIER. | |
#define | IS_LATER(a, b) ((((u32)(b))-((u32)(a))) > 0x80000000UL) |
a after b, with wraparound; see IS_EARLIER. | |
#define | IS_EARLIER_OR_EQUAL(a, b) ((((u32)(b))-((u32)(a))) < 0x80000000UL) |
a before or same as b, with wraparound; see IS_EARLIER. | |
#define | IS_EARLIER16(a, b) ((u16)(((u16)(a))-((u16)(b))) > 0x8000UL) |
a before b, with wraparound, for u16 values; see IS_EARLIER | |
#define | IS_LATER_OR_EQUAL16(a, b) ((u16)(((u16)(a))-((u16)(b))) < 0x8000UL) |
a after or same as b, with wraparound, for u16 values; see IS_EARLIER. | |
#define | IS_LATER16(a, b) ((u16)(((u16)(b))-((u16)(a))) > 0x8000UL) |
a after b, with wraparound, for u16 values; see IS_EARLIER. | |
#define | IS_EARLIER_OR_EQUAL16(a, b) ((u16)(((u16)(b))-((u16)(a))) < 0x8000UL) |
a before or same as b, with wraparound, for u16 values; see IS_EARLIER. | |
#define | IS_EARLIER8(a, b) ((u8)(((u8)(a))-((u8)(b))) > 0x80UL) |
a before b, with wraparound, for u8 values; see IS_EARLIER | |
#define | IS_LATER_OR_EQUAL8(a, b) ((u8)(((u8)(a))-((u8)(b))) < 0x80UL) |
a after or same as b, with wraparound, for u8 values; see IS_EARLIER. | |
#define | IS_LATER8(a, b) ((u8)(((u8)(b))-((u8)(a))) > 0x80UL) |
a after b, with wraparound, for u8 values; see IS_EARLIER. | |
#define | IS_EARLIER_OR_EQUAL8(a, b) ((u8)(((u8)(b))-((u8)(a))) < 0x80UL) |
a before or same as b, with wraparound, for u8 values; see IS_EARLIER. | |
Miscellaneous macro hackery | |
#define | STRUCT_MEMBER_OFFSET(structure, member) ((uptr) &(((structure *) 0)->member)) |
Find the offset of a particular member within some structure. | |
#define | XSTR(arg) STR(arg) |
The (now) traditional, but still disgusting, two-level stringification song and dance to stringify an expansion result, using XSTR and STR. | |
#define | STR(arg) #arg |
The (now) traditional, but still disgusting, two-level stringification song and dance to stringify an expansion result, using XSTR and STR. | |
#define | MIN(a, b) (((a)<(b))?(a):(b)) |
The traditional minimum value macro. | |
#define | MAX(a, b) (((a)>(b))?(a):(b)) |
The traditional maximum value macro. | |
#define | FILEPOS __FILE__ ":" XSTR(__LINE__) |
FILEPOS yields the current position in the source code as a "SFBMacros.h:63"-style string. | |
Operations on SFB face codes. | |
These macros are generally only valid for the "physical faces" like NORTH - WEST | |
#define | CLOCKWISE_FACE(dir) GET_MAP4BY2(MAP4BY2(EAST,WEST,SOUTH,NORTH),dir) |
Maps N->E, S->W, E->S, W->N. | |
#define | COUNTERCLOCKWISE_FACE(dir) GET_MAP4BY2(MAP4BY2(WEST,EAST,NORTH,SOUTH),dir) |
Maps N->W, S->E, E->N, W->S. | |
#define | ANTICLOCKWISE_FACE(dir) COUNTERCLOCKWISE_FACE(dir) |
#define | OPPOSITE_FACE(dir) GET_MAP4BY2(MAP4BY2(SOUTH,NORTH,WEST,EAST),dir) |
Maps N->S, S->N, E->W, W->E. | |
#define | FACE_NAME(face) (faceNames[face]) |
Maps N,S,E,W -> "North","South","East","West". | |
#define | FACE_CODE(face) GET_MAP4BY8(MAP4BY8('N','S','E','W'),face) |
Maps N,S,E,W -> 'N','S','E','W'. | |
#define | FACE_NUMBER_FROM_CODE(code) (((((code)&~0x20)^(((code)&~0x20)>>1))-1)&0x3) |
Maps 'N','n'->NORTH, 'S','s'->SOUTH, 'E','e'->EAST, 'W','w'->WEST. | |
#define | IS_FACE_CODE(code) |
'N','n','S','s','E','e','W','w'->1,everything else-> 0 | |
const char *const | faceNames [] |
#define B36_6 | ( | a, | |||
b, | |||||
c, | |||||
d, | |||||
e, | |||||
f | ) | (B36_5(a,b,c,d,e)*36u+B36_1(f)) |
A length 6 base 36 constant.
(Note: Some argument combinations are invalid)
#define B36_7 | ( | a, | |||
b, | |||||
c, | |||||
d, | |||||
e, | |||||
f, | |||||
g | ) | (B36_6(a,b,c,d,e,f)*36u+B36_1(g)) |
A length 7 base 36 constant.
(Note: Argument 'a' must be 0 to have even a chance of this producing a valid constant. Why does this macro exist?)
#define BIT_PAIR_AT_POSITION | ( | bits, | |||
newValue, | |||||
position | ) | ((bits) = ((bits)&(~(3<<(position))))|((newValue)<<(position))) |
Set a consecutive pair of bits in bits, located at position, to value newValue.
newValue must be in the range of 0 to 3 for correct operation.
... u32 num = 0; // num: ...000000 binary BIT_PAIR_AT_POSITION(num,3,1); // num: ...000110 binary println(num); // prints 6 BIT_PAIR_AT_POSITION(num,2,2); // num: ...001010 binary println(num); // prints 10 ...
#define BLINK_MAP | ( | red, | |||
green, | |||||
blue | ) | MAP3BY3(blue,green,red) |
Use a MAP3BY3 to encode a 'blink code' of red, green, and blue flash counts.
BLINK_MAP puts red at the left of the map, so that any BLINK_MAP with red less than 4 will yield a constant that fits in 8 bits -- which the compiler will be able to generate in one instruction via an immediate operand, avoiding a memory reference.
red | number of red flashes, 0 to 7 | |
green | number of green flashes, 0 to 7 | |
blue | number of blue flashes, 0 to 7 |
... API_ASSERT(foo<bar,BLINK_MAP(0,2,1)); // Die blinking 0,2,1 (a sketch custom code), unless foo < bar ...
#define CLEAR_BIT | ( | value, | |||
bitNum | ) | ((value) &= ~(1<<(bitNum))) |
#define GET_BIT | ( | value, | |||
bitNum | ) | (((value)>>(bitNum))&1) |
#define GET_BLINK_MAP_COLOR | ( | code, | |||
color | ) | GET_MAP3BY3(code,2-(color)) |
Access the color flash counts encoded by BLINK_MAP.
code | The value created by BLINK_MAP | |
color | The color to access, either 0==RED, 1==GREEN, or 2==BLUE |
... u32 map = BLINK_MAP(2,0,4); // Create a blink map println(GET_BLINK_MAP_COLOR(map,0)); // prints 2 println(GET_BLINK_MAP_COLOR(map,1)); // prints 0 println(GET_BLINK_MAP_COLOR(map,2)); // prints 4 ...
#define GET_MAP3BY3 | ( | map, | |||
idx | ) | (((map)>>((idx)*3))&0x7) |
Access the values encoded by MAP3BY3.
map | The value created by MAP3BY3 | |
idx | The array index to access, from 0 to 2 |
... u32 num = MAP3BY3(2,0,4); // Create a 3 by 3 SCAM println(GET_MAP3BY3(num,0)); // prints 2 println(GET_MAP3BY3(num,1)); // prints 0 println(GET_MAP3BY3(num,2)); // prints 4 ...
#define GET_MAP4BY2 | ( | map, | |||
idx | ) | (((map)>>((idx)<<1))&0x3) |
Access the values encoded by MAP4BY2.
map | The value created by MAP4BY2 | |
idx | The array index to access, from 0 to 3 |
... u32 num = MAP4BY2(1,2,3,3); // Create a 4 by 2 SCAM println(GET_MAP4BY2(num,0)); // prints 1 println(GET_MAP4BY2(num,1)); // prints 2 println(GET_MAP4BY2(num,2)); // prints 3 println(GET_MAP4BY2(num,3)); // prints 3 ...
#define GET_MAP4BY4 | ( | map, | |||
idx | ) | (((map)>>((idx)<<2))&0xf) |
Access the values encoded by MAP4BY4.
map | The value created by MAP4BY4 | |
idx | The array index to access, from 0 to 3 |
... u32 num = MAP4BY4(9,7,2,0xf); // Create a 4 by 4 SCAM println(GET_MAP4BY4(num,0)); // prints 9 println(GET_MAP4BY2(num,1)); // prints 7 println(GET_MAP4BY2(num,2)); // prints 2 println(GET_MAP4BY2(num,3)); // prints 15 ...
#define GET_MAP4BY8 | ( | map, | |||
idx | ) | (((map)>>((idx)<<3))&0xff) |
Access the values encoded by MAP4BY8.
map | The value created by MAP4BY8 | |
idx | The array index to access, from 0 to 3 |
... u32 num = MAP4BY8(0x12,' ',99,127); // Create a 4 by 8 SCAM println(GET_MAP4BY8(num,0)); // prints 18 println(GET_MAP4BY8(num,1)); // prints 32 (ASCII value of the space ' ' char) println(GET_MAP4BY8(num,2)); // prints 99 println(GET_MAP4BY8(num,3)); // prints 127 ...
Functions like millis() and micros() can be tricky to use robustly.
It's not too hard to write code like:
u32 end = millis()+1000; // Compute the value of millis() 1 second from now ..prepare.. // Take some time preparing to work.. while (millis() < end) { // ..then while there's still time in this second [[WARNING! CONTAINS ERROR!]] ..work.. // ..do some low-priority work }
which seems very safe, and will indeed work correctly most of the time. But suppose the prepare step might sometimes take more than one second? You might answer "So what? Then the while
loop will just quit immediately, because millis() is already later than end
so there's no time left to work."
Indeed. But, just suppose your sketch has already been running for a long long time. After about 49 days, the total number of elapsed milliseconds exceeds the maximum possible value of a u32!
When that happens, millis() "rolls over" back to zero! So a terrible possibility arises. Suppose:
millis()+1000
doesn't quite roll over, so end
gets a very large value, andwhile
loop will then perform its low-priority work, not for less than a second, but for the next 49 days!(If you can't even dream of your sketch running for six weeks solid, well, you be the judge. Still, one might consider dreaming bigger -- or consider micros(), which rolls over about every 70 minutes. And either way, the fix is sweet; read on.)
The fundamental problem, given that counters will eventually roll over, is that '<' doesn't quite capture the most useful notion of 'earlier' or 'before'. In the above example, if end
is very large and millis() is very small, the most sensible interpretation is that millis() has wrapped and is therefore 'later' than or 'after' end
, even though in that case millis() is numerically less than end
.
And we could try to fix our code along those lines, saying that "< means earlier" unless some added special-case code decides that a wraparound has occurred. But, it turns out, there's a better, faster, and cleaner way to do it.
With two values a and b referenced to the same rollover counter, what we'd really like to know is: Would the counter count from a to b quicker than b to a, considering rollovers? If counting from a to b is shorter, then we're better off saying a is earlier than b.
And that's exactly the comparison the IS_EARLIER macro makes.
And, it does it wicked fast: The comparison itself is typically just three ARM assembly language instructions. If IS_EARLIER(a,b)
is true
, then it takes less counting-ups-with-possible-wrapping to go from a to b than b to a, so we assume a is earlier than b. Now, in general that assumption could be wrong, but in any particular case if we know our millis() operands are less than about 24 days apart (or micros() operands are less than about a half hour apart), then we are golden.
Our resulting code, hardly changed but now satisfyingly robust, looks like this:
u32 end = millis()+1000; // Compute the value of millis() 1 second from now ..prepare.. // Take some time preparing to work.. while (IS_EARLIER(millis(),end)) { // ..then while there's still time in this second ..work.. // ..do some low-priority work }
a before or same as b, with wraparound; see IS_EARLIER.
a before or same as b, with wraparound, for u16 values; see IS_EARLIER.
a before or same as b, with wraparound, for u8 values; see IS_EARLIER.
#define IS_FACE_CODE | ( | code | ) |
Value:
(((code)&~0x20)=='N'|| \ ((code)&~0x20)=='S'|| \ ((code)&~0x20)=='E'|| \ ((code)&~0x20)=='W')
a after b, with wraparound; see IS_EARLIER.
a after b, with wraparound, for u16 values; see IS_EARLIER.
a after b, with wraparound, for u8 values; see IS_EARLIER.
a after or same as b, with wraparound; see IS_EARLIER.
a after or same as b, with wraparound, for u16 values; see IS_EARLIER.
a after or same as b, with wraparound, for u8 values; see IS_EARLIER.
#define MAP3BY3 | ( | a, | |||
b, | |||||
c | ) | ((((((u16) c)<<3)|(b))<<3)|(a)) |
Encode 3 numbers each 3 bits long.
The primary use of such 3 by 3 maps is for efficiently storing and accessing the 'blink codes' displayed when errors occur; see BLINK_MAP and SFBErrors.h .
These macros (MAP3BY3, MAP4BY2, MAP4BY4, MAP4BY8) encode a small array of small numbers into a single constant value -- a Small Constant Array Map (SCAM) -- which can be accessed and stored with relatively little code and memory. They come in matched pairs -- a MAPxBYy
to make a SCAM, and a GET_MAPxBYy
to access it. In such pairings, the x is the number of associations in the map, and the y is number of bits in each mapped value.
In all cases it is the programmer's responsibility to ensure that all arguments passed to these macros are in range for the sizes involved; the macros do no error checking. Note also that if any of the arguments to a MAPxBYy
macro are not compile-time constants, there are likely no efficiency gains, and it is probably not worth using these macros, in that context, at all.
a | first argument becomes index 0 in the map | |
b | second argument becomes index 1 in the map | |
c | third argument becomes index 2 in the map |
... u32 num = MAP3BY3(2,0,4); // Create a 3 by 3 SCAM println(GET_MAP3BY3(num,0)); // prints 2 println(GET_MAP3BY3(num,1)); // prints 0 println(GET_MAP3BY3(num,2)); // prints 4 ...
#define MAP4BY2 | ( | a, | |||
b, | |||||
c, | |||||
d | ) | ((((((((u8) d)<<2)|(c))<<2)|(b))<<2)|(a)) |
Encode 4 numbers each 2 bits long, see MAP3BY3 for background.
a | first argument becomes index 0 in the map | |
b | second argument becomes index 1 in the map | |
c | third argument becomes index 2 in the map | |
d | fourth argument becomes index 3 in the map |
... u32 num = MAP4BY2(1,2,3,3); // Create a 4 by 2 SCAM println(GET_MAP4BY2(num,0)); // prints 1 println(GET_MAP4BY2(num,1)); // prints 2 println(GET_MAP4BY2(num,2)); // prints 3 println(GET_MAP4BY2(num,3)); // prints 3 ...
#define MAP4BY4 | ( | a, | |||
b, | |||||
c, | |||||
d | ) | ((((((((u16) d)<<4)|(c))<<4)|(b))<<4)|(a)) |
Encode 4 numbers each 4 bits long, see MAP3BY3 for background.
a | first argument becomes index 0 in the map | |
b | second argument becomes index 1 in the map | |
c | third argument becomes index 2 in the map | |
d | fourth argument becomes index 3 in the map |
... u32 num = MAP4BY4(9,7,2,0xf); // Create a 4 by 4 SCAM println(GET_MAP4BY4(num,0)); // prints 9 println(GET_MAP4BY2(num,1)); // prints 7 println(GET_MAP4BY2(num,2)); // prints 2 println(GET_MAP4BY2(num,3)); // prints 15 ...
#define MAP4BY8 | ( | a, | |||
b, | |||||
c, | |||||
d | ) | ((((((((u32) d)<<8)|(c))<<8)|(b))<<8)|(a)) |
Encode 4 numbers each 8 bits long, see MAP3BY3 for background.
a | first argument becomes index 0 in the map | |
b | second argument becomes index 1 in the map | |
c | third argument becomes index 2 in the map | |
d | fourth argument becomes index 3 in the map |
... u32 num = MAP4BY8(0x12,' ',99,127); // Create a 4 by 8 SCAM println(GET_MAP4BY8(num,0)); // prints 18 println(GET_MAP4BY8(num,1)); // prints 32 (ASCII value of the space ' ' char) println(GET_MAP4BY8(num,2)); // prints 99 println(GET_MAP4BY8(num,3)); // prints 127 ...
#define MAX | ( | a, | |||
b | ) | (((a)>(b))?(a):(b)) |
The traditional maximum value macro.
This is unsafe because it evaluates one of its arguments twice, so it must not be used with arguments that have side-effects.
#define MIN | ( | a, | |||
b | ) | (((a)<(b))?(a):(b)) |
The traditional minimum value macro.
This is unsafe because it evaluates one of its arguments twice, so it must not be used with arguments that have side-effects.
#define REGISTER_OFFSET | ( | baseAddress, | |||
byteOffset | ) | (*((uv32 *) (((u32)(baseAddress))+(byteOffset)))) |
Access a 32 bit H/W register.
Access given a base address and a BYTE COUNT offset, (which must be a multiple of four or you'll be making an unaligned access).
#define SET_BIT | ( | value, | |||
bitNum | ) | ((value) |= (1<<(bitNum))) |
#define STRUCT_MEMBER_OFFSET | ( | structure, | |||
member | ) | ((uptr) &(((structure *) 0)->member)) |
Find the offset of a particular member within some structure.
Sometimes it is necessary or helpful to know how for 'into' a given struct
or class
some particular member is located. STRUCT_MEMBER_OFFSET produces a non-negative u32
giving the offset to that member from the beginning of the structure, in bytes.
struct Foo { // Some random struct.. u8 title[17]; u8 type; u32 value; }; ... println(STRUCT_MEMBER_OFFSET(Foo,type)); // Prints 17. 'title' takes 17 bytes, which land at // offsets 0..16, and then 'type' immediately follows.
#define TEST_BIT | ( | value, | |||
bitNum | ) | ((value)&(1<<(bitNum))) |
Check if bit bitNum in value is set.
Typically produces slightly faster code, compared to GET_BIT, when bitNum is a constant.