0

I need to use a specific library that issues error messages in the form of String texts. The library uses the Serial.println() function to send the messages to the Arduino IDE's serial monitor.

The problem is that I have the Serial lines from the Arduino linked to another device, therefore I can't use the Serial Monitor to see the messages. I have a method in the Main Arduino sketch that sends any String text msg generated to another device using Udp commands (wireless). This device is connected to a serial monitor unit.

My question is: How can I invoke the Udp method inside the main sketch of the Arduino program from within the aforementioned library? This would help me to convert the Serial.print() text messages from the library directly into Udp messages to be able to visualize them.

The Udp method I'm using is declared as void UdpSend(String msg) in the Arduino sketch. I'd like to use something similar inside the library to wrap the text msg and send it over to the method on the main program.

Any example or link to get this information will help.

EDIT1:

@Majenko,

  1. On the target library, added: void libUdpSend(const char *libMsg);
  2. On the sketch, I added this method (Udp comm handler):

     void libUdpSend(const char *libMsg)
     {
       Udp.begin(localPort);  
       Udp.beginPacket(Udp.remoteIP(), localPort);
       Udp.write(libMsg);    
       Udp.endPacket();   
       delay(40);  
     }
    
  3. Added this line on the library (right after the declaration on 1.) to test through the remote serial interface:

    libUdpSend("String wrapper has been implemented SUCCESSFULLY!");
    

When trying to compile linking the library, the following exception occurrs:

error: expected constructor, destructor, or type conversion before '(' token libUdpSend("String wrapper has been implemented SUCCESSFULLY!");

I then switched to String as this is the type I want to wrap, Same steps:

  1. On the target library, added: void libUdpSend(String *libMsg);
  2. On the sketch:

    void libUdpSend(String *libMsg)
    {
      Udp.begin(localPort);  
      Udp.beginPacket(Udp.remoteIP(), localPort);
      Udp.write(libMsg.c_str());    
      Udp.endPacket();   
      delay(40);  
    }
    

Now the error message says:

request for member 'c_str' in 'libMsg', which is of pointer type 'String*' (maybe you meant to use '->' ?)

I am not an expert on pointers so I'd need some help on how to assign the pointer as argument on the UdpWrite function using the '->' command proposed by the compliler?

Let me know your thoughts on this.

  • I have a simple library for debug messages over Telnet github.com/jandrassy/TelnetStream . it creates an instance which can be used instead of Serial in any source file which includes TelnetStream.h – Juraj Apr 5 at 6:56
  • 2
    send a bug report to the lib creators and say that hardcoding serial for debug output is the wrong thing to do. – ratchet freak Apr 5 at 8:03
2

The connection between a sketch and a library is not one-way as many suppose. Things can go quite happily in both directions.

What you are proposing is something I do quite often when developing a library and I need to get some debugging information out of the library. Yes, it's possible to directly use Serial in the library, but that's something I don't like, and often isn't appropriate anyway, as in your situation.

However, doing it the way you propose (and I use) is actually very simple.

You just make your function in your sketch and tell the library to use it.

For example, in your sketch:

void debug(const char *msg) {
    Serial3.println(msg);
}

And in the library add the line:

void debug(const char *msg);

Then at any point in the same file (or translation unit) you can use

debug("I am here");

That is assuming that the file that you are using it in is a C++ file (.cpp). If it's a C file (.c) then you have to treat things very slightly differently. You see, C++ makes a mess of the function names (even vanilla functions like that) which means they can't be seen by C files. So you have to tell the compiler "I'd like this to be usable in a C file, please".

Which you do with a special "extern" wrapper around your function:

extern "C" {
    void debug(const char *msg) {
        Serial3.println(msg);
    }
}

And then debug() is usable in a C file in the same way as above.

However now it won't work in a C++ file... (round and round we go...)

Simple to fix: add the extern "C" to the prototype in the C++ file:

extern "C" {
    void debug(const char *msg);
}

If you want to include your "extern" in a header file that could be included into either C or C++ files it's very common to use a construct such as:

#if defined(__cplusplus)
extern "C" {
#endif

void debug(const char *msg);

#if defined(__cplusplus)
}
#endif

That will add the extern "C" wrapper for C++ files (identified by the presence of the macro __cplusplus) but omit it for C files.

I have used "const char *" as the parameter for this example, but you can choose whatever parameters are appropriate for your usage.

  • @ Majenko - thx for your answer. I implemented the solution as you proposed it but the compiler is throwing an error generated on the modified library. ``` error: expected constructor, destructor, or type conversion before '(' token libUdpSend("String wrapper has been implemented SUCCESSFULLY!"); ``` I tried to put the code here but the comment section has very limited size. I might send you a bit more of the info via email perhaps?. Any ideas on something in the code I might be missing? The target library is .cpp btw, so no extern C structure needed. Thanks -EZ – Ed Zamper Apr 6 at 3:01
  • Just edit your question and add it there. – Majenko Apr 6 at 6:21
  • See "EDIT 1" in the original question. Thanks! – Ed Zamper Apr 7 at 0:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.