292 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /******************************************************************************/
 | |
| /* FILENAME	: xf.h                                                            */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* GOAL		  : Offers the femto XF functions (for PIC CPU)                     */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* AUTHOR   : Medard Rieder / Pascal Sartoretti                               */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* DATE:    : original (Medard Rieder 08.2011)                                */
 | |
| /*            corrections & simplified (Pascal Sartoretti 06.2016)            */
 | |
| /******************************************************************************/
 | |
| #include <stdbool.h>              // boolean types
 | |
| #include "xf.h"
 | |
| #include "../mcc_generated_files/mcc.h"
 | |
| 
 | |
| /*
 | |
|  * private methods of the XF
 | |
|  */
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Push an event on the events queue                           */
 | |
| /* INPUT        : ev - the event number (not 0)                               */
 | |
| /*                inISR - (true if called in an ISR, else false)              */
 | |
| /* OUTPUT       : return false if the queue was full, else true               */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| bool XF_pushEvent(Event ev, bool inISR, TimerID* tmid);
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Pop an event on the events queue                            */
 | |
| /* INPUT        : inISR - (true if called in an ISR, else false)              */
 | |
| /* OUTPUT       : return the next waiting event if any, else 0                */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| Event XF_popEvent(bool inISR);
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Post a timer in timers queue                                */
 | |
| /* INPUT        : tm - time before event arrives                              */
 | |
| /*                ev - event to post                                          */
 | |
| /*                inISR - (true if called in an ISR, else false)              */
 | |
| /* OUTPUT       : return the timer Id used                                    */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| TimerID XF_scheduleTimer(Time tm, Event ev, bool inISR);
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Switch of the interrupts                                    */
 | |
| /* INPUT        : inISR - (true if called in an ISR, else f                   */
 | |
| /* OUTPUT       : none                                                        */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| static void ENTERCRITICAL(bool inISR);
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Switch on the interrupts                                    */
 | |
| /* INPUT        : inISR - (true if called in an ISR, else f                   */
 | |
| /* OUTPUT       : none                                                        */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| static void LEAVECRITICAL(bool inISR);
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * the XF instance
 | |
|  */
 | |
| XF theXF;      // really the XF
 | |
| 
 | |
| 
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Init the XF structure                                       */
 | |
| /* INPUT        : -                                                           */
 | |
| /* OUTPUT       : -                                                           */
 | |
| /* COMMENTS     : Have to be called once                                      */
 | |
| /******************************************************************************/
 | |
| void XF_init()
 | |
| {
 | |
|     int i;
 | |
|     for (i=0; i<MAXEVENT; i++)
 | |
|     {
 | |
|         Event_init(&(theXF.eventQueue[i]));
 | |
|     }
 | |
| 
 | |
|     for (i=0; i<MAXTIMER; i++)
 | |
|     {
 | |
|         theXF.timerList[i].tm = NULLTIMER;
 | |
|         Event_init(&(theXF.timerList[i].ev));
 | |
|     }
 | |
|     theXF.in = 0;
 | |
|     theXF.out = 0;
 | |
| }
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Push an event on the events queue                           */
 | |
| /* INPUT        : ev - the event number (not 0)                               */
 | |
| /*                inISR - (true if called in an ISR, else false)              */
 | |
| /* OUTPUT       : return false if the queue was full, else true               */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| bool XF_pushEvent(Event ev, bool inISR, TimerID* tmid)
 | |
| {
 | |
|     uint8_t temp;
 | |
|     Time tm;
 | |
|     tm = Event_getDelay(&ev); 
 | |
|     if ( tm > 0)
 | |
|     {
 | |
|         Event_setDelay(&ev,0);
 | |
|         *tmid = XF_scheduleTimer(tm, ev, inISR);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         ENTERCRITICAL(inISR);
 | |
| 
 | |
|         temp = (theXF.in+1) % (uint8_t)(sizeof(theXF.eventQueue) / sizeof(Event));
 | |
|         if(temp == theXF.out)
 | |
|         {      
 | |
|           LEAVECRITICAL(inISR);
 | |
|           return false;
 | |
|         }
 | |
|         theXF.eventQueue[theXF.in] = ev;
 | |
|         theXF.in = temp;
 | |
|         LEAVECRITICAL(inISR);
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Pop an event on the events queue                            */
 | |
| /* INPUT        : inISR - (true if called in an ISR, else false)              */
 | |
| /* OUTPUT       : return the next waiting event if any, else 0                */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| Event XF_popEvent(bool inISR)
 | |
| {
 | |
|     Event ev;
 | |
|     ev.id = NULLEVENT;
 | |
|     ev.target = NULL;
 | |
|     ev.processEvent = NULL;
 | |
| 
 | |
|     ENTERCRITICAL(inISR);
 | |
|     if(theXF.in == theXF.out)
 | |
|     {
 | |
|       LEAVECRITICAL(inISR);
 | |
|       return ev;
 | |
|     }
 | |
|     ev = theXF.eventQueue[theXF.out];
 | |
|     theXF.out = (theXF.out + 1)%(uint8_t)(sizeof(theXF.eventQueue) / sizeof(Event));
 | |
|     LEAVECRITICAL(inISR);
 | |
|     return ev;    
 | |
| }
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Post a timer in timers queue                                */
 | |
| /* INPUT        : tm - time before event arrives                              */
 | |
| /*                ev - event to post                                          */
 | |
| /*                inISR - (true if called in an ISR, else false)              */
 | |
| /* OUTPUT       : return the timer Id used                                    */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| TimerID XF_scheduleTimer(Time tm, Event ev, bool inISR)
 | |
| {
 | |
|     uint8_t i;
 | |
| 
 | |
|     ENTERCRITICAL(inISR);
 | |
|     for (i=0; i<MAXTIMER; i++)
 | |
|     {
 | |
|         if (theXF.timerList[i].ev.id == NULLEVENT)
 | |
|         {
 | |
|             theXF.timerList[i].tm = tm;
 | |
|             theXF.timerList[i].ev = ev;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //here you could react
 | |
|     //if timerlist is full
 | |
| 
 | |
|     LEAVECRITICAL(inISR);
 | |
|     return i;
 | |
| }
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Remove a timer in timers queue                              */
 | |
| /* INPUT        : id - the timer id to remove                                 */
 | |
| /*                inISR - (true if called in an ISR, else false)              */
 | |
| /* OUTPUT       : -                                                           */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| void XF_unscheduleTimer(TimerID id, bool inISR)
 | |
| {
 | |
|     ENTERCRITICAL(inISR);
 | |
|     theXF.timerList[id].tm = NULLTIMER;
 | |
|     Event_init(&(theXF.timerList[id].ev)); 
 | |
|     LEAVECRITICAL(inISR);
 | |
| }
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Decrement timers to post events if time elapsed             */
 | |
| /* INPUT        : -                                                           */
 | |
| /* OUTPUT       : -                                                           */
 | |
| /* COMMENTS     : This function has to be called from the timer ISR           */
 | |
| /******************************************************************************/
 | |
| void XF_decrementAndQueueTimers()
 | |
| {
 | |
|     uint8_t i;
 | |
|     for (i=0; i<MAXTIMER; i++)
 | |
|     {
 | |
|         if (theXF.timerList[i].ev.id != NULLEVENT)
 | |
|         {
 | |
|             theXF.timerList[i].tm-=TICKINTERVAL;
 | |
|             if (theXF.timerList[i].tm ==0)
 | |
|             {
 | |
|                 TimerID dummy;
 | |
|                 if (XF_pushEvent(theXF.timerList[i].ev, true, &dummy) == true)
 | |
|                 {  
 | |
|                   XF_unscheduleTimer(i, true);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                   theXF.timerList[i].tm=1;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //here you could use done to react
 | |
|     //if timerID was not found (done == 0)
 | |
| }
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Lock interrupts if not in ISR                               */
 | |
| /* INPUT        : -                                                           */
 | |
| /* OUTPUT       : -                                                           */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| static void ENTERCRITICAL(bool inISR)
 | |
| {
 | |
|     if (inISR == false)
 | |
|     {
 | |
|       //GIE = 0;
 | |
|       INTERRUPT_GlobalInterruptDisable();
 | |
|     }
 | |
| }
 | |
| 
 | |
| /******************************************************************************/
 | |
| /* FUNCTION     : Unlock interrupts if not in ISR                             */
 | |
| /* INPUT        : -                                                           */
 | |
| /* OUTPUT       : -                                                           */
 | |
| /* COMMENTS     : -                                                           */
 | |
| /******************************************************************************/
 | |
| static void LEAVECRITICAL(bool inISR)
 | |
| {
 | |
|     if (inISR == false)
 | |
|     {
 | |
|       //GIE = 1;
 | |
|      INTERRUPT_GlobalInterruptEnable();   
 | |
|     }
 | |
| }
 | |
| 
 | |
| TimerID POST(void* target, processEventT processEvent, uint8_t id, Time delay , int64_t data)
 | |
| {
 | |
|     TimerID tmid = MAXTIMER;  //this is to say that no timer has been scheduled
 | |
|                               //is a timer has been scheduled, the ID will be 
 | |
|                               //from 0 to MAXTIMER-1
 | |
|     Event ev;
 | |
|     Event_init(&ev);
 | |
|     Event_setTarget(&ev,target);
 | |
|     Event_setPE(&ev,processEvent);
 | |
|     Event_setId(&ev,id);
 | |
|     Event_setDelay(&ev,delay);
 | |
|     Event_setData(&ev,data);
 | |
|     XF_pushEvent(ev,false,&tmid);
 | |
|     return tmid;
 | |
| }
 | |
| 
 | |
| void XF_executeOnce()
 | |
| {
 | |
|     Event ev = XF_popEvent(false);
 | |
|     //if this event is valid
 | |
|     if (ev.id != NULLEVENT)
 | |
|     {
 | |
|         //if this event has a valid target
 | |
|         if (ev.target != NULL)
 | |
|         {
 | |
|             //if this event has a valid state machine
 | |
|             //function pointer
 | |
|             if (ev.processEvent != NULL)
 | |
|             {
 | |
|                 //call the state machine method function 
 | |
|                 //and pass the event as parameter
 | |
|                 ev.processEvent(&ev);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| } |