Is there a way to reference one variable with another? Preferably by name.

I have, will have, a text file on SD card, it will hold the text I want displayed on an LCD

Obviously I can open the file and read a line or character which I then print on the LCD, hardly rocket science ....
However I want to have the text work like a mark-up language so that I can include dynamic data.
Suppose I decide that text in square brackets needs to be replaced with the contents of a string array ...
My file might look like this ...

  • Battery Status -
    Voltage: [BatVolts]V
    Temperature: [BatTemp]C

When stepping through the file I would want to replace [BatVolts] with the contents of of the char array BatVoltrs.

Obviously I could have a huge list of If's or a case statement but I don't like either of options much ...
If there is better way I would very much appreciate some help, I'v been digging and cant find what I need.

Thanks
Al

Obviously I could have a huge list of If's or a case statement but I don't like either of options much

That's too bad.

At compile time, the names go away, so the Arduino has no way of knowing which array you mean when you wish to refer to an array by name.

You can either do as you suggest or create a map (a collection of key, value pairs) at compile time. The key will be the array name. The value will be the address where the data is stored.

When you encounter a name in your file, see if the name is in your map. If so, you know the address where the data is.

Another way to do the same thing would be to make your file like this:

     - Battery Status -
Voltage:          [%1]V
Temperature:  [%2]C

Set up a 2d array of char and when you see %, send the nth row to the LCD. Of course, you'll need to populate the array appropriately, which effectively means you're replicating the mapping functionality.

An easier solution maybe:

char strFromFile[] = "     - Battery Status -\nVoltage:          %sV\nTemperature:  %sC"; //normally in your file...

char dest[128];
sprintf( dest, strFromFile, BatVolts, BatTemp );
...

Or if you really want to replace the [keywords], you could make a strreplace function (many examples on google) and then use it like:

strreplace( strFromFile, "[BatVolts]", BatVolts);
...

Or even

#define ReplaceKeyword(keyword) strreplace(strFromFile, "["#keyword"]", keyword)

ReplaceKeyword( BatVolts );
...

Just giving ideas out of my head, I don't know if it will help :slight_smile:

Dyslexicbloke:
When stepping through the file I would want to replace [BatVolts] with the contents of of the char array BatVoltrs.

And I assume that there are other variables that you would want to be able to refer to.

Some implementations of printf() and its friends support positional specifiers. That means that your format string can refer to a specified argument, instead of just referring to the next unused argument as it normally would. As far as I remember, the syntax for invoking this would be something like %1$d (to insert the first argument as a decimal number) instead of just %d to print the next argument as a decimal number. Obviously it works for all format directives and arguments. However, I don't know if the AVR libc supports it - and I'm too lazy to go find out. If it's available, it would give you a nice simple, flexible solution as long as the list of variables that you wanted access to was fixed and known in advance.

Its all interesting and useful stuff ...

The idea was to make the display definition file easy to read, human read, whilst including information that the program can use to fetch and format the appropriate value ...

I discovered that dtostrf works for floats, I think because the implementation of floats and doubles is the same for the Arduino IDE.
Anyway I decided that numbers, ones I may want to display anyway, would always be held as floats, just to keep the code streamlined.

The text file will need to be used by two routines, one to populate the LCD and a second to mimic that on a web page.
Ignoring the web page for the time being, I will need a routine that accepts a file mane as an argument and then displays that file, inserting dynamic data as it go's.

I think based on the suggestions, that I have all I need to be building and manipulating the stings.
It also seems clear that fetching a variable based on a human readable name at run-time may not be worth the effort, given the requirement to map the names anyway.
I think where I am now is using a case statement, in a single function, to effectively map variables to names at design time making them usable at run time.

I am well up for any additional suggestions though.
Would getting pointers help? I hear C++ is all about pointers which I appreciate conceptually but have never used .. That's what you get for learning VB
could I use a struct or class to work similarly to the case and if I could is there any point?

Thanks
Al

I discovered that dtostrf works for floats, I think because the implementation of floats and doubles is the same for the Arduino IDE.

No. It's because when you pass a float to a function that expects a double, the float gets a temporary promotion (to double).

Is there a way to reference one variable with another?

Isn't that called a "pointer"?

PaulS's suggestion to use a map seems ideally suited to this task. No need to use tediously large switch statements or if/else if chains.

PaulS:

I discovered that dtostrf works for floats, I think because the implementation of floats and doubles is the same for the Arduino IDE.

No. It's because when you pass a float to a function that expects a double, the float gets a temporary promotion (to double).

It depends. If you are programming in C and call a function without a prototype in scope, all float's are converted to double, and char/short values are promoted to int. This isn't true for C++, since C++ requires prototypes (the arduino IDE creates the prototypes behind your back). Likewise if you are programming in C/C++ and call a varardic function (one that accepts variable arguments like printf), the default promotion rules kick in.

On the other hand, if you are call a non-varardic function with a proper prototype, the compiler does not have to convert floats to doubles. Given the compiler knows the types of the called function, it will do an implicit conversion from the type of the argument that is passed to the type of the argument in the function.

The usual naming convention says that math type rounds that ends in 'f' take float arguments, I would imagine dtostrf takes a float as an argument, and dtostr takes a double. On the AVR based systems, both have the same representation, but on other systems (like the DUE), float and double likely have different representations.

Sorry to be late to the party. May I suggest a different possibility? This sounds like a potential application for Bitlash, specifically a tweaked version of the bitlashsd example.

I see a couple approaches:

  1. If you can tolerate your message files on the sd card looking like (well, being) bitlash code:
print "Temperature is:", getTemperature();
print "Pressure is:", getPressure();
...

...it might be (well, it would be) easier to integrate your existing sensor and display code into the Bitlashsd example (as user functions) than write your proposed parser. Then you have a general display engine you can program with files on the SD card. Bitlash is at http://bitlash.net and you can see the sd card example here: bitlash/bitlashsd.pde at master · billroy/bitlash · GitHub

  1. On the other hand you may really want plain text files with only the code escaped in []. The Bitlash web server example does this; you can embed code in [] in PROGMEM web page templates for execution at page rendering time. You could steal that code and use it in your parser to pick out bits of Bitlash to execute and embed using user functions like #1.

Make any sense? Happy to help with questions and complications.

-br

The usual naming convention says that math type rounds that ends in 'f' take float arguments, I would imagine dtostrf takes a float as an argument

No. The leading d says the function takes a double. The trailing f is to distinguish it from the similar dtostre() function. The e version "formats" the number in exponential form. The f version "formats" the number in fixed form.

Both dtostrf() and dtostre() are C functions, not C++, so the C calling convention (float gets promoted to double) applies.

Thanks for the clarification RE functions and their origin, I am sure as I progress it will get more intuitive but I think it will take a while.
The thing I am most concerned about, apart from not knowing what is available, is not being aware of overheads.
For example I have read somewhere that the string class is far more powerful than playing with char arrays but that it carries a heavy memory burden.

I assume that other functions suffer the same issue and I have no idea how to decide to do something, long hand if you will, or hunt down a function that will take the complexity out of the task.

bitlashsd sounds interesting ...
It hadn't occurred to me to look into web server type code but I guess that is essentially what I am doing rendering a mixture of fixed and dynamic text to a display I mean.
Given that I ideally want to display a facsimile of the LCD and its soft keys on a web page perhaps I would be better coming at this from the other end.
I see no reason why I couldn't modify code that renders an html page to push data onto the LCD at the same time.
If I were to use a 20 X 4 array if DIV's to represent the display on the web page then the code that populated the DIV's could easily be made to do both.

Onward and upward ...
Thanks

The String class is easier to use, but not more powerful, because it still uses chars and cstring functions to do it's job :slight_smile:

You can find it in \hardware\arduino\cores\arduino\WString.cpp