Stratagies for code error detection and checking and recovery...

KurtE

Senior Member+
I know the title is sort of vague and also covers a lot of ground.

But wondering what approaches we should take when we are developing (hopefully) reusable code for Teensy and hopefully the more global Arduino system.

There are many parts to this and I also have a feeling that what is easiest for beginners to understand may not always be what advanced users would prefer, but hopefully there is enough common ground.

But for example: working on the DMA code.

There is currently a method: void transferCount(unsigned int len) ;

Now on the T3.x there are cases where the maximum count is 32767 and other cases where the maximum is 511.

Currently the code does a check for > 32767 and just returns doing nothing...

Now what should it do? If I should pass in 65535 for example, the function will silently fail, and then when I start the DMA transfer it will simply try to use whatever was in the field and in many cases the code will just hang or will return with other code expecting that many bytes transferred and did not. Either way not good.

So what should it do? Again trying to think more global.

a) simply remove the tests, as it does not help recover and the programmer should know better.

b) Change code to return something like a bool, so it would return false. Could help, but I bet the return value would not be looked at by 90+% of code.

c) like b) but maybe add either it returns an error code or there is a system error facility, that it would set the last error and return false...

d) Throw some form of exception - Which some code higher up try/catch could handle or not...

There are times where I personally would like something like d) but not sure if it fits with the Arduino world.

Also wish there was a default handler, that would catch most errors probably in main which would maybe try to print out what error happened and maybe a little more info like the address where the fault happened. So for example if you are working on T3.5 and have an 8 bit access to a 32 bit register which faults, it might give you an idea of the fault and where it happened.... But maybe just wishful thinking.

Thoughts?
 
I usually try to implement a simple version of your suggestion d). It is easy to implement and the caller does not need to check each and every function call for errors. If you want to be notified on errors just pass a callback function to the constructor (or to begin if you prefer). The same callback can be used for all classes supporting the error callback.

Code:
//--------------------------------------------------
// Example class 

using errFunc_t = void(*)(int errCode);

class myClass
{
  public:
    myClass(int someParam, errFunc_t f = nullptr)
      : errFunc(f)
    {
      //....
    }

    void doSomething()
    {
      //...
      // ups, something went wrong
      onError(1);
    }


  private:

    void onError(int errCode)
    {
      if (errFunc != nullptr) errFunc(errCode);
    }

    errFunc_t errFunc;
};

//-------------------------------------------------

// this user supplied function will be called in case of an error. 
// in this example it loudly shouts out "Error!" and quits execution
 

void panic(int err)
{
  Serial.printf("Error: %d", err);

  pinMode(LED_BUILTIN, OUTPUT);
  while (1)
  {
    digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    delay(100);
  }
}

//------------------------------------------------
// Simply pass the error callback to the constructor.
// If you don't pass a callback errors will be
// ignored. E.g. after the testing phase.

myClass test(1, panic);

void setup() {
  test.doSomething();
}


void loop() {
}
 
Last edited:
@KurtE. You must be reading error checking in the book :). Anyway I try a bit a error checking the long way in some of my code, but was playing around with micropython and had a case where I used the try-catch method and it worked easier than I could of coded it.

I did just try a test in for the 3.5 with the try-catch method and of course it threw an error but the message basically said to change the compiler flag to -fexceptions. So I changed the flag but then it came back and threw some other errors. So to use try-catch, which I would think would be optimal, there would probably be some effort to getting it to work.

That would leave writing your own error catching routine like luni. Also saw some error checking using switch-case which could be used as well. He also makes a lot of edits for arudino tests in a number of the files I looked at.

Cheers

Postscript: For the heck of it I tried using the StandardCplusplus library and compiled for cout/cerr and it compiled without an issue. I did figure out to it works to get stuff to stream to the serial port though which cout and cerr needs. (look in serstream and iostream.)
 
Last edited:
@luni - Thanks, looks interesting. At least it gives a way to report the errors, Would be interesting to see how it works in practice. I may introduce some of it in my own stuff.

That is if you for example are setting up something like DMA, and the call is maybe 4 or 5 levels deep where it detects that the count is invalid. You call off to your onError which reports the issue, but when that function returns, you are still 5 levels deep in the call, so still need something like bool or error code to be tested and bail at each level? Also maybe each level also calls it's onError as well?

@mjs513 - partially the book ;) :D

But also I just finished debugging the code issue in posting #1 for the 2nd time... Upgrading to beta 2 overwrote my fix, which is still pending And then looking at my fix, I left the check in for > 327767 which simply returns doing nothing.... And I went what's the point...

Also because of a set of postings up on the Arduino Developers mail list, where I am trying to get some consensus to update the SPI interface and have it adopted into other platforms... like a version of SPI.transfer(buf, retbuf, cnt) which is a simple extension of current one that only has one buffer... One of the responses was along the line that all of the Arduino C... is bad and complained about a lot of things including the error stuff. I responded with sort of the question of this thread and had no responses to it.

Also because over the years I have spent a lot of time debugging stuff, that would be a lot easier if there was some simple system support. Example when I was implementing some of the Serial code for T3.5/6 for the new Serial ports, I ran into issues, where the processor would reset, after some trial and error would figure out that I had not enabled access to the Uarts registers... Sure would have been nice if the system caught the error and printed an error to the serial port like: Uncaught fault 5 at <address>
Of course it would be nice if it also maybe gave name to error and maybe could give function name, maybe even a stack trace...

And also partially because of recent emails from Arduino Developers group, about six projects for the near future of Arduino... And wondered if they were going to address this as Arduino has grown to boards and capabilities and wonder if it should be something addressed sooner than later.

---------------------

Back to main thing I was trying (maybe poorly) to ask. what level of support makes sense to build into the Teensy core/libraries and hopefully extend that to Arduino proper?

In the old days another option would be to use something like setjmp/longjmp - but there are lots of issues of not going through the proper unwind of calls (objects going out of scope...)

On my Linux port of code (which I will rework with more modern stuff), My main function also uses signal handling to recover in some cases (sigaction(SIGINT, ...), likewise SIGQUIT, such that if the user hit's ctrl+c my code will detect it. First catch will try to bail cleanly, second catch will bail...

@mjs513 - I also mean to try out the try/catch. I was pretty sure, that additional stuff had to be enabled. I also remember in old days lots of arguments into the merit of it. Does putting in all of the tests and checking failure cause the code to grow more or does the support for try/catch which has to walk up the chain looking for handlers, cause more code... So


But this also does lead to a more generic question, of how much of the modern C++ practices should be used in the Teensy stuff... But maybe I should instead ask that in my other thread: Teach Old Dog New Tricks...

But still wondering!
 
Think the methods you use to catch erorrs is going to be depndendent on whar portion of the code base you are working with. If you are working with the core code you might want to use some tbng like a superclass that would definite key errors (got that one from https://en.m.wikipedia.org/wiki/Exception_handling which is actually good reading). If you are developing library you could probably use more of link's approach (would like to see an example of that, the do something always gets me. In my code maybe a combination of try catch throw and luni's method as well play condition statements.

As to your other question.about how much of modern stuff should be included, think the real question is what has been missing that should get put back in because the mcu is more capable of handling it. Sticking with exceptions, try catch grow had probably around for more than 20 years.

From what I am reading current c++ try catch can increase program size if not careful and can be abused.

Think no matter what we do we will never catch every error. At least that's what I ha e seen over the years.

Guess this is just me rambling. Sorry about that.
 
That is if you for example are setting up something like DMA, and the call is maybe 4 or 5 levels deep where it detects that the count is invalid. You call off to your onError which reports the issue, but when that function returns, you are still 5 levels deep in the call, so still need something like bool or error code to be tested and bail at each level? Also maybe each level also calls it's onError as well?

I think in nearly all cases where you would raise an error you would not want to continue your program anyway. So as in my example above the error function should simply NOT return at all. This assumption makes implementation of such things much easier (I think you can even enforce that with __attribute__(noreturn)). Removing all those errors should be done during debugging.

From a printout in my office: KISS and avoid overengineering :))
 
@luni - you make a good point! There are lots of these errors that are fetal, like passing invalid pin numbers to a display driver...
 
@luni - you make a good point! There are lots of these errors that are fetal, like passing invalid pin numbers to a display driver...

as we have teensies, one could on fatal error enter in a

Code:
pinMode(13,OUTPUT) while(1) {delay(100); digitalWriteFast(13,!digitalReadFast(13));}
mode
 
Yep - I have done something similar to this in the past... Actually I used to have code (different processor, Axon I think), that would blink out the error code number...
 
There is no chance whatsoever that Arduino will use exceptions. The overhead is way too much for AVR or low end ARM (like Teensy LC).

The Teensy toolchain has exceptions disabled and all the libraries are compiled without exception support. You can expect things to break when exceptions try to cross across non-exception code (e.g. a library function calls your exception-throwing code).

A standard error reporting facility would be nice (like 'stderr'). A lot of the time, the caller can't do anything particularly useful when a library error occurs, so error code checking is really just there for debugging purposes (which the error reporting facility would serve just as well).
 
as we have teensies, one could on fatal error enter in a

Code:
pinMode(13,OUTPUT) while(1) {delay(100); digitalWriteFast(13,!digitalReadFast(13));}
mode
I seriously hope, no library will do that. I have used the LED pin as input and using it as output would have been quite unhealthy for the hardware.
 
I seriously hope, no library will do that. I have used the LED pin as input and using it as output would have been quite unhealthy for the hardware.

:confused: pin_13 [ #define LED_BUILTIN (13) ] is designed for output to the Teensy LED?
 
There is no chance whatsoever that Arduino will use exceptions. The overhead is way too much for AVR or low end ARM (like Teensy LC).

The Teensy toolchain has exceptions disabled and all the libraries are compiled without exception support. You can expect things to break when exceptions try to cross across non-exception code (e.g. a library function calls your exception-throwing code).
Thanks, my gut told me that was very likely true. Although it might be nice as an option for larger T3.x boards.

A standard error reporting facility would be nice (like 'stderr'). A lot of the time, the caller can't do anything particularly useful when a library error occurs, so error code checking is really just there for debugging purposes (which the error reporting facility would serve just as well).
I agree and at least at one point I think it was partially setup in the Core3 code to do debug output messages to Serial1, which is a lot easier to do than USB... I have done something like this in my own code before where I define DEBUGSERIAL or the like to some serial port and then have diagnostics go out to there...

As I believe I mentioned earlier, it would be great if we could for debug support build a version of unused_isr
That if a fault happens, it will print out Which fault happened and the location it happened... Maybe if possible include some stack/callback information.
Also if real fancy maybe some of the symbol data saved as part of hex? And give the nearest local name?

If so maybe have Error system that generates an exception? that gets printed if possible?
 
Back
Top