Sharing a solution for handling timeout when using a ressource (channel, ports) that might be blocking the processor because its condition is not ready. This could be a channel waiting a token or accessing a port (in or out) which is triggered by a clock not available.
the select statement gives lot of possibilities with its "default" case, but I could not find a solution for ports, so here is a possible implementation with an friendly integration within a "if" statement (like setjump/longjump library).
Three routines are needed to set, test and clear the timer in charge of the timeout:
timeout_setEvent is used to prepare the timer ressource to generate the event after a given delay (in number of ticks)
timeout_running is organised so that it can be used as a condition of an "if" statement. it contains mechanism to save and restore the stack pointer in case the "if (true)" code is more complex than just accessing the port, but this is not recommended as no-one can say exactly what the compiler will generate.
timeout_clearAllEvents should be used immediately after the code accessing the blocking resource.
Code: Select all
static inline void timeout_setEvent(timer tmr, int delay) {
asm volatile (
"\n\t gettime r11" // get time
"\n\t add r11,r11,%1" // add given delay
"\n\t setd res[%0], r11" // set timer target value
"\n\t setc res[%0], 9" // set timer event condition after
: : "r"(tmr),"r"(delay):"r11" ); //return result
}
static inline unsigned timeout_running(timer tmr) {
unsigned result;
asm volatile (
"\n\t ldap r11, .Levent%=" // get address of temporary label below
"\n\t setv res[%1], r11 " // set resource vector address
"\n\t ldaw r11,sp[0]" // get stack pointer value
"\n\t setev res[%1], r11" // set environement vector to SP
"\n\t ldc %0, 1" // result will be 1
"\n\t eeu res[%1]" // enable timer resource event
"\n\t setsr 1" // enable any events in our thread
"\n\t bu .Lexit%=" // end ( go back to "if" statement )
"\n .Levent%=:" // event entry point
"\n\t get r11, ed" // get exception data register which is the SP value set with setev
"\n\t set sp, r11" // restore stack pointer
"\n\t ldc %0, 0" // result forced to 0
"\n .Lexit%=:" // exit point
: "=r"(result) : "r"(tmr) : "r11" ); //return result
return result;
}
static inline void timeout_clearAllEvents() {
asm volatile("clre");
}
a typical example:
Code: Select all
timer tmr;
timeout_setEvent(tmr,500000000);
int val = 0;
if ( timeout_running(tmr) ) {
//code for accessing the blocking resource
myport :> val;
//clear events imediatelly after getting port value
timeout_clearAllEvents();
//some basic treatment can continue here but preferably outside of the "if"
} else {
// timeout event is raised and can be managed here
}
fabriceo