Conflicting Use of PROGMEM and #define?

Hi,

I'm getting started with the RePaper Development Board from Adafruit (https://learn.adafruit.com/repaper-eink-development-board/overview) and am confused while reviewing their demo code. After reading about PROGMEM and #define I am unsure on what seems like conflicting or useless use of these keywords. The code is as follows:

PROGMEM const
#define unsigned
#define char uint8_t
#include IMAGE_1_FILE
#undef char
#undef unsigned

What is going on here? Does the IDE interpret multiple lines at once? Are we assigning all const types to PROGMEM? And making any unsigned types use the #define methodology?

Also what does undef do (did not see a reference)? Does the "#undef unsigned" line conflict with the "#define unsigned" line?

Why would we assign a type of memory space to variable types without variables?

Thanks, Haji

Which file did you get that from? The first line should probably be:

#define PROGMEM const

Pete

The code is from the demo.ino file.

The example code given is still confusing. How can you #define and PROGMEM at the same time? And why would you call this on a variable type without a variable?

Haji: And why would you call this on a variable type without a variable?

define is a simple text replacement BEFORE the code goes to the compiler. You can define anything you want. There are no variable types or anything at that point. It's just text. What this means is, "go through the text of the code and find all instances of the word "char" and replace it with "uint8_t".

What they are doing is making sure that even on machines where a char is 16 bits, at least for the purposes of this one include file char will be treated as 8 bits. After including the file, they #undefine those things so they don't affect the rest of the code.

The definition of unsigned is probably to let the included file know something. There are probably #ifdef #else or #ifndef statements in that include that will include different sections of code depending on whether that has been defined or not.

The "PROGMEM const" just precedes what is included from the image file. An image file begins with, for example,

static unsigned char cat_2_0_bits[] = {

so this is just extended to:

PROGMEM const static unsigned char cat_2_0_bits[] = {

because the two #defines on lines 2 and 3 are removed by the preprocessor.

And therefore the first line should NOT be:

#define PROGMEM const

Pete

Thanks for the explanations. I understand the "#define char uint8_t" line now and perhaps the PROGMEM const line. Checking my understanding, the #include line essentially just replaces the IMAGE_1_FILE with the text of that file, thus creating the situation described by el_supremo:

The "PROGMEM const" just precedes what is included from the image file. An image file begins with, for example, Code: [Select] static unsigned char cat_2_0_bits[] = {

so this is just extended to: Code: [Select] PROGMEM const static unsigned char cat_2_0_bits[] = {

Is the text replacement idea correct?

I'm still slightly confused because the syntax explained by the PROGMEM reference does not match the code above. The syntax is explained as:

const dataType variableName[] PROGMEM = {data0, data1, data3...};

As far of the definition of unsigned. Looking at the IMAGE_1_FILE in a text editor reveals no #ifdef #else or #ifndef statements. Is this where these things would be located?

Looking at the image file perhaps gives the intention of the code. The .xbm image file is essentially an array of bytes defining the image. This array is declared at the top as:

static unsigned char text_image_1_44_bits[] = {

Based on replacement of char to uint8_t explained by Delta_G, was the intention perhaps to replace const with unsigned? I'm not sure why one would do this though since each byte in the .xbm format represents 8 pixels that have a black (1) or white (0) status. It doesn't seem that interpreting it as a signed or unsigned byte would make any difference.

It expands to

PROGMEM const static uint8_t cat_2_0_bits[] = {}

in order to always interpret the data as a byte array, even on setups with wide char support (where char is 16 bit). The #undef's undo the effect of the #defines to make char and unsigned work as normal again subsequently.

Ok I think I'm getting this. Still wondering if my interpretation of #include as an in-line replacement of the text in the IMAGE_1_FILE is correct?

With MarkT's expansion, I think I have an interpretation for the "#define unsigned" line. Essentially, does this 'replace' any reference to unsigned with nothing? Since there is no text after unsigned does it just omit any references to unsigned?

I'm still wondering about the syntax of PROGMEM and use in this example as explained in my post above.

And thanks for explaining the use of undef, that makes sense.

With the background provided by the answers and some searching I can explain some things. My question about the PROGMEM syntax is still open though.

Firstly, as noted in the #define reference - "A #define without a token-string removes occurrences of identifier from the source file. The identifier remains defined and can be tested by using the #if defined and #ifdef directives." So therefore, yes, the example code will omit any references to unsigned after the "#define unsigned" and before the "#undef unsigned".

Secondly, according to the #include reference - the #include "Tells the preprocessor to treat the contents of a specified file as if they appear in the source program at the point where the directive appears." So yes, #include is just an in-text replacement.

Did not realize I could go to the C/C++ references to get more information on these commands as they are really just C/C++ things and not arduino specific.

I am still wondering about the syntax of the PROGMEM command and it's use in this example code. To me this seems like a problem. Does anyone understand what is going on here?

Thanks for all the help everyone! It's been a long time since C/C++ for me and I've only dabbled lightly in arduino previously.

Arduino IS C++. That's all it is. Someone just wrote some libraries and functions for the AVR specific stuff like reading pins and stuff. But all that even is just plain old regular vanilla C++ and that's how you use it.

Does anyone understand what is going on here?

It’s a relatively common portability hack, at least in princple.

The IMAGE_1_FILE is probably program generated by an ancient and revered utility (which must not be changed), and contains something like:

static unsigned char text_image_1_44_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ... };

Which is very generic C. When included in the sketch, we want it a format specifically convenient to our particular processor (notably, in flash memory.) with the code and redefinitions shown, we’ll get:

PROGMEM const  [color=brown]// from the text; our definitions spans[/color][color=brown] several lines[/color]
[color=brown]// #defines not present after pre-processing[/color]
static [color=red]uint8_t[/color] text_image_1_44_bits[] = {  [color=brown]// uint8_t substituted for "char", "unsigned" deleted[/color]
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ...

Some of those changes aren’t necessary for AVR, but the program source provides a very generic format that could be easily modified for nearly any cpu…

Alright so I figured out the answer to my syntax question for PROGMEM. I should have read the documentation further. After the initial syntax snippet quoted above it goes on to say:

Note that because PROGMEM is a variable modifier, there is no hard and fast rule about where it should go, so the Arduino compiler accepts all of the definitions below, which are also synonymous. However experiments have indicated that, in various versions of Arduino (having to do with GCC version), PROGMEM may work in one location and not in another. The "string table" example below has been tested to work with Arduino 13. Earlier versions of the IDE may work better if PROGMEM is included after the variable name.

const dataType variableName[] PROGMEM = {}; // use this form const PROGMEM dataType variableName[] = {}; // or this form const dataType PROGMEM variableName[] = {}; // not this one

Which does say that PROGMEM can essentially go anywhere in the declaration. This is slightly confusing since const comes before everything else in these examples, but comes after PROGMEM in the demo.ino code provided by Adafruit. I'm taking this to mean that PROGMEM can come before or after const but in my coding it will come after since this is how the reference is.

I think it's worth noting that there are actually two different reference pages. One contains the const qualifier and one does not:

Thanks for the help on this everyone!!! This was really good for my learning and I appreciate your input.