//****************************************************************************
// Product: QF/C++ port to x86, uC/OS-II, Open Watcom, Large model
// Last Updated for Version: 5.1.0
// Date of the Last Update: Sep 30, 2013
//
// Q u a n t u m L e a P s
// ---------------------------
// innovating embedded systems
//
// Copyright (C) 2002-2013 Quantum Leaps, LLC. All rights reserved.
//
// This program is open source software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Alternatively, this program may be distributed and modified under the
// terms of Quantum Leaps commercial licenses, which expressly supersede
// the GNU General Public License and are specifically designed for
// licensees interested in retaining the proprietary status of their code.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// Contact information:
// Quantum Leaps Web sites: http://www.quantum-leaps.com
// http://www.state-machine.com
// e-mail: info@quantum-leaps.com
//****************************************************************************
#include "qf_pkg.h"
#include "qassert.h"
#include // for _dos_setvect()/_dos_getvect()
namespace QP {
Q_DEFINE_THIS_MODULE("qf_port")
// Local objects -------------------------------------------------------------
static void interrupt (*l_dosSpareISR)(void);
//............................................................................
void QF::init(void) {
OSInit(); // initialize uC/OS-II
}
//............................................................................
int16_t QF::run(void) {
// install uC/OS-II context switch vector
l_dosSpareISR = _dos_getvect(uCOS);
_dos_setvect(uCOS, (void interrupt (*)(void))&OSCtxSw);
// NOTE the QF::onStartup() callback must be invoked from the task level
OSStart(); // start uC/OS-II multitasking
return static_cast(0); // return success
}
//............................................................................
void QF::stop(void) {
QF_CRIT_STAT_
QF_CRIT_ENTRY_();
_dos_setvect(uCOS, l_dosSpareISR); // restore the original DOS vector
QF_CRIT_EXIT_();
onCleanup(); // cleanup callback
}
//............................................................................
void QF::thread_(QActive *act) {
while (act->m_thread != 0U) { // loop until cleared in QActive::stop()
QEvt const *e = act->get_(); // wait for event
act->dispatch(e); // dispatch to the active object's state machine
gc(e); // check if the event is garbage, and collect it if so
}
QF::remove_(act); // remove this object from the framework
OSTaskDel(OS_PRIO_SELF); // make uC/OS-II forget about this task
}
//............................................................................
extern "C" void task_function(void *pdata) { // uC/OS-II task signature
QF::thread_(static_cast(pdata));
}
//............................................................................
void QActive::start(uint8_t prio,
QEvt const *qSto[], uint32_t qLen,
void *stkSto, uint32_t stkSize,
QEvt const *ie)
{
m_eQueue = OSQCreate((void **)qSto, qLen);
Q_ASSERT(m_eQueue != (OS_EVENT *)0); // uC/OS-II queue created
m_prio = prio; // set the QF priority
QF::add_(this); // make QF aware of this active object
init(ie); // execute the initial transition
QS_FLUSH(); // flush the trace buffer to the host
uint8_t p_ucos = QF_MAX_ACTIVE - m_prio; // map QF priority to uC/OS-II
INT8U err = OSTaskCreateExt(&task_function, // the task function
this, // the 'pdata' parameter
&(((OS_STK *)stkSto)[(stkSize / sizeof(OS_STK)) - 1]), // ptos
p_ucos, // uC/OS-II task priority
p_ucos, // the unique priority is the task id as well
(OS_STK *)stkSto, // pbos
stkSize/sizeof(OS_STK), // size of the stack in OS_STK units
(void *)0, // pext
(INT16U)OS_TASK_OPT_STK_CLR); // opt
Q_ASSERT(err == OS_NO_ERR); // uC/OS-II task created
m_thread = 1U; // to keep the active object task loop spinning
}
//............................................................................
void QActive::stop(void) {
m_thread = 0U; // stop the active object task loop
INT8U err;
OSQDel(m_eQueue, OS_DEL_ALWAYS, &err); // cleanup the uC/OS-II queue
Q_ASSERT(err == OS_NO_ERR);
}
//............................................................................
#ifndef Q_SPY
bool QActive::post(QEvt const *e, uint16_t const margin)
#else
bool QActive::post(QEvt const *e, uint16_t const margin,
void const *sender)
#endif
{
bool status;
QF_CRIT_STAT_
QF_CRIT_ENTRY_();
uint16_t nFree = static_cast(
((OS_Q_DATA *)m_eQueue)->OSQSize
- ((OS_Q_DATA *)m_eQueue)->OSNMsgs);
if (nFree > margin) {
QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_POST_FIFO, QS::priv_.aoObjFilter, this)
QS_TIME_(); // timestamp
QS_OBJ_(sender); // the sender object
QS_SIG_(e->sig); // the signal of the event
QS_OBJ_(this); // this active object (recipient)
QS_2U8_(e->poolId_, e->refCtr_); // pool Id/ref Ctr of the event
QS_EQC_(0); // number of free entries (unknown)
QS_EQC_(0); // min number of free entries (unknown)
QS_END_NOCRIT_()
if (e->poolId_ != u8_0) { // is it a pool event?
QF_EVT_REF_CTR_INC_(e); // increment the reference counter
}
QF_CRIT_EXIT_();
Q_ALLEGE(OSQPost((OS_EVENT *)m_eQueue, (void *)e) == OS_NO_ERR);
status = true; // return success
}
else {
Q_ASSERT(margin != u16_0); // can tollerate dropping evts?
QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_POST_ATTEMPT, QS::priv_.aoObjFilter,
this)
QS_TIME_(); // timestamp
QS_OBJ_(sender); // the sender object
QS_SIG_(e->sig); // the signal of the event
QS_OBJ_(this); // this active object (recipient)
QS_2U8_(e->poolId_, e->refCtr_); // pool Id/ref Ctr of the event
QS_EQC_(nFree); // number of free entries
QS_EQC_(static_cast(margin)); // margin requested
QS_END_NOCRIT_()
status = false; // return failure
}
QF_CRIT_EXIT_();
return status;
}
//............................................................................
void QActive::postLIFO(QEvt const *e) {
QF_CRIT_STAT_
QF_CRIT_ENTRY_();
QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_POST_LIFO, QS::priv_.aoObjFilter, this)
QS_TIME_(); // timestamp
QS_SIG_(e->sig); // the signal of this event
QS_OBJ_(this); // this active object
QS_2U8_(e->poolId_, e->refCtr_); // pool Id/ref Ctr of the event
QS_EQC_(0); // number of free entries (unknown)
QS_EQC_(0); // min number of free entries (unknown)
QS_END_NOCRIT_()
if (e->poolId_ != u8_0) { // is it a pool event?
QF_EVT_REF_CTR_INC_(e); // increment the reference counter
}
Q_ALLEGE(OSQPost((OS_EVENT *)m_eQueue, (void *)e) == OS_NO_ERR);
QF_CRIT_EXIT_();
}
//............................................................................
QEvt const *QActive::get_(void) {
INT8U err;
QEvt const *e = static_cast(
OSQPend((OS_EVENT *)m_eQueue, 0, &err));
QS_CRIT_STAT_
Q_ASSERT(err == OS_NO_ERR);
QS_BEGIN_(QS_QF_ACTIVE_GET, QS::priv_.aoObjFilter, this)
QS_TIME_(); // timestamp
QS_SIG_(e->sig); // the signal of this event
QS_OBJ_(this); // this active object
QS_2U8_(e->poolId_, e->refCtr_); // pool Id/ref Ctr of the event
QS_EQC_(0); // number of free entries (unknown)
QS_END_()
return e;
}
} // namespace QP