This repository has been archived on 2024-01-25. You can view files and clone it, but cannot push or open issues or pull requests.
SummerSchool2-Controller/306-controller_interface.X/xf/xf.c
2023-08-22 09:22:00 +02:00

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);
}
}
}
}