diff --git a/coordinates/Sgp4Propagator.h b/coordinates/Sgp4Propagator.h index 781e17e1..95739762 100644 --- a/coordinates/Sgp4Propagator.h +++ b/coordinates/Sgp4Propagator.h @@ -2,7 +2,7 @@ #define SGP4PROPAGATOR_H_ #include -#include +#include "../contrib/sgp4/sgp4unit.h" #include class Sgp4Propagator { diff --git a/datapool/HkSwitchHelper.cpp b/datapool/HkSwitchHelper.cpp index f6e572ac..caae2146 100644 --- a/datapool/HkSwitchHelper.cpp +++ b/datapool/HkSwitchHelper.cpp @@ -1,5 +1,5 @@ #include -#include +//#include #include HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) : @@ -56,18 +56,19 @@ void HkSwitchHelper::completionFailedReceived(ActionId_t actionId, } ReturnValue_t HkSwitchHelper::switchHK(SerializeIF* sids, bool enable) { - ActionId_t action = HKService::DISABLE_HK; - if (enable) { - action = HKService::ENABLE_HK; - } - - ReturnValue_t result = commandActionHelper.commandAction( - objects::PUS_HK_SERVICE, action, sids); - - if (result != HasReturnvaluesIF::RETURN_OK) { - eventProxy->forwardEvent(SWITCHING_TM_FAILED, result); - } - return result; +// ActionId_t action = HKService::DISABLE_HK; +// if (enable) { +// action = HKService::ENABLE_HK; +// } +// +// ReturnValue_t result = commandActionHelper.commandAction( +// objects::PUS_HK_SERVICE, action, sids); +// +// if (result != HasReturnvaluesIF::RETURN_OK) { +// eventProxy->forwardEvent(SWITCHING_TM_FAILED, result); +// } +// return result; + return HasReturnvaluesIF::RETURN_OK; } MessageQueueIF* HkSwitchHelper::getCommandQueuePtr() { diff --git a/devicehandlers/FixedSlotSequence.cpp b/devicehandlers/FixedSlotSequence.cpp index 88ec5717..3b10dea2 100644 --- a/devicehandlers/FixedSlotSequence.cpp +++ b/devicehandlers/FixedSlotSequence.cpp @@ -30,7 +30,7 @@ void FixedSlotSequence::executeAndAdvance() { } } -uint32_t FixedSlotSequence::getIntervalMs() { +uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { uint32_t oldTime; std::list::iterator it; it = current; @@ -53,6 +53,23 @@ uint32_t FixedSlotSequence::getIntervalMs() { return lengthMs - oldTime + (*it)->pollingTimeMs; } +uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { + uint32_t currentTime; + std::list::iterator it; + it = current; + // Get the pollingTimeMs of the current slot object. + currentTime = (*it)->pollingTimeMs; + + //if it is the first slot, calculate difference to last slot + if (it == slotList.begin()){ + return lengthMs - (*(--slotList.end()))->pollingTimeMs + currentTime; + } + // get previous slot + it--; + + return currentTime - (*it)->pollingTimeMs; +} + bool FixedSlotSequence::slotFollowsImmediately() { uint32_t currentTime = (*current)->pollingTimeMs; std::list::iterator it; diff --git a/devicehandlers/FixedSlotSequence.h b/devicehandlers/FixedSlotSequence.h index 161b3a34..f8fd9a36 100644 --- a/devicehandlers/FixedSlotSequence.h +++ b/devicehandlers/FixedSlotSequence.h @@ -59,10 +59,20 @@ public: * * \details This method is vitally important for the operation of the PST. By fetching the polling time * of the current slot and that of the next one (or the first one, if the list end is reached) - * it calculates and returns the interval in clock ticks within which the handler execution - * shall take place. + * it calculates and returns the interval in milliseconds within which the handler execution + * shall take place. If the next slot has the same time as the current one, it is ignored until + * a slot with different time or the end of the PST is found. */ - uint32_t getIntervalMs(); + uint32_t getIntervalToNextSlotMs(); + + /** + * \brief This method returns the time difference between the current slot and the previous slot + * + * \details This method is vitally important for the operation of the PST. By fetching the polling time + * of the current slot and that of the prevous one (or the last one, if the slot is the first one) + * it calculates and returns the interval in milliseconds that the handler execution shall be delayed. + */ + uint32_t getIntervalToPreviousSlotMs(); /** * \brief This method returns the length of this FixedSlotSequence instance. diff --git a/framework.mk b/framework.mk index 84ae87b5..b38c133e 100644 --- a/framework.mk +++ b/framework.mk @@ -1,7 +1,9 @@ -# This file needs FRAMEWORK_PATH set correctly +# This file needs FRAMEWORK_PATH and API set correctly +# Valid API settings: rtems, linux, freeRTOS CXXSRC += $(wildcard $(FRAMEWORK_PATH)/action/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/container/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/contrib/sgp4/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/controller/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp) @@ -22,12 +24,25 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/modes/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/monitoring/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/objectmanager/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/*.cpp) -#TODO should be ifdef'd + +# select the OS +ifeq ($(OS),rtems) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp) +else ifeq ($(OS),linux) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp) +else ifeq ($(OS),freeRTOS) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/FreeRTOS/*.cpp) +else +$(error invalid OS specified, valid OS are rtems, linux, freeRTOS) +endif + CXXSRC += $(wildcard $(FRAMEWORK_PATH)/parameters/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/power/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/returnvalues/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/rmap/*.cpp) + +# easier without it for now +#CXXSRC += $(wildcard $(FRAMEWORK_PATH)/rmap/*.cpp) + CXXSRC += $(wildcard $(FRAMEWORK_PATH)/serialize/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/serviceinterface/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/storagemanager/*.cpp) diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index f25fde22..bbe2f0ef 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -1,6 +1,8 @@ #ifndef FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ #define FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ +// COULDDO: We could support blocking calls + #include #include class MessageQueueIF { diff --git a/osal/Endiness.h b/osal/Endiness.h index 6e23ce57..4d236ba0 100644 --- a/osal/Endiness.h +++ b/osal/Endiness.h @@ -1,13 +1,30 @@ #ifndef FRAMEWORK_OSAL_ENDINESS_H_ #define FRAMEWORK_OSAL_ENDINESS_H_ -//We have to define BYTE_ORDER for that specific OS/Hardware so this must be done somewhere -#ifndef API -#error Please specify Operating System API. Supported: API=RTEMS_API -#elif API == RTEMS_API -#include "rtems/RtemsBasic.h" + +/* + * BSD-style endian declaration + */ +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + + +// This is a GCC C extension +#ifndef BYTE_ORDER +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define BYTE_ORDER BIG_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define BYTE_ORDER LITTLE_ENDIAN +#else +#error "Can't decide which end is which!" +#endif #endif + #endif /* FRAMEWORK_OSAL_ENDINESS_H_ */ diff --git a/osal/FreeRTOS/Clock.cpp b/osal/FreeRTOS/Clock.cpp new file mode 100644 index 00000000..cffc2125 --- /dev/null +++ b/osal/FreeRTOS/Clock.cpp @@ -0,0 +1,195 @@ +#include +#include +#include +#include "Timekeeper.h" + +#include +#include + +//TODO sanitize input? +//TODO much of this code can be reused for tick-only systems + +uint16_t Clock::leapSeconds = 0; +MutexIF* Clock::timeMutex = NULL; + +uint32_t Clock::getTicksPerSecond(void) { + return 1000; +} + +ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { + + timeval time_timeval; + + ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval); + if (result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + + return setClock(&time_timeval); +} + +ReturnValue_t Clock::setClock(const timeval* time) { + timeval uptime = getUptime(); + + timeval offset = *time - uptime; + + Timekeeper::instance()->setOffset(offset); + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getClock_timeval(timeval* time) { + timeval uptime = getUptime(); + + timeval offset = Timekeeper::instance()->getOffset(); + + *time = offset + uptime; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getUptime(timeval* uptime) { + *uptime = getUptime(); + + return HasReturnvaluesIF::RETURN_OK; +} + +timeval Clock::getUptime() { + TickType_t ticksSinceStart = xTaskGetTickCount(); + + return Timekeeper::ticksToTimeval(ticksSinceStart); +} + +ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { + timeval uptime = getUptime(); + *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getClock_usecs(uint64_t* time) { + timeval time_timeval; + ReturnValue_t result = getClock_timeval(&time_timeval); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + *time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { + timeval time_timeval; + ReturnValue_t result = getClock_timeval(&time_timeval); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + struct tm time_tm; + + gmtime_r(&time_timeval.tv_sec,&time_tm); + + time->year = time_tm.tm_year + 1900; + time->month = time_tm.tm_mon + 1; + time->day = time_tm.tm_mday; + + time->hour = time_tm.tm_hour; + time->minute = time_tm.tm_min; + time->second = time_tm.tm_sec; + + time->usecond = time_timeval.tv_usec; + + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, + timeval* to) { + struct tm time_tm; + + time_tm.tm_year = from->year - 1900; + time_tm.tm_mon = from->month - 1; + time_tm.tm_mday = from->day; + + time_tm.tm_hour = from->hour; + time_tm.tm_min = from->minute; + time_tm.tm_sec = from->second; + + time_t seconds = mktime(&time_tm); + + to->tv_sec = seconds; + to->tv_usec = from->usecond; + //Fails in 2038.. + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { + *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. + / 3600.; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { + //SHOULDDO: works not for dates in the past (might have less leap seconds) + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint16_t leapSeconds; + ReturnValue_t result = getLeapSeconds(&leapSeconds); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + timeval leapSeconds_timeval = { 0, 0 }; + leapSeconds_timeval.tv_sec = leapSeconds; + + //initial offset between UTC and TAI + timeval UTCtoTAI1972 = { 10, 0 }; + + timeval TAItoTT = { 32, 184000 }; + + *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { + if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + leapSeconds = leapSeconds_; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + *leapSeconds_ = leapSeconds; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::checkOrCreateClockMutex() { + if (timeMutex == NULL) { + MutexFactory* mutexFactory = MutexFactory::instance(); + if (mutexFactory == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + timeMutex = mutexFactory->createMutex(); + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp new file mode 100644 index 00000000..4b89b4f2 --- /dev/null +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -0,0 +1,112 @@ +#include +#include "FixedTimeslotTask.h" + +uint32_t FixedTimeslotTask::deadlineMissedCount = 0; + +FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod overallPeriod, + void (*setDeadlineMissedFunc)()) : + started(false), handle(NULL), pst(overallPeriod * 1000) { + xTaskCreate(taskEntryPoint, name, setStack, this, setPriority, &handle); + // All additional attributes are applied to the object. + this->deadlineMissedFunc = setDeadlineMissedFunc; +} + +FixedTimeslotTask::~FixedTimeslotTask() { +} + +void FixedTimeslotTask::taskEntryPoint(void* argument) { + + //The argument is re-interpreted as FixedTimeslotTask. The Task object is global, so it is found from any place. + FixedTimeslotTask *originalTask( + reinterpret_cast(argument)); + // Task should not start until explicitly requested + // in FreeRTOS, tasks start as soon as they are created if the scheduler 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() + // if it is not set and we get here, the scheduler was started 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) { + vTaskSuspend(NULL); + } + + originalTask->taskFunctionality(); + debug << "Polling task " << originalTask->handle + << " returned from taskFunctionality." << std::endl; +} + +void FixedTimeslotTask::missedDeadlineCounter() { + FixedTimeslotTask::deadlineMissedCount++; + if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { + error << "PST missed " << FixedTimeslotTask::deadlineMissedCount + << " deadlines." << std::endl; + } +} + +ReturnValue_t FixedTimeslotTask::startTask() { + started = true; + + // We must not call resume if scheduler is not started yet + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + vTaskResume(handle); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) { + pst.addSlot(componentId, slotTimeMs, executionStep, this); + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t FixedTimeslotTask::getPeriodMs() const { + return pst.getLengthMs(); +} + +ReturnValue_t FixedTimeslotTask::checkSequence() const { + return pst.checkSequence(); +} + +void FixedTimeslotTask::taskFunctionality() { + // A local iterator for the Polling Sequence Table is created to find the start time for the first entry. + std::list::iterator it = pst.current; + + //The start time for the first entry is read. + uint32_t intervalMs = (*it)->pollingTimeMs; + TickType_t interval = pdMS_TO_TICKS(intervalMs); + + TickType_t xLastWakeTime; + /* 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. + After this assignment, xLastWakeTime is updated automatically internally within + vTaskDelayUntil(). */ + xLastWakeTime = xTaskGetTickCount(); + + // wait for first entry's start time + vTaskDelayUntil(&xLastWakeTime, interval); + + /* Enter the loop that defines the task behavior. */ + for (;;) { + //The component for this slot is executed and the next one is chosen. + this->pst.executeAndAdvance(); + if (pst.slotFollowsImmediately()) { + //Do nothing + } else { + // we need to wait before executing the current slot + //this gives us the time to wait: + intervalMs = this->pst.getIntervalToPreviousSlotMs(); + interval = pdMS_TO_TICKS(intervalMs); + vTaskDelayUntil(&xLastWakeTime, interval); + //TODO deadline missed check + } + + } +} + +ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/osal/FreeRTOS/FixedTimeslotTask.h new file mode 100644 index 00000000..bed13051 --- /dev/null +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -0,0 +1,89 @@ +#ifndef POLLINGTASK_H_ +#define POLLINGTASK_H_ + +#include +#include +#include + +#include +#include "task.h" + +class FixedTimeslotTask: public FixedTimeslotTaskIF { +public: + /** + * @brief The standard constructor of the class. + * + * @details This is the general constructor of the class. In addition to the TaskBase parameters, + * the following variables are passed: + * + * @param (*setDeadlineMissedFunc)() The function pointer to the deadline missed function that shall be assigned. + * + * @param getPst The object id of the completely initialized polling sequence. + */ + FixedTimeslotTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod overallPeriod, + void (*setDeadlineMissedFunc)()); + + /** + * @brief The destructor of the class. + * + * @details The destructor frees all heap memory that was allocated on thread initialization for the PST and + * the device handlers. This is done by calling the PST's destructor. + */ + virtual ~FixedTimeslotTask(void); + + ReturnValue_t startTask(void); + /** + * This static function can be used as #deadlineMissedFunc. + * It counts missedDeadlines and prints the number of missed deadlines every 10th time. + */ + static void missedDeadlineCounter(); + /** + * A helper variable to count missed deadlines. + */ + static uint32_t deadlineMissedCount; + + ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep); + + uint32_t getPeriodMs() const; + + ReturnValue_t checkSequence() const; + + ReturnValue_t sleepFor(uint32_t ms); +protected: + bool started; + TaskHandle_t handle; + + FixedSlotSequence pst; + + /** + * @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. + * Currently, only one function for missing any deadline is allowed. + * If not used, it shall be declared NULL. + */ + void (*deadlineMissedFunc)(void); + /** + * @brief This is the entry point in a new polling thread. + * + * @details This method, that is the generalOSAL::checkAndRestartPeriod( this->periodId, interval ); entry point in the new thread, is here set to generate + * and link the Polling Sequence Table to the thread object and start taskFunctionality() + * on success. If operation of the task is ended for some reason, + * the destructor is called to free allocated memory. + */ + static void taskEntryPoint(void* argument); + + /** + * @brief This function holds the main functionality of the thread. + * + * + * @details Holding the main functionality of the task, this method is most important. + * It links the functionalities provided by FixedSlotSequence with the OS's System Calls + * to keep the timing of the periods. + */ + void taskFunctionality(void); +}; + +#endif /* POLLINGTASK_H_ */ diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp new file mode 100644 index 00000000..0811188a --- /dev/null +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -0,0 +1,104 @@ +#include "MessageQueue.h" + +#include + +// TODO I guess we should have a way of checking if we are in an ISR and then use the "fromISR" versions of all calls + +MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : + lastPartner(0), defaultDestination(0) { + handle = xQueueCreate(message_depth, max_message_size); + if (handle == NULL) { + //TODO + ; + } +} + +MessageQueue::~MessageQueue() { + if (handle != NULL) { + vQueueDelete(handle); + } +} + +ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, bool ignoreFault) { + return sendMessage(sendTo, message, this->getId(), ignoreFault); +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { + return sendToDefault(message, this->getId()); +} + +ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { + if (this->lastPartner != 0) { + return sendMessage(this->lastPartner, message, this->getId()); + } else { + //TODO: Good returnCode + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + *receivedFrom = this->lastPartner; + return status; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { + BaseType_t result = xQueueReceive(handle, message, 0); + if (result == pdPASS){ + return HasReturnvaluesIF::RETURN_OK; + } else { + //TODO Queue Empty + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +MessageQueueId_t MessageQueue::getLastPartner() const { + return lastPartner; +} + +ReturnValue_t MessageQueue::flush(uint32_t* count) { + //TODO FreeRTOS does not support flushing partially + //Is always successful + xQueueReset(handle); + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t MessageQueue::getId() const { + return (MessageQueueId_t) handle; +} + +void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + this->defaultDestination = defaultDestination; +} + +ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + message->setSender(sentFrom); + + BaseType_t result = xQueueSendToBack((void * )sendTo, message, 0); + if (result != pdPASS) { + if (!ignoreFault) { + //TODO errr reporter + } + //TODO queue is full + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return 0; +} + +MessageQueueId_t MessageQueue::getDefaultDestination() const { + return defaultDestination; +} + +bool MessageQueue::isDefaultDestinationSet() const { + return 0; +} + diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h new file mode 100644 index 00000000..1fdb96a4 --- /dev/null +++ b/osal/FreeRTOS/MessageQueue.h @@ -0,0 +1,145 @@ +#ifndef MESSAGEQUEUE_H_ +#define MESSAGEQUEUE_H_ + +#include +#include +#include + +#include +#include + +//TODO this class assumes that MessageQueueId_t is the same size as void* (the FreeRTOS handle type), compiler will catch this but it might be nice to have something checking or even an always working solution +// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ + +/** + * @brief This class manages sending and receiving of message queue messages. + * + * @details Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also provides + * methods to send a message to a user-defined or a default destination. In addition + * it also provides a reply method to answer to the queue it received its last message + * from. + * The MessageQueue should be used as "post box" for a single owning object. So all + * message queue communication is "n-to-one". + * For creating the queue, as well as sending and receiving messages, the class makes + * use of the operating system calls provided. + * \ingroup message_queue + */ +class MessageQueue : public MessageQueueIF { +public: + /** + * @brief The constructor initializes and configures the message queue. + * @details By making use of the according operating system call, a message queue is created + * and initialized. The message depth - the maximum number of messages to be + * buffered - may be set with the help of a parameter, whereas the message size is + * automatically set to the maximum message queue message size. The operating system + * sets the message queue id, or i case of failure, it is set to zero. + * @param message_depth The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size With this parameter, the maximum message size can be adjusted. + * This should be left default. + */ + MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + /** + * @brief The destructor deletes the formerly created message queue. + * @details This is accomplished by using the delete call provided by the operating system. + */ + virtual ~MessageQueue(); + /** + * @brief This operation sends a message to the given destination. + * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its + * queue id as "sentFrom" parameter. + * @param sendTo This parameter specifies the message queue id of the destination message queue. + * @param message A pointer to a previously created message, which is sent. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + ReturnValue_t sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, bool ignoreFault = false ); + /** + * @brief This operation sends a message to the default destination. + * @details As in the sendMessage method, this function uses the sendToDefault call of the + * MessageQueueSender parent class and adds its queue id as "sentFrom" information. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t sendToDefault( MessageQueueMessage* message ); + /** + * @brief This operation sends a message to the last communication partner. + * @details This operation simplifies answering an incoming message by using the stored + * lastParnter information as destination. If there was no message received yet + * (i.e. lastPartner is zero), an error code is returned. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t reply( MessageQueueMessage* message ); + + /** + * @brief This function reads available messages from the message queue and returns the sender. + * @details It works identically to the other receiveMessage call, but in addition returns the + * sender's queue id. + * @param message A pointer to a message in which the received data is stored. + * @param receivedFrom A pointer to a queue id in which the sender's id is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessage* message, + MessageQueueId_t *receivedFrom); + + /** + * @brief This function reads available messages from the message queue. + * @details If data is available it is stored in the passed message pointer. The message's + * original content is overwritten and the sendFrom information is stored in the + * lastPartner attribute. Else, the lastPartner information remains untouched, the + * message's content is cleared and the function returns immediately. + * @param message A pointer to a message in which the received data is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessage* message); + /** + * Deletes all pending messages in the queue. + * @param count The number of flushed messages. + * @return RETURN_OK on success. + */ + ReturnValue_t flush(uint32_t* count); + /** + * @brief This method returns the message queue id of the last communication partner. + */ + MessageQueueId_t getLastPartner() const; + /** + * @brief This method returns the message queue id of this class's message queue. + */ + MessageQueueId_t getId() const; + /** + * \brief With the sendMessage call, a queue message is sent to a receiving queue. + * \details This method takes the message provided, adds the sentFrom information and passes + * it on to the destination provided with an operating system call. The OS's return + * value is returned. + * \param sendTo This parameter specifies the message queue id to send the message to. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** + * \brief The sendToDefault method sends a queue message to the default destination. + * \details In all other aspects, it works identical to the sendMessage method. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + */ + virtual ReturnValue_t sendToDefault( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** + * \brief This method is a simple setter for the default destination. + */ + void setDefaultDestination(MessageQueueId_t defaultDestination); + /** + * \brief This method is a simple getter for the default destination. + */ + MessageQueueId_t getDefaultDestination() const; + + bool isDefaultDestinationSet() const; +private: + QueueHandle_t handle; + MessageQueueId_t defaultDestination; + MessageQueueId_t lastPartner; +}; + +#endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/Mutex.cpp b/osal/FreeRTOS/Mutex.cpp new file mode 100644 index 00000000..7c511091 --- /dev/null +++ b/osal/FreeRTOS/Mutex.cpp @@ -0,0 +1,50 @@ +#include "Mutex.h" + +#include + +const uint32_t MutexIF::NO_TIMEOUT = 0; + +Mutex::Mutex() { + handle = xSemaphoreCreateMutex(); + //TODO print error +} + +Mutex::~Mutex() { + if (handle != 0) { + vSemaphoreDelete(handle); + } + +} + +ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { + if (handle == 0) { + //TODO Does not exist + return HasReturnvaluesIF::RETURN_FAILED; + } + TickType_t timeout = portMAX_DELAY; + if (timeoutMs != NO_TIMEOUT) { + timeout = pdMS_TO_TICKS(timeoutMs); + } + + BaseType_t returncode = xSemaphoreTake(handle, timeout); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + //TODO could not be acquired/timeout + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t Mutex::unlockMutex() { + if (handle == 0) { + //TODO Does not exist + return HasReturnvaluesIF::RETURN_FAILED; + } + BaseType_t returncode = xSemaphoreGive(handle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + //TODO is not owner + return HasReturnvaluesIF::RETURN_FAILED; + } +} diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h new file mode 100644 index 00000000..91f29585 --- /dev/null +++ b/osal/FreeRTOS/Mutex.h @@ -0,0 +1,22 @@ +#ifndef OS_RTEMS_MUTEX_H_ +#define OS_RTEMS_MUTEX_H_ + +#include + + +#include +#include "semphr.h" + + + +class Mutex : public MutexIF { +public: + Mutex(); + ~Mutex(); + ReturnValue_t lockMutex(uint32_t timeoutMs); + ReturnValue_t unlockMutex(); +private: + SemaphoreHandle_t handle; +}; + +#endif /* OS_RTEMS_MUTEX_H_ */ diff --git a/osal/FreeRTOS/MutexFactory.cpp b/osal/FreeRTOS/MutexFactory.cpp new file mode 100644 index 00000000..cadb54fb --- /dev/null +++ b/osal/FreeRTOS/MutexFactory.cpp @@ -0,0 +1,28 @@ +#include + +#include "../FreeRTOS/Mutex.h" + +//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? -> one is on heap the other on bss/data +//MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); +MutexFactory* MutexFactory::factoryInstance = NULL; + +MutexFactory::MutexFactory() { +} + +MutexFactory::~MutexFactory() { +} + +MutexFactory* MutexFactory::instance() { + if (factoryInstance == NULL){ + factoryInstance = new MutexFactory(); + } + return MutexFactory::factoryInstance; +} + +MutexIF* MutexFactory::createMutex() { + return new Mutex(); +} + +void MutexFactory::deleteMutex(MutexIF* mutex) { + delete mutex; +} diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp new file mode 100644 index 00000000..bd7c6c8c --- /dev/null +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -0,0 +1,85 @@ +#include +#include +#include "PeriodicTask.h" + +PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod setPeriod, + void (*setDeadlineMissedFunc)()) : + started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( + setDeadlineMissedFunc) { + + xTaskCreate(taskEntryPoint, name, setStack, this, setPriority, &handle); + +} + +PeriodicTask::~PeriodicTask(void) { + //Do not delete objects, we were responsible for ptrs only. +} + +void PeriodicTask::taskEntryPoint(void* argument) { + //The argument is re-interpreted as PeriodicTask. The Task object is global, so it is found from any place. + PeriodicTask *originalTask(reinterpret_cast(argument)); + // Task should not start until explicitly requested + // in FreeRTOS, tasks start as soon as they are created if the scheduler 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() + // if it is not set and we get here, the scheduler was started 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) { + vTaskSuspend(NULL); + } + + originalTask->taskFunctionality(); + debug << "Polling task " << originalTask->handle + << " returned from taskFunctionality." << std::endl; +} + +ReturnValue_t PeriodicTask::startTask() { + started = true; + + // We must not call resume if scheduler is not started yet + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + vTaskResume(handle); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +void PeriodicTask::taskFunctionality() { + TickType_t xLastWakeTime; + const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); + /* 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. + After this assignment, xLastWakeTime is updated automatically internally within + vTaskDelayUntil(). */ + xLastWakeTime = xTaskGetTickCount(); + /* Enter the loop that defines the task behavior. */ + for (;;) { + for (ObjectList::iterator it = objectList.begin(); + it != objectList.end(); ++it) { + (*it)->performOperation(); + } + //TODO deadline missed check + vTaskDelayUntil(&xLastWakeTime, xPeriod); + } +} + +ReturnValue_t PeriodicTask::addComponent(object_id_t object) { + ExecutableObjectIF* newObject = objectManager->get( + object); + if (newObject == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back(newObject); + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t PeriodicTask::getPeriodMs() const { + return period * 1000; +} diff --git a/osal/FreeRTOS/PeriodicTask.h b/osal/FreeRTOS/PeriodicTask.h new file mode 100644 index 00000000..e7ba8dd2 --- /dev/null +++ b/osal/FreeRTOS/PeriodicTask.h @@ -0,0 +1,110 @@ +#ifndef MULTIOBJECTTASK_H_ +#define MULTIOBJECTTASK_H_ + +#include +#include +#include + +#include +#include "task.h" + +#include + +class ExecutableObjectIF; + +/** + * @brief This class represents a specialized task for periodic activities of multiple objects. + * + * @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute + * multiple objects that implement the ExecutableObjectIF interface. The objects must be + * added prior to starting the task. + * + * @ingroup task_handling + */ +class PeriodicTask: public PeriodicTaskIF { +public: + /** + * @brief Standard constructor of the class. + * @details The class is initialized without allocated objects. These need to be added + * with #addObject. + * In the underlying TaskBase class, a new operating system task is created. + * In addition to the TaskBase parameters, the period, the pointer to the + * aforementioned initialization function and an optional "deadline-missed" + * function pointer is passed. + * @param priority Sets the priority of a task. Values range from a low 0 to a high 99. + * @param stack_size The stack size reserved by the operating system for the task. + * @param setPeriod The length of the period with which the task's functionality will be + * executed. It is expressed in clock ticks. + * @param setDeadlineMissedFunc The function pointer to the deadline missed function + * that shall be assigned. + */ + PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, TaskPeriod setPeriod, + void (*setDeadlineMissedFunc)()); + /** + * @brief Currently, the executed object's lifetime is not coupled with the task object's + * lifetime, so the destructor is empty. + */ + virtual ~PeriodicTask(void); + + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask(void); + /** + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object Id of the object to add. + * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. + */ + ReturnValue_t addComponent(object_id_t object); + + uint32_t getPeriodMs() const; + + ReturnValue_t sleepFor(uint32_t ms); +protected: + bool started; + TaskHandle_t handle; + + typedef std::vector ObjectList; //!< Typedef for the List of objects. + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + /** + * @brief The period of the task. + * @details The period determines the frequency of the task's execution. It is expressed in clock ticks. + */ + TaskPeriod period; + /** + * @brief The pointer to the deadline-missed function. + * @details This pointer stores the function that is executed if the task's deadline is missed. + * So, each may react individually on a timing failure. The pointer may be NULL, + * then nothing happens on missing the deadline. The deadline is equal to the next execution + * of the periodic task. + */ + void (*deadlineMissedFunc)(void); + /** + * @brief This is the function executed in the new task's context. + * @details It converts the argument back to the thread object type and copies the class instance + * to the task context. The taskFunctionality method is called afterwards. + * @param A pointer to the task object itself is passed as argument. + */ + + static void taskEntryPoint(void* argument); + /** + * @brief The function containing the actual functionality of the task. + * @details The method sets and starts + * the task's period, then enters a loop that is repeated as long as the isRunning + * attribute is true. Within the loop, all performOperation methods of the added + * objects are called. Afterwards the checkAndRestartPeriod system call blocks the task + * until the next period. + * On missing the deadline, the deadlineMissedFunction is executed. + */ + void taskFunctionality(void); +}; + +#endif /* MULTIOBJECTTASK_H_ */ diff --git a/osal/FreeRTOS/QueueFactory.cpp b/osal/FreeRTOS/QueueFactory.cpp new file mode 100644 index 00000000..16d70c00 --- /dev/null +++ b/osal/FreeRTOS/QueueFactory.cpp @@ -0,0 +1,35 @@ +#include + +#include "../FreeRTOS/MessageQueue.h" + + +QueueFactory* QueueFactory::factoryInstance = NULL; + + +ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom) { + + return 0; +} + +QueueFactory* QueueFactory::instance() { + if (factoryInstance == NULL) { + factoryInstance = new QueueFactory; + } + return factoryInstance; +} + +QueueFactory::QueueFactory() { +} + +QueueFactory::~QueueFactory() { +} + +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t message_depth, + uint32_t max_message_size) { + return new MessageQueue(message_depth, max_message_size); +} + +void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { + delete queue; +} diff --git a/osal/FreeRTOS/TaskFactory.cpp b/osal/FreeRTOS/TaskFactory.cpp new file mode 100644 index 00000000..656a1e9a --- /dev/null +++ b/osal/FreeRTOS/TaskFactory.cpp @@ -0,0 +1,50 @@ +#include +#include + +#include "PeriodicTask.h" +#include "FixedTimeslotTask.h" + +//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? +TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); + +TaskFactory::~TaskFactory() { +} + +TaskFactory* TaskFactory::instance() { + return TaskFactory::factoryInstance; +} + +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, + TaskPriority taskPriority_, TaskStackSize stackSize_, + TaskPeriod period_, + TaskDeadlineMissedFunction deadLineMissedFunction_) { + return (PeriodicTaskIF*) (new PeriodicTask(name_, taskPriority_, stackSize_, + period_, deadLineMissedFunction_)); +} + +FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, + TaskPriority taskPriority_, TaskStackSize stackSize_, + TaskPeriod period_, + TaskDeadlineMissedFunction deadLineMissedFunction_) { + return (FixedTimeslotTaskIF*) (new FixedTimeslotTask(name_, taskPriority_, + stackSize_, period_, deadLineMissedFunction_)); +} + +ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { + if (task == NULL) { + //delete self + vTaskDelete(NULL); + return HasReturnvaluesIF::RETURN_OK; + } else { + //TODO not implemented + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t TaskFactory::delayTask(uint32_t delayMs) { + vTaskDelay(pdMS_TO_TICKS(delayMs)); + return HasReturnvaluesIF::RETURN_OK; +} + +TaskFactory::TaskFactory() { +} diff --git a/osal/FreeRTOS/Timekeeper.cpp b/osal/FreeRTOS/Timekeeper.cpp new file mode 100644 index 00000000..81f7f997 --- /dev/null +++ b/osal/FreeRTOS/Timekeeper.cpp @@ -0,0 +1,42 @@ +#include "Timekeeper.h" +#include + +Timekeeper::Timekeeper() : + offset( { 0, 0 }) { + // TODO Auto-generated constructor stub + +} + +Timekeeper * Timekeeper::myinstance = NULL; + +const timeval& Timekeeper::getOffset() const { + return offset; +} + +Timekeeper* Timekeeper::instance() { + if (myinstance == NULL) { + myinstance = new Timekeeper(); + } + return myinstance; +} + +void Timekeeper::setOffset(const timeval& offset) { + this->offset = offset; +} + +Timekeeper::~Timekeeper() { + // TODO Auto-generated destructor stub +} + +timeval Timekeeper::ticksToTimeval(TickType_t ticks) { + timeval uptime; + uptime.tv_sec = ticks / configTICK_RATE_HZ; + + //TODO explain, think about overflow + uint32_t subsecondTicks = ticks % configTICK_RATE_HZ; + uint64_t usecondTicks = subsecondTicks * 1000000; + + uptime.tv_usec = usecondTicks / configTICK_RATE_HZ; + + return uptime; +} diff --git a/osal/FreeRTOS/Timekeeper.h b/osal/FreeRTOS/Timekeeper.h new file mode 100644 index 00000000..2ba3e4a9 --- /dev/null +++ b/osal/FreeRTOS/Timekeeper.h @@ -0,0 +1,33 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ +#define FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ + +#include + +#include + +/** + * A Class to basically store the time difference between uptime and UTC + * so the "time-agnostic" FreeRTOS can keep an UTC Time + * + * Implemented as Singleton, so the FSFW Clock Implementation (see Clock.cpp) + * can use it without having a member. + */ + +class Timekeeper { +private: + Timekeeper(); + + timeval offset; + + static Timekeeper * myinstance; +public: + static Timekeeper * instance(); + virtual ~Timekeeper(); + + static timeval ticksToTimeval(TickType_t ticks); + + const timeval& getOffset() const; + void setOffset(const timeval& offset); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ */ diff --git a/osal/FreeRTOS/main.cpp b/osal/FreeRTOS/main.cpp new file mode 100644 index 00000000..3e760984 --- /dev/null +++ b/osal/FreeRTOS/main.cpp @@ -0,0 +1,31 @@ +//entry point into "bsp" +void init(void); + +#include +#include +#include "task.h" + + +void initTask(void *parameters) { + init(); +} + +int main(void) { + + if ( pdPASS + != xTaskCreate(initTask, "init", 512, NULL, + configMAX_PRIORITIES - 1, NULL)) { + //print_uart0("Could not create task1\r\n"); + } + + vTaskStartScheduler(); + + //Scheduler should never return + + //print_uart0("This is bad\n"); + + for (;;) + ; + + return 0; +} diff --git a/osal/CpuUsage.cpp b/osal/rtems/CpuUsage.cpp similarity index 100% rename from osal/CpuUsage.cpp rename to osal/rtems/CpuUsage.cpp diff --git a/osal/CpuUsage.h b/osal/rtems/CpuUsage.h similarity index 100% rename from osal/CpuUsage.h rename to osal/rtems/CpuUsage.h diff --git a/osal/rtems/PollingTask.cpp b/osal/rtems/PollingTask.cpp index c2ad74cd..13174ac3 100644 --- a/osal/rtems/PollingTask.cpp +++ b/osal/rtems/PollingTask.cpp @@ -86,7 +86,7 @@ void PollingTask::taskFunctionality() { //Do nothing } else { //The interval for the next polling slot is selected. - interval = this->pst.getIntervalMs(); + interval = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs()); //The period is checked and restarted with the new interval. //If the deadline was missed, the deadlineMissedFunc is called. status = rtems_rate_monotonic_period(periodId, interval); diff --git a/power/Fuse.h b/power/Fuse.h index 06b4ae81..6da24178 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -21,8 +21,7 @@ class Fuse: public SystemObject, public ReceivesParameterMessagesIF { friend void (Factory::setStaticFrameworkObjectIds)(); private: - //TODO, modern gcc complains about const - static const float RESIDUAL_POWER = 0.005 * 28.5; //!< This is the upper limit of residual power lost by fuses and switches. Worst case is Fuse and one of two switches on. See PCDU ICD 1.9 p29 bottom + static constexpr float RESIDUAL_POWER = 0.005 * 28.5; //!< This is the upper limit of residual power lost by fuses and switches. Worst case is Fuse and one of two switches on. See PCDU ICD 1.9 p29 bottom public: struct VariableIds { uint32_t pidVoltage; diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index 515b0ddb..64d1cb35 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -55,6 +55,7 @@ enum { DEVICE_COMMUNICATION_IF, //DC BSP, //BSP TIME_STAMPER_IF, //TSI 52 + SGP4PROPAGATOR_CLASS, //SGP4 53 FW_CLASS_ID_COUNT //is actually count + 1 ! }; diff --git a/serialize/EndianSwapper.h b/serialize/EndianSwapper.h index b46a2852..46f09224 100644 --- a/serialize/EndianSwapper.h +++ b/serialize/EndianSwapper.h @@ -25,6 +25,8 @@ public: return tmp; #elif BYTE_ORDER == BIG_ENDIAN return in; +#else +#error Unknown Byte Order #endif } static void swap(uint8_t* out, const uint8_t* in, uint32_t size) { diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index ceb81c4b..4bab4016 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -2,8 +2,8 @@ #include #include -//TODO Think of something different -#include +// to be implemented by bsp +extern "C" void printChar(const char*); int ServiceInterfaceBuffer::overflow(int c) { // Handle output @@ -28,7 +28,7 @@ int ServiceInterfaceBuffer::sync(void) { this->log_message.c_str(), (unsigned long) loggerTime.hour, (unsigned long) loggerTime.minute, (unsigned long) loggerTime.second, - (unsigned long) loggerTime.ticks); + (unsigned long) loggerTime.usecond /1000); // Write log_message and time this->putChars(preamble, preamble + sizeof(preamble)); // Handle output @@ -39,6 +39,27 @@ int ServiceInterfaceBuffer::sync(void) { return 0; } + +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) { + char array[BUF_SIZE]; + uint32_t length = end - begin; + if (length > sizeof(array)) { + length = sizeof(array); + } + memcpy(array, begin, length); + + for( ; begin != end; begin++){ + printChar(begin); + } + +} + #ifdef UT699 ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) { this->log_message = set_message; diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index 1688b115..672d238e 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -6,6 +6,46 @@ #include #include + +class ServiceInterfaceBuffer: public std::basic_streambuf > { + friend class ServiceInterfaceStream; +public: + ServiceInterfaceBuffer(std::string set_message, uint16_t port); +protected: + bool isActive; + // This is called when buffer becomes full. If + // buffer is not used, then this is called every + // time when characters are put to stream. + virtual int overflow(int c = Traits::eof()); + + // This function is called when stream is flushed, + // for example when std::endl is put to stream. + virtual int sync(void); + +private: + // For additional message information + std::string log_message; + // For EOF detection + typedef std::char_traits Traits; + + // Work in buffer mode. It is also possible to work without buffer. + static size_t const BUF_SIZE = 128; + char buf[BUF_SIZE]; + + // In this function, the characters are parsed. + void putChars(char const* begin, char const* end); +}; + + + + + + + + + + #ifdef UT699 class ServiceInterfaceBuffer: public std::basic_streambuf > { diff --git a/tasks/TaskFactory.h b/tasks/TaskFactory.h index 2a1684e6..8a59adf1 100644 --- a/tasks/TaskFactory.h +++ b/tasks/TaskFactory.h @@ -1,16 +1,14 @@ #ifndef FRAMEWORK_TASKS_TASKFACTORY_H_ #define FRAMEWORK_TASKS_TASKFACTORY_H_ +#include #include #include - - - /** * Singleton Class that produces Tasks. */ -class TaskFactory{ +class TaskFactory { public: virtual ~TaskFactory(); /** @@ -29,7 +27,10 @@ public: * @param deadLineMissedFunction_ Function to be called if a deadline was missed * @return PeriodicTaskIF* Pointer to the newly created Task */ - PeriodicTaskIF* createPeriodicTask(OSAL::TaskName name_,OSAL::TaskPriority taskPriority_,OSAL::TaskStackSize stackSize_,OSAL::TaskPeriod periodInSeconds_,OSAL::TaskDeadlineMissedFunction deadLineMissedFunction_); + PeriodicTaskIF* createPeriodicTask(TaskName name_, + TaskPriority taskPriority_, TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_); /** * @@ -40,15 +41,24 @@ public: * @param deadLineMissedFunction_ Function to be called if a deadline was missed * @return FixedTimeslotTaskIF* Pointer to the newly created Task */ - FixedTimeslotTaskIF* createFixedTimeslotTask(OSAL::TaskName name_,OSAL::TaskPriority taskPriority_,OSAL::TaskStackSize stackSize_,OSAL::TaskPeriod periodInSeconds_,OSAL::TaskDeadlineMissedFunction deadLineMissedFunction_); - + FixedTimeslotTaskIF* createFixedTimeslotTask(TaskName name_, + TaskPriority taskPriority_, TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_); /** * Function to be called to delete a task - * @param task The pointer to the task that shall be deleted + * @param task The pointer to the task that shall be deleted, NULL specifies current Task * @return Success of deletion */ - ReturnValue_t deleteTask(PeriodicTaskIF* task); + static ReturnValue_t deleteTask(PeriodicTaskIF* task = NULL); + + /** + * Function to be called to delay current task + * @param delay The delay in milliseconds + * @return Success of deletion + */ + static ReturnValue_t delayTask(uint32_t delayMs); private: /** @@ -57,9 +67,6 @@ private: TaskFactory(); static TaskFactory* factoryInstance; - }; - - #endif /* FRAMEWORK_TASKS_TASKFACTORY_H_ */ diff --git a/tasks/Typedef.h b/tasks/Typedef.h index bbea059a..190d05d7 100644 --- a/tasks/Typedef.h +++ b/tasks/Typedef.h @@ -1,21 +1,11 @@ #ifndef FRAMEWORK_TASKS_TYPEDEF_H_ #define FRAMEWORK_TASKS_TYPEDEF_H_ - -#ifndef API -#error Please specify Operating System API. Supported: API=RTEMS_API -#elif API == RTEMS_API -#include -namespace OSAL{ - typedef const char* TaskName; - typedef rtems_task_priority TaskPriority; - typedef size_t TaskStackSize; - typedef double TaskPeriod; - typedef void (*TaskDeadlineMissedFunction)(); -}; -#endif - - - +//TODO more generic? +typedef const char* TaskName; +typedef uint8_t TaskPriority; +typedef uint16_t TaskStackSize; +typedef double TaskPeriod; +typedef void (*TaskDeadlineMissedFunction)(); #endif /* FRAMEWORK_TASKS_TYPEDEF_H_ */ diff --git a/thermal/AbstractTemperatureSensor.h b/thermal/AbstractTemperatureSensor.h index d620bd05..75437dca 100644 --- a/thermal/AbstractTemperatureSensor.h +++ b/thermal/AbstractTemperatureSensor.h @@ -21,8 +21,7 @@ public: static const Event TEMP_SENSOR_LOW = MAKE_EVENT(1, SEVERITY::LOW); static const Event TEMP_SENSOR_GRADIENT = MAKE_EVENT(2, SEVERITY::LOW); - //TODO, modern gcc complains about const - static const float ZERO_KELVIN_C = -273.15; + static constexpr float ZERO_KELVIN_C = -273.15; AbstractTemperatureSensor(object_id_t setObjectid, ThermalModuleIF *thermalModule); virtual ~AbstractTemperatureSensor(); diff --git a/thermal/ThermalModuleIF.h b/thermal/ThermalModuleIF.h index a363aed6..2d11a6f2 100644 --- a/thermal/ThermalModuleIF.h +++ b/thermal/ThermalModuleIF.h @@ -18,8 +18,7 @@ public: NON_OPERATIONAL = 0, OPERATIONAL = 1, UNKNOWN = 2 }; - //TODO, modern gcc complains about const - static const float INVALID_TEMPERATURE = 999; + static constexpr float INVALID_TEMPERATURE = 999; virtual ~ThermalModuleIF() { diff --git a/timemanager/CCSDSTime.cpp b/timemanager/CCSDSTime.cpp index a4eaf555..171db377 100644 --- a/timemanager/CCSDSTime.cpp +++ b/timemanager/CCSDSTime.cpp @@ -44,8 +44,8 @@ ReturnValue_t CCSDSTime::convertToCcsds(Ccs_mseconds* to, to->hour = from->hour; to->minute = from->minute; to->second = from->second; - to->secondEminus2 = from->ticks / 10; - to->secondEminus4 = (from->ticks % 10) * 10; + to->secondEminus2 = from->usecond / 10000; + to->secondEminus4 = (from->usecond % 10) * 10 / 1000; return RETURN_OK; } @@ -128,13 +128,13 @@ ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* f to->month = temp->month; to->day = temp->day; - to->ticks = 0; + to->usecond = 0; if (subsecondsLength > 0) { *foundLength += 1; if (temp->secondEminus2 >= 100) { return INVALID_TIME_FORMAT; } - to->ticks = temp->secondEminus2 * 10; + to->usecond = temp->secondEminus2 * 10000; } if (subsecondsLength > 1) { @@ -142,7 +142,7 @@ ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* f if (temp->secondEminus4 >= 100) { return INVALID_TIME_FORMAT; } - to->ticks += temp->secondEminus4 / 10; + to->usecond += temp->secondEminus4 / 10 * 1000; } return RETURN_OK; @@ -170,7 +170,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* to->hour = hour; to->minute = minute; to->second = second; - to->ticks = (second - floor(second)) * 1000; + to->usecond = (second - floor(second)) * 1000000; return RETURN_OK; } @@ -190,7 +190,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* to->hour = hour; to->minute = minute; to->second = second; - to->ticks = (second - floor(second)) * 1000; + to->usecond = (second - floor(second)) * 1000000; return RETURN_OK; } @@ -425,7 +425,7 @@ ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) { return INVALID_TIME_FORMAT; } - if (time->ticks > 999) { + if (time->usecond > 999999) { return INVALID_TIME_FORMAT; } diff --git a/timemanager/CCSDSTime.h b/timemanager/CCSDSTime.h index bb7ad23a..92060d5d 100644 --- a/timemanager/CCSDSTime.h +++ b/timemanager/CCSDSTime.h @@ -1,6 +1,8 @@ #ifndef CCSDSTIME_H_ #define CCSDSTIME_H_ +// COULDDO: have calls in Clock.h which return time quality and use timespec accordingly + #include #include #include diff --git a/timemanager/Clock.h b/timemanager/Clock.h index 680350c4..af657247 100644 --- a/timemanager/Clock.h +++ b/timemanager/Clock.h @@ -18,13 +18,15 @@ public: uint32_t hour; //!< Hour, 0 .. 23. uint32_t minute; //!< Minute, 0 .. 59. uint32_t second; //!< Second, 0 .. 59. - uint32_t ticks; //!< Elapsed ticks between seconds. + uint32_t usecond; //!< Microseconds, 0 .. 999999 } TimeOfDay_t; /**static Clock* TimeOfDay_t(); * This method returns the number of clock ticks per second. * In RTEMS, this is typically 1000. * @return The number of ticks. + * + * @deprecated, we should not worry about ticks, but only time */ static uint32_t getTicksPerSecond(void); /** @@ -55,9 +57,13 @@ public: * * @param[out] time A pointer to a timeval struct where the uptime is stored. * @return\c RETURN_OK on success. Otherwise, the OS failure code is returned. + * + * @deprecated, I do not think this should be able to fail, use timeval getUptime() */ static ReturnValue_t getUptime(timeval* uptime); + static timeval getUptime(); + /** * Get the time since boot in milliseconds *