Suggestion: Make error(...) a weak function

28 Mar 2014

Hey guys! I'm working on a project that will hopefully make it's way into production at some point, so I need a way to override the default error(...) macro (and maybe exit() too while I'm at it) to stop it from spitting stuff out on the UART in a production design. In my case, the UART pins are being used for other things, so using them would be potentially destructive. Additionally, I'd like to be able to override these functions without having to modify the mbed libraries, making future library updates easier to implement.

Now, I noticed that mbed_die() is already weakly linked, making it easy to replace in the project code. Therefore, my proposal is to replace the error(...) macro with a weakly linked function. That would also give me the ability to capture any error text and redirect it somewhere else for later discovery by a desktop application. I realize I could accomplish this by creating a custom Stream class that redirects stderr, but since not all targets have DEVICE_STDIO_MESSAGES enabled (in my case the LPC11U35 doesn't, for good reason), this is a fragile solution.

A weakly linked exit() would also be nice to have, as my device is going to be battery powered. As such, exit() will need to ensure that the regulator enable pin gets pulled down if the code ever exits unexpectedly, otherwise the device will get stuck turned on until the battery dies.

31 Mar 2014

I just submit a pull request on GitHub that changes the error(...) definiton to a weak function. Using the modified library, overriding error is now possible for any target, regardless of whether or not DEVICE_STDIO_MESSAGES is enabled. The syntax is like so:

main.cpp

#include <stdarg.h>
#include "mbed.h"

DigitalOut myled(LED1);

//Custom override for error()
void error(const char* format, ...) {
    char sprintf_buffer[128];
    
    va_list arg;
    va_start(arg, format);
    vsprintf(sprintf_buffer, format, arg);
    va_end(arg);
    
    fprintf(stderr, "Custom error: %s", sprintf_buffer);
}

int main()
{
    error("Boom %i!\n", 123);

    while(1) {
        myled = 1;
        wait(0.2);
        myled = 0;
        wait(0.2);
    }
}


Note that in this case I didn't call exit(1) in my custom error function. Normally, this would have to be done since the system is in an unknown state at this point.

31 Mar 2014

Seems like a good option. And while often the goal would be calling exit, I definately see options to not do it:

Option 1 would be reading the error string: not intended for that, but it does allow you to differentiate between error sources and depending on the error do something else than locking up the microcontroller. As random example, if you have a sensor network you could transmit one last package with an error code, and after that calling exit. Or for example changing the blink pattern depending on the error you got.

Option 2 would be not locking up the microcontroller, but instead forcing a software reset (possibly after logging the error somewhere).

31 Mar 2014

Erik - wrote:

Seems like a good option. And while often the goal would be calling exit, I definately see options to not do it:

Option 1 would be reading the error string: not intended for that, but it does allow you to differentiate between error sources and depending on the error do something else than locking up the microcontroller. As random example, if you have a sensor network you could transmit one last package with an error code, and after that calling exit. Or for example changing the blink pattern depending on the error you got.

Option 2 would be not locking up the microcontroller, but instead forcing a software reset (possibly after logging the error somewhere).

Option 3 would be to save a crash report to the built-in EEPROM for later discovery by a desktop application that could phone it home. (this is what I'm hoping to do with it)

31 Mar 2014

But then you would still call exit(1) in the end ;). And I see some cases where you either want a custom exit pattern, or not exitting at all. Anyway, the pull request does allow the user to make it happen.

First I also wondered why you required extra includes in the serial_api files, but then I saw it got those originally from including error,h, that was also pretty bad.

31 Mar 2014

Erik - wrote:

But then you would still call exit(1) in the end ;). And I see some cases where you either want a custom exit pattern, or not exitting at all. Anyway, the pull request does allow the user to make it happen.

Right, sorry!