How to call function if needed, which may but not must be declared elsewhere?

I make my own softserial based on TIM2, then I moved it to separate mojserial.cpp and mojserial.h file, included in main.cpp and it works.

Now I want make a call in mojserial.cpp file in byte_been_recived (for example) function to other function which maybe or may be not deffinied (let's say recv_callback() ) it maybe used/defined in main.cpp and I want make it so it compiles with or without usage of recv_callback().

How should I write this?

//main.cpp
#include "mojserial.h"

setup(){};

loop {};

recv_callback()  //what about types like void here?
{
  digitalWrite(BUILTIN_LED,1);
}

//mojserial.cpp
...
void byte_been_recived()
{
...
if (some_condition) recv_callback();  //how to declare it? should I also add it to .h file?

}

the call to revc_callback() in mojserial.cpp requires a declaration of that function in mojserial.cpp. i don't believe you want mojserial.cpp to be dependent on an external function, in that way.

you could add a function to mojserial.cpp that passes a callback function ptr to mojserial.cpp, which if set, can be called in mojserial.cpp

consider the following output produced by the code below

byte_been_received
byte_been_received
myCallback

mojserial.h

void mojSerialCallback (void (*f) (void));
void byte_been_received (void);

mojserial.cpp

#include <Arduino.h>
#include "mojserial.h"

void (*callback) (void);
bool  some_condition  = true;

void
mojSerialCallback (
    void (*f) (void))
{
    callback = f;
}

void byte_been_received()
{
    Serial.println (__func__);
    if (* callback)
        if (some_condition)
            (*callback) ();
}

.ino

#include "mojserial.h"

void
myCallback (void)
{
    Serial.println (__func__);
}

void
setup (void) 
{
    Serial.begin (9600);

    byte_been_received ();

    mojSerialCallback (myCallback);
    byte_been_received ();
}

void loop() {
}
1 Like

Every function, that you call must be declared e.g. in your mojserial.cpp. Otherwise the compiler does not know how to call it.
But you can declare it with the attribute 'weak' like this:

int recv_callback() __attribute__ ((weak));

In this case the linker will not complain if it is not defined. But before calling this function, you must check if it exists:

if ( recv_callback ) val = recv_callback();

1 Like

Or, I think, you can declare a default one in your library and that one will be used if the linker can't find a global one:

int recv_callback()  __attribute__ ((weak));
int recv_callback()  {return 0}
1 Like

Thank you all for your answers.
@gcjr I don't know if I describe this well, but function byte_been_received() is called by ISR so I don't want to call it from setup(). I want to make something like library (or just 2 files which I can include in other projects) And have ability to "extend" this interrupt subroutine. Something like event handler. So I do my job in byte_been_received() triggered by interrupt and if user (programmer) declared recv_callback() in main.cpp or other place - call it. If not declared - it's fine.
But I see from your answer then I can make (global) variable for function pointer, and set it up to address of recv_callback() declared in main.cpp and call it if pointer != null, thanks!

MicroBahner and johnwasser (mention restrictions, sorry) I think this is what I want. I make default empty function with (weak) attribute and if someone declare it elsewhere it do the job, if not, there will be no errors.

ps. How I can post nice colored syntax? I use "formatted text" button and I don't see "code" tag/button here?
ps2. Why weak word have two brackets?

That's the syntax of __attribute__

Use the code button </> at the top of your editor. With multiline code it is colored then.

1 Like

Another weekend came and I did some testing.
Because my function ( recv_callback()) is called from interrupt I have problem with using Serial.print functions in it - they are two slow and disrupted timing. But changing LED_BUILTIN status work fine.

I must declare it in mojserial.h as weak. If I don't define it anywhere else it will compile without errors but doesn't work. Probably execute some random code :slight_smile: If I define it in mojserial.cpp as empty body it works fine, and if I add definition in main.cpp it switch automagicaly to execute code from main.cpp.

I also read there are some problem with weak symbols: Weak symbol - Wikipedia and c - GCC behavior for unresolved weak functions - Stack Overflow

Typically, an ISR will add data to a buffer and exit. When the code gets back to loop() it will check for data in the buffer. That way the slow stuff is not being done in the ISR. For example, Serial is interrupt driven: there is an interrupt when a character arrives. The ISR puts the received character in a buffer and Serial.available() checks to see how many characters are in the buffer.

Sure, I just wanted to pass byte from my serial to hardware serial for testing.
My "lib" also set flags which may be tested and handled in main loop and it work.
I send AT\r\n to modem by my serial and he respond me OK, and when there is a byte avaliable from my serial I sent it to terminal via Serial.write() in main loop;