Keywords.txt and LITERAL1

Hi,

I wrote a little library (lets say myLittleLib.h & myLittleLib.cpp, also config.h) where I use some defines, f.e.

#define DIM_TIME 500

within my config.h, which is then included in the myLittleLib.h.
This way, I can include and use the library (as long as the defines are stored in config.h within the library folder) using

#include "myLittleLib.h"

, all fine.

Now I´d like to define within the sketch, so I wrote a keywords.txt, also stored within the library/myLittleLib folder, just one line:

DIM_TIME LITERAL1

exactly one tab between DIM_TIME and LITERAL1.

Within the sketch, I now first define DIM_TIME, then I include the library:

#define DIM_TIME 500
#include "myLittleLib.h"

and comment it out within the config.h of the library.

Strangely, I get the error
"DIM_TIME was not declared in this scope".

Sadly, there is no useful google hit when searching for the LITERAL1-stuff. All is that is that it has to be set within the keywords.txt.

The keywords.txt file is used for syntax highlighting only, it doesn't change anything about the actual code.

Are you trying to use DIM_TIME in myLittleLib.cpp? You can't do that, because it's compiled separately from your sketch.

Pieter

PieterP:
The keywords.txt file is used for syntax highlighting only, it doesn't change anything about the actual code.

Are you trying to use DIM_TIME in myLittleLib.cpp? You can't do that, because it's compiled separately from your sketch.

Pieter

Exactly, I use DIM_TIME within the myLittleLib.cpp.
I know there is definitely a way to use defines within the lib, f.e. the mySensors library works this way, there is "a lot" of stuff you define within the sketch. F.e. you can define MY_DEBUG and get the debug prints from the lib without using the define furthermore within the sketch..

Inso:
Exactly, I use DIM_TIME within the myLittleLib.cpp.
I know there is definitely a way to use defines within the lib, f.e. the mySensors library works this way, there is "a lot" of stuff you define within the sketch. F.e. you can define MY_DEBUG and get the debug prints from the lib without using the define furthermore within the sketch..

That is only possible if the defines are used just in the header files, not in the implementation files.

PieterP:
That is only possible if the defines are used just in the header files, not in the implementation files.

That would be absolutely enough for me, sadly if i set DIM_TIME only as a default value within the myLittleLib.h and use it nowhere else, I have the same problem: ... is not declared in this scope.

Time to stop the hand waving and post some actual code along with the actual (not paraphrased) error messages. Use Code Tags for both.

If you include the header file from the CPP file, you have the same problem, because including a file is just copy-and-pasting its contents into the current file.

You have to make the header file self-contained. You can make some functions inline if you have to, and you can split up the header file into two parts: one that uses the define, and one that's included from the CPP file.

gfvalvo:
Time to stop the hand waving and post some actual code along with the actual (not paraphrased) error messages. Use Code Tags for both.

Sketch:

#define DIM_TIME 500
#include "myLittleLib.h"

void setup() {}

void loop() {}

myLittleLib.h

#pragma once

#include <Arduino.h>

class myLittleLib
{
	private:
	public:
	static void myTest(int myTestParam = DIM_TIME);
};

myLittleLib.cpp

#include "myLittleLib.h"

void myLittleLib::myTest(int myTestParam){
	
}

Error:
In file included from C:\Users\myLittleLibExample\Documents\Arduino\libraries\myLittleLib\myLittleLib.cpp:1:0:

C:\Users\myLittleLibExample\Documents\Arduino\libraries\myLittleLib\myLittleLib.h:10:39: error: 'DIM_TIME' was not declared in this scope

static void myTest(int myTestParam = DIM_TIME);

^

Inso:
I know there is definitely a way to use defines within the lib, f.e. the mySensors library works this way, there is "a lot" of stuff you define within the sketch. F.e. you can define MY_DEBUG and get the debug prints from the lib without using the define furthermore within the sketch..

So do it the same way as the mySensors library:

There appears to be no "MySensors.cpp" so that could explain why the preprocessor defines aren't needed there.

Add a .begin method to your class so this kind of setup information can be passed in during setup()

#define is a really old remnant of original C and should be avoided in C++.

johnwasser:
So do it the same way as the mySensors library:
GitHub - mysensors/MySensors at master
There appears to be no "MySensors.cpp" so that could explain why the preprocessor defines aren't needed there.

After the answer of PieterP (thank you very much btw :slight_smile: ), I remembered I was able to set MY_NODE_ID to a number within my sketch, which was then used by the MSGW. So I took a look for the define and where to find it within the library, and found three files (except the keywords.txt):

MyConfig.h:

/**
 * @def MY_PASSIVE_NODE
 * @brief If enabled, the node operates fully autonomously, i.e. messages are sent without ACKing.
 *
 * @note All transport-related checks and safety-mechanisms are disabled.
 * @note Requires that @ref MY_NODE_ID is set, @ref MY_PARENT_NODE_ID and
 *       @ref MY_PARENT_NODE_IS_STATIC are optional.
 * @note Singing, registration, and OTA FW update are disabled.
 */
//#define MY_PASSIVE_NODE

/**
 * @def MY_NODE_ID
 * @brief Node id defaults to AUTO (tries to fetch id from controller).
 */
#ifndef MY_NODE_ID
#define MY_NODE_ID (AUTO)
#endif

It only sets it if I do not manually define it..

MySensors.h

#if (MY_NODE_ID == AUTO)
#error MY_PASSIVE_NODE configuration requires setting MY_NODE_ID
#endif

only the error message

and

MyTransport.CPP

if (MY_NODE_ID != AUTO) {
 TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%" PRIu8 "\n"),(uint8_t)MY_NODE_ID);
 // Set static ID
 _transportConfig.nodeId = (uint8_t)MY_NODE_ID;
 // Save static ID to eeprom (for bootloader)
 hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID);
 }

[...]

#if !defined(MY_GATEWAY_FEATURE) && (MY_NODE_ID == AUTO)
 _transportToken = (uint8_t)(hwMillis() & 0xFF);
 if (_transportToken == AUTO) {
 _transportToken++;    // AUTO as token not allowed
 }
 const uint8_t sensorID = _transportToken;
#else
 const uint8_t sensorID = NODE_SENSOR_ID;
#endif

[...]

#if (MY_NODE_ID == AUTO)
 // only active if node ID dynamic
 if ((_msg.sensor == _transportToken) || (_msg.sensor == AUTO)) {
 (void)transportAssignNodeID(_msg.getByte());
 } else {
 TRANSPORT_DEBUG(PSTR("!TSF:MSG:ID TK INVALID\n"));
 }
#endif

[...]

// enhanced ID assignment
#if !defined(MY_GATEWAY_FEATURE) && (MY_NODE_ID == AUTO)
static uint8_t _transportToken = AUTO;
#endif

Which leads me.. nowhere XD. It seems they are able to use it within the cpp-file without a problem..

As already advised several times above:
.ino file:

#define DIM_TIME 500
#include "myLittleLib.h"

void setup() {
  Serial.begin(115200);
  myLittleLib::myTest();
}

void loop() {}

myLittleLib.h:

#pragma once

#include <Arduino.h>

class myLittleLib
{
  private:
  public:
  static void myTest(int myTestParam = DIM_TIME) {
    // Put function implementation here -- i.e.:
    Serial.println(myTestParam);
  }
};

Inso:
It seems they are able to use it within the cpp-file without a problem..

No, with that code the .cpp file will ALWAYS see the #define(d) value of 'MY_NODE_ID' as 'AUTO' because that's how it's defined in the .h file. It doesn't matter how you #define 'MY_NODE_ID' in your .ino file, it will never, ever, ever, ever, ever be seen in the .cpp file. That's just the way it works.

gfvalvo:
No, with that code the .cpp file will ALWAYS see the #define(d) value of 'MY_NODE_ID' as 'AUTO' because that's how it's defined in the .h file. It doesn't matter how you #define 'MY_NODE_ID' in your .ino file, it will never, ever, ever, ever, ever be seen in the .cpp file. That's just the way it works.

I have used the library very frequently, and MY_NODE_ID was not used within my code anywhere. On the other hand, there is f.e.

MyTransport.cpp

if (MY_NODE_ID != AUTO) {
			TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%" PRIu8 "\n"),(uint8_t)MY_NODE_ID);
			// Set static ID
			_transportConfig.nodeId = (uint8_t)MY_NODE_ID;
			// Save static ID to eeprom (for bootloader)
			hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID);
		}

which definitely used the ID set in the sketch to write f.e. the log file I then directly can see when debugging the gateway on the controller (RPI3).
You can also see on this post here: he only defines the NODE_ID before including and nowhere else, and the node id was set.

However, back to your solution. So if I need DIM_TIME in my library as a global variable, your way would be then writing a method setting a variable, and call this one from the .h - file method which can pass the define then, right?

Inso:
I have used the library very frequently, and MY_NODE_ID was not used within my code anywhere. On the other hand, there is f.e.

I don't know what that means and posting snippets is pointless. My statement stands: You can't change the definition of a macro as seen by a .cpp file by a using a #define directive in your .ino file. Period. End of story. Move on.

However, back to your solution. So if I need DIM_TIME in my library as a global variable, your way would be then writing a method setting a variable, and call this one from the .h - file method which can pass the define then, right?

I don't know what any of that means either. DIM_TIME is not a variable (global or otherwise). It's a pre-processor macro. What about the example I posted doesn't make sense?

gfvalvo:
I don't know what that means and posting snippets is pointless. My statement stands: You can't change the definition of a macro as seen by a .cpp file by a using a #define directive in your .ino file. Period. End of story. Move on.
I don't know what any of that means either. DIM_TIME is not a variable (global or otherwise). It's a pre-processor macro. What about the example I posted doesn't make sense?

On the first point: Its definitely possible within the other library. I have postet all code snippets which mention the MY_NODE_ID, and there is no re-setting or something else anywhere within the library. They definitely use the pre-processor-macro directly within a cpp-file, I just cannot find out how they pass it over.

On the second: as the solution I tried to explain is very ugly and would lead to awful code (my lib contains a few classes and dozens of methods, also dozens of #defines and so on..^^) I will rewrite it using templates or setter methods instead. Or maybe I post the question over in the mySensors-forum and find out how they did it.

Thank you (and all others^^) very much for the great help and explanations. If I get the information how they did it, I will definitely post it here :wink: .

Inso:
If I get the information how they did it, I will definitely post it here :wink: .

Here's how. From MySensors.h:

#include "core/MyGatewayTransport.cpp"

IMO, a REALLY bad thing to do. If MySensors.h get's #include(d) into one or more .cpp files in addition to the .ino file, there will be multiple definitions of all the functions contained within and you'll get a mass of linker errors.