Merge remote-tracking branch 'upstream/master' into mueller_CSB_improvements

This commit is contained in:
Robin Müller 2020-07-25 11:00:27 +02:00
commit 136a68000b
15 changed files with 455 additions and 255 deletions

View File

@ -1,5 +1,5 @@
#ifndef HYBRIDITERATOR_H_ #ifndef FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_
#define HYBRIDITERATOR_H_ #define FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_
#include <framework/container/ArrayList.h> #include <framework/container/ArrayList.h>
#include <framework/container/SinglyLinkedList.h> #include <framework/container/SinglyLinkedList.h>
@ -8,34 +8,32 @@ template<typename T, typename count_t = uint8_t>
class HybridIterator: public LinkedElement<T>::Iterator, class HybridIterator: public LinkedElement<T>::Iterator,
public ArrayList<T, count_t>::Iterator { public ArrayList<T, count_t>::Iterator {
public: public:
HybridIterator() : HybridIterator() {}
value(NULL), linked(NULL), end(NULL) {
}
HybridIterator(typename LinkedElement<T>::Iterator *iter) : HybridIterator(typename LinkedElement<T>::Iterator *iter) :
LinkedElement<T>::Iterator(*iter), value( LinkedElement<T>::Iterator(*iter), value(iter->value),
iter->value), linked(true), end(NULL) { linked(true) {
} }
HybridIterator(LinkedElement<T> *start) : HybridIterator(LinkedElement<T> *start) :
LinkedElement<T>::Iterator(start), value( LinkedElement<T>::Iterator(start), value(start->value),
start->value), linked(true), end(NULL) { linked(true) {
} }
HybridIterator(typename ArrayList<T, count_t>::Iterator start, HybridIterator(typename ArrayList<T, count_t>::Iterator start,
typename ArrayList<T, count_t>::Iterator end) : typename ArrayList<T, count_t>::Iterator end) :
ArrayList<T, count_t>::Iterator(start), value(start.value), linked( ArrayList<T, count_t>::Iterator(start), value(start.value),
false), end(end.value) { linked(false), end(end.value) {
if (value == this->end) { if (value == this->end) {
value = NULL; value = NULL;
} }
} }
HybridIterator(T *firstElement, T *lastElement) : HybridIterator(T *firstElement, T *lastElement) :
ArrayList<T, count_t>::Iterator(firstElement), value(firstElement), linked( ArrayList<T, count_t>::Iterator(firstElement), value(firstElement),
false), end(++lastElement) { linked(false), end(++lastElement) {
if (value == end) { if (value == end) {
value = NULL; value = NULL;
} }
@ -44,17 +42,17 @@ public:
HybridIterator& operator++() { HybridIterator& operator++() {
if (linked) { if (linked) {
LinkedElement<T>::Iterator::operator++(); LinkedElement<T>::Iterator::operator++();
if (LinkedElement<T>::Iterator::value != NULL) { if (LinkedElement<T>::Iterator::value != nullptr) {
value = LinkedElement<T>::Iterator::value->value; value = LinkedElement<T>::Iterator::value->value;
} else { } else {
value = NULL; value = nullptr;
} }
} else { } else {
ArrayList<T, count_t>::Iterator::operator++(); ArrayList<T, count_t>::Iterator::operator++();
value = ArrayList<T, count_t>::Iterator::value; value = ArrayList<T, count_t>::Iterator::value;
if (value == end) { if (value == end) {
value = NULL; value = nullptr;
} }
} }
return *this; return *this;
@ -66,11 +64,11 @@ public:
return tmp; return tmp;
} }
bool operator==(HybridIterator other) { bool operator==(const HybridIterator& other) const {
return value == other->value; return value == other.value;
} }
bool operator!=(HybridIterator other) { bool operator!=(const HybridIterator& other) const {
return !(*this == other); return !(*this == other);
} }
@ -82,11 +80,11 @@ public:
return value; return value;
} }
T* value; T* value = nullptr;
private: private:
bool linked; bool linked = false;
T *end; T *end = nullptr;
}; };
#endif /* HYBRIDITERATOR_H_ */ #endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */

View File

@ -35,7 +35,7 @@ ReturnValue_t ChildHandlerBase::initialize() {
parent->registerChild(getObjectId()); parent->registerChild(getObjectId());
} }
healthHelper.setParentQeueue(parentQueue); healthHelper.setParentQueue(parentQueue);
modeHelper.setParentQueue(parentQueue); modeHelper.setParentQueue(parentQueue);

View File

@ -1085,7 +1085,7 @@ ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage(
void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) { void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) {
modeHelper.setParentQueue(parentQueueId); modeHelper.setParentQueue(parentQueueId);
healthHelper.setParentQeueue(parentQueueId); healthHelper.setParentQueue(parentQueueId);
} }
bool DeviceHandlerBase::isAwaitingReply() { bool DeviceHandlerBase::isAwaitingReply() {

View File

@ -38,7 +38,7 @@ MessageQueueId_t HealthDevice::getCommandQueue() const {
} }
void HealthDevice::setParentQueue(MessageQueueId_t parentQueue) { void HealthDevice::setParentQueue(MessageQueueId_t parentQueue) {
healthHelper.setParentQeueue(parentQueue); healthHelper.setParentQueue(parentQueue);
} }
bool HealthDevice::hasHealthChanged() { bool HealthDevice::hasHealthChanged() {

View File

@ -29,11 +29,11 @@ HasHealthIF::HealthState HealthHelper::getHealth() {
} }
ReturnValue_t HealthHelper::initialize(MessageQueueId_t parentQueue) { ReturnValue_t HealthHelper::initialize(MessageQueueId_t parentQueue) {
setParentQeueue(parentQueue); setParentQueue(parentQueue);
return initialize(); return initialize();
} }
void HealthHelper::setParentQeueue(MessageQueueId_t parentQueue) { void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) {
this->parentQueue = parentQueue; this->parentQueue = parentQueue;
} }

View File

@ -78,7 +78,7 @@ public:
/** /**
* @param parentQueue the Queue id of the parent object. Set to 0 if no parent present * @param parentQueue the Queue id of the parent object. Set to 0 if no parent present
*/ */
void setParentQeueue(MessageQueueId_t parentQueue); void setParentQueue(MessageQueueId_t parentQueue);
/** /**
* *

View File

@ -1,6 +1,7 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include "FixedTimeslotTask.h" #include "FixedTimeslotTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0; uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
@ -18,16 +19,19 @@ FixedTimeslotTask::~FixedTimeslotTask() {
void FixedTimeslotTask::taskEntryPoint(void* argument) { void FixedTimeslotTask::taskEntryPoint(void* argument) {
//The argument is re-interpreted as FixedTimeslotTask. The Task object is global, so it is found from any place. // The argument is re-interpreted as FixedTimeslotTask. The Task object is
// global, so it is found from any place.
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument)); FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
// Task should not start until explicitly requested /* Task should not start until explicitly requested,
// in FreeRTOS, tasks start as soon as they are created if the scheduler is running * but in FreeRTOS, tasks start as soon as they are created if the scheduler
// but not if the scheduler is not running. * is running but not if the scheduler is not running.
// to be able to accommodate both cases we check a member which is set in #startTask() * To be able to accommodate both cases we check a member which is set in
// if it is not set and we get here, the scheduler was started before #startTask() was called and we need to suspend * #startTask(). If it is not set and we get here, the scheduler was started
// if it is set, the scheduler was not running before #startTask() was called and we can continue * before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (!originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(NULL);
} }
@ -58,11 +62,6 @@ ReturnValue_t FixedTimeslotTask::startTask() {
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) { if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
if(slotTimeMs == 0) {
// FreeRTOS throws a sanity error for zero values, so we set
// the time to one millisecond.
slotTimeMs = 1;
}
pst.addSlot(componentId, slotTimeMs, executionStep, this); pst.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -81,8 +80,9 @@ ReturnValue_t FixedTimeslotTask::checkSequence() const {
} }
void FixedTimeslotTask::taskFunctionality() { void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry. // A local iterator for the Polling Sequence Table is created to find the
auto slotListIter = pst.current; // start time for the first entry.
FixedSlotSequence::SlotListIter slotListIter = pst.current;
//The start time for the first entry is read. //The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs; uint32_t intervalMs = slotListIter->pollingTimeMs;
@ -90,29 +90,65 @@ void FixedTimeslotTask::taskFunctionality() {
TickType_t xLastWakeTime; TickType_t xLastWakeTime;
/* The xLastWakeTime variable needs to be initialized with the current tick /* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to explicitly. count. Note that this is the only time the variable is written to
After this assignment, xLastWakeTime is updated automatically internally within explicitly. After this assignment, xLastWakeTime is updated automatically
vTaskDelayUntil(). */ internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount(); xLastWakeTime = xTaskGetTickCount();
// wait for first entry's start time // wait for first entry's start time
if(interval > 0) {
vTaskDelayUntil(&xLastWakeTime, interval); vTaskDelayUntil(&xLastWakeTime, interval);
}
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
//The component for this slot is executed and the next one is chosen. //The component for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance(); this->pst.executeAndAdvance();
if (pst.slotFollowsImmediately()) { if (not pst.slotFollowsImmediately()) {
//Do nothing // Get the interval till execution of the next slot.
} else {
// we need to wait before executing the current slot
//this gives us the time to wait:
intervalMs = this->pst.getIntervalToPreviousSlotMs(); intervalMs = this->pst.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs); interval = pdMS_TO_TICKS(intervalMs);
checkMissedDeadline(xLastWakeTime, interval);
// Wait for the interval. This exits immediately if a deadline was
// missed while also updating the last wake time.
vTaskDelayUntil(&xLastWakeTime, interval); vTaskDelayUntil(&xLastWakeTime, interval);
//TODO deadline missed check }
}
} }
void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand
* it. */
TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval;
// Tick count has overflown
if(currentTickCount < xLastWakeTime) {
// Time to wake has overflown as well. If the tick count
// is larger than the time to wake, a deadline was missed.
if(timeToWake < xLastWakeTime and
currentTickCount > timeToWake) {
handleMissedDeadline();
}
}
// No tick count overflow. If the timeToWake has not overflown
// and the current tick count is larger than the time to wake,
// a deadline was missed.
else if(timeToWake > xLastWakeTime and currentTickCount > timeToWake) {
handleMissedDeadline();
}
}
void FixedTimeslotTask::handleMissedDeadline() {
#ifdef DEBUG
sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
} }
} }

View File

@ -1,26 +1,27 @@
#ifndef POLLINGTASK_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#define POLLINGTASK_H_ #define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#include <framework/devicehandlers/FixedSlotSequence.h> #include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/tasks/FixedTimeslotTaskIF.h> #include <framework/tasks/FixedTimeslotTaskIF.h>
#include <framework/tasks/Typedef.h> #include <framework/tasks/Typedef.h>
extern "C" { #include <freertos/FreeRTOS.h>
#include "FreeRTOS.h" #include <freertos/task.h>
#include "task.h"
}
class FixedTimeslotTask: public FixedTimeslotTaskIF { class FixedTimeslotTask: public FixedTimeslotTaskIF {
public: public:
/** /**
* @brief The standard constructor of the class. * Keep in mind that you need to call before vTaskStartScheduler()!
* * A lot of task parameters are set in "FreeRTOSConfig.h".
* @details This is the general constructor of the class. In addition to the TaskBase parameters, * @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN
* the following variables are passed: * @param setPriority Number of priorities specified by
* * configMAX_PRIORITIES. High taskPriority_ number means high priority.
* @param (*setDeadlineMissedFunc)() The function pointer to the deadline missed function that shall be assigned. * @param setStack Stack size in words (not bytes!).
* * Lower limit specified by configMINIMAL_STACK_SIZE
* @param getPst The object id of the completely initialized polling sequence. * @param overallPeriod Period in seconds.
* @param setDeadlineMissedFunc Callback if a deadline was missed.
* @return Pointer to the newly created task.
*/ */
FixedTimeslotTask(const char *name, TaskPriority setPriority, FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod, TaskStackSize setStack, TaskPeriod overallPeriod,
@ -28,16 +29,18 @@ public:
/** /**
* @brief The destructor of the class. * @brief The destructor of the class.
* * @details
* @details The destructor frees all heap memory that was allocated on thread initialization for the PST and * The destructor frees all heap memory that was allocated on thread
* the device handlers. This is done by calling the PST's destructor. * initialization for the PST and the device handlers. This is done by
* calling the PST's destructor.
*/ */
virtual ~FixedTimeslotTask(void); virtual ~FixedTimeslotTask(void);
ReturnValue_t startTask(void); ReturnValue_t startTask(void);
/** /**
* This static function can be used as #deadlineMissedFunc. * This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time. * It counts missedDeadlines and prints the number of missed deadlines
* every 10th time.
*/ */
static void missedDeadlineCounter(); static void missedDeadlineCounter();
/** /**
@ -46,13 +49,14 @@ public:
static uint32_t deadlineMissedCount; static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep); int8_t executionStep) override;
uint32_t getPeriodMs() const; uint32_t getPeriodMs() const override;
ReturnValue_t checkSequence() const; ReturnValue_t checkSequence() const override;
ReturnValue_t sleepFor(uint32_t ms) override;
ReturnValue_t sleepFor(uint32_t ms);
protected: protected:
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;
@ -60,32 +64,35 @@ protected:
FixedSlotSequence pst; FixedSlotSequence pst;
/** /**
* @brief This attribute holds a function pointer that is executed when a deadline was missed. * @brief This attribute holds a function pointer that is executed when
* * a deadline was missed.
* @details Another function may be announced to determine the actions to perform when a deadline was missed. * @details
* Currently, only one function for missing any deadline is allowed. * Another function may be announced to determine the actions to perform
* If not used, it shall be declared NULL. * when a deadline was missed. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL.
*/ */
void (*deadlineMissedFunc)(void); void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the entry point in a new polling thread. * @brief This is the entry point for a new task.
* * @details
* @details This method, that is the generalOSAL::checkAndRestartPeriod( this->periodId, interval ); entry point in the new thread, is here set to generate * This method starts the task by calling taskFunctionality(), as soon as
* and link the Polling Sequence Table to the thread object and start taskFunctionality() * all requirements (task scheduler has started and startTask()
* on success. If operation of the task is ended for some reason, * has been called) are met.
* the destructor is called to free allocated memory.
*/ */
static void taskEntryPoint(void* argument); static void taskEntryPoint(void* argument);
/** /**
* @brief This function holds the main functionality of the thread. * @brief This function holds the main functionality of the thread.
* * @details
* * Core function holding the main functionality of the task
* @details Holding the main functionality of the task, this method is most important. * It links the functionalities provided by FixedSlotSequence with the
* It links the functionalities provided by FixedSlotSequence with the OS's System Calls * OS's System Calls to keep the timing of the periods.
* to keep the timing of the periods.
*/ */
void taskFunctionality(void); void taskFunctionality(void);
void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval);
void handleMissedDeadline();
}; };
#endif /* POLLINGTASK_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ */

View File

@ -1,11 +1,58 @@
#include <framework/timemanager/Clock.h> #include <framework/timemanager/Clock.h>
#include <framework/serviceinterface/ServiceInterfaceBuffer.h> #include <framework/serviceinterface/ServiceInterfaceBuffer.h>
#include <cstring> #include <cstring>
#include <inttypes.h>
// to be implemented by bsp // to be implemented by bsp
extern "C" void printChar(const char*); extern "C" void printChar(const char*, bool errStream);
#ifndef UT699
ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage,
bool addCrToPreamble, bool buffered , bool errStream, uint16_t port):
isActive(true), logMessage(setMessage),
addCrToPreamble(addCrToPreamble), buffered(buffered),
errStream(errStream) {
if(buffered) {
// Set pointers if the stream is buffered.
setp( buf, buf + BUF_SIZE );
}
preamble.reserve(MAX_PREAMBLE_SIZE);
preamble.resize(MAX_PREAMBLE_SIZE);
}
void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) {
char array[BUF_SIZE];
uint32_t length = end - begin;
if (length > sizeof(array)) {
length = sizeof(array);
}
memcpy(array, begin, length);
for(; begin != end; begin++){
if(errStream) {
printChar(begin, true);
}
else {
printChar(begin, false);
}
}
}
#endif
int ServiceInterfaceBuffer::overflow(int c) { int ServiceInterfaceBuffer::overflow(int c) {
if(not buffered and this->isActive) {
if (c != Traits::eof()) {
if(errStream) {
printChar(reinterpret_cast<const char*>(&c), true);
}
else {
printChar(reinterpret_cast<const char*>(&c), false);
}
}
return 0;
}
// Handle output // Handle output
putChars(pbase(), pptr()); putChars(pbase(), pptr());
if (c != Traits::eof()) { if (c != Traits::eof()) {
@ -20,52 +67,70 @@ int ServiceInterfaceBuffer::overflow(int c) {
} }
int ServiceInterfaceBuffer::sync(void) { int ServiceInterfaceBuffer::sync(void) {
if (this->isActive) { if(not this->isActive and not buffered) {
Clock::TimeOfDay_t loggerTime; if(not buffered) {
Clock::getDateAndTime(&loggerTime); setp(buf, buf + BUF_SIZE - 1);
char preamble[96] = { 0 }; }
sprintf(preamble, "%s: | %lu:%02lu:%02lu.%03lu | ", return 0;
this->log_message.c_str(), (unsigned long) loggerTime.hour, }
(unsigned long) loggerTime.minute, if(not buffered) {
(unsigned long) loggerTime.second, return 0;
(unsigned long) loggerTime.usecond /1000); }
// Write log_message and time
this->putChars(preamble, preamble + sizeof(preamble)); size_t preambleSize = 0;
auto preamble = getPreamble(&preambleSize);
// Write logMessage and time
this->putChars(preamble.data(), preamble.data() + preambleSize);
// Handle output // Handle output
this->putChars(pbase(), pptr()); this->putChars(pbase(), pptr());
}
// This tells that buffer is empty again // This tells that buffer is empty again
setp(buf, buf + BUF_SIZE - 1); setp(buf, buf + BUF_SIZE - 1);
return 0; return 0;
} }
#ifndef UT699 bool ServiceInterfaceBuffer::isBuffered() const {
return buffered;
ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) {
this->log_message = set_message;
this->isActive = true;
setp( buf, buf + BUF_SIZE );
} }
void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { std::string ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) {
char array[BUF_SIZE]; Clock::TimeOfDay_t loggerTime;
uint32_t length = end - begin; Clock::getDateAndTime(&loggerTime);
if (length > sizeof(array)) { size_t currentSize = 0;
length = sizeof(array); char* parsePosition = &preamble[0];
if(addCrToPreamble) {
preamble[0] = '\r';
currentSize += 1;
parsePosition += 1;
} }
memcpy(array, begin, length); int32_t charCount = sprintf(parsePosition,
"%s: | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ",
for( ; begin != end; begin++){ this->logMessage.c_str(), loggerTime.hour,
printChar(begin); loggerTime.minute,
loggerTime.second,
loggerTime.usecond /1000);
if(charCount < 0) {
printf("ServiceInterfaceBuffer: Failure parsing preamble\r\n");
return "";
}
if(charCount > MAX_PREAMBLE_SIZE) {
printf("ServiceInterfaceBuffer: Char count too large for maximum "
"preamble size");
return "";
}
currentSize += charCount;
if(preambleSize != nullptr) {
*preambleSize = currentSize;
}
return preamble;
} }
}
#endif
#ifdef UT699 #ifdef UT699
#include <framework/osal/rtems/Interrupt.h> #include <framework/osal/rtems/Interrupt.h>
ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) { ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message,
uint16_t port) {
this->log_message = set_message; this->log_message = set_message;
this->isActive = true; this->isActive = true;
setp( buf, buf + BUF_SIZE ); setp( buf, buf + BUF_SIZE );

View File

@ -1,51 +1,71 @@
#ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ #ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_
#define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ #define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <iostream> #include <iostream>
#include <iosfwd>
#include <sstream> #include <sstream>
#include <cstdio> #include <iomanip>
#ifndef UT699 #ifndef UT699
class ServiceInterfaceBuffer: public std::basic_streambuf<char,
std::char_traits<char> > { /**
* @brief This is the underlying stream buffer which implements the
* streambuf class and overloads the overflow() and sync() methods
* @details
* This class is used to modify the output of the stream, for example by adding.
* It also calls the char printing function which is implemented in the
* board supply package (BSP).
*/
class ServiceInterfaceBuffer:
public std::streambuf {
friend class ServiceInterfaceStream; friend class ServiceInterfaceStream;
public: public:
ServiceInterfaceBuffer(std::string set_message, uint16_t port); static constexpr uint8_t MAX_PREAMBLE_SIZE = 40;
ServiceInterfaceBuffer(std::string setMessage, bool addCrToPreamble,
bool buffered, bool errStream, uint16_t port);
protected: protected:
bool isActive; bool isActive;
// This is called when buffer becomes full. If //! This is called when buffer becomes full. If
// buffer is not used, then this is called every //! buffer is not used, then this is called every
// time when characters are put to stream. //! time when characters are put to stream.
virtual int overflow(int c = Traits::eof()); int overflow(int c = Traits::eof()) override;
// This function is called when stream is flushed, //! This function is called when stream is flushed,
// for example when std::endl is put to stream. //! for example when std::endl is put to stream.
virtual int sync(void); int sync(void) override;
bool isBuffered() const;
private: private:
// For additional message information //! For additional message information
std::string log_message; std::string logMessage;
std::string preamble;
// For EOF detection // For EOF detection
typedef std::char_traits<char> Traits; typedef std::char_traits<char> Traits;
// Work in buffer mode. It is also possible to work without buffer. //! This is useful for some terminal programs which do not have
//! implicit carriage return with newline characters.
bool addCrToPreamble;
//! Specifies whether the stream operates in buffered or unbuffered mode.
bool buffered;
//! This specifies to print to stderr and work in unbuffered mode.
bool errStream;
//! Needed for buffered mode.
static size_t const BUF_SIZE = 128; static size_t const BUF_SIZE = 128;
char buf[BUF_SIZE]; char buf[BUF_SIZE];
// In this function, the characters are parsed. //! In this function, the characters are parsed.
void putChars(char const* begin, char const* end); void putChars(char const* begin, char const* end);
std::string getPreamble(size_t * preambleSize = nullptr);
}; };
#endif #endif
#ifdef UT699 #ifdef UT699
class ServiceInterfaceBuffer: public std::basic_streambuf<char, class ServiceInterfaceBuffer: public std::basic_streambuf<char,
std::char_traits<char> > { std::char_traits<char> > {

View File

@ -1,11 +1,32 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
ServiceInterfaceStream::ServiceInterfaceStream(std::string setMessage,
bool addCrToPreamble, bool buffered, bool errStream, uint16_t port) :
std::ostream(&streambuf),
streambuf(setMessage, addCrToPreamble, buffered, errStream, port) {}
void ServiceInterfaceStream::setActive( bool myActive) { void ServiceInterfaceStream::setActive( bool myActive) {
this->buf.isActive = myActive; this->streambuf.isActive = myActive;
} }
ServiceInterfaceStream::ServiceInterfaceStream(std::string set_message, std::string ServiceInterfaceStream::getPreamble() {
uint16_t port) : return streambuf.getPreamble();
std::basic_ostream<char, std::char_traits<char> >(&buf), buf( }
set_message, port) {
void ServiceInterfaceStream::print(std::string error,
bool withPreamble, bool withNewline, bool flush) {
if(not streambuf.isBuffered() and withPreamble) {
*this << getPreamble() << error;
}
else {
*this << error;
}
if(withNewline) {
*this << "\n";
}
// if mode is non-buffered, no need to flush.
if(flush and streambuf.isBuffered()) {
this->flush();
}
} }

View File

@ -3,28 +3,56 @@
#include <framework/serviceinterface/ServiceInterfaceBuffer.h> #include <framework/serviceinterface/ServiceInterfaceBuffer.h>
#include <iostream> #include <iostream>
#include <iosfwd>
#include <sstream>
#include <cstdio> #include <cstdio>
// Unfortunately, there must be a forward declaration of log_fe /**
// (MUST be defined in main), to let the system know where to write to. * Generic service interface stream which can be used like std::cout or
namespace sif { * std::cerr but has additional capability. Add preamble and timestamp
extern std::ostream debug; * to output. Can be run in buffered or unbuffered mode.
extern std::ostream info; */
extern std::ostream warning; class ServiceInterfaceStream : public std::ostream {
extern std::ostream error;
}
class ServiceInterfaceStream : public std::basic_ostream< char, std::char_traits< char > > {
protected:
ServiceInterfaceBuffer buf;
public: public:
ServiceInterfaceStream( std::string set_message, uint16_t port = 1234 ); /**
* This constructor is used by specifying the preamble message.
* Optionally, the output can be directed to stderr and a CR character
* can be prepended to the preamble.
* @param setMessage message of preamble.
* @param addCrToPreamble Useful for applications like Puttty.
* @param buffered specify whether to use buffered mode.
* @param errStream specify which output stream to use (stderr or stdout).
*/
ServiceInterfaceStream(std::string setMessage,
bool addCrToPreamble = false, bool buffered = true,
bool errStream = false, uint16_t port = 1234);
//! An inactive stream will not print anything.
void setActive( bool ); void setActive( bool );
/**
* This can be used to retrieve the preamble in case it should be printed in
* the unbuffered mode.
* @return Preamle consisting of log message and timestamp.
*/
std::string getPreamble();
/**
* This prints an error with a preamble. Useful if using the unbuffered
* mode. Flushes in default mode (prints immediately).
*/
void print(std::string error, bool withPreamble = true,
bool withNewline = true, bool flush = true);
protected:
ServiceInterfaceBuffer streambuf;
}; };
// Forward declaration of interface streams. These should be instantiated in
// main. They can then be used like std::cout or std::cerr.
namespace sif {
extern ServiceInterfaceStream debug;
extern ServiceInterfaceStream info;
extern ServiceInterfaceStream warning;
extern ServiceInterfaceStream error;
}
#endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */ #endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */

View File

@ -1,15 +1,5 @@
/** #ifndef FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_
* @file ExecutableObjectIF.h #define FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_
*
* @brief This file contains the definition for the ExecutableObjectIF interface.
*
* @author Bastian Baetz
*
* @date 12.03.2012
*/
#ifndef EXECUTABLEOBJECTIF_H_
#define EXECUTABLEOBJECTIF_H_
class PeriodicTaskIF; class PeriodicTaskIF;
@ -20,6 +10,7 @@ class PeriodicTaskIF;
* @brief The interface provides a method to execute objects within a task. * @brief The interface provides a method to execute objects within a task.
* @details The performOperation method, that is required by the interface is * @details The performOperation method, that is required by the interface is
* executed cyclically within a task context. * executed cyclically within a task context.
* @author Bastian Baetz
*/ */
class ExecutableObjectIF { class ExecutableObjectIF {
public: public:
@ -37,13 +28,26 @@ public:
/** /**
* @brief Function called during setup assignment of object to task * @brief Function called during setup assignment of object to task
* @details Has to be called from the function that assigns the object to a task and * @details
* enables the object implementation to overwrite this function and get a reference to the executing task * Has to be called from the function that assigns the object to a task and
* enables the object implementation to overwrite this function and get
* a reference to the executing task
* @param task_ Pointer to the taskIF of this task * @param task_ Pointer to the taskIF of this task
*/ */
virtual void setTaskIF(PeriodicTaskIF* task_) { virtual void setTaskIF(PeriodicTaskIF* task_) {};
/**
* This function should be called after the object was assigned to a
* specific task.
*
* Example: Can be used to get task execution frequency.
* The task is created after initialize() and the object ctors have been
* called so the execution frequency can't be cached in initialize()
* @return
*/
virtual ReturnValue_t initializeAfterTaskCreation() {
return HasReturnvaluesIF::RETURN_OK;
} }
}; };
#endif /* EXECUTABLEOBJECTIF_H_ */ #endif /* FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_ */

View File

@ -5,11 +5,13 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/globalfunctions/arrayprinter.h> #include <framework/globalfunctions/arrayprinter.h>
TmTcBridge::TmTcBridge(object_id_t objectId_, TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t ccsdsPacketDistributor_): SystemObject(objectId_), object_id_t tmStoreId, object_id_t tcStoreId):
ccsdsPacketDistributor(ccsdsPacketDistributor_) SystemObject(objectId),tmStoreId(tmStoreId), tcStoreId(tcStoreId),
tcDestination(tcDestination)
{ {
TmTcReceptionQueue = QueueFactory::instance()-> tmTcReceptionQueue = QueueFactory::instance()->
createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH); createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH);
} }
@ -22,8 +24,9 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(
return RETURN_OK; return RETURN_OK;
} }
else { else {
sif::warning << "TmTcBridge: Number of packets sent per cycle " sif::warning << "TmTcBridge::setNumberOfSentPacketsPerCycle: Number of "
"exceeds limits. Keeping default value." << std::endl; << "packets sent per cycle exceeds limits. "
<< "Keeping default value." << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
} }
@ -35,27 +38,35 @@ ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(
return RETURN_OK; return RETURN_OK;
} }
else { else {
sif::warning << "TmTcBridge: Number of packets stored " sif::warning << "TmTcBridge::setMaxNumberOfPacketsStored: Number of "
"exceeds limits. Keeping default value." << std::endl; << "packets stored exceeds limits. "
<< "Keeping default value." << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
} }
ReturnValue_t TmTcBridge::initialize() { ReturnValue_t TmTcBridge::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE); tcStore = objectManager->get<StorageManagerIF>(tcStoreId);
if (tcStore == NULL) { if (tcStore == nullptr) {
return RETURN_FAILED; sif::error << "TmTcBridge::initialize: TC store invalid. Make sure"
"it is created and set up properly." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
tmStore = objectManager->get<StorageManagerIF>(objects::TM_STORE); tmStore = objectManager->get<StorageManagerIF>(tmStoreId);
if (tmStore == NULL) { if (tmStore == nullptr) {
return RETURN_FAILED; sif::error << "TmTcBridge::initialize: TM store invalid. Make sure"
"it is created and set up properly." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
AcceptsTelecommandsIF* tcDistributor = AcceptsTelecommandsIF* tcDistributor =
objectManager->get<AcceptsTelecommandsIF>(ccsdsPacketDistributor); objectManager->get<AcceptsTelecommandsIF>(tcDestination);
if (tcDistributor == NULL) { if (tcDistributor == nullptr) {
return RETURN_FAILED; sif::error << "TmTcBridge::initialize: TC Distributor invalid"
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
TmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue());
tmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue());
return RETURN_OK; return RETURN_OK;
} }
@ -63,26 +74,25 @@ ReturnValue_t TmTcBridge::performOperation(uint8_t operationCode) {
ReturnValue_t result; ReturnValue_t result;
result = handleTc(); result = handleTc();
if(result != RETURN_OK) { if(result != RETURN_OK) {
sif::error << "TMTC Bridge: Error handling TCs" << std::endl; sif::debug << "TmTcBridge::performOperation: "
<< "Error handling TCs" << std::endl;
} }
result = handleTm(); result = handleTm();
if (result != RETURN_OK) { if (result != RETURN_OK) {
sif::error << "TMTC Bridge: Error handling TMs" << std::endl; sif::debug << "TmTcBridge::performOperation: "
<< "Error handling TMs" << std::endl;
} }
return result; return result;
} }
ReturnValue_t TmTcBridge::handleTc() { ReturnValue_t TmTcBridge::handleTc() {
uint8_t * recvBuffer = nullptr; return HasReturnvaluesIF::RETURN_OK;
size_t recvLen = 0;
ReturnValue_t result = receiveTc(&recvBuffer, &recvLen);
return result;
} }
ReturnValue_t TmTcBridge::handleTm() { ReturnValue_t TmTcBridge::handleTm() {
ReturnValue_t result = handleTmQueue(); ReturnValue_t result = handleTmQueue();
if(result != RETURN_OK) { if(result != RETURN_OK) {
sif::error << "TMTC Bridge: Reading TM Queue failed" << std::endl; sif::warning << "TmTcBridge: Reading TM Queue failed" << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
@ -97,8 +107,8 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
TmTcMessage message; TmTcMessage message;
const uint8_t* data = nullptr; const uint8_t* data = nullptr;
size_t size = 0; size_t size = 0;
for (ReturnValue_t result = TmTcReceptionQueue->receiveMessage(&message); for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message);
result == RETURN_OK; result = TmTcReceptionQueue->receiveMessage(&message)) result == RETURN_OK; result = tmTcReceptionQueue->receiveMessage(&message))
{ {
if(communicationLinkUp == false) { if(communicationLinkUp == false) {
result = storeDownlinkData(&message); result = storeDownlinkData(&message);
@ -112,7 +122,7 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
result = sendTm(data, size); result = sendTm(data, size);
if (result != RETURN_OK) { if (result != RETURN_OK) {
sif::error << "TMTC Bridge: Could not send TM packet"<< std::endl; sif::warning << "TmTcBridge: Could not send TM packet" << std::endl;
tmStore->deleteData(message.getStorageId()); tmStore->deleteData(message.getStorageId());
return result; return result;
@ -123,13 +133,12 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
} }
ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) {
//debug << "TMTC Bridge: Comm Link down. "
// "Saving packet ID to be sent later\r\n" << std::flush;
store_address_t storeId = 0; store_address_t storeId = 0;
if(tmFifo.full()) { if(tmFifo.full()) {
sif::error << "TMTC Bridge: TM downlink max. number of stored packet IDs " sif::error << "TmTcBridge::storeDownlinkData: TM downlink max. number "
"reached! Overwriting old data" << std::endl; << "of stored packet IDs reached! "
<< "Overwriting old data" << std::endl;
tmFifo.retrieve(&storeId); tmFifo.retrieve(&storeId);
tmStore->deleteData(storeId); tmStore->deleteData(storeId);
} }
@ -183,10 +192,20 @@ void TmTcBridge::registerCommDisconnect() {
} }
MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) { MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) {
return TmTcReceptionQueue->getId(); return tmTcReceptionQueue->getId();
} }
void TmTcBridge::printData(uint8_t * data, size_t dataLen) { void TmTcBridge::printData(uint8_t * data, size_t dataLen) {
arrayprinter::print(data, dataLen); arrayprinter::print(data, dataLen);
} }
uint16_t TmTcBridge::getIdentifier() {
// This is no PUS service, so we just return 0
return 0;
}
MessageQueueId_t TmTcBridge::getRequestQueue() {
// Default implementation: Relay TC messages to TC distributor directly.
return tmTcReceptionQueue->getDefaultDestination();
}

View File

@ -1,16 +1,18 @@
#ifndef FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ #ifndef FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_
#define FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ #define FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_
#include <framework/objectmanager/SystemObject.h>
#include <framework/tmtcservices/AcceptsTelemetryIF.h> #include <framework/tmtcservices/AcceptsTelemetryIF.h>
#include <framework/tasks/ExecutableObjectIF.h> #include <framework/tasks/ExecutableObjectIF.h>
#include <framework/ipc/MessageQueueIF.h> #include <framework/ipc/MessageQueueIF.h>
#include <framework/storagemanager/StorageManagerIF.h> #include <framework/storagemanager/StorageManagerIF.h>
#include <framework/objectmanager/SystemObject.h> #include <framework/tmtcservices/AcceptsTelecommandsIF.h>
#include <framework/tmtcservices/TmTcMessage.h>
#include <framework/container/FIFO.h> #include <framework/container/FIFO.h>
#include <framework/tmtcservices/TmTcMessage.h>
class TmTcBridge : public AcceptsTelemetryIF, class TmTcBridge : public AcceptsTelemetryIF,
public AcceptsTelecommandsIF,
public ExecutableObjectIF, public ExecutableObjectIF,
public HasReturnvaluesIF, public HasReturnvaluesIF,
public SystemObject { public SystemObject {
@ -22,7 +24,8 @@ public:
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
TmTcBridge(object_id_t objectId_, object_id_t ccsdsPacketDistributor_); TmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId);
virtual ~TmTcBridge(); virtual ~TmTcBridge();
/** /**
@ -57,45 +60,42 @@ public:
*/ */
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;
/**
* Return TMTC Reception Queue /** AcceptsTelemetryIF override */
* @param virtualChannel virtual MessageQueueId_t getReportReceptionQueue(
* @return
*/
MessageQueueId_t getReportReceptionQueue(
uint8_t virtualChannel = 0) override; uint8_t virtualChannel = 0) override;
/** AcceptsTelecommandsIF override */
virtual uint16_t getIdentifier() override;
virtual MessageQueueId_t getRequestQueue() override;
protected: protected:
//! Cached for initialize function.
object_id_t tmStoreId = objects::NO_OBJECT;
object_id_t tcStoreId = objects::NO_OBJECT;
object_id_t tcDestination = objects::NO_OBJECT;
//! Used to send and receive TMTC messages. //! Used to send and receive TMTC messages.
//! TmTcMessage is used to transport messages between tasks. //! The TmTcMessage class is used to transport messages between tasks.
MessageQueueIF* TmTcReceptionQueue = nullptr; MessageQueueIF* tmTcReceptionQueue = nullptr;
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr; StorageManagerIF* tmStore = nullptr;
object_id_t ccsdsPacketDistributor = 0; StorageManagerIF* tcStore = nullptr;
//! Used to specify whether communication link is up
bool communicationLinkUp = false; //! Used to specify whether communication link is up. Will be true
//! by default, so telemetry will be handled immediately.
bool communicationLinkUp = true;
bool tmStored = false; bool tmStored = false;
/** /**
* @brief Handle TC reception * @brief Handle TC reception
* @details * @details
* Default implementation provided, but is empty. * Default implementation provided, but is empty.
* Child handler should override this in most cases orsend TC to the * In most cases, TC reception will be handled in a separate task anyway.
* TC distributor directly with the address of the reception queue by
* calling getReportRecptionQueue()
* @return * @return
*/ */
virtual ReturnValue_t handleTc(); virtual ReturnValue_t handleTc();
/**
* Implemented by child class. Perform receiving of Telecommand,
* for example by implementing specific drivers or wrappers,
* e.g. UART Communication or an ethernet stack
* @param recvBuffer [out] Received data
* @param size [out] Size of received data
* @return
*/
virtual ReturnValue_t receiveTc(uint8_t ** recvBuffer, size_t * size) = 0;
/** /**
* Handle Telemetry. Default implementation provided. * Handle Telemetry. Default implementation provided.
* Calls sendTm() * Calls sendTm()
@ -104,7 +104,8 @@ protected:
virtual ReturnValue_t handleTm(); virtual ReturnValue_t handleTm();
/** /**
* Read the TM Queue and send TM if necessary. Default implementation provided * Read the TM Queue and send TM if necessary.
* Default implementation provided
* @return * @return
*/ */
virtual ReturnValue_t handleTmQueue(); virtual ReturnValue_t handleTmQueue();
@ -117,7 +118,8 @@ protected:
/** /**
* Implemented by child class. Perform sending of Telemetry by implementing * Implemented by child class. Perform sending of Telemetry by implementing
* communication drivers or wrappers, e.g. UART communication or lwIP stack. * communication drivers or wrappers, e.g. serial communication or a socket
* call.
* @param data * @param data
* @param dataLen * @param dataLen
* @return * @return