F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
ActiveComponentBase.cpp
Go to the documentation of this file.
1 #include <FpConfig.hpp>
3 #include <Fw/Types/Assert.hpp>
4 #include <Os/TaskString.hpp>
5 #include <cstdio>
6 
7 //#define DEBUG_PRINT(...) printf(##__VA_ARGS__); fflush(stdout)
8 #define DEBUG_PRINT(...)
9 
10 namespace Fw {
11 
13 
14  public:
16  return sizeof(m_buff);
17  }
18 
20  return m_buff;
21  }
22 
23  const U8* getBuffAddr() const {
24  return m_buff;
25  }
26 
27  private:
28 
30 
31  };
32 
34 
35  }
36 
38  DEBUG_PRINT("ActiveComponent %s destructor.\n",this->getObjName());
39  }
40 
42  QueuedComponentBase::init(instance);
43  }
44 
45 #if FW_OBJECT_TO_STRING == 1 && FW_OBJECT_NAMES == 1
46  void ActiveComponentBase::toString(char* buffer, NATIVE_INT_TYPE size) {
47  FW_ASSERT(size > 0);
48  FW_ASSERT(buffer != nullptr);
49  PlatformIntType status = snprintf(buffer, static_cast<size_t>(size), "ActComp: %s", this->m_objName.toChar());
50  if (status < 0) {
51  buffer[0] = 0;
52  }
53  }
54 #endif
55 
57  Os::TaskString taskName;
58 
59 #if FW_OBJECT_NAMES == 1
60  taskName = this->getObjName();
61 #else
62  char taskNameChar[FW_TASK_NAME_BUFFER_SIZE];
63  (void)snprintf(taskNameChar,sizeof(taskNameChar),"ActComp_%d",Os::Task::getNumTasks());
64  taskName = taskNameChar;
65 #endif
66  // Cooperative threads tasks externalize the task loop, and as such use the state machine as their task function
67  // Standard multithreading tasks use the task loop to respectively call the state machine
68  Os::Task::taskRoutine routine = (m_task.isCooperative()) ? this->s_taskStateMachine : this->s_taskLoop;
69  Os::Task::Arguments arguments(taskName, routine, this, priority, stackSize, cpuAffinity, static_cast<PlatformUIntType>(identifier));
70  Os::Task::Status status = this->m_task.start(arguments);
71  FW_ASSERT(status == Os::Task::Status::OP_OK,static_cast<NATIVE_INT_TYPE>(status));
72  }
73 
76  SerializeStatus stat = exitBuff.serialize(static_cast<I32>(ACTIVE_COMPONENT_EXIT));
77  FW_ASSERT(FW_SERIALIZE_OK == stat,static_cast<NATIVE_INT_TYPE>(stat));
78  (void)this->m_queue.send(exitBuff,0,Os::Queue::QUEUE_NONBLOCKING);
79  DEBUG_PRINT("exit %s\n", this->getObjName());
80  }
81 
83  DEBUG_PRINT("join %s\n", this->getObjName());
84  return this->m_task.join();
85  }
86 
88  return this->m_task.join();
89  }
90 
91  void ActiveComponentBase::s_taskStateMachine(void* component_pointer) {
92  FW_ASSERT(component_pointer != nullptr);
93  // cast void* back to active component
94  ActiveComponentBase* component = static_cast<ActiveComponentBase*>(component_pointer);
95 
96  // Each invocation of this function runs a single stage of the thread lifecycle. This has moved the thread
97  // while loop to the top level such that it can be replaced by something else (e.g. cooperative thread
98  // dispatcher) and is not intrinsic to this code.
99  switch (component->m_stage) {
100  // The first stage the active component triggers the "preamble" call before moving into the dispatching
101  // stage of the component thread.
102  case Lifecycle::CREATED:
103  component->preamble();
104  component->m_stage = Lifecycle::DISPATCHING;
105  break;
106  // The second stage of the active component triggers the dispatching loop dispatching messages until an
107  // exit message is received.
108  case Lifecycle::DISPATCHING:
109  if (component->dispatch() == MsgDispatchStatus::MSG_DISPATCH_EXIT) {
110  component->m_stage = Lifecycle::FINALIZING;
111  }
112  break;
113  // The second-to-last stage is where the finalizer is called. This will transition to the final stage
114  // automatically after the finalizer is called
115  case Lifecycle::FINALIZING:
116  component->finalizer();
117  component->m_stage = Lifecycle::DONE;
118  break;
119  // The last stage does nothing, cooperative tasks live here forever, threaded tasks exit on this condition
120  case Lifecycle::DONE:
121  break;
122  default:
123  FW_ASSERT(0);
124  break;
125  }
126  }
127 
128  void ActiveComponentBase::s_taskLoop(void* component_pointer) {
129  FW_ASSERT(component_pointer != nullptr);
130  ActiveComponentBase* component = static_cast<ActiveComponentBase*>(component_pointer);
131  // A non-cooperative task switching implementation is just a while-loop around the active component
132  // state-machine. Here the while loop is at top-level.
133  while (component->m_stage != ActiveComponentBase::Lifecycle::DONE) {
134  ActiveComponentBase::s_taskStateMachine(component);
135  }
136  }
137 
139  // Cooperative tasks should return rather than block when no messages are available
140  if (this->m_task.isCooperative() and m_queue.getNumMsgs() == 0) {
141  return MsgDispatchStatus::MSG_DISPATCH_EMPTY;
142  }
143  return this->doDispatch();
144  }
145 
147  }
148 
150  }
151 
152 }
#define DEBUG_PRINT(...)
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:51
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:26
PlatformUIntType NATIVE_UINT_TYPE
Definition: BasicTypes.h:52
unsigned int PlatformUIntType
int PlatformIntType
DefaultTypes.hpp provides fallback defaults for the platform types.
#define FW_TASK_NAME_BUFFER_SIZE
Max size of task name.
Definition: FpConfig.h:263
C++-compatible configuration header for fprime configuration.
Os::Task::Status join()
Join the thread.
Os::Task m_task
task object for active component
@ ACTIVE_COMPONENT_EXIT
message to exit active component task
ActiveComponentBase(const char *name)
Constructor.
void start(Os::Task::ParamType priority=Os::Task::TASK_DEFAULT, Os::Task::ParamType stackSize=Os::Task::TASK_DEFAULT, Os::Task::ParamType cpuAffinity=Os::Task::TASK_DEFAULT, Os::Task::ParamType identifier=Os::Task::TASK_DEFAULT)
called by instantiator when task is to be started
void exit()
exit task in active component
virtual ~ActiveComponentBase()
Destructor.
MsgDispatchStatus dispatch()
The function that will dispatching messages.
virtual void finalizer()
A function that will be called after exiting the loop.
virtual void preamble()
A function that will be called before the event loop is entered.
const U8 * getBuffAddr() const
gets buffer address for data reading, const version
NATIVE_UINT_TYPE getBuffCapacity() const
returns capacity, not current size, of buffer
U8 * getBuffAddr()
gets buffer address for data filling
void init()
Object initializer.
Definition: ObjBase.cpp:27
virtual MsgDispatchStatus doDispatch()=0
method to dispatch a single message in the queue.
Os::Queue m_queue
queue object for active component
SerializeStatus serialize(U8 val)
serialize 8-bit unsigned int
QueueStatus send(const Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE priority, QueueBlocking block)
send a message
Definition: QueueCommon.cpp:13
@ QUEUE_NONBLOCKING
Queue receive always returns even if there is no message.
Definition: Queue.hpp:42
NATIVE_INT_TYPE getNumMsgs() const
get the number of messages in the queue
Definition: Queue.cpp:211
static FwSizeType getNumTasks()
get the current number of tasks
Definition: Task.cpp:170
bool isCooperative() override
determine if the task is cooperative multitasking (implementation specific)
Definition: Task.cpp:160
FwSizeType ParamType
backwards-compatible parameter type
Definition: Task.hpp:218
Status start(const Arguments &arguments) override
start the task
Definition: Task.cpp:82
Status join() override
block until the task has ended
Definition: Task.cpp:130
void(* taskRoutine)(void *ptr)
Prototype for task routine started in task context.
Definition: Task.hpp:58
SerializeStatus
forward declaration for string
@ FW_SERIALIZE_OK
Serialization/Deserialization operation was successful.
@ OP_OK
Operation was successful.
Definition: FileSystem.hpp:15