A Library Question

Hello

I am working on a large sketch project with an eye on turning it into a library. I am not ready to turn the sketch to library right now, but I want to include what might be needed into the sketch.

The question I have is there a way to call a user sketch from inside a library . The following code shows what I am talking about

**Library cpp file**

SD.print(Log_Sample_Num)

SD.print(" ,)";

SD.print(Log_Time);

SD.print(" ,");

SD.println(SampleDataString());

**User Sketch file**

String SampleDataString()

{

String ReturnString = “”

if(GPS.fix)

{

RerurnString = GPS.Lat + GPS.Long;

}

else

{

ReturnString = “,,”;

}

// Gentrate the rest of ReturnString

return ReturnString;

}

Thanks for help :slight_smile:

It is not a good idea to use String objects with Arduino. They cause memory problems and program crashes.

Use the far more reliable C-strings (character arrays) and associated C-string manipulation functions, like strlen(), strcat(), etc. instead.

Thanks for the heads up jremington :smiley:

I looked in the Language Reference and I could not find how to use a C-sting variable. I did find how to define a string (char string) I changed the user sketch using the C-strings

User Sketch file

String SampleDataString()

{

chr ReturnString[] = “” <<------------------

if(GPS.fix)

{

RerurnString = GPS_Lat + GPS_Long;

}

else

{

ReturnString = “,,”;

}

// Gentrate the rest of ReturnString

return ReturnString;

}

What do you suggest to use instead the Arduino String objects as used in the above example? Also is there a website or tutorial that explains all the C-strings functions ( with examples if possible)?

I am newbie to programming an coding so please excuse stupid questions.

I could not edit my post

My bad wording

I am newbie to programming an coding so please excuse stupid questions.

Should read:

I am newbie to programming an coding so ny help would be appreciated

I googled “C string tutorial” and the top two hits were the following. They look fine.

https://www.tutorialspoint.com/cprogram … trings.htm

https://www.programiz.com/c-programming/c-strings

I to Googled and found a web page that showed me how to declear the string as a array,

We are getting off topic about a library function calling a user sketch question. Before getting back the topic question I have one last question.

In the following code sinbit I need to add a single char to a string is causing a error

while (Serial.available())
{
char c = Serial.read();
if ( c == ‘\n’)
{
ParseCommand(command);
break;
}
else
{
command = command + c; <<< == Error happens here
}

What would be the proper C-string should it be.

  1. It would be really, really nice if you would explicitly say what “Error happens here” when asking for help. Show actual code with actual errors.

  2. What are the variable types?

  3. The error is that in c/c++ you can’t concatenate a character to anything like that

Sorry about that. The error message is :

Arduino: 1.8.5 (Windows 10), Board: “Arduino M0 Pro (Programming Port)”
H:\DataLogger\DataLogger Software\DataLogger_V4\DataLogger_Prgm_V2.ino\DataLogger_Prgm_V2.ino.ino: In function ‘void loop()’:
DataLogger_Prgm_V2.ino:230: error: incompatible types in assignment of ‘char*’ to ‘char [1]’
command = command + c;
^
Multiple libraries were found for “SD.h”
Used: C:\Program Files (x86)\Arduino\libraries\SD
Not used: C:\Users\Rocke\Documents\Arduino\libraries\arduino_625652
exit status 1
incompatible types in assignment of ‘char*’ to ‘char [1]’
This report would have more information with
“Show verbose output during compilation”
option enabled in File → Preferences.

Again here the code with declared variaable types:

if(USB_Enable && digitalRead(USB_PWR))
{
char command[] = “”; <<< — “command” variable

// Check to see if it’s time to send USB data
if(USB_Enable && RadioTX_Time <= millis()) Serial.println(“,,” + DataStringGen());
// Check for a recived USB command/char
while (Serial.available())
{
char c = Serial.read(); <<== “c” variable
if ( c == ‘\n’)
{
ParseCommand(command);
break;
}
else
{
command = command + c; <<==Error statement
}
}
}

I want to thank you for the great help and suggestions :smiley:

Add a new variable “index” of type int.

Then, instead of

command = command + c;

Use this code

index = strlen(command);
command[index++] = c;
command[index] = '\0';

Just make certain that you declare command large enough to hold all the characters you think will be in the string (char array) plus the null terminator.

:smiley: That did the trick Thanks DanV

Now lets get back to topic question. Is it possible for a library function to call main sketch function? As the sketch sits right now the library will be calling 3 different main sketch functions.

It’s my personal opinion that including a library simply makes the functions in it available anywhere in the program scope.

That pretty much puts them at the same level as the functions and code everywhere in the program.

Could a library function call a main program function? Sure, why not?

But, this kind of precludes the purpose of the library which is usually to build a set of functions that are reusable and can be included in many programs without having to rewrite them.

So, you would likely need to have your function “SampleDataString()” in more any of your programs that you plan to include your library into in order for the compiler to not bitch about the unresolved function call to “SampleDataString()” which is in your library function (whew…).

Why not put “SampleDataString()” in your library?

Now, there are possibilities of having a pointer to a function and then defining it to point to your main sketch function, but that’s beyond the scope of this reply.

As the sketch sits right now the library will be calling 3 different main sketch functions.

I agree with DanV. There is no point in writing a “library” that requires a user’s program to have several different specific functions.

Who else would want to use such a thing, and why?

A library provides useful, frequently needed, well written and well documented functions.

You could look at the main sketch 3 functions as variables used in the library. Like in the following code sample. The library calls SampleDataString() which is defined in the user’s main sketch. This allows the user to define what info they want to be logged onto the SD card. In this example the user wants the GPS info to be the first 2 variables, which are define in the library. All the rest of SD card writing is also done in the library. So the user only has to write code for the 3 different functions (TX_DataString , SampleDataString, and EventStep) every thing else resides in the library.

Library cpp file
SD.print(Log_Sample_Num)
SD.print(" ,)";
SD.print(Log_Time);
SD.print(" ,");
SD.println(SampleDataString());
User Sketch file
String SampleDataString()
{
String ReturnString = “”
if(GPS.fix)
{
RerurnString = GPS.Lat + GPS.Long;
}
else
{
ReturnString = “,,”;
}
// Gentrate the rest of ReturnString
return ReturnString;
Side note:
I am changing the code to use C_Sting code instead of the Arduino String functions.
}

It is easier for the user just to write code to log the data of interest to the SD card, using the reliable, well written and well documented functions provided by the SD library.

… using the reliable, well written and well documented functions provided by the SD library.

Agreed!

But, if it works for you, then all is good.

It’s not the first time I’ve seen this sort of thing and I’m sure it won’t be the last.

DanV addressed my concern in item #3: concatenation.

However if the code you show is really all there is, then it’s working from sheer dumb luck and will eventually crash or cause hard-to-find problems. You need to allocate memory for the command array, not just initialize it to “”

e.g.,

// Declare command buffer for 20 character length
#define COMMAND_BUFFER_LEN 20
char command[COMMAND_BUFFER_LEN ];
// Initialize to all zeros
memset(command, 0, COMMAND_BUFFER_LEN );

While I mostly agree with DanV and jremington, I also slightly disagree - let me explain. What you are effectively asking is can a library use a callback function. When used in a library, a callback function gives the library user the option of modifying some part of the functionality provided by the library. But take note, there are two key words in the previous sentence - “option” and “some”. If you force the user to specify all the behavior of the library, then what’s the point of the library in the first place? I believe this is, to some extent, the point DanV and jremington are making (sorry, if I misread your posts).

In your case, I don’t think you’re forcing the user to specify all of the functionality provided by the library, but I think there are things you could do a little better. It appears to me your library does two things - store a fixed, pre-defined block of data onto an SD card and then store a user defined string after that. So the real functionality your library offers is storing this standard block of data - i.e. the user doesn’t have to “reinvent the wheel” each time they want to do this. The part I think you’re missing, is making the user-defined string, that’s stored after, optional. Right now, anyone that uses your library as is and forgets to define SampleDataString() will get compile errors. This will happen even if all they care about is storing the standard block of data. What I would recommend is having your library (weakly) define SampleDataString() to provide a default string (or no string), then if the user wants, they can override your definition of SampleDataString() with their own. If your library defines a class that the user instantiates, you can do this another way by having a constructor that takes a function pointer as an argument, stores it, and then your library uses this pointer to “call back” to the user code when the time is right.

As an example, look at the Arduino IDE’s use of the serialEvent() function. In the main program loop that the IDE creates, after it calls your loop() function, it then checks if serialEventRun is defined (which will be if you include HardwareSerial.h), and if so calls serialEventRun() which in turn calls serialEvent() whenever serial data is available. By default this function is weakly defined in HardwareSerial.cpp to do nothing, but the weak attribute, attribute((weak)), allows the user, in their sketch, to override this function, if they wish. So the Arduino IDE, a library of sorts (if you allow me to view it that way), provides the core functionality we all know and love - call setup() then repeatedly call loop() - as well as additional, and optional, functionality of alerting the user whenever serial data is available. To use this additional functionality, though, requires the user to define the serialEvent() function.

Anyway, I hope this helps or perhaps provides some alternate vantage point.

Mike

The project is for a high power rocketry flight computer . The library is all the core code to read the sensors (Acc,Alt,GPS, ETC) along with logging the info to the SD card and sending Radio data. I am just tiring to make it as simple as possible to the end user,

As of right now ( work in process) the core code is over 1000 lines of code. Having the user to copy or enter the core code will lead to a lot of typos and/or syntax errors. So placing all the core code into library means the user does not have to create a sketch to do the core operations and only needs to write the code for the required functions. Thus making the user sketch more reliable and easy to use (not mentioning easier to debug).