diff --git a/container/ArrayList.h b/container/ArrayList.h index a37a1c424..8138864b7 100644 --- a/container/ArrayList.h +++ b/container/ArrayList.h @@ -1,5 +1,5 @@ -#ifndef ARRAYLIST_H_ -#define ARRAYLIST_H_ +#ifndef FRAMEWORK_CONTAINER_ARRAYLIST_H_ +#define FRAMEWORK_CONTAINER_ARRAYLIST_H_ #include #include @@ -7,8 +7,9 @@ /** * @brief A List that stores its values in an array. - * @details The backend is an array that can be allocated - * by the class itself or supplied via ctor. + * @details + * The underlying storage is an array that can be allocated by the class + * itself or supplied via ctor. * * @ingroup container */ @@ -19,81 +20,13 @@ public: static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST; static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01); - /** - * An Iterator to go trough an ArrayList - * - * It stores a pointer to an element and increments the - * pointer when incremented itself. - */ - class Iterator { - public: - /** - * Empty ctor, points to NULL - */ - Iterator() : - value(0) { - - } - - /** - * Initializes the Iterator to point to an element - * - * @param initialize - */ - Iterator(T *initialize) { - value = initialize; - } - - /** - * The current element the iterator points to - */ - T *value; - - Iterator& operator++() { - value++; - return *this; - } - - Iterator operator++(int) { - Iterator tmp(*this); - operator++(); - return tmp; - } - - Iterator& operator--() { - value--; - return *this; - } - - Iterator operator--(int) { - Iterator tmp(*this); - operator--(); - return tmp; - } - - T operator*() { - return *value; - } - - T *operator->() { - return value; - } - - const T *operator->() const{ - return value; - } - - //SHOULDDO this should be implemented as non-member - bool operator==(const typename ArrayList::Iterator& other) const{ - return (value == other.value); - } - - //SHOULDDO this should be implemented as non-member - bool operator!=(const typename ArrayList::Iterator& other) const { - return !(*this == other); - } - } - ; + /** + * Copying is forbiden by declaring copy ctor and copy assignment deleted + * It is too ambigous in this case. + * (Allocate a new backend? Use the same? What to do in an modifying call?) + */ + ArrayList(const ArrayList& other) = delete; + const ArrayList& operator=(const ArrayList& other) = delete; /** * Number of Elements stored in this List @@ -134,6 +67,78 @@ public: } } + /** + * An Iterator to go trough an ArrayList + * + * It stores a pointer to an element and increments the + * pointer when incremented itself. + */ + class Iterator { + public: + /** + * Empty ctor, points to NULL + */ + Iterator(): value(0) {} + + /** + * Initializes the Iterator to point to an element + * + * @param initialize + */ + Iterator(T *initialize) { + value = initialize; + } + + /** + * The current element the iterator points to + */ + T *value; + + Iterator& operator++() { + value++; + return *this; + } + + Iterator operator++(int) { + Iterator tmp(*this); + operator++(); + return tmp; + } + + Iterator& operator--() { + value--; + return *this; + } + + Iterator operator--(int) { + Iterator tmp(*this); + operator--(); + return tmp; + } + + T operator*() { + return *value; + } + + T *operator->() { + return value; + } + + const T *operator->() const{ + return value; + } + + //SHOULDDO this should be implemented as non-member + bool operator==(const typename ArrayList::Iterator& other) const{ + return (value == other.value); + } + + //SHOULDDO this should be implemented as non-member + bool operator!=(const typename ArrayList::Iterator& other) const { + return !(*this == other); + } + }; + /** * Iterator pointing to the first stored elmement * @@ -223,19 +228,6 @@ public: return (maxSize_ - size); } -private: - /** - * This is the copy constructor - * - * It is private, as copying is too ambigous in this case. (Allocate a new backend? Use the same? - * What to do in an modifying call?) - * - * @param other - */ - ArrayList(const ArrayList& other) : - size(other.size), entries(other.entries), maxSize_(other.maxSize_), - allocated(false) {} - protected: /** * pointer to the array in which the entries are stored diff --git a/container/HybridIterator.h b/container/HybridIterator.h index 1c56aa13b..db1ce4bc8 100644 --- a/container/HybridIterator.h +++ b/container/HybridIterator.h @@ -8,13 +8,11 @@ template class HybridIterator: public LinkedElement::Iterator, public ArrayList::Iterator { public: - HybridIterator() : - value(NULL), linked(NULL), end(NULL) { - } + HybridIterator() {} HybridIterator(typename LinkedElement::Iterator *iter) : - LinkedElement::Iterator(*iter), value( - iter->value), linked(true), end(NULL) { + LinkedElement::Iterator(*iter), value(iter->value), + linked(true) { } @@ -66,11 +64,11 @@ public: return tmp; } - bool operator==(HybridIterator other) { + bool operator==(const HybridIterator& other) { return value == other.value; } - bool operator!=(HybridIterator other) { + bool operator!=(const HybridIterator& other) { return !(*this == other); } @@ -82,11 +80,11 @@ public: return value; } - T* value; + T* value = nullptr; private: - bool linked; - T *end; + bool linked = false; + T *end = nullptr; }; #endif /* HYBRIDITERATOR_H_ */ diff --git a/container/RingBufferBase.h b/container/RingBufferBase.h index 3ef782d87..1beb51c26 100644 --- a/container/RingBufferBase.h +++ b/container/RingBufferBase.h @@ -2,12 +2,14 @@ #define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ #include +#include template class RingBufferBase { public: - RingBufferBase(uint32_t startAddress, uint32_t size, bool overwriteOld) : - start(startAddress), write(startAddress), size(size), overwriteOld(overwriteOld) { + RingBufferBase(uint32_t startAddress, const size_t size, bool overwriteOld) : + start(startAddress), write(startAddress), size(size), + overwriteOld(overwriteOld) { for (uint8_t count = 0; count < N_READ_PTRS; count++) { read[count] = startAddress; } @@ -83,7 +85,7 @@ protected: const uint32_t start; uint32_t write; uint32_t read[N_READ_PTRS]; - const uint32_t size; + const size_t size; const bool overwriteOld; void incrementWrite(uint32_t amount) { write = ((write + amount - start) % size) + start; diff --git a/container/SimpleRingBuffer.cpp b/container/SimpleRingBuffer.cpp index 63dc3514b..4e50109be 100644 --- a/container/SimpleRingBuffer.cpp +++ b/container/SimpleRingBuffer.cpp @@ -1,11 +1,16 @@ #include -#include +#include -SimpleRingBuffer::SimpleRingBuffer(uint32_t size, bool overwriteOld) : - RingBufferBase<>(0, size, overwriteOld), buffer(NULL) { +SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld) : + RingBufferBase<>(0, size, overwriteOld) { buffer = new uint8_t[size]; } +SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size, + bool overwriteOld): + RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {} + + SimpleRingBuffer::~SimpleRingBuffer() { delete[] buffer; } @@ -66,3 +71,4 @@ ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount, incrementRead(amount, READ_PTR); return HasReturnvaluesIF::RETURN_OK; } + diff --git a/container/SimpleRingBuffer.h b/container/SimpleRingBuffer.h index 4552a1c0a..b5bc2c1c6 100644 --- a/container/SimpleRingBuffer.h +++ b/container/SimpleRingBuffer.h @@ -5,13 +5,29 @@ #include /** - * @brief Circular buffer implementation, useful for buffering into data streams. - * @details Note that the deleteData() has to be called to increment the read pointer + * @brief Circular buffer implementation, useful for buffering + * into data streams. + * @details + * Note that the deleteData() has to be called to increment the read pointer. + * This class allocated dynamically, so * @ingroup containers */ class SimpleRingBuffer: public RingBufferBase<> { public: - SimpleRingBuffer(uint32_t size, bool overwriteOld); + /** + * This constructor allocates a new internal buffer with the supplied size. + * @param size + * @param overwriteOld + */ + SimpleRingBuffer(const size_t size, bool overwriteOld); + /** + * This constructor takes an external buffer with the specified size. + * @param buffer + * @param size + * @param overwriteOld + */ + SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld); + virtual ~SimpleRingBuffer(); /** @@ -30,7 +46,8 @@ public: * @param trueAmount * @return */ - ReturnValue_t readData(uint8_t* data, uint32_t amount, bool readRemaining = false, uint32_t* trueAmount = NULL); + ReturnValue_t readData(uint8_t* data, uint32_t amount, + bool readRemaining = false, uint32_t* trueAmount = nullptr); /** * Delete data starting by incrementing read pointer @@ -39,11 +56,12 @@ public: * @param trueAmount * @return */ - ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, uint32_t* trueAmount = NULL); + ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, + uint32_t* trueAmount = nullptr); private: // static const uint8_t TEMP_READ_PTR = 1; static const uint8_t READ_PTR = 0; - uint8_t* buffer; + uint8_t* buffer = nullptr; }; #endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ diff --git a/container/SinglyLinkedList.h b/container/SinglyLinkedList.h index 54e7687cd..3c0078fc4 100644 --- a/container/SinglyLinkedList.h +++ b/container/SinglyLinkedList.h @@ -1,8 +1,9 @@ -#ifndef SINGLYLINKEDLIST_H_ -#define SINGLYLINKEDLIST_H_ +#ifndef FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_ +#define FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_ + +#include +#include -#include -#include /** * @brief Linked list data structure, * each entry has a pointer to the next entry (singly) @@ -14,11 +15,8 @@ public: T *value; class Iterator { public: - LinkedElement *value; - Iterator() : - value(NULL) { - - } + LinkedElement *value = nullptr; + Iterator() {} Iterator(LinkedElement *element) : value(element) { @@ -47,12 +45,11 @@ public: } }; - LinkedElement(T* setElement, LinkedElement* setNext = NULL) : value(setElement), - next(setNext) { - } - virtual ~LinkedElement(){ + LinkedElement(T* setElement, LinkedElement* setNext = nullptr): + value(setElement), next(setNext) {} + + virtual ~LinkedElement(){} - } virtual LinkedElement* getNext() const { return next; } @@ -61,15 +58,15 @@ public: this->next = next; } - void setEnd() { - this->next = nullptr; + virtual void setEnd() { + this->next = nullptr; } LinkedElement* begin() { return this; } LinkedElement* end() { - return NULL; + return nullptr; } private: LinkedElement *next; @@ -78,21 +75,21 @@ private: template class SinglyLinkedList { public: - SinglyLinkedList() : - start(NULL) { - } + using ElementIterator = typename LinkedElement::Iterator; + + SinglyLinkedList() {} + + SinglyLinkedList(ElementIterator start) : + start(start.value) {} - SinglyLinkedList(typename LinkedElement::Iterator start) : - start(start.value) { - } SinglyLinkedList(LinkedElement* startElement) : - start(startElement) { - } - typename LinkedElement::Iterator begin() const { - return LinkedElement::Iterator::Iterator(start); + start(startElement) {} + + ElementIterator begin() const { + return ElementIterator::Iterator(start); } - typename LinkedElement::Iterator::Iterator end() const { - return LinkedElement::Iterator::Iterator(); + typename ElementIterator::Iterator end() const { + return ElementIterator::Iterator(); } uint32_t getSize() const { @@ -107,8 +104,15 @@ public: void setStart(LinkedElement* setStart) { start = setStart; } + + void setEnd(LinkedElement* setEnd) { + setEnd->setEnd(); + } + + // SHOULDDO: Insertion operation ? + protected: - LinkedElement *start; + LinkedElement *start = nullptr; }; #endif /* SINGLYLINKEDLIST_H_ */ diff --git a/datapool/DataSetBase.cpp b/datapool/DataSetBase.cpp index 60b20f296..b788d05da 100644 --- a/datapool/DataSetBase.cpp +++ b/datapool/DataSetBase.cpp @@ -53,6 +53,10 @@ ReturnValue_t DataSetBase::read(uint32_t lockTimeout) { return result; } +uint16_t DataSetBase::getFillCount() const { + return fillCount; +} + ReturnValue_t DataSetBase::readVariable(uint16_t count) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; // These checks are often performed by the respective diff --git a/datapool/DataSetBase.h b/datapool/DataSetBase.h index 8bf9a99a3..8f7d892a9 100644 --- a/datapool/DataSetBase.h +++ b/datapool/DataSetBase.h @@ -101,8 +101,10 @@ public: */ virtual ReturnValue_t unlockDataPool() override; + virtual uint16_t getFillCount() const; + /* SerializeIF implementations */ - ReturnValue_t serialize(uint8_t** buffer, size_t* size, + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize, bool bigEndian) const override; virtual size_t getSerializedSize() const override; virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, diff --git a/datapool/DataSetIF.h b/datapool/DataSetIF.h index 9c5b13c81..437f324f6 100644 --- a/datapool/DataSetIF.h +++ b/datapool/DataSetIF.h @@ -43,6 +43,7 @@ public: */ virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0; + virtual uint16_t getFillCount() const = 0; private: /** * @brief Most underlying data structures will have a pool like structure diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp index 58694508f..e0731a96c 100644 --- a/datapoollocal/LocalDataPoolManager.cpp +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -1,16 +1,17 @@ #include #include -#include -#include #include #include +#include #include -LocalDataPoolManager::LocalDataPoolManager(OwnsLocalDataPoolIF* owner) { +LocalDataPoolManager::LocalDataPoolManager(OwnsLocalDataPoolIF* owner, + uint32_t replyQueueDepth, bool appendValidityBuffer): + appendValidityBuffer(appendValidityBuffer) { if(owner == nullptr) { sif::error << "HkManager: Invalid supplied owner!" << std::endl; - std::exit(0); + return; } this->owner = owner; mutex = MutexFactory::instance()->createMutex(); @@ -23,6 +24,8 @@ LocalDataPoolManager::LocalDataPoolManager(OwnsLocalDataPoolIF* owner) { sif::error << "LocalDataPoolManager::LocalDataPoolManager: " "Could not set IPC store." << std::endl; } + hkQueue = QueueFactory::instance()->createMessageQueue(replyQueueDepth, + HousekeepingMessage::HK_MESSAGE_SIZE); } LocalDataPoolManager::~LocalDataPoolManager() {} @@ -30,19 +33,35 @@ LocalDataPoolManager::~LocalDataPoolManager() {} ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { if(not mapInitialized) { ReturnValue_t result = - owner->initializeHousekeepingPoolEntries(localDpMap); + owner->initializePoolEntries(localDpMap); if(result == HasReturnvaluesIF::RETURN_OK) { mapInitialized = true; } return result; } - sif::warning << "HousekeepingManager: The map" << std::endl; + sif::warning << "HousekeepingManager: The map should only be initialized " + "once!" << std::endl; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( HousekeepingMessage& message) { - return HasReturnvaluesIF::RETURN_FAILED; + Command_t command = message.getCommand(); + switch(command) { + // I think those are the only commands which can be handled here.. + case(HousekeepingMessage::ADD_HK_REPORT_STRUCT): + case(HousekeepingMessage::ADD_DIAGNOSTICS_REPORT_STRUCT): + // We should use OwnsLocalPoolDataIF to specify those functions.. + return HasReturnvaluesIF::RETURN_OK; + case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): + case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): + return generateSetStructurePacket(message.getSid()); + case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): + case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): + return generateHousekeepingPacket(message.getSid()); + default: + return CommandMessageIF::UNKNOWN_COMMAND; + } } ReturnValue_t LocalDataPoolManager::printPoolEntry( @@ -51,7 +70,7 @@ ReturnValue_t LocalDataPoolManager::printPoolEntry( if (poolIter == localDpMap.end()) { sif::debug << "HousekeepingManager::fechPoolEntry:" " Pool entry not found." << std::endl; - return OwnsLocalDataPoolIF::POOL_ENTRY_NOT_FOUND; + return POOL_ENTRY_NOT_FOUND; } poolIter->second->print(); return HasReturnvaluesIF::RETURN_OK; @@ -61,6 +80,15 @@ MutexIF* LocalDataPoolManager::getMutexHandle() { return mutex; } +void LocalDataPoolManager::setHkPacketDestination( + MessageQueueId_t destinationQueueId) { + this->currentHkPacketDestination = destinationQueueId; +} + +const OwnsLocalDataPoolIF* LocalDataPoolManager::getOwner() const { + return owner; +} + ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid) { LocalDataSet* dataSetToSerialize = dynamic_cast( owner->getDataSetHandle(sid)); @@ -70,28 +98,84 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid) { return HasReturnvaluesIF::RETURN_FAILED; } store_address_t storeId; - size_t hkSize = dataSetToSerialize->getSerializedSize(); - uint8_t* storePtr = nullptr; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, hkSize,&storePtr); + ReturnValue_t result = serializeHkPacketIntoStore(&storeId, + dataSetToSerialize); if(result != HasReturnvaluesIF::RETURN_OK) { - sif::warning << "HousekeepingManager::generateHousekeepingPacket: " - "Could not get free element from IPC store." << std::endl; return result; } - size_t size = 0; - dataSetToSerialize->serialize(&storePtr, &size, hkSize, false); - // and now we have to set a HK message and send it the queue. - return HasReturnvaluesIF::RETURN_OK; + + // and now we set a HK message and send it the HK packet destination. + MessageQueueMessage message; + HousekeepingMessage hkMessage(&message); + hkMessage.setHkReportMessage(sid, storeId); + if(hkQueue == nullptr) { + return QUEUE_NOT_SET; + } + + if(currentHkPacketDestination != MessageQueueIF::NO_QUEUE) { + result = hkQueue->sendMessage(currentHkPacketDestination, &hkMessage); + } + else { + result = hkQueue->sendToDefault(&hkMessage); + } + + return result; } -void LocalDataPoolManager::setHkPacketQueue(MessageQueueIF *msgQueue) { - this->hkPacketQueue = msgQueue; +ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid) { + LocalDataSet* dataSet = dynamic_cast( + owner->getDataSetHandle(sid)); + if(dataSet == nullptr) { + sif::warning << "HousekeepingManager::generateHousekeepingPacket:" + " Set ID not found" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + size_t expectedSize = dataSet->getFillCount() * sizeof(lp_id_t); + uint8_t* storePtr = nullptr; + store_address_t storeId; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + expectedSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "HousekeepingManager::generateHousekeepingPacket: " + "Could not get free element from IPC store." << std::endl; + return result; + } + size_t size = 0; + result = dataSet->serializeLocalPoolIds(&storePtr, &size, + expectedSize, false); + if(expectedSize != size) { + sif::error << "HousekeepingManager::generateSetStructurePacket: " + "Expected size is not equal to serialized size" << std::endl; + } + return result; } -void LocalDataPoolManager::setHkReplyQueue(MessageQueueIF *replyQueue) { - this->hkReplyQueue = replyQueue; +ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( + store_address_t *storeId, LocalDataSet* dataSet) { + size_t hkSize = dataSet->getSerializedSize(); + uint8_t* storePtr = nullptr; + ReturnValue_t result = ipcStore->getFreeElement(storeId, hkSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "HousekeepingManager::generateHousekeepingPacket: " + "Could not get free element from IPC store." << std::endl; + return result; + } + size_t size = 0; + + if(appendValidityBuffer) { + result = dataSet->serializeWithValidityBuffer(&storePtr, + &size, hkSize, false); + } + else { + result = dataSet->serialize(&storePtr, &size, hkSize, false); + } + + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "HousekeepingManager::serializeHkPacketIntoStore: " + "Serialization proccess failed!" << std::endl; + } + return result; } -const OwnsLocalDataPoolIF* LocalDataPoolManager::getOwner() const { - return owner; -} + + diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h index d1a2d410c..b64917241 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/datapoollocal/LocalDataPoolManager.h @@ -13,6 +13,8 @@ #include +class LocalDataSet; + /** * @brief This class is the managing instance for local data pool. * @details @@ -37,8 +39,16 @@ class LocalDataPoolManager { friend class LocalPoolVector; friend class LocalDataSet; public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER; - LocalDataPoolManager(OwnsLocalDataPoolIF* owner); + static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x0); + static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x1); + + static constexpr ReturnValue_t QUEUE_NOT_SET = MAKE_RETURN_CODE(0x2); + //static constexpr ReturnValue_t SET_NOT_FOUND = MAKE_RETURN_CODE(0x3); + + LocalDataPoolManager(OwnsLocalDataPoolIF* owner, + uint32_t replyQueueDepth = 20, bool appendValidityBuffer = true); virtual~ LocalDataPoolManager(); /* Copying forbidden */ @@ -46,6 +56,8 @@ public: LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete; ReturnValue_t generateHousekeepingPacket(sid_t sid); + ReturnValue_t generateSetStructurePacket(sid_t sid); + ReturnValue_t handleHousekeepingMessage(HousekeepingMessage& message); /** @@ -57,10 +69,7 @@ public: ReturnValue_t initializeHousekeepingPoolEntriesOnce(); //! Set the queue for HK packets, which are sent unrequested. - void setHkPacketQueue(MessageQueueIF* msgQueue); - //! Set the queue for replies. This can be set manually or by the owner - //! class if the manager if message are relayed by it. - void setHkReplyQueue(MessageQueueIF* replyQueue); + void setHkPacketDestination(MessageQueueId_t destinationQueueId); const OwnsLocalDataPoolIF* getOwner() const; @@ -70,6 +79,10 @@ private: //! This is the map holding the actual data. Should only be initialized //! once ! bool mapInitialized = false; + //! This specifies whether a validity buffer is appended at the end + //! of generated housekeeping packets. + bool appendValidityBuffer = true; + LocalDataPool localDpMap; //! Every housekeeping data manager has a mutex to protect access @@ -79,13 +92,14 @@ private: //! The class which actually owns the manager (and its datapool). OwnsLocalDataPoolIF* owner = nullptr; - //! Used for replies. - //! (maybe we dont need this, the sender can be retrieved from command - //! message..) - MessageQueueIF* hkReplyQueue = nullptr; - //! Used for HK packets, which are generated without requests. - //! Maybe this will just be the TM funnel. - MessageQueueIF* hkPacketQueue = nullptr; + //! Queue used for communication, for example commands. + //! Is also used to send messages. + MessageQueueIF* hkQueue = nullptr; + + //! HK replies will always be a reply to the commander, but HK packet + //! can be sent to another destination by specifying this message queue + //! ID, for example to a dedicated housekeeping service implementation. + MessageQueueId_t currentHkPacketDestination = MessageQueueIF::NO_QUEUE; //! Global IPC store is used to store all packets. StorageManagerIF* ipcStore = nullptr; @@ -113,6 +127,8 @@ private: PoolEntry **poolEntry); void setMinimalSamplingFrequency(float frequencySeconds); + ReturnValue_t serializeHkPacketIntoStore(store_address_t* storeId, + LocalDataSet* dataSet); }; @@ -123,14 +139,14 @@ ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, if (poolIter == localDpMap.end()) { sif::debug << "HousekeepingManager::fechPoolEntry:" " Pool entry not found." << std::endl; - return OwnsLocalDataPoolIF::POOL_ENTRY_NOT_FOUND; + return POOL_ENTRY_NOT_FOUND; } *poolEntry = dynamic_cast< PoolEntry* >(poolIter->second); if(*poolEntry == nullptr) { sif::debug << "HousekeepingManager::fetchPoolEntry:" " Pool entry not found." << std::endl; - return OwnsLocalDataPoolIF::POOL_ENTRY_TYPE_CONFLICT; + return POOL_ENTRY_TYPE_CONFLICT; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/datapoollocal/LocalDataSet.cpp b/datapoollocal/LocalDataSet.cpp index 243c9cc1d..27ad4bc2a 100644 --- a/datapoollocal/LocalDataSet.cpp +++ b/datapoollocal/LocalDataSet.cpp @@ -1,22 +1,26 @@ #include #include +#include + +#include +#include LocalDataSet::LocalDataSet(OwnsLocalDataPoolIF *hkOwner): DataSetBase() { - if(hkOwner != nullptr) { - hkManager = hkOwner->getHkManagerHandle(); - } - else { - // config error, error output here. - } + if(hkOwner == nullptr) { + sif::error << "LocalDataSet::LocalDataSet: Owner can't be nullptr!" + << std::endl; + } + hkManager = hkOwner->getHkManagerHandle(); } LocalDataSet::LocalDataSet(object_id_t ownerId): DataSetBase() { - OwnsLocalDataPoolIF* hkOwner = objectManager->get( - ownerId); - if(hkOwner == nullptr) { - // config error, error output here. - } - hkManager = hkOwner->getHkManagerHandle(); + OwnsLocalDataPoolIF* hkOwner = objectManager->get( + ownerId); + if(hkOwner == nullptr) { + sif::error << "LocalDataSet::LocalDataSet: Owner can't be nullptr!" + << std::endl; + } + hkManager = hkOwner->getHkManagerHandle(); } LocalDataSet::~LocalDataSet() { @@ -27,9 +31,65 @@ ReturnValue_t LocalDataSet::lockDataPool(uint32_t timeoutMs) { return mutex->lockMutex(timeoutMs); } +ReturnValue_t LocalDataSet::serializeWithValidityBuffer(uint8_t **buffer, + size_t *size, const size_t maxSize, bool bigEndian) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); + uint8_t validityMask[validityMaskSize]; + uint8_t validBufferIndex = 0; + uint8_t validBufferIndexBit = 0; + for (uint16_t count = 0; count < fillCount; count++) { + if(registeredVariables[count]->isValid()) { + // set validity buffer here. + this->bitSetter(validityMask + validBufferIndex, + validBufferIndexBit, true); + if(validBufferIndexBit == 7) { + validBufferIndex ++; + validBufferIndexBit = 0; + } + else { + validBufferIndexBit ++; + } + } + result = registeredVariables[count]->serialize(buffer, size, maxSize, + bigEndian); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + // copy validity buffer to end + std::memcpy(*buffer, validityMask, validityMaskSize); + *size += validityMaskSize; + return result; +} + ReturnValue_t LocalDataSet::unlockDataPool() { MutexIF* mutex = hkManager->getMutexHandle(); return mutex->unlockMutex(); } +ReturnValue_t LocalDataSet::serializeLocalPoolIds(uint8_t** buffer, + size_t* size, const size_t maxSize, bool bigEndian) const { + for (uint16_t count = 0; count < fillCount; count++) { + lp_id_t currentPoolId = registeredVariables[count]->getDataPoolId(); + auto result = AutoSerializeAdapter::serialize(¤tPoolId, buffer, + size, maxSize, bigEndian); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization" + " error!" << std::endl; + return result; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +void LocalDataSet::bitSetter(uint8_t* byte, uint8_t position, + bool value) const { + if(position > 7) { + sif::debug << "Pool Raw Access: Bit setting invalid position" << std::endl; + return; + } + uint8_t shiftNumber = position + (7 - 2 * position); + *byte |= 1UL << shiftNumber; +} diff --git a/datapoollocal/LocalDataSet.h b/datapoollocal/LocalDataSet.h index 54da5562c..48138e631 100644 --- a/datapoollocal/LocalDataSet.h +++ b/datapoollocal/LocalDataSet.h @@ -55,6 +55,23 @@ public: */ ~LocalDataSet(); + /** + * Special version of the serilization function which appends a + * validity buffer at the end. Each bit of this validity buffer + * denotes whether the container data set entries are valid from left + * to right, MSB first. + * @param buffer + * @param size + * @param maxSize + * @param bigEndian + * @param withValidityBuffer + * @return + */ + ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer, + size_t* size, const size_t maxSize, bool bigEndian) const; + + ReturnValue_t serializeLocalPoolIds(uint8_t** buffer, + size_t* size, const size_t maxSize, bool bigEndian) const; protected: private: /** @@ -79,6 +96,16 @@ private: ReturnValue_t unlockDataPool() override; LocalDataPoolManager* hkManager; + + /** + * Sets the bit at the bit-position of a byte provided by its address + * to the specified value (zero or one). + * @param byte Pointer to byte to bitset. + * @param position MSB first, 0 to 7 possible. + * @param value Value to set. + * @return + */ + void bitSetter(uint8_t* byte, uint8_t position, bool value) const; }; #endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ */ diff --git a/datapoollocal/OwnsLocalDataPoolIF.h b/datapoollocal/OwnsLocalDataPoolIF.h index cf94f946a..6fc108896 100644 --- a/datapoollocal/OwnsLocalDataPoolIF.h +++ b/datapoollocal/OwnsLocalDataPoolIF.h @@ -40,16 +40,38 @@ class OwnsLocalDataPoolIF { public: virtual~ OwnsLocalDataPoolIF() {}; - static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING; - static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0XA0); - static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0xA1); + static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; + /** Command queue for housekeeping messages. */ virtual MessageQueueId_t getCommandQueue() const = 0; - virtual ReturnValue_t initializeHousekeepingPoolEntries( - LocalDataPool& localDataPoolMap) = 0; - //virtual float setMinimalHkSamplingFrequency() = 0; + + /** Is used by pool owner to initialize the pool map once */ + virtual ReturnValue_t initializePoolEntries( + LocalDataPool& localDataPoolMap) = 0; + + /** Can be used to get a handle to the local data pool manager. */ virtual LocalDataPoolManager* getHkManagerHandle() = 0; + + /** + * This function is used by the pool manager to get a valid dataset + * from a SID + * @param sid Corresponding structure ID + * @return + */ virtual DataSetIF* getDataSetHandle(sid_t sid) = 0; + + /* These function can be implemented by pool owner, as they are required + * by the housekeeping message interface */ + virtual ReturnValue_t addDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + virtual ReturnValue_t removeDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + virtual ReturnValue_t changeCollectionInterval(sid_t sid, + dur_seconds_t newInterval) { + return HasReturnvaluesIF::RETURN_FAILED; + }; }; #endif /* FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ */ diff --git a/devicehandlers/DeviceCommunicationIF.h b/devicehandlers/DeviceCommunicationIF.h index 20565025e..a2662d465 100644 --- a/devicehandlers/DeviceCommunicationIF.h +++ b/devicehandlers/DeviceCommunicationIF.h @@ -72,7 +72,7 @@ public: * by implementing and calling related drivers or wrapper functions. * @param cookie * @param data - * @param len + * @param len If this is 0, nothing shall be sent. * @return * - @c RETURN_OK for successfull send * - Everything else triggers failure event with returnvalue as parameter 1 diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index bf6998485..1ae056a6d 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -1350,7 +1350,7 @@ void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { } void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ - executingTask = task_; + executingTask = task_; } // Default implementations empty. @@ -1360,7 +1360,7 @@ void DeviceHandlerBase::debugInterface(uint8_t positionTracker, void DeviceHandlerBase::performOperationHook() { } -ReturnValue_t DeviceHandlerBase::initializeHousekeepingPoolEntries( +ReturnValue_t DeviceHandlerBase::initializePoolEntries( LocalDataPool &localDataPoolMap) { return RETURN_OK; } @@ -1369,6 +1369,19 @@ LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { return &hkManager; } +ReturnValue_t DeviceHandlerBase::addDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DeviceHandlerBase::removeDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t DeviceHandlerBase::changeCollectionInterval(sid_t sid, + dur_seconds_t newInterval) { + return HasReturnvaluesIF::RETURN_OK; +} + DataSetIF* DeviceHandlerBase::getDataSetHandle(sid_t sid) { auto iter = deviceReplyMap.find(sid.ownerSetId); if(iter != deviceReplyMap.end()) { diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 4ee3d652c..1290742c3 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -477,12 +477,17 @@ protected: * @param localDataPoolMap * @return */ - virtual ReturnValue_t initializeHousekeepingPoolEntries( + virtual ReturnValue_t initializePoolEntries( LocalDataPool& localDataPoolMap) override; /** Get the HK manager object handle */ virtual LocalDataPoolManager* getHkManagerHandle() override; + virtual ReturnValue_t addDataSet(sid_t sid) override; + virtual ReturnValue_t removeDataSet(sid_t sid) override; + virtual ReturnValue_t changeCollectionInterval(sid_t sid, + dur_seconds_t newInterval) override; + /** * @brief Hook function for child handlers which is called once per * performOperation(). Default implementation is empty. @@ -703,7 +708,9 @@ protected: bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. - PeriodicTaskIF* executingTask = nullptr;//!< Pointer to the task which executes this component, is invalid before setTaskIF was called. + //! Pointer to the task which executes this component, is invalid + //! before setTaskIF was called. + PeriodicTaskIF* executingTask = nullptr; static object_id_t powerSwitcherId; //!< Object which switches power on and off. diff --git a/events/EventManager.cpp b/events/EventManager.cpp index 73e77e94a..30f5ed718 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -8,13 +8,16 @@ const uint16_t EventManager::POOL_SIZES[N_POOLS] = { sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher), sizeof(ReporterRangeMatcher) }; -//If one checks registerListener calls, there are around 40 (to max 50) objects registering for certain events. -//Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. So a good guess is 75 to a max of 100 pools required for each, which fits well. +// If one checks registerListener calls, there are around 40 (to max 50) +// objects registering for certain events. +// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. +// So a good guess is 75 to a max of 100 pools required for each, which fits well. +// SHOULDDO: Shouldn't this be in the config folder and passed via ctor? const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 }; EventManager::EventManager(object_id_t setObjectId) : - SystemObject(setObjectId), eventReportQueue(NULL), mutex(NULL), factoryBackend( - 0, POOL_SIZES, N_ELEMENTS, false, true) { + SystemObject(setObjectId), + factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) { mutex = MutexFactory::instance()->createMutex(); eventReportQueue = QueueFactory::instance()->createMessageQueue( MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE); @@ -130,20 +133,23 @@ void EventManager::printEvent(EventMessage* message) { break; default: string = translateObject(message->getReporter()); - sif::error << "EVENT: "; + sif::debug << "EventManager: "; if (string != 0) { - sif::error << string; - } else { - sif::error << "0x" << std::hex << message->getReporter() << std::dec; + sif::debug << string; } - sif::error << " reported " << translateEvents(message->getEvent()) << " (" - << std::dec << message->getEventId() << ") " << std::endl; - - sif::error << std::hex << "P1 Hex: 0x" << message->getParameter1() << ", P1 Dec: " - << std::dec << message->getParameter1() << std::endl; - sif::error << std::hex << "P2 Hex: 0x" << message->getParameter2() << ", P2 Dec: " - << std::dec << message->getParameter2() << std::endl; + else { + sif::debug << "0x" << std::hex << message->getReporter() << std::dec; + } + sif::debug << " reported " << translateEvents(message->getEvent()) + << " (" << std::dec << message->getEventId() << ") " + << std::endl; + sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1() + << ", P1 Dec: " << std::dec << message->getParameter1() + << std::endl; + sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2() + << ", P2 Dec: " << std::dec << message->getParameter2() + << std::endl; break; } diff --git a/events/EventManager.h b/events/EventManager.h index 76dde9f8d..6fac83526 100644 --- a/events/EventManager.h +++ b/events/EventManager.h @@ -36,11 +36,11 @@ public: ReturnValue_t performOperation(uint8_t opCode); protected: - MessageQueueIF* eventReportQueue; + MessageQueueIF* eventReportQueue = nullptr; std::map listenerList; - MutexIF* mutex; + MutexIF* mutex = nullptr; static const uint8_t N_POOLS = 3; LocalPool factoryBackend; diff --git a/housekeeping/HousekeepingMessage.cpp b/housekeeping/HousekeepingMessage.cpp index d47fb92ad..d7efd7031 100644 --- a/housekeeping/HousekeepingMessage.cpp +++ b/housekeeping/HousekeepingMessage.cpp @@ -4,8 +4,8 @@ HousekeepingMessage::HousekeepingMessage(MessageQueueMessageIF* message): CommandMessageBase(message) { if(message->getMaximumMessageSize() < HK_MESSAGE_SIZE) { - sif::error << "CommandMessage::ComandMessage: Passed message buffer" - " can not hold minimum "<< HK_MESSAGE_SIZE + sif::error << "HousekeepingMessage::HousekeepingMessage: Passed " + "message buffer can not hold minimum " << HK_MESSAGE_SIZE << " bytes!" << std::endl; return; } diff --git a/housekeeping/HousekeepingMessage.h b/housekeeping/HousekeepingMessage.h index c5e31fdad..c6a33c835 100644 --- a/housekeeping/HousekeepingMessage.h +++ b/housekeeping/HousekeepingMessage.h @@ -36,8 +36,8 @@ union sid_t { class HousekeepingMessage : public CommandMessageBase { public: - static constexpr size_t HK_MESSAGE_SIZE = sizeof(MessageQueueId_t) - + sizeof(Command_t) + sizeof(sid_t) * sizeof(uint32_t); + static constexpr size_t HK_MESSAGE_SIZE = CommandMessageIF::HEADER_SIZE + + sizeof(sid_t) + sizeof(uint32_t); /** * The HK message is initialized with a pointer to a message which holds @@ -96,6 +96,7 @@ public: void setParameter(uint32_t parameter); uint32_t getParameter() const; + sid_t getSid() const; void setHkReportMessage(sid_t sid, store_address_t storeId); void setHkDiagnosticsMessage(sid_t sid, store_address_t storeId); @@ -106,7 +107,7 @@ public: virtual size_t getMinimumMessageSize() const override; virtual void clear() override; private: - sid_t getSid() const; + void setSid(sid_t sid); virtual uint8_t* getData() override; diff --git a/ipc/CommandMessage.cpp b/ipc/CommandMessage.cpp index 163a6a2d6..9a8a82f24 100644 --- a/ipc/CommandMessage.cpp +++ b/ipc/CommandMessage.cpp @@ -12,7 +12,7 @@ CommandMessage::CommandMessage(MessageQueueMessageIF* receiverMessage): if(receiverMessage->getMaximumMessageSize() < getMinimumMessageSize()) { sif::error << "CommandMessage::ComandMessage: Passed message buffer" - " can not hold minimum "<< MINIMUM_COMMAND_MESSAGE_SIZE + " can not hold minimum "<< getMinimumMessageSize() << " bytes!" << std::endl; return; } diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index 18ec1092f..f3a65fcdd 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -1,6 +1,7 @@ -#include #include "FixedTimeslotTask.h" +#include + uint32_t FixedTimeslotTask::deadlineMissedCount = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; @@ -18,16 +19,19 @@ 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. + // 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 + /* Task should not start until explicitly requested, + * but 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) { + if (not originalTask->started) { vTaskSuspend(NULL); } @@ -58,11 +62,6 @@ ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { if (objectManager->get(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); return HasReturnvaluesIF::RETURN_OK; } @@ -81,7 +80,8 @@ ReturnValue_t FixedTimeslotTask::checkSequence() const { } 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 + // start time for the first entry. SlotListIter slotListIter = pst.current; //The start time for the first entry is read. @@ -96,22 +96,37 @@ void FixedTimeslotTask::taskFunctionality() { xLastWakeTime = xTaskGetTickCount(); // wait for first entry's start time - vTaskDelayUntil(&xLastWakeTime, interval); + if(interval > 0) { + 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 - } + this->pst.executeAndAdvance(); + if (not pst.slotFollowsImmediately()) { + /* If all operations are finished and the difference of the + * current time minus the last wake time is larger than the + * expected wait period, a deadline was missed. */ + if(xTaskGetTickCount() - xLastWakeTime >= + pdMS_TO_TICKS(this->pst.getIntervalToPreviousSlotMs())) { +#ifdef DEBUG + sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << + " missed deadline!\n" << std::flush; +#endif + if(deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } + // Continue immediately, no need to wait. + break; + } + + // 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); + } } } @@ -119,3 +134,4 @@ 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 index fe93dafff..183fad20c 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -1,12 +1,12 @@ -#ifndef POLLINGTASK_H_ -#define POLLINGTASK_H_ +#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ -#include +#include #include #include -#include -#include "task.h" +#include +#include class FixedTimeslotTask: public FixedTimeslotTaskIF { public: @@ -29,16 +29,18 @@ public: /** * @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. + * @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. + * It counts missedDeadlines and prints the number of missed deadlines + * every 10th time. */ static void missedDeadlineCounter(); /** @@ -47,13 +49,13 @@ public: static uint32_t deadlineMissedCount; 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); + ReturnValue_t sleepFor(uint32_t ms) override; protected: bool started; @@ -62,30 +64,29 @@ protected: 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. + * @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. + * @brief This is the entry point for a new task. + * @details + * This method starts the task by calling taskFunctionality(), as soon as + * all requirements (task scheduler has started and startTask() + * has been called) are met. */ 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. + * @details + * Core function holding the main functionality of the task + * It links the functionalities provided by FixedSlotSequence with the + * OS's System Calls to keep the timing of the periods. */ void taskFunctionality(void); }; diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index a8e405613..43928f7c2 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -12,8 +12,8 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, BaseType_t status = xTaskCreate(taskEntryPoint, name, setStack, this, setPriority, &handle); if(status != pdPASS){ - sif::debug << "PeriodicTask Insufficient heap memory remaining. Status: " - << status << std::endl; + sif::debug << "PeriodicTask Insufficient heap memory remaining. " + "Status: " << status << std::endl; } } @@ -23,14 +23,17 @@ PeriodicTask::~PeriodicTask(void) { } void PeriodicTask::taskEntryPoint(void* argument) { - //The argument is re-interpreted as PeriodicTask. The Task object is global, so it is found from any place. + // 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 + /* Task should not start until explicitly requested, + * but 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 (not originalTask->started) { vTaskSuspend(NULL); @@ -61,38 +64,45 @@ 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(). */ + 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(); + for (auto const& object: objectList) { + object->performOperation(); } /* If all operations are finished and the difference of the * current time minus the last wake time is larger than the * wait period, a deadline was missed. */ if(xTaskGetTickCount() - xLastWakeTime >= xPeriod) { +#ifdef DEBUG sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << " missed deadline!\n" << std::flush; +#endif if(deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } } + vTaskDelayUntil(&xLastWakeTime, xPeriod); } } -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { +ReturnValue_t PeriodicTask::addComponent(object_id_t object, bool setTaskIF) { ExecutableObjectIF* newObject = objectManager->get( object); - if (newObject == NULL) { + if (newObject == nullptr) { + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + "it implement ExecutableObjectIF" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } + if(setTaskIF) { + newObject->setTaskIF(this); + } objectList.push_back(newObject); return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/FreeRTOS/PeriodicTask.h b/osal/FreeRTOS/PeriodicTask.h index a449328e3..a580f519f 100644 --- a/osal/FreeRTOS/PeriodicTask.h +++ b/osal/FreeRTOS/PeriodicTask.h @@ -5,10 +5,8 @@ #include #include -extern "C" { #include #include -} #include @@ -22,7 +20,9 @@ class ExecutableObjectIF; class PeriodicTask: public PeriodicTaskIF { public: /** - * @brief Standard constructor of the class. + * Keep in Mind that you need to call before this vTaskStartScheduler()! + * A lot of task parameters are set in "FreeRTOSConfig.h". + * TODO: why does this need to be called before vTaskStartScheduler? * @details * The class is initialized without allocated objects. * These need to be added with #addComponent. @@ -38,8 +38,9 @@ public: * The function pointer to the deadline missed function that shall * be assigned. */ - PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, - TaskPeriod setPeriod,void (*setDeadlineMissedFunc)()); + 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. @@ -53,56 +54,66 @@ public: * The address of the task object is passed as an argument * to the system call. */ - ReturnValue_t startTask(void); + ReturnValue_t startTask() override; /** * 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. + * @return + * -@c RETURN_OK on success + * -@c RETURN_FAILED if the object could not be added. */ - ReturnValue_t addComponent(object_id_t object); + ReturnValue_t addComponent(object_id_t object, + bool setTaskIF = true) override; - uint32_t getPeriodMs() const; + uint32_t getPeriodMs() const override; - ReturnValue_t sleepFor(uint32_t ms); + ReturnValue_t sleepFor(uint32_t ms) override; protected: bool started; TaskHandle_t handle; - typedef std::vector ObjectList; //!< Typedef for the List of objects. + //! Typedef for the List of objects. + typedef std::vector ObjectList; /** * @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. + * @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. + * @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. + * @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. + * @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); }; diff --git a/osal/host/FixedTimeslotTask.h b/osal/host/FixedTimeslotTask.h index bb2f757aa..b12cc6d3d 100644 --- a/osal/host/FixedTimeslotTask.h +++ b/osal/host/FixedTimeslotTask.h @@ -2,7 +2,7 @@ #define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ #include -#include +#include #include #include diff --git a/osal/linux/FixedTimeslotTask.h b/osal/linux/FixedTimeslotTask.h index 916e6d6cc..409cd9821 100644 --- a/osal/linux/FixedTimeslotTask.h +++ b/osal/linux/FixedTimeslotTask.h @@ -2,7 +2,7 @@ #define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ #include -#include +#include #include #include diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index df5bbf930..fe8ac19ce 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -1,12 +1,13 @@ #include #include -#include #include +#include + PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): - PosixThread(name_,priority_,stackSize_),objectList(),started(false), - periodMs(period_),deadlineMissedFunc(deadlineMissedFunc_) { + PosixThread(name_, priority_, stackSize_), objectList(), started(false), + periodMs(period_), deadlineMissedFunc(deadlineMissedFunc_) { } PeriodicPosixTask::~PeriodicPosixTask() { @@ -21,12 +22,18 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) { return NULL; } -ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { +ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object, + bool setTaskIF) { ExecutableObjectIF* newObject = objectManager->get( object); - if (newObject == NULL) { + if (newObject == nullptr) { + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + "it implements ExecutableObjectIF" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } + if(setTaskIF) { + newObject->setTaskIF(this); + } objectList.push_back(newObject); return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/linux/PeriodicPosixTask.h b/osal/linux/PeriodicPosixTask.h index 85de0d597..1d62a5659 100644 --- a/osal/linux/PeriodicPosixTask.h +++ b/osal/linux/PeriodicPosixTask.h @@ -39,7 +39,8 @@ public: * @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); + ReturnValue_t addComponent(object_id_t object, + bool setTaskIF = true) override; uint32_t getPeriodMs() const; diff --git a/osal/rtems/PollingTask.cpp b/osal/rtems/PollingTask.cpp index 6b0c0fbd6..a6be7ddf4 100644 --- a/osal/rtems/PollingTask.cpp +++ b/osal/rtems/PollingTask.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/osal/rtems/PollingTask.h b/osal/rtems/PollingTask.h index 82ec65a2d..5bf8cf57e 100644 --- a/osal/rtems/PollingTask.h +++ b/osal/rtems/PollingTask.h @@ -1,7 +1,7 @@ #ifndef POLLINGTASK_H_ #define POLLINGTASK_H_ -#include +#include #include #include "TaskBase.h" diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index 870efb461..ddee539e3 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -61,8 +61,9 @@ enum { MUTEX_IF, //MUX 55 MESSAGE_QUEUE_IF,//MQI 56 SEMAPHORE_IF, //SPH 57 - HOUSEKEEPING, //HK 58 + LOCAL_POOL_OWNER_IF, //LPIF 58 POOL_VARIABLE_IF, //PVA 59 + HOUSEKEEPING_MANAGER, //HKM 60 FW_CLASS_ID_COUNT //is actually count + 1 ! }; diff --git a/serialize/SerializeAdapter.h b/serialize/SerializeAdapter.h index 87e4457ae..62c202043 100644 --- a/serialize/SerializeAdapter.h +++ b/serialize/SerializeAdapter.h @@ -65,6 +65,21 @@ // No type specification necessary here. class AutoSerializeAdapter { public: + /** + * Serialize object into buffer. + * @tparam T Type of object. + * @param object Object to serialize + * @param buffer + * Serialize into this buffer, pointer to pointer has to be passed, + * *buffer will be incremented automatically. + * @param size [out] + * Update passed size value, will be incremented by serialized size + * @param max_size + * Maximum size for range checking + * @param bigEndian + * Set to true if host-to-network conversion or vice-versa is needed + * @return + */ template static ReturnValue_t serialize(const T* object, uint8_t** buffer, size_t* size, const size_t max_size, bool bigEndian) { diff --git a/tasks/ExecutableObjectIF.h b/tasks/ExecutableObjectIF.h index 5c5955c1c..516b4084b 100644 --- a/tasks/ExecutableObjectIF.h +++ b/tasks/ExecutableObjectIF.h @@ -37,8 +37,10 @@ public: /** * @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 - * enables the object implementation to overwrite this function and get a reference to the executing task + * @details + * 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 */ virtual void setTaskIF(PeriodicTaskIF* task_) { diff --git a/devicehandlers/FixedSequenceSlot.cpp b/tasks/FixedSequenceSlot.cpp similarity index 53% rename from devicehandlers/FixedSequenceSlot.cpp rename to tasks/FixedSequenceSlot.cpp index bb97a8e5c..c46b4fc00 100644 --- a/devicehandlers/FixedSequenceSlot.cpp +++ b/tasks/FixedSequenceSlot.cpp @@ -1,19 +1,14 @@ -/** - * @file PollingSlot.cpp - * @brief This file defines the PollingSlot class. - * @date 19.12.2012 - * @author baetz - */ - -#include #include +#include #include FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId, PeriodicTaskIF* executingTask) : - handler(NULL), pollingTimeMs(setTime), opcode(setSequenceId) { + pollingTimeMs(setTime), opcode(setSequenceId) { handler = objectManager->get(handlerId); - handler->setTaskIF(executingTask); + if(executingTask != nullptr) { + handler->setTaskIF(executingTask); + } } FixedSequenceSlot::~FixedSequenceSlot() {} diff --git a/devicehandlers/FixedSequenceSlot.h b/tasks/FixedSequenceSlot.h similarity index 78% rename from devicehandlers/FixedSequenceSlot.h rename to tasks/FixedSequenceSlot.h index 7868cce30..72a35c744 100644 --- a/devicehandlers/FixedSequenceSlot.h +++ b/tasks/FixedSequenceSlot.h @@ -1,22 +1,17 @@ -/** - * @file FixedSequenceSlot.h - * @brief This file defines the PollingSlot class. - * @date 19.12.2012 - * @author baetz - */ - -#ifndef FIXEDSEQUENCESLOT_H_ -#define FIXEDSEQUENCESLOT_H_ +#ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ +#define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ #include #include class PeriodicTaskIF; /** - * @brief This class is the representation of a single polling sequence table entry. - * - * @details The PollingSlot class is the representation of a single polling - * sequence table entry. + * @brief This class is the representation of a single polling sequence + * table entry. + * @details + * The PollingSlot class is the representation of a single polling + * sequence table entry. + * @author baetz */ class FixedSequenceSlot { public: @@ -27,7 +22,7 @@ public: /** * @brief Handler identifies which device handler object is executed in this slot. */ - ExecutableObjectIF* handler; + ExecutableObjectIF* handler = nullptr; /** * @brief This attribute defines when a device handler object is executed. @@ -43,7 +38,7 @@ public: * @details The state of this value decides what communication routine is * called in the PST executable or the device handler object. */ - uint8_t opcode; + uint8_t opcode; /** * @brief Operator overload for the comparison operator to diff --git a/devicehandlers/FixedSlotSequence.cpp b/tasks/FixedSlotSequence.cpp similarity index 98% rename from devicehandlers/FixedSlotSequence.cpp rename to tasks/FixedSlotSequence.cpp index aeb97f3a5..3e542bfce 100644 --- a/devicehandlers/FixedSlotSequence.cpp +++ b/tasks/FixedSlotSequence.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : diff --git a/devicehandlers/FixedSlotSequence.h b/tasks/FixedSlotSequence.h similarity index 97% rename from devicehandlers/FixedSlotSequence.h rename to tasks/FixedSlotSequence.h index 145cdbc30..7de1884c4 100644 --- a/devicehandlers/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -1,8 +1,8 @@ -#ifndef FIXEDSLOTSEQUENCE_H_ -#define FIXEDSLOTSEQUENCE_H_ +#ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ +#define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ -#include #include +#include #include diff --git a/tasks/FixedTimeslotTaskIF.h b/tasks/FixedTimeslotTaskIF.h index 7edd67519..023b5ee04 100644 --- a/tasks/FixedTimeslotTaskIF.h +++ b/tasks/FixedTimeslotTaskIF.h @@ -12,11 +12,18 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF { public: virtual ~FixedTimeslotTaskIF() {} + /** + * Add an object with a slot time and the execution step to the task. + * The execution step shall be passed to the object. + * @param componentId + * @param slotTimeMs + * @param executionStep + * @return + */ virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) = 0; + /** Check whether the sequence is valid */ virtual ReturnValue_t checkSequence() const = 0; }; - - #endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */ diff --git a/tasks/PeriodicTaskIF.h b/tasks/PeriodicTaskIF.h index 304a7de60..6f4909771 100644 --- a/tasks/PeriodicTaskIF.h +++ b/tasks/PeriodicTaskIF.h @@ -1,9 +1,11 @@ -#ifndef PERIODICTASKIF_H_ -#define PERIODICTASKIF_H_ +#ifndef FRAMEWORK_TASK_PERIODICTASKIF_H_ +#define FRAMEWORK_TASK_PERIODICTASKIF_H_ #include +#include #include class ExecutableObjectIF; + /** * New version of TaskIF * Follows RAII principles, i.e. there's no create or delete method. @@ -17,11 +19,27 @@ public: */ virtual ~PeriodicTaskIF() { } /** - * @brief With the startTask method, a created task can be started for the first time. + * @brief With the startTask method, a created task can be started + * for the first time. */ virtual ReturnValue_t startTask() = 0; - virtual ReturnValue_t addComponent(object_id_t object) {return HasReturnvaluesIF::RETURN_FAILED;}; + /** + * Add a component (object) to a periodic task. The pointer to the + * task can be set optionally + * @param object + * Add an object to the task. The most important case is to add an + * executable object with a function which will be called regularly + * (see ExecutableObjectIF) + * @param setTaskIF + * Can be used to specify whether the task object pointer is passed + * to the component. + * @return + */ + virtual ReturnValue_t addComponent(object_id_t object, + bool setTaskIF = true) { + return HasReturnvaluesIF::RETURN_FAILED; + }; virtual ReturnValue_t sleepFor(uint32_t ms) = 0; diff --git a/tmtcservices/CommandingServiceBase.cpp b/tmtcservices/CommandingServiceBase.cpp index 97856b40a..4d29c10e6 100644 --- a/tmtcservices/CommandingServiceBase.cpp +++ b/tmtcservices/CommandingServiceBase.cpp @@ -412,5 +412,6 @@ void CommandingServiceBase::checkTimeout() { } } - - +void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) { + executingTask = task_; +} diff --git a/tmtcservices/CommandingServiceBase.h b/tmtcservices/CommandingServiceBase.h index 5e2c31713..05f50709b 100644 --- a/tmtcservices/CommandingServiceBase.h +++ b/tmtcservices/CommandingServiceBase.h @@ -97,9 +97,7 @@ public: * Used to setup the reference of the task, that executes this component * @param task_ Pointer to the taskIF of this task */ - virtual void setTaskIF(PeriodicTaskIF* task_){ - executingTask = task_; - }; + virtual void setTaskIF(PeriodicTaskIF* task_); protected: /**