PSAS/ PicCore/ docs/ errors

pic_error.c: Errors handling routines

Introduction

Handling errors on a PIC is no easy thing to do. In fact, it sucks: there's no stdout - the UART is as close as you can get. But often you don't have access to the UART. You've got a single stinkin' LED. Or maybe you have an I2C to serial interface? or just the CAN bus? Who knows, and PicCore certainly doesn't. So the error routines here are meant to log and store errors in a useful way: it's up to the application code to decide what to do with the errors, and get the errors out to the user.

There are two arrays of uint8_t's called piccore_error_log[] and piccore_error_count_log[]. Together, they make a 12 bit status register for each type of error. Think of them as a single an indexed array, where the index is the error number. Meaning, if I log an error #34, piccore_error_log[34] and piccore_error_log[34/2] (more on the divide-by-2 below) is where that fact is stored.

There are two different domains in PicCore: the application and PicCore itself. So the error arrays are divided into two different array's in one: 0 - (n-1) are for your application errors (where there are n application errors), and n - (n+(m-1)) are for PicCore errors (where m is the number of PicCore errors). The reason this is one array broken into two sections (rather than two independent arrays) is that it greatly speeds up the searching and retreiving an error process. But since we've got ROM to burn, there are two seperate logging routines, one for the application (pc_log_error) and one for PicCore (pc_log_pc_error), so that applications can't overwrite PicCore errors by accident (and vice versa).

What's the largest n and m can be? Well, probably around 128 errors all together. Plus or minus. There are only about 32 PicCore errors so far, so there is plenty of room for application errors. Sorry, it's a PIC, not an ARM, so that's all you get. So far, I haven't ever used more than about 20 application errors in any of my applications but maybe that's because I'm an error wimp.

So, you ask, what's stored in the array with the error number as the index?

In the piccore_error_log[] there is:

    000000 00
       |    |
       |     \- 2 bits of error state: 0 (OK, no error) - 3 (Critical error)
       \------- 6 bits of sequence number: 1 - 63

The 6 most significant bits, the error sequence number , is a running count of how many errors have been logged from 1 to 63. It's basically a handy way of discovering what order things happened in. It's automatically generated and incremented when errors are logged by PicCore. Note that it starts from 1 so that we know that error numbers with a sequence number of zero have never been set. And you can clear the sequence if you need to.

The least two significant bits, the error state , is just what you'd expect: a number which indicates how what the state of the error is:

    ERR_STATE_OK         // No error has occurred yet, or the error was cleared.
    ERR_STATE_FLAG       // Something annoying happened; it's recorded here, but may not warrent warning the outside world
    ERR_STATE_WARNING    // Something bad happened; it's recorded here, and you ought to tell the world about it
    ERR_STATE_CRITICAL   // It's the End Of The World As We Know It; record that fact and scream for help.

.. and there are routines to set the state, as you'd expect.

So the byte indexed by the error number gives the error state and the error sequencey number: how bad it is, and when it happened in the sequence of all errors up to 63 errors. This might not be obvious: errors that are not set are 000000 00 = 0. the lowest error number possible is 0000001 01: sequence 1 with ERR_STATE_FLAG set.

So we have the status of each error (in the state) and when it occurred (in the sequence number), but what about how many times that error has occurred? I'm glad you asked! There's another array called pc_error_count_log[] which contains a nibble for every error. So we can count up to 15 for each error number. It's not great, but it gives you an idea of how frquently something is happening. That's where that divide-by-2 comes into play; we're packing nibbles together in bytes.

So, to summarize: the error number points to an entry in an array that contains:

Why do it like this? Well, it turns out it's a handy way to deal with errors when you have limitted means of communcating an error to a user. It's sort of a black board model, if you will: every routine can store information in it, and any routine can read the results out in a time sequential fashion (via the sequence number) or error number fasion (via the going up the array). And there are routines to do just what you expect: clear errors, find the highest error state, clear counts, etc.


Logging Errors

void pclogerror (apperrort, apperrorstatet) // for mainline routines
void pclogerrorlp (apperrort, apperrorstatet) // for low priority interrupt routines>
void pclogerrorhp (apperrort, apperrorstate_t) // for high priority interrupt routines>


Discussion: These are the routines you'd call for logging an error. Why three routines? one for errors that occur in mainline code, one for errors that occur in code called by low priority interrupts, and one for errors that occur in high priority interrupt routines. Remember, PICC18 has three "threads" - main, low priority ints, high priority ints. But since there's no recursion - none whatsoever - the threads can't call any of the same routines. Dumb, huh?

If you call this routine multiple times for a single error, the error count will increase but nothing else will happen unless the error state is larger than was previously logged: i.e., the maximum error is preserved. To clear or downgrade the error, use pc_set_error_state below.
Arguments: app_error_t: that's the application's "error number" found in app_errors.h located in your application's directory. It's a typedef'd enumeration, which picc18 should fit into a uint8_t, which is in the file app_errors.h. Remember, it's really the index into the pc_error_log.
app_error_state_t: this is the error's "state". Again, it's a typedef'd enum (see above).
Returns: Nothing.

Setting Error States

void pcseterrorstate (apperrort, apperrorstatet) // for mainline routines
void pcseterrorstatelp (apperrort, apperrorstatet) // for low priority interrupt routines>
void pcseterrorstatehp (apperrort, apperrorstatet) // for high priority interrupt routines>


Discussion: These are the routines you'd call for setting the state on an error. In general, you'd usually use this to clear an error by setting it's state to ERR_STATE_OK (see intro above). Call this function won't touch the sequence number or the count. Remember, there are three routines for the three threads: mainline code, low priority interrupts and high priority interrupts.
Arguments: app_error_t: that's the application's "error number" found in app_errors.h located in your application's directory. It's a typedef'd enumeration, which picc18 should fit into a uint8_t, which is in the file app_errors.h. Remember, it's really the index into the pc_error_log.
app_error_state_t: this is the error's "state". Again, it's a typedef'd enum (see above).
Returns: Nothing.

Reading Error Information, State, Count, etc.

uint8t pcgeterrorinfo (apperrort) // for mainline routines


Discussion: Returns the byte in the error routine which stores the error status: the 6 bits of the sequence number and the 2 bits of the error state. See introduction above.
Arguments: app_error_t: specifies the error number you want the status of.
Returns: A uint8_t (unsigned char) which has the error information (sequence number and state) in it. To get the count, you need to call pc_get_error_count, see below.

apperrort pcgetnext_error (void) // for mainline routines


Discussion: Steps through the error array from error #0 to #m and returns a single error each time it encounters an error. Thus you get the "next" error in the array.
Arguments: Nothing.
Returns: app_error_t: error number or 0xFF if no error number to return (no error, or hit end of array and starting over).

apperrort pcgeterror_sequence (void) // for mainline routines


Discussion: Steps through the errors in order of the sequence number and returns the next error, thus getting a quasi-chronological error log.
Arguments: Nothing.
Returns: app_error_t: error number or 0xFF if no error number to return (no error, or hit end of array and starting over).

apperrorstatet pcgeterrorstate (void) // for mainline routines


Discussion: Steps through the error array and returns the maximum error state.
Arguments: Nothing.
Returns: app_error_state_t: the maximum error state: currently 0 (ok) - 3 (critical)

uint8t pcgeterrorcount (apperrort) // for mainline routines
uint8t pcgeterrorcountlp (apperrort) // for low priority interrupt routines>
uint8t pcgeterrorcounthp (apperrort) // for high priority interrupt routines>


Discussion: Get the count - the number of times an error has been logged - for a given error number.
Arguments: app_error_t: specifies which error you're interested in.
Returns: uint8_t of the count, but since the count is only a nibble it's 0 - F.

Reseting Errors

void pcclearerror_sequence (void) // for mainline routines


Discussion: Clears the error sequence, the 6 bit count of when an error happened. It clears the sequence number bits in the error array, and then resets the sequence count back to 1.
Arguments: Nothing.
Returns: Nothing.

void pcclearerror_log (void) // for mainline routines


Discussion: Completely clear out all the error arrays. Error sequence, state, and count will all be set to zero.
Arguments: Nothing.
Returns: Nothing.

void pcclearerrorcount (apperrort) // for mainline routines
void pcclearerrorcountlp (apperrort) // for low priority interrupt routines>
void pcclearerrorcounthp (apperror_t) // for high priority interrupt routines>


Discussion: Clear the count of a specified error.
Arguments: app_error_t: specifies which error count you want to clear.
Returns: Nothing.

PicCore Routines

There routines are part of PicCore, and shouldn't be used by the application. But, you need to know they exist since you might have to trace down a PicCore error one day. Note that most of the application routines aren't mirrored for PicCore; PicCore shouldn't be the one determining how to use the errors - that's up to you and your code. But note this: both enums - app_error_t and pc_error_t - are just uint8_t, so you can use the above routines to access PicCore errors as well!

Logging PicCore Errors

void pclogpcerror (pcerrort, pcerrorstatet) // for mainline routines
void pclogpcerrorlp (pcerrort, pcerrorstatet) // for low priority interrupt routines>
void pclogpcerrorhp (pcerrort, pcerrorstatet) // for high priority interrupt routines>


Discussion: Applications can ignore these three routines; they're for logging PicCore errors. There are seperate routines so that the two domains (app/PicCore) can't stomp on each other.
Arguments: pc_error_t: that's piccore's "error number". pc_error_state_t: this is the error's state, OK, flagged, warning, etc.
Returns: Nothing.

Setting PicCore Error States

void pcsetpcerrorstate (pcerrort,pcerrorstatet) // for mainline routines
void pcsetpcerrorstatelp (pcerrort,pcerrorstatet) // for low priority interrupt routines>
void pcsetpcerrorstatehp (pcerrort,pcerrorstate_t) // for high priority interrupt routines>


Discussion: Routines for clearing PicCore errors.
Arguments: app_error_t: that's the PicCore "error number" fournd in pc_errors.h.
Returns: Nothing.

Back