# SFBMacros.h File Reference

Various utility macro definitions. More...

`#include "SFBTypes.h"`

Include dependency graph for SFBMacros.h:

This graph shows which files directly or indirectly include this file:

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
#define | B36_2(a, b) (B36_1(a)*36u+B36_1(b))
#define | B36_3(a, b, c) (B36_2(a,b)*36u+B36_1(c))
#define | B36_4(a, b, c, d) (B36_3(a,b,c)*36u+B36_1(d))
#define | B36_5(a, b, c, d, e) (B36_4(a,b,c,d)*36u+B36_1(e))
#define | B36_6(a, b, c, d, e, f) (B36_5(a,b,c,d,e)*36u+B36_1(f))
#define | B36_7(a, b, c, d, e, f, g) (B36_6(a,b,c,d,e,f)*36u+B36_1(g))
#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) ((((code)>>6)==1) && ((0x00884020>>((code)&0x1f))&1))
| 'N','n', 'S','s', 'E','e', 'W','w'->1, everything else-> 0
const char *const | faceNames []

## Detailed Description

Various utility macro definitions.

Author:
  David H. Ackley.

Date:
  (C) 2008 All rights reserved.

Code License:
  The GNU Lesser General Public License

License Note:
  All code samples shown in documentation are placed into the public domain.

## Define Documentation

#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.

Returns:
  the modified value of bits.

Example:

        ...
         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.

Parameters:

  | red | number of red flashes, 0 to 7
  | green | number of green flashes, 0 to 7
  | blue | number of blue flashes, 0 to 7

Example:

        ...
         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)))

Clear bit bitNum in value.

Example:

        ...
         u32 num = 3;      // I.e., 11 in binary
         CLEAR_BIT(num,0); // Num is now 10 in binary
         println(num);     // Prints 2
       ...

#define GET_BIT | ( | value,
|  | bitNum |  | ) | (((value)>>(bitNum))&1)

Access bit bitNum in value.

Returns:
  1 if the specified bit is set, else 0

Example:

        ...
         u32 num = 2;      // I.e., 11 in binary
         println(GET_BIT(num,1));     // Prints 1 since bit 1 of binary 10 is set
         println(GET_BIT(num,3));     // Prints 0 since bit 3 of binary 10 is clear
       ...

#define GET_BLINK_MAP_COLOR | ( | code,
|  | color |  | ) | GET_MAP3BY3(code,2-(color))

Access the color flash counts encoded by BLINK_MAP.

Parameters:

  | code | The value created by BLINK_MAP
  | color | The color to access, either 0==RED, 1==GREEN, or 2==BLUE

Example:

        ...
         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.

Parameters:

  | map | The value created by MAP3BY3
  | idx | The array index to access, from 0 to 2

Example:

        ...
         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.

Parameters:

  | map | The value created by MAP4BY2
  | idx | The array index to access, from 0 to 3

Example:

        ...
         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.

Parameters:

  | map | The value created by MAP4BY4
  | idx | The array index to access, from 0 to 3

Example:

        ...
         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.

Parameters:

  | map | The value created by MAP4BY8
  | idx | The array index to access, from 0 to 3

Example:

        ...
         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 IS_EARLIER | ( | a,
|  | b |  | ) | ((((u32)(a))-((u32)(b))) > 0x80000000UL)

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:

1. As the code is entered, millis() happens to be very large, but `millis()+1000` doesn't quite roll over, so `end` gets a very large value, and
2. the prepare step runs overtime by enough that millis() then does roll over, and so begins returning very small values. That means
3. the `while` 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
          }

and it will work as desired so long as the prepare step definitely finishes in less than about 24 days.

#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_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_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.

#define IS_LATER | ( | a,
|  | b |  | ) | ((((u32)(b))-((u32)(a))) > 0x80000000UL)

a after b, with wraparound; 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_LATER8 | ( | a,
|  | b |  | ) | ((u8)(((u8)(b))-((u8)(a))) > 0x80UL)

a after b, with wraparound, for u8 values; see IS_EARLIER.

#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_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_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 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.

Parameters:

  | 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

Example:

        ...
         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.

Parameters:

  | 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

Example:

        ...
         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.

Parameters:

  | 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

Example:

        ...
         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.

Parameters:

  | 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

Example:

        ...
         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.

Returns:
  the larger of its two arguments

#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.

Returns:
  the smaller of its two arguments

#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)))

Set bit bitNum in value.

Example:

        ...
         u32 num = 0;
         SET_BIT(num,3);
         println(num);     // Prints 8 (since that's 1000 in binary)
       ...

#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.

Example:

       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.

Returns:
  0 if the specified bit is clear, else a non-zero value (not necessarily 1)

Example:

        ...
         u32 num = 2;      // I.e., 10 in binary
         if (TEST_BIT(num,1)) println("Yes"); else println("No"); // prints Yes
       ...