You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
5.5 KiB
C
159 lines
5.5 KiB
C
/*****************************************************************************
|
|
* Active Object pattern implementation based on uC/OS-II (uC/AO)
|
|
*
|
|
* Q u a n t u m L e a P s
|
|
* ------------------------
|
|
* Modern Embedded Software
|
|
*
|
|
* Copyright (C) 2020 Quantum Leaps, LLC. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: APACHE-2.0
|
|
*
|
|
* This software is distributed by Quantum Leaps, LLC under the terms of
|
|
* Apache License Version 2.0, which is the same license used for uC/OS-II RTOS.
|
|
* The text of the license is available at: www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
* Contact information:
|
|
* <www.state-machine.com>
|
|
* <info@state-machine.com>
|
|
*****************************************************************************/
|
|
#include "uc_ao.h" /* uC/AO interface */
|
|
|
|
Q_DEFINE_THIS_MODULE("uc_ao") /* this module name for Q_ASSERT() */
|
|
|
|
/*..........................................................................*/
|
|
void Active_ctor(Active * const me, DispatchHandler dispatch) {
|
|
me->dispatch = dispatch; /* attach the dispatch handler for the "me" AO */
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
/* Thread function for all Active Objects (uC/OS-II task signature) */
|
|
static void Active_eventLoop(void *pdata) {
|
|
Active *me = (Active *)pdata; /* the AO instance "me" */
|
|
|
|
/* initialize the AO */
|
|
static Event const initEvt = { INIT_SIG };
|
|
(*me->dispatch)(me, &initEvt);
|
|
|
|
/* event loop ("message pump") */
|
|
while (1) {
|
|
Event *e; /* pointer to event object ("message") */
|
|
INT8U err; /* uC/OS-II error status */
|
|
|
|
/* wait for any event and receive it into object 'e' */
|
|
e = OSQPend(me->queue, 0U, &err); /* BLOCKING! */
|
|
Q_ASSERT(err == 0U);
|
|
|
|
/* dispatch event to the active object 'me' */
|
|
(*me->dispatch)(me, e); /* NO BLOCKING! */
|
|
}
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
void Active_start(Active * const me,
|
|
uint8_t prio, /* priority (1-based) */
|
|
Event **queueSto,
|
|
uint32_t queueLen,
|
|
void *stackSto,
|
|
uint32_t stackSize,
|
|
uint16_t opt)
|
|
{
|
|
INT8U err;
|
|
OS_STK *stk_sto = stackSto;
|
|
INT32U stk_depth = (stackSize / sizeof(OS_STK));
|
|
|
|
/* precondition */
|
|
Q_ASSERT(me /* AO instance must be provided (cannot be NULL) */
|
|
&& (0 < prio) && (prio < OS_LOWEST_PRIO - 2U));
|
|
|
|
me->queue = OSQCreate((void **)queueSto, queueLen);
|
|
Q_ASSERT(me->queue); /* queue must be created */
|
|
|
|
me->thread = OS_LOWEST_PRIO - 2U - prio; /* uC/OS-II priority */
|
|
err = OSTaskCreateExt(
|
|
&Active_eventLoop, /* the thread function */
|
|
me, /* the 'pdata' parameter */
|
|
#if OS_STK_GROWTH
|
|
&stk_sto[stk_depth - 1], /* ptos */
|
|
#else
|
|
stk_sto, /* ptos */
|
|
#endif
|
|
me->thread, /* uC/OS-II priority */
|
|
prio, /* task ID -- the unique AO priority */
|
|
stk_sto, /* pbos */
|
|
stk_depth, /* stack depth */
|
|
(void *)0, /* pext */
|
|
opt); /* task options */
|
|
Q_ASSERT(err == 0U); /* thread must be created */
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
void Active_post(Active * const me, Event const * const e) {
|
|
OSQPost(me->queue, (void *)e);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* Time Event services... */
|
|
|
|
static TimeEvent *l_tevt[10]; /* all TimeEvents in the application */
|
|
static uint_fast8_t l_tevtNum; /* current number of TimeEvents */
|
|
|
|
/*..........................................................................*/
|
|
void TimeEvent_ctor(TimeEvent * const me, Signal sig, Active *act) {
|
|
#if OS_CRITICAL_METHOD == 3
|
|
OS_CPU_SR cpu_sr;
|
|
#endif
|
|
|
|
/* no critical section because it is presumed that all TimeEvents
|
|
* are created *before* multitasking has started.
|
|
*/
|
|
me->super.sig = sig;
|
|
me->act = act;
|
|
me->timeout = 0U;
|
|
me->interval = 0U;
|
|
|
|
/* register one more TimeEvent instance */
|
|
OS_ENTER_CRITICAL();
|
|
Q_ASSERT(l_tevtNum < sizeof(l_tevt)/sizeof(l_tevt[0]));
|
|
l_tevt[l_tevtNum] = me;
|
|
++l_tevtNum;
|
|
OS_EXIT_CRITICAL();
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
void TimeEvent_arm(TimeEvent * const me, uint32_t timeout, uint32_t interval) {
|
|
#if OS_CRITICAL_METHOD == 3
|
|
OS_CPU_SR cpu_sr;
|
|
#endif
|
|
OS_ENTER_CRITICAL();
|
|
me->timeout = timeout;
|
|
me->interval = interval;
|
|
OS_EXIT_CRITICAL();
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
void TimeEvent_disarm(TimeEvent * const me) {
|
|
#if OS_CRITICAL_METHOD == 3
|
|
OS_CPU_SR cpu_sr;
|
|
#endif
|
|
OS_ENTER_CRITICAL();
|
|
me->timeout = 0U;
|
|
OS_EXIT_CRITICAL();
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
void TimeEvent_tick(void) {
|
|
uint_fast8_t i;
|
|
for (i = 0U; i < l_tevtNum; ++i) {
|
|
TimeEvent * const t = l_tevt[i];
|
|
Q_ASSERT(t); /* TimeEvent instance must be registered */
|
|
if (t->timeout > 0U) { /* is this TimeEvent armed? */
|
|
if (--t->timeout == 0U) { /* is it expiring now? */
|
|
Active_post(t->act, &t->super);
|
|
t->timeout = t->interval; /* rearm or disarm (one-shot) */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|