1

TL;DR: I want some syntax sugar, to make the code shorter and more beautiful.

Pelude:

I'm writing a library for Arduino, that should help store configuration in EEPROM (power-independend flash memory).

To use it, person should do something like:

#include "myEeprom.h"

//Instantiate global configuration object
myeeprom config;

//Define constants for convinient use, values are indexes of config fields
const int CONF_BTN_ACTIVE = 0;
const int CONF_DEFAULT_LEVEL = 1;
const int CONF_USER_NAME = 2;

//Function, that defines configuration of config fields, that would be stored
//it sould be called inside of setup() function
void init_config_fields()
{
    //Set first field  (see how constants are used as indexed)
    //each field is a struct { int type, char* name, int bytes_size }
    config.fields[CONF_BTN_ACTIVE] = {
        myeeprom::TYPE_BOOL,
        "CONF_BTN_ACTIVE",
        1
    };
    // next one
    config.fields[CONF_DEFAULT_LEVEL] = {
        myeeprom::TYPE_INT,
        "CONF_BTN_ACTIVE",
        4
    };
    // next one
    config.fields[CONF_USER_NAME] = {
        myeeprom::TYPE_STR,
        "CONF_USER_NAME",
        16 // size in bytes is actually only used if type is TYPE_STR
    }

    // make myeeprom know, how much field does stored in it.
    config.fields_count = 3;
    // make myeeprom calculate all addresses of config fields, 
    // read it's values, and do other useful stuff.
    config.init();
}

...

// Somewhere in code:
// read data:
bool is_btn_active;
config.read(CONF_BTN_ACTIVE, &is_btn_active);
// write data
config.write(CONF_DEFAULT_LEVEL, 175);
// read data by string key (for example we got it from Serial):
config.read("CONF_BTN_ACTIVE", &is_btn_active);
// display all config to Serial with debugging function:
for (int i=0; i < config.fields_count; i++)
{
   Serial.print("config field ");
   config.debug_print(i, &Serial);
   Serial.print("\n");
}

Now, the question!

I want to have a macro, that could solve this tasks:

  1. Allow me to write strings like "CONF_BTN_ACTIVE" just once, not repeating whem. They are used twise, first as a constant, for convinience when writing programm, and, second, for debugging convinience in runtime. But if there are alot of such fields, the code is getting ugly :(

  2. Allow me not to write full amount of fields (like config.fields_count = 3).

So, the code whould look like:

#include "myEeprom.h"

//Instantiate global configuration object
myeeprom config;

//Function, that defines configuration of config fields, that would be stored
//it sould be called inside of setup() function
void init_config_fields()
{
    //Create fields config and constants with use of macro 
    add_config_magic_macro(config, CONF_BTN_ACTIVE, myeeprom::TYPE_BOOL, 1)
    // next one
    add_config_magic_macro(config, CONF_DEFAULT_LEVEL, myeeprom::TYPE_INT, 4)
    // next one
    add_config_magic_macro(config, CONF_USER_NAME, myeeprom::TYPE_STR, 16);

    // make myeeprom calculate all addresses of config fields, 
    // read it's values, and do other useful stuff.
    config.init();
}

As i've discovered, I cannot create statically incrementing constant macros without boost preprocessor, so, it shouldn't be it.

I can use some non-constant variable and increment it in add_config_magic_macro, but, I don't now how to create global constants when I call such a macro inside a function, and I cant run this code outside of a function.

Ideally this should be compile-time non-dynamic initialization of a fields configuration array, because of arduino's little amount of runtime memory.

Answer to the question How to use Macro argument as string literal? doesn't help, because I need macro to create global const and, at the same time local, in-function structure with the string.

MihanEntalpo
  • 1,952
  • 2
  • 14
  • 31
  • you can write and read a whole struct, so why this? – Juraj Nov 05 '19 at 14:28
  • The problem is in that fact, that I must repeat name of config field twise: 1) in constant name 2) in string (name of the field) – MihanEntalpo Nov 05 '19 at 15:47
  • the complete approach you are try to do is a wrong way. but if you really want to go this way, you can stringify a variable or constant name with # preprocessor operator https://stackoverflow.com/questions/10507264/how-to-use-macro-argument-as-string-literal – Juraj Nov 05 '19 at 15:56
  • Possible duplicate of [How to use Macro argument as string literal?](https://stackoverflow.com/questions/10507264/how-to-use-macro-argument-as-string-literal) – Juraj Nov 05 '19 at 15:56
  • @Juraj thanks for being close enough to what I've asked :) Of course, I can use #VAR to create string of macro argument, but the problem is, that macro should put one part of it inside the function, and other part - outside. For example, add_config_magic_macro(config, CONF_BTN_ACTIVE, myeeprom::TYPE_BOOL, 1) should create line: const int CONF_BTN_ACTIVE=1; and also fill in the structure inside function – MihanEntalpo Nov 06 '19 at 08:37

0 Answers0