mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 00:44:37 -06:00
* Add sequence dispatcher component * Add seq start port to cmd sequencer * Update author names and some include paths * Get fully compiling, move consts/enums to correct places, check for connections on init * Add spelling exceptions * Get unit tests almost compiling... * Fix string type in port, call component init in test * Fix unit test compilation errors and assertions * Switch back to using StringBase * Switch to FwIndexType, remove textLogIn * UpperCamel events, add warning for unexpected seq start * remove init method, add check for connected to getNextAvailableIdx * Update sdd, change event from low to high, static cast a portnum * Add state diagram, add more warnings, fix wrong header types, use assert instead of warning for runSeq --------- Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
187 lines
7.6 KiB
C++
187 lines
7.6 KiB
C++
// ======================================================================
|
|
// \title SeqDispatcher.cpp
|
|
// \author zimri.leisher
|
|
// \brief cpp file for SeqDispatcher component implementation class
|
|
// ======================================================================
|
|
|
|
#include <Svc/SeqDispatcher/SeqDispatcher.hpp>
|
|
|
|
namespace Svc {
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Construction, initialization, and destruction
|
|
// ----------------------------------------------------------------------
|
|
|
|
SeqDispatcher ::SeqDispatcher(const char* const compName)
|
|
: SeqDispatcherComponentBase(compName) {}
|
|
|
|
SeqDispatcher ::~SeqDispatcher() {}
|
|
|
|
FwIndexType SeqDispatcher::getNextAvailableSequencerIdx() {
|
|
for (FwIndexType i = 0; i < SeqDispatcherSequencerPorts; i++) {
|
|
if (this->isConnected_seqRunOut_OutputPort(i) &&
|
|
this->m_entryTable[i].state == SeqDispatcher_CmdSequencerState::AVAILABLE) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void SeqDispatcher::runSequence(FwIndexType sequencerIdx,
|
|
const Fw::StringBase& fileName,
|
|
Fw::Wait block) {
|
|
// this function is only designed for internal usage
|
|
// we can guarantee it cannot be called with input that would fail
|
|
FW_ASSERT(sequencerIdx >= 0 && sequencerIdx < SeqDispatcherSequencerPorts,
|
|
sequencerIdx);
|
|
FW_ASSERT(this->isConnected_seqRunOut_OutputPort(sequencerIdx));
|
|
FW_ASSERT(this->m_entryTable[sequencerIdx].state ==
|
|
SeqDispatcher_CmdSequencerState::AVAILABLE,
|
|
this->m_entryTable[sequencerIdx].state);
|
|
|
|
if (block == Fw::Wait::NO_WAIT) {
|
|
this->m_entryTable[sequencerIdx].state =
|
|
SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK;
|
|
} else {
|
|
this->m_entryTable[sequencerIdx].state =
|
|
SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK;
|
|
}
|
|
|
|
this->m_sequencersAvailable--;
|
|
this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
|
|
this->m_entryTable[sequencerIdx].sequenceRunning = fileName;
|
|
|
|
this->m_dispatchedCount++;
|
|
this->tlmWrite_dispatchedCount(this->m_dispatchedCount);
|
|
this->seqRunOut_out(sequencerIdx,
|
|
this->m_entryTable[sequencerIdx].sequenceRunning);
|
|
}
|
|
|
|
void SeqDispatcher::seqStartIn_handler(
|
|
NATIVE_INT_TYPE portNum, //!< The port number
|
|
const Fw::StringBase& fileName //!< The sequence file name
|
|
) {
|
|
FW_ASSERT(portNum >= 0 && portNum < SeqDispatcherSequencerPorts, portNum);
|
|
if (this->m_entryTable[portNum].state ==
|
|
SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK ||
|
|
this->m_entryTable[portNum].state ==
|
|
SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK) {
|
|
// we were aware of this sequencer running a sequence
|
|
if (this->m_entryTable[portNum].sequenceRunning != fileName) {
|
|
// uh oh. entry table is wrong
|
|
// let's just update it to be correct. nothing we can do about
|
|
// it except raise a warning and update our state
|
|
this->log_WARNING_HI_ConflictingSequenceStarted(static_cast<U16>(portNum), fileName, this->m_entryTable[portNum].sequenceRunning);
|
|
this->m_entryTable[portNum].sequenceRunning = fileName;
|
|
}
|
|
} else {
|
|
// we were not aware that this sequencer was running. ground must have
|
|
// directly commanded that specific sequencer
|
|
|
|
// warn because this may be unintentional
|
|
this->log_WARNING_LO_UnexpectedSequenceStarted(static_cast<U16>(portNum), fileName);
|
|
|
|
// update the state
|
|
this->m_entryTable[portNum].state =
|
|
SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK;
|
|
this->m_entryTable[portNum].sequenceRunning = fileName;
|
|
this->m_sequencersAvailable--;
|
|
this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
|
|
}
|
|
}
|
|
|
|
void SeqDispatcher::seqDoneIn_handler(
|
|
NATIVE_INT_TYPE portNum, //!< The port number
|
|
FwOpcodeType opCode, //!< Command Op Code
|
|
U32 cmdSeq, //!< Command Sequence
|
|
const Fw::CmdResponse& response //!< The command response argument
|
|
) {
|
|
FW_ASSERT(portNum >= 0 && portNum < SeqDispatcherSequencerPorts, portNum);
|
|
if (this->m_entryTable[portNum].state !=
|
|
SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK &&
|
|
this->m_entryTable[portNum].state !=
|
|
SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_NO_BLOCK) {
|
|
// this sequencer was not running a sequence that we were aware of.
|
|
|
|
// we should have caught this in seqStartIn and updated the state
|
|
// accordingly, but somehow we didn't? very sad and shouldn't happen
|
|
|
|
// anyways, don't have to do anything cuz now that this seq we didn't know
|
|
// about is done, the sequencer is available again (which is its current
|
|
// state in our internal entry table already)
|
|
this->log_WARNING_LO_UnknownSequenceFinished(static_cast<U16>(portNum));
|
|
} else {
|
|
// ok, a sequence has finished that we knew about
|
|
if (this->m_entryTable[portNum].state ==
|
|
SeqDispatcher_CmdSequencerState::RUNNING_SEQUENCE_BLOCK) {
|
|
// we need to give a cmd response cuz some other sequence is being blocked
|
|
// by this
|
|
this->cmdResponse_out(this->m_entryTable[portNum].opCode,
|
|
this->m_entryTable[portNum].cmdSeq, response);
|
|
|
|
if (response == Fw::CmdResponse::EXECUTION_ERROR) {
|
|
// dispatched sequence errored
|
|
this->m_errorCount++;
|
|
this->tlmWrite_errorCount(this->m_errorCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
// all command responses mean the sequence is no longer running
|
|
// so component should be available
|
|
this->m_entryTable[portNum].state = SeqDispatcher_CmdSequencerState::AVAILABLE;
|
|
this->m_entryTable[portNum].sequenceRunning = "<no seq>";
|
|
this->m_sequencersAvailable++;
|
|
this->tlmWrite_sequencersAvailable(this->m_sequencersAvailable);
|
|
}
|
|
|
|
//! Handler for input port seqRunIn
|
|
void SeqDispatcher::seqRunIn_handler(NATIVE_INT_TYPE portNum,
|
|
const Fw::StringBase& fileName) {
|
|
FwIndexType idx = this->getNextAvailableSequencerIdx();
|
|
// no available sequencers
|
|
if (idx == -1) {
|
|
this->log_WARNING_HI_NoAvailableSequencers();
|
|
return;
|
|
}
|
|
|
|
this->runSequence(idx, fileName, Fw::Wait::NO_WAIT);
|
|
}
|
|
// ----------------------------------------------------------------------
|
|
// Command handler implementations
|
|
// ----------------------------------------------------------------------
|
|
|
|
void SeqDispatcher ::RUN_cmdHandler(const FwOpcodeType opCode,
|
|
const U32 cmdSeq,
|
|
const Fw::CmdStringArg& fileName,
|
|
Fw::Wait block) {
|
|
FwIndexType idx = this->getNextAvailableSequencerIdx();
|
|
// no available sequencers
|
|
if (idx == -1) {
|
|
this->log_WARNING_HI_NoAvailableSequencers();
|
|
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
|
|
return;
|
|
}
|
|
|
|
this->runSequence(idx, fileName, block);
|
|
|
|
if (block == Fw::Wait::NO_WAIT) {
|
|
// return instantly
|
|
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
|
|
} else {
|
|
// otherwise don't return a response yet. just save the opCode and cmdSeq
|
|
// so we can return a response later
|
|
this->m_entryTable[idx].opCode = opCode;
|
|
this->m_entryTable[idx].cmdSeq = cmdSeq;
|
|
}
|
|
}
|
|
|
|
void SeqDispatcher::LOG_STATUS_cmdHandler(
|
|
const FwOpcodeType opCode, /*!< The opcode*/
|
|
const U32 cmdSeq) { /*!< The command sequence number*/
|
|
for(FwIndexType idx = 0; idx < SeqDispatcherSequencerPorts; idx++) {
|
|
this->log_ACTIVITY_LO_LogSequencerStatus(static_cast<U16>(idx), this->m_entryTable[idx].state, Fw::LogStringArg(this->m_entryTable[idx].sequenceRunning));
|
|
}
|
|
}
|
|
} // end namespace components
|