Having user definable mappings called by library functions

I'm trying to write up some code I've developed in to a library I can make more broad use of, putting it in to h and cpp files and such so as to be able to call it from other sketch code.

But in some of the code I want to "libraryise", I've got things like this which happen inside a function:

if(RealTimeVariable==1){
  Length=sizeof(Type1Array);
  memmove(ClonedArray,Type1Array,sizeof(ClonedArray));
  Ready=1;
}else if(RealTimeVariable==2){
  Length=sizeof(Type2Array);
  memmove(ClonedArray,Type2Array,sizeof(ClonedArray));
  Ready=1;
}else if(RealTimeVariable==5){
  Length=sizeof(Type4Array);
  memmove(ClonedArray,Type4Array,sizeof(ClonedArray));
  Ready=1;
}else if(RealTimeVariable==7){
  Length=sizeof(Type2Array);
  memmove(ClonedArray,Type2Array,sizeof(ClonedArray));
  Ready=1;
}

Where a variable within the function I want to libraryise, "RealTimeVariable" is used to select which of a bunch of different arrays should be cloned in to a copy array. Later processing is then done on ClonedArray.

There is a mapping here between RealTimeVariable and which array gets copied:
RTV=1, Type1Array
RTV=2, Type2Array
RTV=5, Type4Array
RTV=7, Type2Array

I want to make this mapping "user definable", in the ino sketch code when using the library. Ideally not having to force the arrays, in the finalised version, to be named as TypeXArray either.

As you can see, the X in TypeXArray doesn't necessarily correspond to the value of RealTimeVariable, and there are options for one-to-one and many-to-one mappings, for any RealTimeVariable value there will be only one array type to select, but multiple RealTimeVariable values may sometimes lead to the same TypeXArray being cloned.

If RealTimeVariable isn't equal to any option on the mapping then no cloning occurs and the Ready flag is not set to 1.

The TypeXArray arrays are not all the same length, but they are all guaranteed to be shorter than the size available for ClonedArray. Where the memmove is done, the proper things of TypeXArray get copied over, as does "junk" following them from whatever areas of memory next get read due to the copying of a whole ClonedArray worth of bytes. The Length measure is used by later code to know to ignore and write zeroes over the later parts in ClonedArray.

I can guarantee that these arrays are always arrays of uint8_t variables.

Wat then is the best way to "libraryise" this functionality, so a user can define the mapping to use?

Can a library function call a user defiend function in the ino sketch which does this?

Is there a way to supply this mapping to the library code via some sort of "constructor" function which can be used to tell the rest of the library's functions in advance how to arrange the cloning?

This setting of mappings only needs to be done at compile time, not runtime. RealTimeVariable gets measured while running, and detremines which cloning to make, but the mapping for these clonings can be set at compile time and does not change.

What is the best way to proceed, thanks

Best way would be to make a class.
Then initialise your class with the mapping as a function parameter. Just like with lcd libraries where you can hand over the relevant pin numbers.
You could also put the definition in .h as a constant.
The user would then have to edit the .h file. Advantage would be that the program needs less memory...

Where might I find a tutorial on this? I've always found object oriented a little perplexing, are there any example pieces of code I can find anywhere which either let the user pass in their own function to be called by a library (function being a void with no input variables, which then reads and writes to global vriabels shared in both library and user code), or which shows a way to define a mapping which can be used to select an array from a bunch of differently named array variables.
Thanks

This site has a lot of tutorials and examples.

Working with classes is called OOP:
Object Oriented Programming.
Google those for more.

OOP sounds scarry, but it just means that the code is organized around objects (things). That object will then have functions. Once you know how to use it, it is very handy...

I suggest you take this step by step...
Learn to work with .h and .cpp files.
Learn to work with classes.
Put your class in a separate .cpp file.
Then move the .cpp and .h file to a library location.... look for tutorials on the arduino forum...

The mapping can be put in a struct. The struct can be sent to the library via the class constructor (or via a init function).

Is it possible for a #define to be used?

Can one have a library in which there is a line like:
DoDefinedThing;

and then in the user's .ino file have the actual definition:

#define DoDefinedThing if(RealTimeVariable==1){\
  Length=sizeof(Type1Array);\
  memmove(ClonedArray,Type1Array,sizeof(ClonedArray));\
  Ready=1;\
}else if(RealTimeVariable==2){\
  Length=sizeof(Type2Array);\
  memmove(ClonedArray,Type2Array,sizeof(ClonedArray));\
  Ready=1;\
}else if(RealTimeVariable==5){\
  Length=sizeof(Type4Array);\
  memmove(ClonedArray,Type4Array,sizeof(ClonedArray));\
  Ready=1;\
}else if(RealTimeVariable==7){\
  Length=sizeof(Type2Array);\
  memmove(ClonedArray,Type2Array,sizeof(ClonedArray));\
  Ready=1;\
}

If this works I assume it will also work for single line #defines

Like
using SpecialNumber
in a calculation in the library
and having
#define SpecialNumber 251
in the user edited .ino file

If #define's can be used like this it would save me both SRAM requirements and on speed of execution as compared to using object oriented code.
Thanks

#define cannot be more than one line

#define is often used to include or exclude code blocks like this:

#define EXTRACODE



void loop () {
   Some code
#ifdef EXTRACODE
    your extra code
#endif
   Some more,code
}

Definition of variables can also made conditional like this.

By the way: if you make a function and then in your code put a // before all calls to that function, the compiler will be smart enough to not include that code in the binaries...

I've used multi-line #define before, it works somehow.

But can it work when the defined thing is called in a library, but the actual definition is given within the ino file?

My guess is: no.
You can put it in the .h file of your library if it is a const declaration.

I'm trying to test this, itseems the cpp file of a library is out of scope for a #define in the ino file, but in scope or a #define in the h file.

I'd really like to find a way to define the #define in the ino and have it be in scope for the cpp to read it. Is there a way?

Yes, they can. You have to put a '\' at the end of the line to tell the precompiler that the macro definition continues with the next line.

No, that's not possible. A #define is valid only within one compiler run. Every .cpp file in a project will be compiled separately without knowng anything about the others ( apart from information in included .h files ). After all the linker puts it all together.
But the linker doesn't know anything about #define. The (pre)compiler knows only about #define's in included .h files. (And in the .cpp file itself of course)

[Edit]:
A compiler run is divided into 2 steps: First, the precompiler is called. All lines beginning with '#' are instructions for the precompiler. In the end, it is only an automated editor. It doesn't know anything about C/C++. It changes the source text according to the # instructions. E.G. if you have a line
#define MYPIN 5
the precompiler will change all occurencies of 'MYPIN' that follow this #define with '5' and remove the #define itself.
After that, the actual compiler run begins. All lines beginning with '#' are then no longer present, i.e. the compiler doesn't see them at all.

I still do not see why you do not hand the mapping in a class constructor or in a class.init() function...

How can I hand this mapping in via anything but a uer written multi-line#define when it is a command which tells things in the library to select any one of a bunch of arbitrarily named arrays to copy from when an arbitrary uint8_t value occurs within the library function.

And note the stuff in the library is mostly part of an interrupt function, interrupt's don't take arguments inserted in to them, so how could I pass anything in to there anyway? If I called some other function of the library some sort of InterruptSetup(); I can't see how making this in to interruptSetup(type argument1, type argument2...); could then get the variables transferred across from the setup function of the library in to a place insidethe interrupt (within which I'd like to minimise instruction cycles needed and SRAM used, hence #define would be perfectif I could get it to work with the right scope).

Thanks

Sorry, you might be right. I have never seen an isr as a class function. So it might simply be impossible. Certainly I cannot help you with that...

Could the isr trigger a flag and could that flag trigger execution of a function inside a class?
Or does the isr really need the mapping?

Boards based on ESP32, ESP8266, and (I believe) STM32 support passing an argument to an ISR. It's supplied in the attach.Interrupt() function as a 'void *'.

It can be done using some template trickery. See This Post.

Also, ESP32, ESP8266, and STM32 support it using std::function.

Sry if this has already been answered.

The mechanism you might be able to use is a callback function. A library can be written so that a user passes it a pointer to a function the user herself writes right there in her *.ino sketch.

Here is an example sketch that uses the Button2 library, which can be set up to call functions in the user's code based on button activities:


The source code for the library is on github. The idea is based on the use of pointers to functions.

a7

I'm coming round to being happy with any solution where I can use a h file to make some shared #defines, some shared variables and some shared arrays. In use the user would edit the h file to change these where needed, and write their ino file, but have no need to edit the cpp file.

So I've been looking at the way cpp, ino and h files work together. And I came across the "extern" keyword.

Part of me thinks this might be able to do what I need, but while most tutorials on the subjects advise that when an array (or othr variable) is to be shard between a library and an ino file using extern they say to put:
extern uint8_t SharedArray[6]={0};
in either the cpp or the ino
uint8_t SharedArray[6]={0};
in the other of the two
and nothing special in the h file.

However this always gives a compiler error of:

/tmp/arduino_build_333152/sketch/test_library.cpp.o (symbol from plugin): In function `test_func(unsigned char)':
(.text+0x0): multiple definition of `SharedArray'
/tmp/arduino_build_333152/sketch/file_name.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino/Genuino Uno.

Unless extern is used in both the cpp and the ino, where no compiler errors results, but with extern used in both places doesn't that mean that the array never gets properly defined at all?

If I try to declare a shared array or variable in the header file then if it is just one header file and an ino file I'm alright, but as soon as both a .ino and a .cpp are including the h file then I get more multiple definition errors, even though thevariable or array's definition is only in the h file.

#define used in the h file seems to work ok for access in both the ino and cpp. But as I'd be #defining a series of operations which would make calls to variables shared between both the ino file and the cpp file I need a way to get the right scope for these.

Any advice appreciated, thanks.

The 'extern' keyword is a means to use the same variable in different .cpp files ( a .ino in the end is also a .cpp file - the IDE does some additions and creates an .cpp from the .ino. The compiler never sees a .ino file ).

You must distinguish between a variable declaration, and a variable definition.

A declaration only tells the compiler that there is a variable with this type and name. But it will not create the variable ( does not assign a ram address for it. This is accomplished by the 'extern' keyword. Because the variable is not really created, you cannot initialize the variable when using the 'extern' keyword. This declaration is done in the .h file, so that in all files that include it this variable is known at compile time.

If you omit the 'extern' keyword, it's a definition ( and of course implicit a declaration ). The compiler creates the variable in ram. That may be done only once - usually in a .cpp file. Otherwise the linker will complain about a multiple definition.

See My Post #5 in this Thread for a basic guide to breaking a large program into .h / .cpp files for better modularity.

In short:
Shared.h:

#ifndef SHARED_H
#define SHARED_H

#include <Arduino.h>
#define ARRAY_SIZE 10

extern uint8_t sharedArray[ARRAY_SIZE];

#endif

Shared.cpp:

#include "Shared.h"

uint8_t sharedArray[ARRAY_SIZE];

.ino file and all other .cpp files:

#include "Shared.h"