diff --git a/action/ActionHelper.cpp b/action/ActionHelper.cpp index 9c1475f1..ef9f06a9 100644 --- a/action/ActionHelper.cpp +++ b/action/ActionHelper.cpp @@ -49,7 +49,7 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress) { const uint8_t* dataPtr = NULL; - uint32_t size = 0; + size_t size = 0; ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); if (result != HasReturnvaluesIF::RETURN_OK) { CommandMessage reply; @@ -67,16 +67,17 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t act } } -ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data, bool hideSender) { +ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, + ActionId_t replyId, SerializeIF* data, bool hideSender) { CommandMessage reply; store_address_t storeAddress; uint8_t *dataPtr; - uint32_t maxSize = data->getSerializedSize(); + size_t maxSize = data->getSerializedSize(); if (maxSize == 0) { //No error, there's simply nothing to report. return HasReturnvaluesIF::RETURN_OK; } - uint32_t size = 0; + size_t size = 0; ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize, &dataPtr); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/action/CommandActionHelper.cpp b/action/CommandActionHelper.cpp index 05eb9346..77295401 100644 --- a/action/CommandActionHelper.cpp +++ b/action/CommandActionHelper.cpp @@ -20,13 +20,13 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, } store_address_t storeId; uint8_t* storePointer; - uint32_t maxSize = data->getSerializedSize(); + size_t maxSize = data->getSerializedSize(); ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize, &storePointer); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - uint32_t size = 0; + size_t size = 0; result = data->serialize(&storePointer, &size, maxSize, true); if (result != HasReturnvaluesIF::RETURN_OK) { return result; @@ -113,7 +113,7 @@ uint8_t CommandActionHelper::getCommandCount() const { void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) { const uint8_t * data = NULL; - uint32_t size = 0; + size_t size = 0; ReturnValue_t result = ipcStore->getData(storeId, &data, &size); if (result != HasReturnvaluesIF::RETURN_OK) { return; diff --git a/action/HasActionsIF.h b/action/HasActionsIF.h index f30fcb45..12ecb89a 100644 --- a/action/HasActionsIF.h +++ b/action/HasActionsIF.h @@ -7,8 +7,10 @@ #include #include /** - * \brief Interface for component which uses actions + * @brief + * Interface for component which uses actions * + * @details * This interface is used to execute actions in the component. Actions, in the sense of this interface, are activities with a well-defined beginning and * end in time. They may adjust sub-states of components, but are not supposed to change * the main mode of operation, which is handled with the HasModesIF described below. @@ -23,6 +25,8 @@ * parameters and immediately start execution of the action. It is, however, not required to * immediately finish execution. Instead, this may be deferred to a later point in time, at * which the component needs to inform the caller about finished or failed execution. + * + * \ingroup interfaces */ class HasActionsIF { public: @@ -40,10 +44,11 @@ public: /** * Execute or initialize the execution of a certain function. * Returning #EXECUTION_FINISHED or a failure code, nothing else needs to be done. - * When needing more steps, return RETURN_OK and issue steps and completion manually. One "step failed" or completion report must - * be issued! + * When needing more steps, return RETURN_OK and issue steps and completion manually. + * One "step failed" or completion report must be issued! */ - virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) = 0; + virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, + const uint8_t* data, size_t size) = 0; }; diff --git a/action/SimpleActionHelper.cpp b/action/SimpleActionHelper.cpp index 6de372fb..6861fc28 100644 --- a/action/SimpleActionHelper.cpp +++ b/action/SimpleActionHelper.cpp @@ -44,7 +44,7 @@ void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, queueToUse->sendMessage(commandedBy, &reply); } const uint8_t* dataPtr = NULL; - uint32_t size = 0; + size_t size = 0; ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); if (result != HasReturnvaluesIF::RETURN_OK) { ActionMessage::setStepReply(&reply, actionId, 0, result); diff --git a/container/ArrayList.h b/container/ArrayList.h index 9c4c4ceb..f978c984 100644 --- a/container/ArrayList.h +++ b/container/ArrayList.h @@ -6,10 +6,9 @@ #include /** - * A List that stores its values in an array. - * - * The backend is an array that can be allocated by the class itself or supplied via ctor. - * + * @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. * * @ingroup container */ @@ -223,6 +222,7 @@ public: count_t remaining() { return (maxSize_ - size); } + private: /** * This is the copy constructor @@ -233,9 +233,9 @@ private: * @param other */ ArrayList(const ArrayList& other) : - size(other.size), entries(other.entries), maxSize_(other.maxSize_), allocated( - false) { - } + size(other.size), entries(other.entries), maxSize_(other.maxSize_), + allocated(false) {} + protected: /** * pointer to the array in which the entries are stored @@ -251,5 +251,24 @@ protected: */ bool allocated; + /** + * Swap the endianness of the Array list (not the length field !) + * Useful if the case the buffer type is larger than uint8_t + * @param list + */ + void swapArrayListEndianness() { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + count_t i = 0; + // uint8_t buffer does not require swapping of entries. + if(sizeof(T) == 1) { + return; + } + while ((result == HasReturnvaluesIF::RETURN_OK) && (i < size)) { + T newEntry = EndianSwapper::swap(entries[i]); + entries[i] = newEntry; + ++i; + } + } }; + #endif /* ARRAYLIST_H_ */ diff --git a/container/FIFO.h b/container/FIFO.h index 670a50d7..00f56993 100644 --- a/container/FIFO.h +++ b/container/FIFO.h @@ -3,6 +3,11 @@ #include +/** + * @brief Simple First-In-First-Out data structure + * @tparam T Entry Type + * @tparam capacity Maximum capacity + */ template class FIFO { private: @@ -21,7 +26,7 @@ public: readIndex(0), writeIndex(0), currentSize(0) { } - bool emtpy() { + bool empty() { return (currentSize == 0); } @@ -45,7 +50,7 @@ public: } ReturnValue_t retrieve(T *value) { - if (emtpy()) { + if (empty()) { return EMPTY; } else { *value = data[readIndex]; diff --git a/container/FixedArrayList.h b/container/FixedArrayList.h index eeffcc87..12e292b4 100644 --- a/container/FixedArrayList.h +++ b/container/FixedArrayList.h @@ -2,8 +2,10 @@ #define FIXEDARRAYLIST_H_ #include + /** - * \ingroup container + * @brief Array List with a fixed maximum size + * @ingroup container */ template class FixedArrayList: public ArrayList { @@ -14,6 +16,18 @@ public: ArrayList(data, MAX_SIZE) { } + //We could create a constructor to initialize the fixed array list with data and the known size field + //so it can be used for serialization too (with SerialFixedArrrayListAdapter) + //is this feasible? + FixedArrayList(T * data_, count_t count, bool swapArrayListEndianess = false): + ArrayList(data, MAX_SIZE) { + memcpy(this->data, data_, count * sizeof(T)); + this->size = count; + if(swapArrayListEndianess) { + ArrayList::swapArrayListEndianness(); + } + } + FixedArrayList(const FixedArrayList& other) : ArrayList(data, MAX_SIZE) { memcpy(this->data, other.data, sizeof(this->data)); diff --git a/container/FixedMap.h b/container/FixedMap.h index 0b84bf4e..7f3d28f7 100644 --- a/container/FixedMap.h +++ b/container/FixedMap.h @@ -6,7 +6,11 @@ #include /** - * \ingroup container + * @brief Map implementation for maps with a pre-defined size. + * @details Can be initialized with desired maximum size. + * Iterator is used to access pair and + * iterate through map entries. Complexity O(n). + * @ingroup container */ template class FixedMap: public SerializeIF { @@ -52,12 +56,24 @@ public: return ArrayList, uint32_t>::Iterator::value->second; } + // -> operator overloaded, can be used to access value T *operator->() { return &ArrayList, uint32_t>::Iterator::value->second; } + // Can be used to access the key of the iterator + key_t first() { + return ArrayList, uint32_t>::Iterator::value->first; + } + + // Alternative to access value, similar to std::map implementation + T second() { + return ArrayList, uint32_t>::Iterator::value->second; + } }; + + Iterator begin() const { return Iterator(&theMap[0]); } @@ -72,10 +88,10 @@ public: ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) { if (exists(key) == HasReturnvaluesIF::RETURN_OK) { - return KEY_ALREADY_EXISTS; + return FixedMap::KEY_ALREADY_EXISTS; } if (_size == theMap.maxSize()) { - return MAP_FULL; + return FixedMap::MAP_FULL; } theMap[_size].first = key; theMap[_size].second = value; @@ -87,7 +103,7 @@ public: } ReturnValue_t insert(std::pair pair) { - return insert(pair.fist, pair.second); + return insert(pair.first, pair.second); } ReturnValue_t exists(key_t key) const { @@ -148,8 +164,17 @@ public: return theMap.maxSize(); } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + bool full() { + if(_size == theMap.maxSize()) { + return true; + } + else { + return false; + } + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result = SerializeAdapter::serialize(&this->_size, buffer, size, max_size, bigEndian); uint32_t i = 0; @@ -163,7 +188,7 @@ public: return result; } - virtual uint32_t getSerializedSize() const { + virtual size_t getSerializedSize() const { uint32_t printSize = sizeof(_size); uint32_t i = 0; @@ -176,7 +201,7 @@ public: return printSize; } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { ReturnValue_t result = SerializeAdapter::deSerialize(&this->_size, buffer, size, bigEndian); diff --git a/container/FixedOrderedMultimap.h b/container/FixedOrderedMultimap.h index 21629664..3dd20a74 100644 --- a/container/FixedOrderedMultimap.h +++ b/container/FixedOrderedMultimap.h @@ -10,7 +10,7 @@ template> class FixedOrderedMultimap { public: - static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP; + static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MULTIMAP; static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01); static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02); static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); diff --git a/container/HybridIterator.h b/container/HybridIterator.h index b34fdfd0..1c56aa13 100644 --- a/container/HybridIterator.h +++ b/container/HybridIterator.h @@ -67,7 +67,7 @@ public: } bool operator==(HybridIterator other) { - return value == other->value; + return value == other.value; } bool operator!=(HybridIterator other) { diff --git a/container/IndexedRingMemoryArray.h b/container/IndexedRingMemoryArray.h index eacfe3e5..8682780a 100644 --- a/container/IndexedRingMemoryArray.h +++ b/container/IndexedRingMemoryArray.h @@ -8,20 +8,27 @@ #include #include +/** + * Index is the Type used for the list of indices. + * + * @tparam T Type which destribes the index. Needs to be a child of SerializeIF + * to be able to make it persistent + */ template class Index: public SerializeIF{ /** - * Index is the Type used for the list of indices. The template parameter is the type which describes the index, it needs to be a child of SerializeIF to be able to make it persistent + * */ - static_assert(std::is_base_of::value,"Wrong Type for Index, Type must implement SerializeIF"); + static_assert(std::is_base_of::value, + "Wrong Type for Index, Type must implement SerializeIF"); public: Index():blockStartAddress(0),size(0),storedPackets(0){} - Index(uint32_t startAddress):blockStartAddress(startAddress),size(0),storedPackets(0){ - + Index(uint32_t startAddress):blockStartAddress(startAddress), + size(0),storedPackets(0) { } - void setBlockStartAddress(uint32_t newAddress){ + void setBlockStartAddress(uint32_t newAddress) { this->blockStartAddress = newAddress; } @@ -33,7 +40,7 @@ public: return &indexType; } - T* modifyIndexType(){ + T* modifyIndexType() { return &indexType; } /** @@ -128,26 +135,35 @@ private: }; - +/** + * @brief Indexed Ring Memory Array is a class for a ring memory with indices. + * @details + * It assumes that the newest data comes in last + * It uses the currentWriteBlock as pointer to the current writing position + * The currentReadBlock must be set manually + * @tparam T + */ template class IndexedRingMemoryArray: public SerializeIF, public ArrayList, uint32_t>{ /** - * Indexed Ring Memory Array is a class for a ring memory with indices. It assumes that the newest data comes in last - * It uses the currentWriteBlock as pointer to the current writing position - * The currentReadBlock must be set manually + * */ public: - IndexedRingMemoryArray(uint32_t startAddress, uint32_t size, uint32_t bytesPerBlock, SerializeIF* additionalInfo, - bool overwriteOld) :ArrayList,uint32_t>(NULL,(uint32_t)10,(uint32_t)0),totalSize(size),indexAddress(startAddress),currentReadSize(0),currentReadBlockSizeCached(0),lastBlockToReadSize(0), additionalInfo(additionalInfo),overwriteOld(overwriteOld){ - + IndexedRingMemoryArray(uint32_t startAddress, uint32_t size, uint32_t bytesPerBlock, + SerializeIF* additionalInfo, bool overwriteOld): + ArrayList,uint32_t>(NULL,(uint32_t)10,(uint32_t)0),totalSize(size), + indexAddress(startAddress),currentReadSize(0),currentReadBlockSizeCached(0), + lastBlockToReadSize(0), additionalInfo(additionalInfo),overwriteOld(overwriteOld) + { //Calculate the maximum number of indices needed for this blocksize uint32_t maxNrOfIndices = floor(static_cast(size)/static_cast(bytesPerBlock)); //Calculate the Size needeed for the index itself - uint32_t serializedSize = 0; - if(additionalInfo!=NULL){ + size_t serializedSize = 0; + if(additionalInfo!=NULL) { serializedSize += additionalInfo->getSerializedSize(); } + //Size of current iterator type Index tempIndex; serializedSize += tempIndex.getSerializedSize(); @@ -162,6 +178,7 @@ public: error << "IndexedRingMemory: Store is too small for index" << std::endl; } uint32_t useableSize = totalSize - serializedSize; + //Update the totalSize for calculations totalSize = useableSize; @@ -178,12 +195,10 @@ public: this->allocated = true; //Check trueNumberOfBlocks - if(trueNumberOfBlocks<1){ + if(trueNumberOfBlocks<1) { error << "IndexedRingMemory: Invalid Number of Blocks: " << trueNumberOfBlocks; } - - //Fill address into index uint32_t address = trueStartAddress; for (typename IndexedRingMemoryArray::Iterator it = this->begin();it!=this->end();++it) { @@ -193,7 +208,6 @@ public: address += bytesPerBlock; } - //Initialize iterators currentWriteBlock = this->begin(); currentReadBlock = this->begin(); @@ -232,10 +246,10 @@ public: (*typeResetFnc)(it->modifyIndexType()); } - /* + /** * Reading + * @param it */ - void setCurrentReadBlock(typename IndexedRingMemoryArray::Iterator it){ currentReadBlock = it; currentReadBlockSizeCached = it->getSize(); @@ -248,6 +262,7 @@ public: lastBlockToRead = currentWriteBlock; lastBlockToReadSize = currentWriteBlock->getSize(); } + /** * Sets the last block to read to this iterator. * Can be used to dump until block x @@ -292,33 +307,39 @@ public: uint32_t getCurrentReadAddress() const { return getAddressOfCurrentReadBlock() + currentReadSize; } + /** - * Adds readSize to the current size and checks if the read has no more data left and advances the read block + * Adds readSize to the current size and checks if the read has no more data + * left and advances the read block. * @param readSize The size that was read * @return Returns true if the read can go on */ bool addReadSize(uint32_t readSize) { - if(currentReadBlock == lastBlockToRead){ + if(currentReadBlock == lastBlockToRead) { //The current read block is the last to read - if((currentReadSize+readSize) return true currentReadSize += readSize; return true; - }else{ + } + else { //Reached end of read -> return false currentReadSize = lastBlockToReadSize; return false; } - }else{ + } + else { //We are not in the last Block - if((currentReadSize + readSize)::Iterator it(currentReadBlock); //Search if any block between this and the last block is not empty @@ -421,13 +442,13 @@ public: T* modifyCurrentWriteBlockIndexType(){ return currentWriteBlock->modifyIndexType(); } + void updatePreviousWriteSize(uint32_t size, uint32_t storedPackets){ typename IndexedRingMemoryArray::Iterator it = getPreviousBlock(currentWriteBlock); it->addSize(size); it->addStoredPackets(storedPackets); } - /** * Checks if the block has enough space for sizeToWrite * @param sizeToWrite The data to be written in the Block @@ -436,7 +457,10 @@ public: bool hasCurrentWriteBlockEnoughSpace(uint32_t sizeToWrite){ typename IndexedRingMemoryArray::Iterator next = getNextWrite(); uint32_t addressOfNextBlock = next->getBlockStartAddress(); - uint32_t availableSize = ((addressOfNextBlock+totalSize) - (getAddressOfCurrentWriteBlock()+getSizeOfCurrentWriteBlock()))%totalSize; + uint32_t availableSize = + ( ( addressOfNextBlock + totalSize ) - + (getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock())) + % totalSize; return (sizeToWrite < availableSize); } @@ -524,9 +548,9 @@ public: * Get the serialized Size of the index * @return The serialized size of the index */ - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { - uint32_t size = 0; + size_t size = 0; if(additionalInfo!=NULL){ size += additionalInfo->getSerializedSize(); } @@ -694,7 +718,4 @@ private: }; - - - #endif /* FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ */ diff --git a/container/SimpleRingBuffer.h b/container/SimpleRingBuffer.h index 6d7d67e1..4552a1c0 100644 --- a/container/SimpleRingBuffer.h +++ b/container/SimpleRingBuffer.h @@ -4,12 +4,41 @@ #include #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 + * @ingroup containers + */ class SimpleRingBuffer: public RingBufferBase<> { public: SimpleRingBuffer(uint32_t size, bool overwriteOld); virtual ~SimpleRingBuffer(); + + /** + * Write to circular buffer and increment write pointer by amount + * @param data + * @param amount + * @return + */ ReturnValue_t writeData(const uint8_t* data, uint32_t amount); + + /** + * Read from circular buffer at read pointer + * @param data + * @param amount + * @param readRemaining + * @param trueAmount + * @return + */ ReturnValue_t readData(uint8_t* data, uint32_t amount, bool readRemaining = false, uint32_t* trueAmount = NULL); + + /** + * Delete data starting by incrementing read pointer + * @param amount + * @param deleteRemaining + * @param trueAmount + * @return + */ ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, uint32_t* trueAmount = NULL); private: // static const uint8_t TEMP_READ_PTR = 1; diff --git a/container/SinglyLinkedList.h b/container/SinglyLinkedList.h index 0a2e0531..b926bd00 100644 --- a/container/SinglyLinkedList.h +++ b/container/SinglyLinkedList.h @@ -4,7 +4,9 @@ #include #include /** - * \ingroup container + * @brief Linked list data structure, + * each entry has a pointer to the next entry (singly) + * @ingroup container */ template class LinkedElement { @@ -58,6 +60,11 @@ public: virtual void setNext(LinkedElement* next) { this->next = next; } + + void setEnd() { + this->next = NULL; + } + LinkedElement* begin() { return this; } diff --git a/container/group.h b/container/group.h index 5a39d34e..9c70d523 100644 --- a/container/group.h +++ b/container/group.h @@ -4,11 +4,9 @@ /** * @defgroup container Container * - * General Purpose Container to store various elements. - * - * Also contains Adapter classes to print elements to a - * bytestream and to read them from a bytestream, as well - * as an Adapter to swap the endianness. + * General Purpose Containers to store various elements. + * As opposed to the STL library implementation, these implementations + * don't allocate memory dynamically. */ diff --git a/datapool/DataPool.cpp b/datapool/DataPool.cpp index 89543d77..1d3af742 100644 --- a/datapool/DataPool.cpp +++ b/datapool/DataPool.cpp @@ -79,6 +79,7 @@ void DataPool::print() { } } +template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); diff --git a/datapool/DataPool.h b/datapool/DataPool.h index 6e38dc1b..a9af8af0 100644 --- a/datapool/DataPool.h +++ b/datapool/DataPool.h @@ -29,7 +29,7 @@ * \brief This class represents the OBSW global data-pool. * * \details All variables are registered and space is allocated in an initialization - * function, which is passed do the constructor. + * function, which is passed to the constructor. * Space for the variables is allocated on the heap (with a new call). * The data is found by a data pool id, which uniquely represents a variable. * Data pool variables should be used with a blackboard logic in mind, diff --git a/datapool/DataPoolAdmin.cpp b/datapool/DataPoolAdmin.cpp index fe6b9215..25013726 100644 --- a/datapool/DataPoolAdmin.cpp +++ b/datapool/DataPoolAdmin.cpp @@ -26,7 +26,7 @@ MessageQueueId_t DataPoolAdmin::getCommandQueue() const { } ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) { + MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { if (actionId != SET_VALIDITY) { return INVALID_ACTION_ID; } @@ -215,7 +215,7 @@ ReturnValue_t DataPoolAdmin::handleParameterCommand(CommandMessage* command) { ParameterMessage::getParameterId(command)); const uint8_t *storedStream; - uint32_t storedStreamSize; + size_t storedStreamSize; result = storage->getData(ParameterMessage::getStoreId(command), &storedStream, &storedStreamSize); if (result != HasReturnvaluesIF::RETURN_OK) { @@ -272,7 +272,7 @@ ReturnValue_t DataPoolAdmin::sendParameter(MessageQueueId_t to, uint32_t id, return result; } - uint32_t storeElementSize = 0; + size_t storeElementSize = 0; result = wrapper->serialize(&storeElement, &storeElementSize, serializedSize, true); diff --git a/datapool/DataPoolAdmin.h b/datapool/DataPoolAdmin.h index 448d78fb..dffcd462 100644 --- a/datapool/DataPoolAdmin.h +++ b/datapool/DataPoolAdmin.h @@ -33,8 +33,8 @@ public: ReturnValue_t handleMemoryDump(uint32_t address, uint32_t size, uint8_t** dataPointer, uint8_t* copyHere); - ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size); + virtual ReturnValue_t executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, size_t size); //not implemented as ParameterHelper is no used ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, diff --git a/datapool/DataPoolParameterWrapper.cpp b/datapool/DataPoolParameterWrapper.cpp index 0ff2121d..7139a0d8 100644 --- a/datapool/DataPoolParameterWrapper.cpp +++ b/datapool/DataPoolParameterWrapper.cpp @@ -36,7 +36,7 @@ ReturnValue_t DataPoolParameterWrapper::set(uint8_t domainId, } ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer, - uint32_t* size, const uint32_t max_size, bool bigEndian) const { + size_t* size, const size_t max_size, bool bigEndian) const { ReturnValue_t result; result = SerializeAdapter::serialize(&type, buffer, size, max_size, @@ -69,7 +69,7 @@ ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer, } //same as ParameterWrapper -uint32_t DataPoolParameterWrapper::getSerializedSize() const { +size_t DataPoolParameterWrapper::getSerializedSize() const { uint32_t serializedSize = 0; serializedSize += type.getSerializedSize(); serializedSize += sizeof(rows); @@ -80,7 +80,7 @@ uint32_t DataPoolParameterWrapper::getSerializedSize() const { } ReturnValue_t DataPoolParameterWrapper::deSerialize(const uint8_t** buffer, - int32_t* size, bool bigEndian) { + ssize_t* size, bool bigEndian) { return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/datapool/DataPoolParameterWrapper.h b/datapool/DataPoolParameterWrapper.h index faadf659..45d3de53 100644 --- a/datapool/DataPoolParameterWrapper.h +++ b/datapool/DataPoolParameterWrapper.h @@ -11,12 +11,12 @@ public: ReturnValue_t set(uint8_t domainId, uint16_t parameterId); - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; - virtual uint32_t getSerializedSize() const; + virtual size_t getSerializedSize() const; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian); ReturnValue_t copyFrom(const ParameterWrapper *from, diff --git a/datapool/DataSet.cpp b/datapool/DataSet.cpp index b4725c73..eabb4b8c 100644 --- a/datapool/DataSet.cpp +++ b/datapool/DataSet.cpp @@ -106,8 +106,8 @@ uint8_t DataSet::lockDataPool() { return ::dataPool.lockDataPool(); } -ReturnValue_t DataSet::serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { +ReturnValue_t DataSet::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result = RETURN_FAILED; for (uint16_t count = 0; count < fill_count; count++) { result = registeredVariables[count]->serialize(buffer, size, max_size, @@ -119,8 +119,8 @@ ReturnValue_t DataSet::serialize(uint8_t** buffer, uint32_t* size, return result; } -uint32_t DataSet::getSerializedSize() const { - uint32_t size = 0; +size_t DataSet::getSerializedSize() const { + size_t size = 0; for (uint16_t count = 0; count < fill_count; count++) { size += registeredVariables[count]->getSerializedSize(); } @@ -136,7 +136,7 @@ void DataSet::setValid(uint8_t valid) { } } -ReturnValue_t DataSet::deSerialize(const uint8_t** buffer, int32_t* size, +ReturnValue_t DataSet::deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { ReturnValue_t result = RETURN_FAILED; for (uint16_t count = 0; count < fill_count; count++) { diff --git a/datapool/DataSet.h b/datapool/DataSet.h index 982be692..888d45e6 100644 --- a/datapool/DataSet.h +++ b/datapool/DataSet.h @@ -37,44 +37,11 @@ * \ingroup data_pool */ class DataSet: public DataSetIF, public HasReturnvaluesIF, public SerializeIF { -private: + +public: //SHOULDDO we could use a linked list of datapool variables static const uint8_t DATA_SET_MAX_SIZE = 63; //!< This definition sets the maximum number of variables to register in one DataSet. - /** - * \brief This array represents all pool variables registered in this set. - * \details It has a maximum size of DATA_SET_MAX_SIZE. - */ - PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; - /** - * \brief The fill_count attribute ensures that the variables register in the correct array - * position and that the maximum number of variables is not exceeded. - */ - uint16_t fill_count; - /** - * States of the seet. - */ - enum States { - DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED - DATA_SET_WAS_READ //!< DATA_SET_WAS_READ - }; - /** - * \brief state manages the internal state of the data set, which is important e.g. for the - * behavior on destruction. - */ - States state; - /** - * \brief This is a small helper function to facilitate locking the global data pool. - * \details It makes use of the lockDataPool method offered by the DataPool class. - */ - uint8_t lockDataPool(); - /** - * \brief This is a small helper function to facilitate unlocking the global data pool. - * \details It makes use of the freeDataPoolLock method offered by the DataPool class. - */ - uint8_t freeDataPoolLock(); - -public: static const uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; static const ReturnValue_t INVALID_PARAMETER_DEFINITION = MAKE_RETURN_CODE( 0x01 ); @@ -146,14 +113,56 @@ public: */ void setValid(uint8_t valid); - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + /** + * Serialize all registered pool variables into the provided buffer + * @param buffer + * @param size Is incremented by serialized size + * @param max_size + * @param bigEndian + * @return + */ + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; - uint32_t getSerializedSize() const; + virtual size_t getSerializedSize() const; - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian); +private: + /** + * \brief This array represents all pool variables registered in this set. + * \details It has a maximum size of DATA_SET_MAX_SIZE. + */ + PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; + /** + * \brief The fill_count attribute ensures that the variables register in the correct array + * position and that the maximum number of variables is not exceeded. + */ + uint16_t fill_count; + /** + * States of the seet. + */ + enum States { + DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED + DATA_SET_WAS_READ //!< DATA_SET_WAS_READ + }; + /** + * \brief state manages the internal state of the data set, which is important e.g. for the + * behavior on destruction. + */ + States state; + /** + * \brief This is a small helper function to facilitate locking the global data pool. + * \details It makes use of the lockDataPool method offered by the DataPool class. + */ + uint8_t lockDataPool(); + /** + * \brief This is a small helper function to facilitate unlocking the global data pool. + * \details It makes use of the freeDataPoolLock method offered by the DataPool class. + */ + uint8_t freeDataPoolLock(); + }; #endif /* DATASET_H_ */ diff --git a/datapool/PIDReader.h b/datapool/PIDReader.h index 299cc2fe..26a9e2a8 100644 --- a/datapool/PIDReader.h +++ b/datapool/PIDReader.h @@ -126,17 +126,17 @@ public: return *this; } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { return SerializeAdapter::serialize(&value, buffer, size, max_size, bigEndian); } - virtual uint32_t getSerializedSize() const { + virtual size_t getSerializedSize() const { return SerializeAdapter::getSerializedSize(&value); } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return SerializeAdapter::deSerialize(&value, buffer, size, bigEndian); } diff --git a/datapool/PoolEntry.cpp b/datapool/PoolEntry.cpp index c303e56b..e5d4ffde 100644 --- a/datapool/PoolEntry.cpp +++ b/datapool/PoolEntry.cpp @@ -2,7 +2,20 @@ #include template -PoolEntry::PoolEntry( T* initValue, uint8_t set_length, uint8_t set_valid ) : length(set_length), valid(set_valid) { +PoolEntry::PoolEntry(std::initializer_list initValue, uint8_t set_length, + uint8_t set_valid ) : length(set_length), valid(set_valid) { + this->address = new T[this->length]; + if(initValue.size() == 0) { + memset(this->address, 0, this->getByteSize()); + } + else { + memcpy(this->address, initValue.begin(), this->getByteSize()); + } +} + +template +PoolEntry::PoolEntry( T* initValue, uint8_t set_length, uint8_t set_valid ) : + length(set_length), valid(set_valid) { this->address = new T[this->length]; if (initValue != NULL) { memcpy(this->address, initValue, this->getByteSize() ); @@ -11,6 +24,7 @@ PoolEntry::PoolEntry( T* initValue, uint8_t set_length, uint8_t set_valid ) : } } + //As the data pool is global, this dtor is only be called on program exit. //Warning! Never copy pool entries! template @@ -56,6 +70,7 @@ Type PoolEntry::getType() { return PodTypeConversion::type; } +template class PoolEntry; template class PoolEntry; template class PoolEntry; template class PoolEntry; diff --git a/datapool/PoolEntry.h b/datapool/PoolEntry.h index ce41a991..a02c6c60 100644 --- a/datapool/PoolEntry.h +++ b/datapool/PoolEntry.h @@ -5,6 +5,7 @@ #include #include #include +#include /** * \brief This is a small helper class that defines a single data pool entry. * @@ -31,6 +32,7 @@ public: * \param set_length Defines the array length of this entry. * \param set_valid Sets the initialization flag. It is invalid (0) by default. */ + PoolEntry( std::initializer_list initValue = {}, uint8_t set_length = 1, uint8_t set_valid = 0 ); PoolEntry( T* initValue = NULL, uint8_t set_length = 1, uint8_t set_valid = 0 ); /** * \brief The allocated memory for the variable is freed in the destructor. diff --git a/datapool/PoolRawAccess.cpp b/datapool/PoolRawAccess.cpp index 555896bb..b5f94c8c 100644 --- a/datapool/PoolRawAccess.cpp +++ b/datapool/PoolRawAccess.cpp @@ -14,41 +14,62 @@ PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, } } -PoolRawAccess::~PoolRawAccess() { - -} +PoolRawAccess::~PoolRawAccess() {} ReturnValue_t PoolRawAccess::read() { + ReturnValue_t result = RETURN_FAILED; PoolEntryIF* read_out = ::dataPool.getRawData(dataPoolId); if (read_out != NULL) { - valid = read_out->getValid(); - if (read_out->getSize() > arrayEntry) { - arraySize = read_out->getSize(); - typeSize = read_out->getByteSize() / read_out->getSize(); - type = read_out->getType(); - if (typeSize <= sizeof(value)) { - uint16_t arrayPosition = arrayEntry * typeSize; - sizeTillEnd = read_out->getByteSize() - arrayPosition; - uint8_t* ptr = - &((uint8_t*) read_out->getRawData())[arrayPosition]; - memcpy(value, ptr, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - //Error value type too large. - } - } else { - //Error index requested too large + result = handleReadOut(read_out); + if(result == RETURN_OK) { + return result; } } else { - //Error entry does not exist. + result = READ_ENTRY_NON_EXISTENT; } + handleReadError(result); + return result; +} + +ReturnValue_t PoolRawAccess::handleReadOut(PoolEntryIF* read_out) { + ReturnValue_t result = RETURN_FAILED; + valid = read_out->getValid(); + if (read_out->getSize() > arrayEntry) { + arraySize = read_out->getSize(); + typeSize = read_out->getByteSize() / read_out->getSize(); + type = read_out->getType(); + if (typeSize <= sizeof(value)) { + uint16_t arrayPosition = arrayEntry * typeSize; + sizeTillEnd = read_out->getByteSize() - arrayPosition; + uint8_t* ptr = &((uint8_t*) read_out->getRawData())[arrayPosition]; + memcpy(value, ptr, typeSize); + return RETURN_OK; + } else { + result = READ_TYPE_TOO_LARGE; + } + } else { + //debug << "PoolRawAccess: Size: " << (int)read_out->getSize() << std::endl; + result = READ_INDEX_TOO_LARGE; + } + return result; +} + +void PoolRawAccess::handleReadError(ReturnValue_t result) { error << "PoolRawAccess: read of DP Variable 0x" << std::hex << dataPoolId - << std::dec << " failed." << std::endl; + << std::dec << " failed, "; + if(result == READ_TYPE_TOO_LARGE) { + error << "type too large." << std::endl; + } + else if(result == READ_INDEX_TOO_LARGE) { + error << "index too large." << std::endl; + } + else if(result == READ_ENTRY_NON_EXISTENT) { + error << "entry does not exist." << std::endl; + } valid = INVALID; typeSize = 0; sizeTillEnd = 0; memset(value, 0, sizeof(value)); - return HasReturnvaluesIF::RETURN_FAILED; } ReturnValue_t PoolRawAccess::commit() { @@ -89,6 +110,32 @@ ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, return HasReturnvaluesIF::RETURN_OK; } + +ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + if (typeSize + *size <= max_size) { + if (bigEndian) { +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + for (uint8_t count = 0; count < typeSize; count++) { + (*buffer)[count] = value[typeSize - count - 1]; + } +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN + memcpy(*buffer, value, typeSize); +#endif + } else { + memcpy(*buffer, value, typeSize); + } + *size += typeSize; + (*buffer) += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } +} + + Type PoolRawAccess::getType() { return type; } @@ -145,35 +192,12 @@ uint16_t PoolRawAccess::getSizeTillEnd() const { return sizeTillEnd; } -ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - if (typeSize + *size <= max_size) { - if (bigEndian) { -#ifndef BYTE_ORDER_SYSTEM -#error BYTE_ORDER_SYSTEM not defined -#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN - for (uint8_t count = 0; count < typeSize; count++) { - (*buffer)[count] = value[typeSize - count - 1]; - } -#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN - memcpy(*buffer, value, typeSize); -#endif - } else { - memcpy(*buffer, value, typeSize); - } - *size += typeSize; - (*buffer) += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } -} -uint32_t PoolRawAccess::getSerializedSize() const { +size_t PoolRawAccess::getSerializedSize() const { return typeSize; } -ReturnValue_t PoolRawAccess::deSerialize(const uint8_t** buffer, int32_t* size, +ReturnValue_t PoolRawAccess::deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { *size -= typeSize; if (*size >= 0) { diff --git a/datapool/PoolRawAccess.h b/datapool/PoolRawAccess.h index 3e2bd7ae..955c640b 100644 --- a/datapool/PoolRawAccess.h +++ b/datapool/PoolRawAccess.h @@ -3,85 +3,57 @@ #include #include +#include /** - * This class allows accessing Data Pool variables as raw bytes. + * @brief This class allows accessing Data Pool variables as raw bytes. + * @details * This is necessary to have an access method for HK data, as the PID's alone do not - * provide a type information. - * \ingroup data_pool + * provide a type information. Please note that the the raw pool access read() and commit() + * calls are not thread-safe. + * Please supply a data set and use the data set read(), commit() calls for thread-safe + * data pool access. + * @ingroup data_pool */ -class PoolRawAccess: public PoolVariableIF { -private: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The array entry that is fetched from the data pool. - */ - uint8_t arrayEntry; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief This value contains the type of the data pool entry. - */ - Type type; - /** - * \brief This value contains the size of the data pool entry in bytes. - */ - uint8_t typeSize; - /** - * The size of the DP array (single values return 1) - */ - uint8_t arraySize; - /** - * The size (in bytes) from the selected entry till the end of this DataPool variable. - */ - uint16_t sizeTillEnd; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - static const uint8_t RAW_MAX_SIZE = sizeof(double); -protected: - /** - * \brief This is a call to read the value from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read(); - /** - * \brief The commit call writes back the variable's value to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit(); +class PoolRawAccess: public PoolVariableIF, HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t READ_TYPE_TOO_LARGE = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t READ_INDEX_TOO_LARGE = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t READ_ENTRY_NON_EXISTENT = MAKE_RETURN_CODE(0x05); + static const uint8_t RAW_MAX_SIZE = sizeof(double); uint8_t value[RAW_MAX_SIZE]; + + /** + * This constructor is used to access a data pool entry with a + * given ID if the target type is not known. A DataSet object is supplied + * and the data pool entry with the given ID is registered to that data set. + * Please note that a pool raw access buffer only has a buffer + * with a size of double. As such, for vector entries which have + * @param data_pool_id Target data pool entry ID + * @param arrayEntry + * @param data_set Dataset to register data pool entry to + * @param setReadWriteMode + * @param registerVectors If set to true, the constructor checks if + * there are multiple vector entries to registers + * and registers all of them recursively into the data_set + * + */ PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, DataSetIF* data_set, ReadWriteMode_t setReadWriteMode = - PoolVariableIF::VAR_READ); + PoolVariableIF::VAR_READ); /** * \brief The classes destructor is empty. If commit() was not called, the local value is * discarded and not written back to the data pool. */ ~PoolRawAccess(); + /** * \brief This operation returns a pointer to the entry fetched. - * \details This means, it does not return a pointer to byte "index", but to the start byte of - * array entry "index". Example: If the original data pool array consists of an double - * array of size four, getEntry(1) returns &(this->value[8]). + * \details Return pointer to the buffer containing the raw data + * Size and number of data can be retrieved by other means. */ uint8_t* getEntry(); /** @@ -99,6 +71,19 @@ public: */ ReturnValue_t getEntryEndianSafe(uint8_t* buffer, uint32_t* size, uint32_t max_size); + + /** + * @brief Serialize raw pool entry into provided buffer directly + * @param buffer Provided buffer. Raw pool data will be copied here + * @param size [out] Increment provided size value by serialized size + * @param max_size Maximum allowed serialization size + * @param bigEndian Specify endianess + * @return - @c RETURN_OK if serialization was successfull + * - @c SerializeIF::BUFFER_TOO_SHORT if range check failed + */ + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; + /** * With this method, the content can be set from a big endian buffer safely. * @param buffer Pointer to the data to set @@ -140,13 +125,73 @@ public: */ uint16_t getSizeTillEnd() const; - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + size_t getSerializedSize() const; - uint32_t getSerializedSize() const; - - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian); + +protected: + /** + * \brief This is a call to read the value from the global data pool. + * \details When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The operation does NOT provide any mutual exclusive protection by itself ! + * If reading from the data pool without information about the type is desired, + * initialize the raw pool access by supplying a data set and using the data set + * read function, which calls this read function. + * @return -@c RETURN_OK Read successfull + * -@c READ_TYPE_TOO_LARGE + * -@c READ_INDEX_TOO_LARGE + * -@c READ_ENTRY_NON_EXISTENT + */ + ReturnValue_t read(); + /** + * \brief The commit call writes back the variable's value to the data pool. + * \details It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + * + */ + ReturnValue_t commit(); + + ReturnValue_t handleReadOut(PoolEntryIF* read_out); + void handleReadError(ReturnValue_t result); +private: + /** + * \brief To access the correct data pool entry on read and commit calls, the data pool id + * is stored. + */ + uint32_t dataPoolId; + /** + * \brief The array entry that is fetched from the data pool. + */ + uint8_t arrayEntry; + /** + * \brief The valid information as it was stored in the data pool is copied to this attribute. + */ + uint8_t valid; + /** + * \brief This value contains the type of the data pool entry. + */ + Type type; + /** + * \brief This value contains the size of the data pool entry type in bytes. + */ + uint8_t typeSize; + /** + * The size of the DP array (single values return 1) + */ + uint8_t arraySize; + /** + * The size (in bytes) from the selected entry till the end of this DataPool variable. + */ + uint16_t sizeTillEnd; + /** + * \brief The information whether the class is read-write or read-only is stored here. + */ + ReadWriteMode_t readWriteMode; }; #endif /* POOLRAWACCESS_H_ */ diff --git a/datapool/PoolRawAccessHelper.cpp b/datapool/PoolRawAccessHelper.cpp new file mode 100644 index 00000000..cac6e506 --- /dev/null +++ b/datapool/PoolRawAccessHelper.cpp @@ -0,0 +1,169 @@ +/** + * @file PoolRawAccessHelper.cpp + * + * @date 22.12.2019 + * @author R. Mueller + */ + +#include + +#include + +#include + +PoolRawAccessHelper::PoolRawAccessHelper(uint32_t * poolIdBuffer_, + uint8_t numberOfParameters_): + poolIdBuffer(reinterpret_cast(poolIdBuffer_)), + numberOfParameters(numberOfParameters_), validBufferIndex(0), + validBufferIndexBit(1) { +} + +PoolRawAccessHelper::~PoolRawAccessHelper() { +} + +ReturnValue_t PoolRawAccessHelper::serialize(uint8_t **buffer, size_t *size, + const size_t max_size, bool bigEndian) { + SerializationArgs serializationArgs = {buffer, size, max_size, bigEndian}; + ReturnValue_t result; + ssize_t remainingParametersSize = numberOfParameters * 4; + for(uint8_t count=0; count < numberOfParameters; count++) { + result = serializeCurrentPoolEntryIntoBuffer(serializationArgs, + &remainingParametersSize, false); + if(result != RETURN_OK) { + return result; + } + } + if(remainingParametersSize != 0) { + debug << "Pool Raw Access: Remaining parameters size not 0 !" << std::endl; + result = RETURN_FAILED; + } + return result; +} + +ReturnValue_t PoolRawAccessHelper::serializeWithValidityMask(uint8_t ** buffer, + size_t * size, const size_t max_size, bool bigEndian) { + ReturnValue_t result; + SerializationArgs argStruct = {buffer, size, max_size, bigEndian}; + ssize_t remainingParametersSize = numberOfParameters * 4; + uint8_t validityMaskSize = ceil((float)numberOfParameters/8.0); + uint8_t validityMask[validityMaskSize]; + memset(validityMask,0, validityMaskSize); + for(uint8_t count = 0; count < numberOfParameters; count++) { + result = serializeCurrentPoolEntryIntoBuffer(argStruct, + &remainingParametersSize,true,validityMask); + if (result != RETURN_OK) { + return result; + } + } + if(remainingParametersSize != 0) { + debug << "Pool Raw Access: Remaining parameters size not 0 !" << std::endl; + result = RETURN_FAILED; + } + + memcpy(*argStruct.buffer, validityMask, validityMaskSize); + *size += validityMaskSize; + validBufferIndex = 1; + validBufferIndexBit = 0; + return result; +} + +ReturnValue_t PoolRawAccessHelper::serializeCurrentPoolEntryIntoBuffer(SerializationArgs argStruct, + ssize_t * remainingParameters, bool withValidMask, uint8_t * validityMask) { + uint32_t currentPoolId; + // Deserialize current pool ID from pool ID buffer + ReturnValue_t result = AutoSerializeAdapter::deSerialize(¤tPoolId, + &poolIdBuffer,remainingParameters,true); + if(result != RETURN_OK) { + debug << std::hex << "Pool Raw Access Helper: Error deSeralizing pool IDs" << std::dec << std::endl; + return result; + } + result = handlePoolEntrySerialization(currentPoolId, argStruct, withValidMask, validityMask); + return result; +} + +ReturnValue_t PoolRawAccessHelper::handlePoolEntrySerialization(uint32_t currentPoolId,SerializationArgs argStruct, + bool withValidMask, uint8_t * validityMask) { + ReturnValue_t result = RETURN_FAILED; + uint8_t arrayPosition = 0; + uint8_t counter = 0; + bool poolEntrySerialized = false; + //debug << "Pool Raw Access Helper: Handling Pool ID: " << std::hex << currentPoolId << std::endl; + while(not poolEntrySerialized) { + + if(counter > DataSet::DATA_SET_MAX_SIZE) { + error << "Pool Raw Access Helper: Config error, max. number of possible data set variables exceeded" << std::endl; + return result; + } + counter ++; + + DataSet currentDataSet = DataSet(); + //debug << "Current array position: " << (int)arrayPosition << std::endl; + PoolRawAccess currentPoolRawAccess(currentPoolId,arrayPosition,¤tDataSet,PoolVariableIF::VAR_READ); + + result = currentDataSet.read(); + if (result != RETURN_OK) { + debug << std::hex << "Pool Raw Access Helper: Error reading raw dataset with returncode 0x" + << result << std::dec << std::endl; + return result; + } + + result = checkRemainingSize(¤tPoolRawAccess, &poolEntrySerialized, &arrayPosition); + if(result != RETURN_OK) { + error << "Pool Raw Access Helper: Configuration Error at pool ID " << std::hex << currentPoolId + << ". Size till end smaller than 0" << std::dec << std::endl; + return result; + } + + // set valid mask bit if necessary + if(withValidMask) { + if(currentPoolRawAccess.isValid()) { + handleMaskModification(validityMask); + } + validBufferIndexBit ++; + } + + result = currentDataSet.serialize(argStruct.buffer, argStruct.size, + argStruct.max_size, argStruct.bigEndian); + if (result != RETURN_OK) { + debug << "Pool Raw Access Helper: Error serializing pool data with ID 0x" << std::hex << + currentPoolId << " into send buffer with return code " << result << std::dec << std::endl; + return result; + } + + } + return result; +} + +ReturnValue_t PoolRawAccessHelper::checkRemainingSize(PoolRawAccess * currentPoolRawAccess, + bool * isSerialized, uint8_t * arrayPosition) { + int8_t remainingSize = currentPoolRawAccess->getSizeTillEnd() - currentPoolRawAccess->getSizeOfType(); + if(remainingSize == 0) { + *isSerialized = true; + } + else if(remainingSize > 0) { + *arrayPosition += 1; + } + else { + return RETURN_FAILED; + } + return RETURN_OK; +} + +void PoolRawAccessHelper::handleMaskModification(uint8_t * validityMask) { + validityMask[validBufferIndex] = + bitSetter(validityMask[validBufferIndex], validBufferIndexBit, true); + if(validBufferIndexBit == 8) { + validBufferIndex ++; + validBufferIndexBit = 1; + } +} + +uint8_t PoolRawAccessHelper::bitSetter(uint8_t byte, uint8_t position, bool value) { + if(position < 1 or position > 8) { + debug << "Pool Raw Access: Bit setting invalid position" << std::endl; + return byte; + } + uint8_t shiftNumber = position + (6 - 2 * (position - 1)); + byte |= 1UL << shiftNumber; + return byte; +} diff --git a/datapool/PoolRawAccessHelper.h b/datapool/PoolRawAccessHelper.h new file mode 100644 index 00000000..89974ea4 --- /dev/null +++ b/datapool/PoolRawAccessHelper.h @@ -0,0 +1,108 @@ +/** + * @file PoolRawAccessHelper.h + * + * @date 22.12.2019 + */ + +#ifndef FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ +#define FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ + +#include +#include + +/** + * @brief This helper function simplifies accessing data pool entries + * via PoolRawAccess + * @details Can be used for a Housekeeping Service + * like ECSS PUS Service 3 if the type of the datapool entries is unknown. + * The provided dataset can be serialized into a provided buffer automatically by + * providing a buffer of pool IDs + * @ingroup data_pool + */ +class PoolRawAccessHelper: public HasReturnvaluesIF { +public: + /** + * Call this constructor if a dataset needs to be serialized via + * Pool Raw Access + * @param dataSet_ This dataset will be used to perform thread-safe reading + * @param poolIdBuffer_ A buffer of uint32_t pool IDs + * @param numberOfParameters_ The number of parameters / pool IDs + */ + PoolRawAccessHelper(uint32_t * poolIdBuffer_, uint8_t numberOfParameters_); + virtual ~PoolRawAccessHelper(); + + /** + * Serialize the datapool entries derived from the pool ID buffer + * directly into a provided buffer + * @param [out] buffer + * @param [out] size Size of the serialized buffer + * @param max_size + * @param bigEndian + * @return @c RETURN_OK On success + * @c RETURN_FAILED on failure + */ + ReturnValue_t serialize(uint8_t ** buffer, size_t * size, + const size_t max_size, bool bigEndian); + + /** + * Serializes data pool entries into provided buffer with the validity mask buffer + * at the end of the buffer. Every bit of the validity mask denotes + * the validity of a corresponding data pool entry from left to right. + * @param [out] buffer + * @param [out] size Size of the serialized buffer plus size + * of the validity mask + * @return @c RETURN_OK On success + * @c RETURN_FAILED on failure + */ + ReturnValue_t serializeWithValidityMask(uint8_t ** buffer, size_t * size, + const size_t max_size, bool bigEndian); + + +private: + // DataSet * dataSet; + const uint8_t * poolIdBuffer; + uint8_t numberOfParameters; + + uint8_t validBufferIndex; + uint8_t validBufferIndexBit; + + struct SerializationArgs { + uint8_t ** buffer; + size_t * size; + const uint32_t max_size; + bool bigEndian; + }; + /** + * Helper function to serialize single pool entries + * @param pPoolIdBuffer + * @param buffer + * @param remainingParameters + * @param hkDataSize + * @param max_size + * @param bigEndian + * @param withValidMask Can be set optionally to set a provided validity mask + * @param validityMask Can be supplied and will be set if @c withValidMask is set to true + * @return + */ + ReturnValue_t serializeCurrentPoolEntryIntoBuffer(SerializationArgs argStruct, + ssize_t * remainingParameters, bool withValidMask = false, + uint8_t * validityMask = nullptr); + + ReturnValue_t handlePoolEntrySerialization(uint32_t currentPoolId, + SerializationArgs argStruct, bool withValidMask = false, + uint8_t * validityMask = nullptr); + + ReturnValue_t checkRemainingSize(PoolRawAccess * currentPoolRawAccess, + bool * isSerialized, uint8_t * arrayPosition); + void handleMaskModification(uint8_t * validityMask); + /** + * Sets specific bit of a byte + * @param byte + * @param position Position of byte to set from 1 to 8 + * @param value Binary value to set + * @return + */ + uint8_t bitSetter(uint8_t byte, uint8_t position, bool value); +}; + +#endif /* FRAMEWORK_DATAPOOL_POOLRAWACCESSHELPER_H_ */ diff --git a/datapool/PoolVariable.h b/datapool/PoolVariable.h index 25345c0a..d32cdf22 100644 --- a/datapool/PoolVariable.h +++ b/datapool/PoolVariable.h @@ -112,8 +112,7 @@ public: * corresponds to. * \param dataSet The data set in which the variable shall register itself. If NULL, * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. + * \param setReadWriteMode */ PoolVariable(uint32_t set_id, DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode) : @@ -194,17 +193,17 @@ public: return *this; } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { return SerializeAdapter::serialize(&value, buffer, size, max_size, bigEndian); } - virtual uint32_t getSerializedSize() const { + virtual size_t getSerializedSize() const { return SerializeAdapter::getSerializedSize(&value); } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return SerializeAdapter::deSerialize(&value, buffer, size, bigEndian); } diff --git a/datapool/PoolVector.h b/datapool/PoolVector.h index d3617d17..3e82a721 100644 --- a/datapool/PoolVector.h +++ b/datapool/PoolVector.h @@ -197,8 +197,8 @@ public: return *this; } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { uint16_t i; ReturnValue_t result; for (i = 0; i < vector_size; i++) { @@ -211,11 +211,11 @@ public: return result; } - virtual uint32_t getSerializedSize() const { + virtual size_t getSerializedSize() const { return vector_size * SerializeAdapter::getSerializedSize(value); } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { uint16_t i; ReturnValue_t result; diff --git a/devicehandlers/AcceptsDeviceResponsesIF.h b/devicehandlers/AcceptsDeviceResponsesIF.h index 0eedae88..c811158f 100644 --- a/devicehandlers/AcceptsDeviceResponsesIF.h +++ b/devicehandlers/AcceptsDeviceResponsesIF.h @@ -15,9 +15,8 @@ public: /** * Default empty virtual destructor. */ - virtual ~AcceptsDeviceResponsesIF() { -} -virtual MessageQueueId_t getDeviceQueue() = 0; + virtual ~AcceptsDeviceResponsesIF() {} + virtual MessageQueueId_t getDeviceQueue() = 0; }; #endif /* ACCEPTSDEVICERESPONSESIF_H_ */ diff --git a/devicehandlers/AssemblyBase.cpp b/devicehandlers/AssemblyBase.cpp index c250cf73..bd85d1de 100644 --- a/devicehandlers/AssemblyBase.cpp +++ b/devicehandlers/AssemblyBase.cpp @@ -2,10 +2,10 @@ AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth) : - SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth), internalState( - STATE_NONE), recoveryState(RECOVERY_IDLE), recoveringDevice( - childrenMap.end()), targetMode(MODE_OFF), targetSubmode( - SUBMODE_NONE) { + SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth), + internalState(STATE_NONE), recoveryState(RECOVERY_IDLE), + recoveringDevice(childrenMap.end()), targetMode(MODE_OFF), + targetSubmode(SUBMODE_NONE) { recoveryOffTimer.setTimeout(POWER_OFF_TIME_MS); } diff --git a/devicehandlers/ChildHandlerBase.cpp b/devicehandlers/ChildHandlerBase.cpp index 50a5c07e..c3484676 100644 --- a/devicehandlers/ChildHandlerBase.cpp +++ b/devicehandlers/ChildHandlerBase.cpp @@ -2,15 +2,16 @@ #include #include -ChildHandlerBase::ChildHandlerBase(uint32_t ioBoardAddress, - object_id_t setObjectId, object_id_t deviceCommunication, +ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, + object_id_t deviceCommunication, CookieIF * cookie, uint32_t maxDeviceReplyLen, uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, - uint32_t parent, FailureIsolationBase* customFdir, uint32_t cmdQueueSize) : - DeviceHandlerBase(ioBoardAddress, setObjectId, maxDeviceReplyLen, - setDeviceSwitch, deviceCommunication, thermalStatePoolId, - thermalRequestPoolId, (customFdir == NULL? &childHandlerFdir : customFdir), cmdQueueSize), parentId( - parent), childHandlerFdir(setObjectId) { + uint32_t parent, FailureIsolationBase* customFdir, size_t cmdQueueSize) : + DeviceHandlerBase(setObjectId, deviceCommunication, cookie, + setDeviceSwitch, thermalStatePoolId, + thermalRequestPoolId, (customFdir == NULL? &childHandlerFdir : customFdir), + cmdQueueSize), + parentId(parent), childHandlerFdir(setObjectId) { } ChildHandlerBase::~ChildHandlerBase() { diff --git a/devicehandlers/ChildHandlerBase.h b/devicehandlers/ChildHandlerBase.h index 3879f66f..493b22ee 100644 --- a/devicehandlers/ChildHandlerBase.h +++ b/devicehandlers/ChildHandlerBase.h @@ -6,12 +6,11 @@ class ChildHandlerBase: public DeviceHandlerBase { public: - ChildHandlerBase(uint32_t ioBoardAddress, object_id_t setObjectId, - object_id_t deviceCommunication, uint32_t maxDeviceReplyLen, - uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, - uint32_t thermalRequestPoolId, uint32_t parent, - FailureIsolationBase* customFdir = NULL, - uint32_t cmdQueueSize = 20); + ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, + CookieIF * cookie, uint32_t maxDeviceReplyLen, uint8_t setDeviceSwitch, + uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, + uint32_t parent, FailureIsolationBase* customFdir = nullptr, + size_t cmdQueueSize = 20); virtual ~ChildHandlerBase(); virtual ReturnValue_t initialize(); diff --git a/devicehandlers/CommunicationMessage.cpp b/devicehandlers/CommunicationMessage.cpp new file mode 100644 index 00000000..028e8a2e --- /dev/null +++ b/devicehandlers/CommunicationMessage.cpp @@ -0,0 +1,201 @@ +/** + * @file CommunicationMessage.cpp + * + * @date 28.02.2020 + */ + +#include +#include +#include + +CommunicationMessage::CommunicationMessage(): uninitialized(true) { +} + +CommunicationMessage::~CommunicationMessage() {} + +void CommunicationMessage::setSendRequestFromPointer(uint32_t address, + uint32_t dataLen, const uint8_t * data) { + setMessageType(SEND_DATA_FROM_POINTER); + setAddress(address); + setDataLen(dataLen); + setDataPointer(data); +} + +void CommunicationMessage::setSendRequestFromIpcStore(uint32_t address, store_address_t storeId) { + setMessageType(SEND_DATA_FROM_IPC_STORE); + setAddress(address); + setStoreId(storeId.raw); +} + +void CommunicationMessage::setSendRequestRaw(uint32_t address, uint32_t length, + uint16_t sendBufferPosition) { + setMessageType(SEND_DATA_RAW); + setAddress(address); + setDataLen(length); + if(sendBufferPosition != 0) { + setBufferPosition(sendBufferPosition); + } +} + +void CommunicationMessage::setDataReplyFromIpcStore(uint32_t address, store_address_t storeId) { + setMessageType(REPLY_DATA_IPC_STORE); + setAddress(address); + setStoreId(storeId.raw); +} +void CommunicationMessage::setDataReplyFromPointer(uint32_t address, + uint32_t dataLen, uint8_t *data) { + setMessageType(REPLY_DATA_FROM_POINTER); + setAddress(address); + setDataLen(dataLen); + setDataPointer(data); +} + +void CommunicationMessage::setDataReplyRaw(uint32_t address, + uint32_t length, uint16_t receiveBufferPosition) { + setMessageType(REPLY_DATA_RAW); + setAddress(address); + setDataLen(length); + if(receiveBufferPosition != 0) { + setBufferPosition(receiveBufferPosition); + } +} + +void CommunicationMessage::setMessageType(messageType status) { + uint8_t status_uint8 = status; + memcpy(getData() + sizeof(uint32_t), &status_uint8, sizeof(status_uint8)); +} + +void CommunicationMessage::setAddress(address_t address) { + memcpy(getData(),&address,sizeof(address)); +} + +address_t CommunicationMessage::getAddress() const { + address_t address; + memcpy(&address,getData(),sizeof(address)); + return address; +} + +void CommunicationMessage::setBufferPosition(uint16_t bufferPosition) { + memcpy(getData() + sizeof(uint32_t) + sizeof(uint16_t), + &bufferPosition, sizeof(bufferPosition)); +} + +uint16_t CommunicationMessage::getBufferPosition() const { + uint16_t bufferPosition; + memcpy(&bufferPosition, + getData() + sizeof(uint32_t) + sizeof(uint16_t), sizeof(bufferPosition)); + return bufferPosition; +} + +void CommunicationMessage::setDataPointer(const void * data) { + memcpy(getData() + 3 * sizeof(uint32_t), &data, sizeof(uint32_t)); +} + +void CommunicationMessage::setStoreId(store_address_t storeId) { + memcpy(getData() + 2 * sizeof(uint32_t), &storeId.raw, sizeof(uint32_t)); +} + +store_address_t CommunicationMessage::getStoreId() const{ + store_address_t temp; + memcpy(&temp.raw,getData() + 2 * sizeof(uint32_t), sizeof(uint32_t)); + return temp; +} + +void CommunicationMessage::setDataLen(uint32_t length) { + memcpy(getData() + 2 * sizeof(uint32_t), &length, sizeof(length)); +} + +uint32_t CommunicationMessage::getDataLen() const { + uint32_t len; + memcpy(&len, getData() + 2 * sizeof(uint32_t), sizeof(len)); + return len; +} + +void CommunicationMessage::setUint32Data(uint32_t data) { + memcpy(getData() + 3 * sizeof(uint32_t), &data, sizeof(data)); +} + +uint32_t CommunicationMessage::getUint32Data() const{ + uint32_t data; + memcpy(&data,getData() + 3 * sizeof(uint32_t), sizeof(data)); + return data; +} + +void CommunicationMessage::setDataByte(uint8_t byte, uint8_t position) { + if(0 <= position && position <= 3) { + memcpy(getData() + 3 * sizeof(uint32_t) + position * sizeof(uint8_t), &byte, sizeof(byte)); + } + else { + error << "Comm Message: Invalid byte position" << std::endl; + } +} + +uint8_t CommunicationMessage::getDataByte(uint8_t position) const { + if(0 <= position && position <= 3) { + uint8_t byte; + memcpy(&byte, getData() + 3 * sizeof(uint32_t) + position * sizeof(uint8_t), sizeof(byte)); + return byte; + } + else { + return 0; + error << "Comm Message: Invalid byte position" << std::endl; + } +} + +void CommunicationMessage::setDataUint16(uint16_t data, uint8_t position) { + if(position == 0 || position == 1) { + memcpy(getData() + 3 * sizeof(uint32_t) + position * sizeof(uint16_t), &data, sizeof(data)); + } + else { + error << "Comm Message: Invalid byte position" << std::endl; + } + +} + +uint16_t CommunicationMessage::getDataUint16(uint8_t position) const{ + if(position == 0 || position == 1) { + uint16_t data; + memcpy(&data, getData() + 3 * sizeof(uint32_t) + position * sizeof(uint16_t), sizeof(data)); + return data; + } + else { + return 0; + error << "Comm Message: Invalid byte position" << std::endl; + } +} + +CommunicationMessage::messageType CommunicationMessage::getMessageType() const{ + messageType messageType; + memcpy(&messageType, getData() + sizeof(uint32_t),sizeof(uint8_t)); + return messageType; +} + +void CommunicationMessage::setMessageId(uint8_t messageId) { + memcpy(getData() + sizeof(uint32_t) + sizeof(uint8_t), &messageId, sizeof(messageId)); +} + +uint8_t CommunicationMessage::getMessageId() const { + uint8_t messageId; + memcpy(&messageId, getData() + sizeof(uint32_t) + sizeof(uint8_t), sizeof(messageId)); + return messageId; +} + +void CommunicationMessage::clearCommunicationMessage() { + messageType messageType = getMessageType(); + switch(messageType) { + case(messageType::REPLY_DATA_IPC_STORE): + case(messageType::SEND_DATA_FROM_IPC_STORE): { + store_address_t storeId = getStoreId(); + StorageManagerIF *ipcStore = objectManager-> + get(objects::IPC_STORE); + if (ipcStore != NULL) { + ipcStore->deleteData(storeId); + } + } + /* NO BREAK falls through*/ + default: + memset(getData(),0,4*sizeof(uint32_t)); + break; + } +} + diff --git a/devicehandlers/CommunicationMessage.h b/devicehandlers/CommunicationMessage.h new file mode 100644 index 00000000..a92c4b5c --- /dev/null +++ b/devicehandlers/CommunicationMessage.h @@ -0,0 +1,177 @@ +/** + * @file CommunicationMessage.h + * + * @date 28.02.2020 + */ + +#ifndef FRAMEWORK_DEVICEHANDLERS_COMMUNICATIONMESSAGE_H_ +#define FRAMEWORK_DEVICEHANDLERS_COMMUNICATIONMESSAGE_H_ +#include + +#include +#include +#include + +/** + * @brief Used to pass communication information between tasks + * + * @details + * Can be used to pass information like data pointers and + * data sizes between communication tasks + * like the Device Handler Comm Interfaces and Polling Tasks. + * + * Can also be used to exchange actual data if its not too large + * (e.g. Sensor values). + * + */ +class CommunicationMessage: public MessageQueueMessage { +public: + enum messageType { + NONE, + SEND_DATA_FROM_POINTER, + SEND_DATA_FROM_IPC_STORE, + SEND_DATA_RAW, + REPLY_DATA_FROM_POINTER, + REPLY_DATA_IPC_STORE, + REPLY_DATA_RAW, + FAULTY, + }; + + //Add other messageIDs here if necessary. + static const uint8_t COMMUNICATION_MESSAGE_SIZE = HEADER_SIZE + 4 * sizeof(uint32_t); + + CommunicationMessage(); + virtual ~CommunicationMessage(); + + /** + * Message Type is stored as the fifth byte of the message data + * @param status + */ + void setMessageType(messageType status); + messageType getMessageType() const; + + /** + * This is a unique ID which can be used to handle different kinds of messages. + * For example, the same interface (e.g. SPI) could be used to exchange raw data + * (e.g. sensor values) and data stored in the IPC store. + * The ID can be used to distinguish the messages in child implementations. + * The message ID is stored as the sixth byte of the message data. + * @param messageId + */ + void setMessageId(uint8_t messageId); + uint8_t getMessageId() const; + + /** + * Send requests with pointer to the data to be sent and send data length + * @param address Target Address, first four bytes + * @param dataLen Length of data to send, next four bytes + * @param data Pointer to data to send + * + */ + void setSendRequestFromPointer(uint32_t address, uint32_t dataLen, const uint8_t * data); + + /** + * Send requests with a store ID, using the IPC store + * @param address Target Address, first four bytes + * @param storeId Store ID in the IPC store + * + */ + void setSendRequestFromIpcStore(uint32_t address, store_address_t storeId); + + /** + * Send requests with data length and data in message (max. 4 bytes) + * @param address Target Address, first four bytes + * @param dataLen Length of data to send, next four bytes + * @param data Pointer to data to send + * + */ + void setSendRequestRaw(uint32_t address, uint32_t length, + uint16_t sendBufferPosition = 0); + + /** + * Data message with data stored in IPC store + * @param address Target Address, first four bytes + * @param length + * @param storeId + */ + void setDataReplyFromIpcStore(uint32_t address, store_address_t storeId); + + /** + * Data reply with data stored in buffer, passing the pointer to + * the buffer and the data size + * @param address Target Address, first four bytes + * @param dataLen Length of data to send, next four bytes + * @param data Pointer to the data + */ + void setDataReplyFromPointer(uint32_t address, uint32_t dataLen, uint8_t * data); + + /** + * Data message with data stored in actual message. + * 4 byte datafield is intialized with 0. + * Set data with specific setter functions below. + * Can also be used to supply information at which position the raw data should be stored + * in a receive buffer. + */ + void setDataReplyRaw(uint32_t address, uint32_t length, uint16_t receiveBufferPosition = 0); + + /** + * First four bytes of message data + * @param address + */ + void setAddress(address_t address); + + address_t getAddress() const; + /** + * Set byte as position of 4 byte data field + * @param byte + * @param position Position, 0 to 3 possible + */ + void setDataByte(uint8_t byte, uint8_t position); + uint8_t getDataByte(uint8_t position) const; + + /** + * Set 2 byte value at position 1 or 2 of data field + * @param data + * @param position 0 or 1 possible + */ + void setDataUint16(uint16_t data, uint8_t position); + uint16_t getDataUint16(uint8_t position) const; + + void setUint32Data(uint32_t data); + uint32_t getUint32Data() const; + + /** + * Stored in Bytes 13-16 of message data + * @param length + */ + void setDataLen(uint32_t length); + + uint32_t getDataLen() const; + + /** + * Stored in last four bytes (Bytes 17-20) of message data + * @param sendData + */ + void setDataPointer(const void * data); + + /** + * In case the send request data or reply data is to be stored in a buffer, + * a buffer Position can be stored here as the seventh and eigth byte of + * the message, so the receive buffer can't be larger than sizeof(uint16_t) for now. + * @param bufferPosition In case the data is stored in a buffer, the position can be supplied here + */ + void setBufferPosition(uint16_t bufferPosition); + uint16_t getBufferPosition() const; + void setStoreId(store_address_t storeId); + store_address_t getStoreId() const; + + /** + * Clear the message. Deletes IPC Store data + * and sets all data to 0. Also sets message type to NONE + */ + void clearCommunicationMessage(); +private: + bool uninitialized; //!< Could be used to warn if data has not been set. +}; + +#endif /* FRAMEWORK_DEVICEHANDLERS_COMMUNICATIONMESSAGE_H_ */ diff --git a/devicehandlers/Cookie.h b/devicehandlers/Cookie.h deleted file mode 100644 index 495c8c40..00000000 --- a/devicehandlers/Cookie.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef COOKIE_H_ -#define COOKIE_H_ - -class Cookie{ -public: - virtual ~Cookie(){} -}; - - -#endif /* COOKIE_H_ */ diff --git a/devicehandlers/CookieIF.h b/devicehandlers/CookieIF.h new file mode 100644 index 00000000..ca171ff4 --- /dev/null +++ b/devicehandlers/CookieIF.h @@ -0,0 +1,33 @@ +#ifndef COOKIE_H_ +#define COOKIE_H_ +#include +#include + +/** + * @brief Physical address type + */ +typedef uint32_t address_t; + +/** + * @brief This datatype is used to identify different connection over a + * single interface (like RMAP or I2C) + * @details + * To use this class, implement a communication specific child cookie which + * inherits Cookie. Cookie instances are created in config/ Factory.cpp by calling + * CookieIF* childCookie = new ChildCookie(...). + * + * This cookie is then passed to the child device handlers, which stores the + * pointer and passes it to the communication interface functions. + * + * The cookie can be used to store all kinds of information + * about the communication, like slave addresses, communication status, + * communication parameters etc. + * + * @ingroup comm + */ +class CookieIF { +public: + virtual ~CookieIF() {}; +}; + +#endif /* COOKIE_H_ */ diff --git a/devicehandlers/DeviceCommunicationIF.h b/devicehandlers/DeviceCommunicationIF.h index e0aca573..39cfadd7 100644 --- a/devicehandlers/DeviceCommunicationIF.h +++ b/devicehandlers/DeviceCommunicationIF.h @@ -1,63 +1,126 @@ #ifndef DEVICECOMMUNICATIONIF_H_ #define DEVICECOMMUNICATIONIF_H_ -#include +#include +#include #include +/** + * @defgroup interfaces Interfaces + * @brief Interfaces for flight software objects + */ +/** + * @defgroup comm Communication + * @brief Communication software components. + */ + +/** + * @brief This is an interface to decouple device communication from + * the device handler to allow reuse of these components. + * @details + * Documentation: Dissertation Baetz p.138. + * It works with the assumption that received data + * is polled by a component. There are four generic steps of device communication: + * + * 1. Send data to a device + * 2. Get acknowledgement for sending + * 3. Request reading data from a device + * 4. Read received data + * + * To identify different connection over a single interface can return + * so-called cookies to components. + * The CommunicationMessage message type can be used to extend the + * functionality of the ComIF if a separate polling task is required. + * @ingroup interfaces + * @ingroup comm + */ class DeviceCommunicationIF: public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_COMMUNICATION_IF; - static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0x03); - static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x04); - static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x05); - static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x06); - static const ReturnValue_t CANT_CHANGE_REPLY_LEN = MAKE_RETURN_CODE(0x07); + //! This is returned in readReceivedMessage() if no reply was reived. + static const ReturnValue_t NO_REPLY_RECEIVED = MAKE_RETURN_CODE(0x01); - virtual ~DeviceCommunicationIF() { + //! General protocol error. Define more concrete errors in child handler + static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x02); + //! If cookie is a null pointer + static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x04); + // is this needed if there is no open/close call? + static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05); + static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06); - } - - virtual ReturnValue_t open(Cookie **cookie, uint32_t address, - uint32_t maxReplyLen) = 0; + virtual ~DeviceCommunicationIF() {} /** - * Use an existing cookie to open a connection to a new DeviceCommunication. - * The previous connection must not be closed. - * If the returnvalue is not RETURN_OK, the cookie is unchanged and - * can be used with the previous connection. + * @brief Device specific initialization, using the cookie. + * @details + * The cookie is already prepared in the factory. If the communication + * interface needs to be set up in some way and requires cookie information, + * this can be performed in this function, which is called on device handler + * initialization. + * @param cookie + * @return -@c RETURN_OK if initialization was successfull + * - Everything else triggers failure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; + + /** + * Called by DHB in the SEND_WRITE doSendWrite(). + * This function is used to send data to the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param data + * @param len + * @return -@c RETURN_OK for successfull send + * - Everything else triggers failure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen) = 0; + + /** + * Called by DHB in the GET_WRITE doGetWrite(). + * Get send confirmation that the data in sendMessage() was sent successfully. + * @param cookie + * @return -@c RETURN_OK if data was sent successfull + * - Everything else triggers falure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; + + /** + * Called by DHB in the SEND_WRITE doSendRead(). + * It is assumed that it is always possible to request a reply + * from a device. If a requestLen of 0 is supplied, no reply was enabled + * and communication specific action should be taken (e.g. read nothing + * or read everything). * * @param cookie - * @param address - * @param maxReplyLen - * @return + * @param requestLen Size of data to read + * @return -@c RETURN_OK to confirm the request for data has been sent. + * - Everything else triggers failure event with + * returnvalue as parameter 1 */ - virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, - uint32_t maxReplyLen) = 0; - - virtual void close(Cookie *cookie) = 0; - - //SHOULDDO can data be const? - virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, - uint32_t len) = 0; - - virtual ReturnValue_t getSendSuccess(Cookie *cookie) = 0; - - virtual ReturnValue_t requestReceiveMessage(Cookie *cookie) = 0; - - virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, - uint32_t *size) = 0; - - virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address) = 0; - - virtual uint32_t getAddress(Cookie *cookie) = 0; - - virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter) = 0; - - virtual uint32_t getParameter(Cookie *cookie) = 0; + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen) = 0; + /** + * Called by DHB in the GET_WRITE doGetRead(). + * This function is used to receive data from the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param buffer [out] Set reply here (by using *buffer = ...) + * @param size [out] size pointer to set (by using *size = ...). + * Set to 0 if no reply was received + * @return -@c RETURN_OK for successfull receive + * -@c NO_REPLY_RECEIVED if not reply was received. Setting size to + * 0 has the same effect + * - Everything else triggers failure event with + * returnvalue as parameter 1 + */ + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size) = 0; }; #endif /* DEVICECOMMUNICATIONIF_H_ */ diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index ae9199f2..5fb5a9e5 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -16,37 +16,33 @@ object_id_t DeviceHandlerBase::powerSwitcherId = 0; object_id_t DeviceHandlerBase::rawDataReceiverId = 0; object_id_t DeviceHandlerBase::defaultFDIRParentId = 0; -DeviceHandlerBase::DeviceHandlerBase(uint32_t ioBoardAddress, - object_id_t setObjectId, uint32_t maxDeviceReplyLen, - uint8_t setDeviceSwitch, object_id_t deviceCommunication, +DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, + CookieIF * comCookie_, uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, - FailureIsolationBase* fdirInstance, uint32_t cmdQueueSize) : - SystemObject(setObjectId), rawPacket(0), rawPacketLen(0), mode( - MODE_OFF), submode(SUBMODE_NONE), pstStep(0), maxDeviceReplyLen( - maxDeviceReplyLen), wiretappingMode(OFF), defaultRawReceiver(0), storedRawData( - StorageManagerIF::INVALID_ADDRESS), requestedRawTraffic(0), powerSwitcher( - NULL), IPCStore(NULL), deviceCommunicationId(deviceCommunication), communicationInterface( - NULL), cookie( - NULL), commandQueue(NULL), deviceThermalStatePoolId(thermalStatePoolId), deviceThermalRequestPoolId( - thermalRequestPoolId), healthHelper(this, setObjectId), modeHelper( - this), parameterHelper(this), childTransitionFailure(RETURN_OK), ignoreMissedRepliesCount( - 0), fdirInstance(fdirInstance), hkSwitcher(this), defaultFDIRUsed( - fdirInstance == NULL), switchOffWasReported(false),executingTask(NULL), actionHelper(this, NULL), cookieInfo(), ioBoardAddress( - ioBoardAddress), timeoutStart(0), childTransitionDelay(5000), transitionSourceMode( - _MODE_POWER_DOWN), transitionSourceSubMode(SUBMODE_NONE), deviceSwitch( - setDeviceSwitch) { - commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, - CommandMessage::MAX_MESSAGE_SIZE); + FailureIsolationBase* fdirInstance, size_t cmdQueueSize) : + SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), + wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), + deviceCommunicationId(deviceCommunication), comCookie(comCookie_), + deviceThermalStatePoolId(thermalStatePoolId), deviceThermalRequestPoolId(thermalRequestPoolId), + healthHelper(this, setObjectId), modeHelper(this), parameterHelper(this), + fdirInstance(fdirInstance), hkSwitcher(this), + defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false), + executingTask(nullptr), actionHelper(this, nullptr), cookieInfo(), + childTransitionDelay(5000), transitionSourceMode(_MODE_POWER_DOWN), + transitionSourceSubMode(SUBMODE_NONE), deviceSwitch(setDeviceSwitch) +{ + commandQueue = QueueFactory::instance()-> + createMessageQueue(cmdQueueSize, CommandMessage::MAX_MESSAGE_SIZE); cookieInfo.state = COOKIE_UNUSED; insertInCommandMap(RAW_COMMAND_ID); - if (this->fdirInstance == NULL) { - this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, - defaultFDIRParentId); + if (this->fdirInstance == nullptr) { + this->fdirInstance = + new DeviceHandlerFailureIsolation(setObjectId, defaultFDIRParentId); } } DeviceHandlerBase::~DeviceHandlerBase() { - communicationInterface->close(cookie); + delete comCookie; if (defaultFDIRUsed) { delete fdirInstance; } @@ -55,7 +51,6 @@ DeviceHandlerBase::~DeviceHandlerBase() { ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { this->pstStep = counter; - if (counter == 0) { cookieInfo.state = COOKIE_UNUSED; readCommandQueue(); @@ -64,11 +59,13 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { decrementDeviceReplyMap(); fdirInstance->checkForFailures(); hkSwitcher.performOperation(); + performOperationHook(); } if (mode == MODE_OFF) { return RETURN_OK; } - switch (getRmapAction()) { + + switch (getComAction()) { case SEND_WRITE: if ((cookieInfo.state == COOKIE_UNUSED)) { buildInternalCommand(); @@ -88,6 +85,84 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { default: break; } + + return RETURN_OK; +} + +ReturnValue_t DeviceHandlerBase::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + + communicationInterface = objectManager->get( + deviceCommunicationId); + if (communicationInterface == NULL) { + return RETURN_FAILED; + } + + result = communicationInterface->initializeInterface(comCookie); + if (result != RETURN_OK) { + return result; + } + + IPCStore = objectManager->get(objects::IPC_STORE); + if (IPCStore == NULL) { + return RETURN_FAILED; + } + + AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< + AcceptsDeviceResponsesIF>(rawDataReceiverId); + + if (rawReceiver == NULL) { + return RETURN_FAILED; + } + + defaultRawReceiver = rawReceiver->getDeviceQueue(); + + powerSwitcher = objectManager->get(powerSwitcherId); + if (powerSwitcher == NULL) { + return RETURN_FAILED; + } + + result = healthHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + + result = modeHelper.initialize(); + if (result != RETURN_OK) { + return result; + } + result = actionHelper.initialize(commandQueue); + if (result != RETURN_OK) { + return result; + } + result = fdirInstance->initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = parameterHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = hkSwitcher.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + fillCommandAndReplyMap(); + + //Set temperature target state to NON_OP. + DataSet mySet; + PoolVariable thermalRequest(deviceThermalRequestPoolId, &mySet, + PoolVariableIF::VAR_WRITE); + mySet.read(); + thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; + mySet.commit(PoolVariableIF::VALID); + return RETURN_OK; } @@ -256,55 +331,49 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, } } -ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( - DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, - uint8_t periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) { -//No need to check, as we may try to insert multiple times. +ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, + uint16_t maxDelayCycles, size_t replyLen, uint8_t periodic, + bool hasDifferentReplyId, DeviceCommandId_t replyId) { + //No need to check, as we may try to insert multiple times. insertInCommandMap(deviceCommand); if (hasDifferentReplyId) { - return insertInReplyMap(replyId, maxDelayCycles, periodic); + return insertInReplyMap(replyId, maxDelayCycles, replyLen, periodic); } else { - return insertInReplyMap(deviceCommand, maxDelayCycles, periodic); + return insertInReplyMap(deviceCommand, maxDelayCycles, replyLen, periodic); } } ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, - uint16_t maxDelayCycles, uint8_t periodic) { + uint16_t maxDelayCycles, size_t replyLen, uint8_t periodic) { DeviceReplyInfo info; info.maxDelayCycles = maxDelayCycles; info.periodic = periodic; info.delayCycles = 0; + info.replyLen = replyLen; info.command = deviceCommandMap.end(); - std::pair::iterator, bool> returnValue; - returnValue = deviceReplyMap.insert( - std::pair(replyId, info)); - if (returnValue.second) { + std::pair result = deviceReplyMap.emplace(replyId, info); + if (result.second) { return RETURN_OK; } else { return RETURN_FAILED; } } -ReturnValue_t DeviceHandlerBase::insertInCommandMap( - DeviceCommandId_t deviceCommand) { +ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand) { DeviceCommandInfo info; info.expectedReplies = 0; info.isExecuting = false; info.sendReplyTo = NO_COMMANDER; - std::pair::iterator, bool> returnValue; - returnValue = deviceCommandMap.insert( - std::pair(deviceCommand, - info)); - if (returnValue.second) { + std::pair result = deviceCommandMap.emplace(deviceCommand,info); + if (result.second) { return RETURN_OK; } else { return RETURN_FAILED; } } -ReturnValue_t DeviceHandlerBase::updateReplyMapEntry( - DeviceCommandId_t deviceReply, uint16_t delayCycles, - uint16_t maxDelayCycles, uint8_t periodic) { +ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, + uint16_t delayCycles, uint16_t maxDelayCycles, uint8_t periodic) { std::map::iterator iter = deviceReplyMap.find(deviceReply); if (iter == deviceReplyMap.end()) { @@ -416,7 +485,7 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, return; } //Check if more replies are expected. If so, do nothing. - DeviceCommandInfo* info = &(iter->second.command->second); + DeviceCommandInfo * info = &(iter->second.command->second); if (--info->expectedReplies == 0) { //Check if it was transition or internal command. Don't send any replies in that case. if (info->sendReplyTo != NO_COMMANDER) { @@ -429,7 +498,7 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, void DeviceHandlerBase::doSendWrite() { if (cookieInfo.state == COOKIE_WRITE_READY) { - ReturnValue_t result = communicationInterface->sendMessage(cookie, + ReturnValue_t result = communicationInterface->sendMessage(comCookie, rawPacket, rawPacketLen); if (result == RETURN_OK) { @@ -450,12 +519,13 @@ void DeviceHandlerBase::doGetWrite() { return; } cookieInfo.state = COOKIE_UNUSED; - ReturnValue_t result = communicationInterface->getSendSuccess(cookie); + ReturnValue_t result = communicationInterface->getSendSuccess(comCookie); if (result == RETURN_OK) { if (wiretappingMode == RAW) { replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); } - //We need to distinguish here, because a raw command never expects a reply. (Could be done in eRIRM, but then child implementations need to be careful. + //We need to distinguish here, because a raw command never expects a reply. + //(Could be done in eRIRM, but then child implementations need to be careful. result = enableReplyInReplyMap(cookieInfo.pendingCommand); } else { //always generate a failure event, so that FDIR knows what's up @@ -469,12 +539,25 @@ void DeviceHandlerBase::doGetWrite() { } void DeviceHandlerBase::doSendRead() { - ReturnValue_t result; + ReturnValue_t result = RETURN_FAILED; + size_t requestLen = 0; + // If the device handler can only request replies after a command + // has been sent, there should be only one reply enabled and the + // correct reply length will be mapped. + for(DeviceReplyIter iter = deviceReplyMap.begin(); + iter != deviceReplyMap.end();iter++) + { + if(iter->second.delayCycles != 0) { + requestLen = iter->second.replyLen; + break; + } + } - result = communicationInterface->requestReceiveMessage(cookie); + result = communicationInterface->requestReceiveMessage(comCookie, requestLen); if (result == RETURN_OK) { cookieInfo.state = COOKIE_READ_SENT; - } else { + } + else { triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); //We can't inform anyone, because we don't know which command was sent last. //So, we need to wait for a timeout. @@ -485,10 +568,10 @@ void DeviceHandlerBase::doSendRead() { } void DeviceHandlerBase::doGetRead() { - uint32_t receivedDataLen; + size_t receivedDataLen; uint8_t *receivedData; DeviceCommandId_t foundId = 0xFFFFFFFF; - uint32_t foundLen = 0; + size_t foundLen = 0; ReturnValue_t result; if (cookieInfo.state != COOKIE_READ_SENT) { @@ -498,7 +581,7 @@ void DeviceHandlerBase::doGetRead() { cookieInfo.state = COOKIE_UNUSED; - result = communicationInterface->readReceivedMessage(cookie, &receivedData, + result = communicationInterface->readReceivedMessage(comCookie, &receivedData, &receivedDataLen); if (result != RETURN_OK) { @@ -508,7 +591,7 @@ void DeviceHandlerBase::doGetRead() { return; } - if (receivedDataLen == 0) + if (receivedDataLen == 0 or result == DeviceCommunicationIF::NO_REPLY_RECEIVED) return; if (wiretappingMode == RAW) { @@ -539,6 +622,8 @@ void DeviceHandlerBase::doGetRead() { break; case IGNORE_REPLY_DATA: break; + case IGNORE_FULL_PACKET: + return; default: //We need to wait for timeout.. don't know what command failed and who sent it. replyRawReplyIfnotWiretapped(receivedData, foundLen); @@ -557,8 +642,8 @@ void DeviceHandlerBase::doGetRead() { } ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, - uint8_t * *data, uint32_t * len) { - uint32_t lenTmp; + uint8_t ** data, size_t * len) { + size_t lenTmp; if (IPCStore == NULL) { *data = NULL; @@ -579,84 +664,6 @@ ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, } -ReturnValue_t DeviceHandlerBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - - communicationInterface = objectManager->get( - deviceCommunicationId); - if (communicationInterface == NULL) { - return RETURN_FAILED; - } - - result = communicationInterface->open(&cookie, ioBoardAddress, - maxDeviceReplyLen); - if (result != RETURN_OK) { - return result; - } - - IPCStore = objectManager->get(objects::IPC_STORE); - if (IPCStore == NULL) { - return RETURN_FAILED; - } - - AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< - AcceptsDeviceResponsesIF>(rawDataReceiverId); - - if (rawReceiver == NULL) { - return RETURN_FAILED; - } - - defaultRawReceiver = rawReceiver->getDeviceQueue(); - - powerSwitcher = objectManager->get(powerSwitcherId); - if (powerSwitcher == NULL) { - return RETURN_FAILED; - } - - result = healthHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - - result = modeHelper.initialize(); - if (result != RETURN_OK) { - return result; - } - result = actionHelper.initialize(commandQueue); - if (result != RETURN_OK) { - return result; - } - result = fdirInstance->initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = parameterHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = hkSwitcher.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - fillCommandAndReplyMap(); - - //Set temperature target state to NON_OP. - DataSet mySet; - PoolVariable thermalRequest(deviceThermalRequestPoolId, &mySet, - PoolVariableIF::VAR_WRITE); - mySet.read(); - thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; - mySet.commit(PoolVariableIF::VALID); - - return RETURN_OK; - -} void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, MessageQueueId_t sendTo, bool isCommand) { @@ -672,7 +679,6 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, } CommandMessage message; - DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&message, getObjectId(), address, isCommand); @@ -688,7 +694,7 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, //Default child implementations -DeviceHandlerBase::RmapAction_t DeviceHandlerBase::getRmapAction() { +DeviceHandlerBase::CommunicationAction_t DeviceHandlerBase::getComAction() { switch (pstStep) { case 0: return SEND_WRITE; @@ -748,20 +754,20 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, } } -ReturnValue_t DeviceHandlerBase::switchCookieChannel(object_id_t newChannelId) { - DeviceCommunicationIF *newCommunication = objectManager->get< - DeviceCommunicationIF>(newChannelId); - - if (newCommunication != NULL) { - ReturnValue_t result = newCommunication->reOpen(cookie, ioBoardAddress, - maxDeviceReplyLen); - if (result != RETURN_OK) { - return result; - } - return RETURN_OK; - } - return RETURN_FAILED; -} +//ReturnValue_t DeviceHandlerBase::switchCookieChannel(object_id_t newChannelId) { +// DeviceCommunicationIF *newCommunication = objectManager->get< +// DeviceCommunicationIF>(newChannelId); +// +// if (newCommunication != NULL) { +// ReturnValue_t result = newCommunication->reOpen(cookie, logicalAddress, +// maxDeviceReplyLen, comParameter1, comParameter2); +// if (result != RETURN_OK) { +// return result; +// } +// return RETURN_OK; +// } +// return RETURN_FAILED; +//} void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) { storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage); @@ -771,8 +777,8 @@ void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) { replyReturnvalueToCommand(result, RAW_COMMAND_ID); storedRawData.raw = StorageManagerIF::INVALID_ADDRESS; } else { - cookieInfo.pendingCommand = deviceCommandMap.find( - (DeviceCommandId_t) RAW_COMMAND_ID); + cookieInfo.pendingCommand = deviceCommandMap. + find((DeviceCommandId_t) RAW_COMMAND_ID); cookieInfo.pendingCommand->second.isExecuting = true; cookieInfo.state = COOKIE_WRITE_READY; } @@ -811,7 +817,7 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap( iter = deviceReplyMap.find(command->first); } if (iter != deviceReplyMap.end()) { - DeviceReplyInfo *info = &(iter->second); + DeviceReplyInfo * info = &(iter->second); info->delayCycles = info->maxDelayCycles; info->command = command; command->second.expectedReplies = expectedReplies; @@ -837,8 +843,9 @@ ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); if ((result == RETURN_OK) && (numberOfSwitches != 0)) { while (numberOfSwitches > 0) { - if (powerSwitcher->getSwitchState(switches[numberOfSwitches - 1]) - == PowerSwitchIF::SWITCH_OFF) { + if (powerSwitcher-> getSwitchState(switches[numberOfSwitches - 1]) + == PowerSwitchIF::SWITCH_OFF) + { return PowerSwitchIF::SWITCH_OFF; } numberOfSwitches--; @@ -1044,16 +1051,18 @@ ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( } replyReturnvalueToCommand(RETURN_OK); return RETURN_OK; - case DeviceHandlerMessage::CMD_SWITCH_IOBOARD: + case DeviceHandlerMessage::CMD_SWITCH_ADDRESS: if (mode != MODE_OFF) { replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); } else { - result = switchCookieChannel( - DeviceHandlerMessage::getIoBoardObjectId(message)); + // rework in progress + result = RETURN_OK; + //result = switchCookieChannel( + // DeviceHandlerMessage::getIoBoardObjectId(message)); if (result == RETURN_OK) { replyReturnvalueToCommand(RETURN_OK); } else { - replyReturnvalueToCommand(CANT_SWITCH_IOBOARD); + replyReturnvalueToCommand(CANT_SWITCH_ADDRESS); } } return RETURN_OK; @@ -1112,8 +1121,7 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, // hiding of sender needed so the service will handle it as unexpected Data, no matter what state //(progress or completed) it is in - actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, - true); + actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, true); } } else { //unrequested/aperiodic replies @@ -1136,11 +1144,12 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, } ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) { + MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { ReturnValue_t result = acceptExternalDeviceCommands(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } + DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; @@ -1159,7 +1168,7 @@ ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, } void DeviceHandlerBase::buildInternalCommand(void) { -//Neither Raw nor Direct could build a command + // Neither Raw nor Direct could build a command ReturnValue_t result = NOTHING_TO_SEND; DeviceCommandId_t deviceCommandId = NO_COMMAND_ID; if (mode == MODE_NORMAL) { @@ -1177,12 +1186,13 @@ void DeviceHandlerBase::buildInternalCommand(void) { } else { return; } + if (result == NOTHING_TO_SEND) { return; } if (result == RETURN_OK) { - DeviceCommandMap::iterator iter = deviceCommandMap.find( - deviceCommandId); + DeviceCommandMap::iterator iter = + deviceCommandMap.find(deviceCommandId); if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { @@ -1197,6 +1207,7 @@ void DeviceHandlerBase::buildInternalCommand(void) { cookieInfo.state = COOKIE_WRITE_READY; } } + if (result != RETURN_OK) { triggerEvent(DEVICE_BUILDING_COMMAND_FAILED, result, deviceCommandId); } @@ -1270,3 +1281,9 @@ void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ executingTask = task_; } + +void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId, uint32_t parameter) { +} + +void DeviceHandlerBase::performOperationHook() { +} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 756ad530..c162210c 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -17,10 +17,11 @@ #include #include #include +#include #include -#include #include #include +#include namespace Factory{ void setStaticFrameworkObjectIds(); @@ -29,29 +30,53 @@ void setStaticFrameworkObjectIds(); class StorageManagerIF; /** - * \defgroup devices Devices + * @defgroup devices Devices * Contains all devices and the DeviceHandlerBase class. */ /** - * \brief This is the abstract base class for device handlers. - * + * @brief This is the abstract base class for device handlers. + * @details * Documentation: Dissertation Baetz p.138,139, p.141-149 - * SpaceWire Remote Memory Access Protocol (RMAP) * - * It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, the RMAP communication and the - * communication with commanding objects. + * It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, + * communication with physical devices, using the @link DeviceCommunicationIF @endlink, + * and communication with commanding objects. * It inherits SystemObject and thus can be created by the ObjectManagerIF. * * This class uses the opcode of ExecutableObjectIF to perform a step-wise execution. - * For each step an RMAP action is selected and executed. If data has been received (eg in case of an RMAP Read), the data will be interpreted. - * The action for each step can be defined by the child class but as most device handlers share a 4-call (Read-getRead-write-getWrite) structure, - * a default implementation is provided. + * For each step an RMAP action is selected and executed. + * If data has been received (GET_READ), the data will be interpreted. + * The action for each step can be defined by the child class but as most + * device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure, + * a default implementation is provided. NOTE: RMAP is a standard which is used for FLP. + * RMAP communication is not mandatory for projects implementing the FSFW. + * However, the communication principles are similar to RMAP as there are + * two write and two send calls involved. * * Device handler instances should extend this class and implement the abstract functions. * Components and drivers can send so called cookies which are used for communication + * and contain information about the communcation (e.g. slave address for I2C or RMAP structs). + * The following abstract methods must be implemented by a device handler: + * 1. doStartUp() + * 2. doShutDown() + * 3. buildTransitionDeviceCommand() + * 4. buildNormalDeviceCommand() + * 5. buildCommandFromCommand() + * 6. fillCommandAndReplyMap() + * 7. scanForReply() + * 8. interpretDeviceReply() * - * \ingroup devices + * Other important virtual methods with a default implementation + * are the getTransitionDelayMs() function and the getSwitches() function. + * Please ensure that getSwitches() returns DeviceHandlerIF::NO_SWITCHES if + * power switches are not implemented yet. Otherwise, the device handler will + * not transition to MODE_ON, even if setMode(MODE_ON) is called. + * If a transition to MODE_ON is desired without commanding, override the + * intialize() function and call setMode(_MODE_START_UP) before calling + * DeviceHandlerBase::initialize(). + * + * @ingroup devices */ class DeviceHandlerBase: public DeviceHandlerIF, public HasReturnvaluesIF, @@ -67,284 +92,66 @@ public: * The constructor passes the objectId to the SystemObject(). * * @param setObjectId the ObjectId to pass to the SystemObject() Constructor - * @param maxDeviceReplyLen the length the RMAP getRead call will be sent with + * @param maxDeviceReplyLen the largest allowed reply size * @param setDeviceSwitch the switch the device is connected to, for devices using two switches, overwrite getSwitches() + * @param deviceCommuncation Communcation Interface object which is used to implement communication functions + * @param thermalStatePoolId + * @param thermalRequestPoolId + * @param fdirInstance + * @param cmdQueueSize */ - DeviceHandlerBase(uint32_t ioBoardAddress, object_id_t setObjectId, - uint32_t maxDeviceReplyLen, uint8_t setDeviceSwitch, - object_id_t deviceCommunication, uint32_t thermalStatePoolId = - PoolVariableIF::NO_PARAMETER, + DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, + CookieIF * comCookie_, uint8_t setDeviceSwitch, + uint32_t thermalStatePoolId = PoolVariableIF::NO_PARAMETER, uint32_t thermalRequestPoolId = PoolVariableIF::NO_PARAMETER, - FailureIsolationBase* fdirInstance = NULL, uint32_t cmdQueueSize = 20); - - virtual MessageQueueId_t getCommandQueue(void) const; - + FailureIsolationBase* fdirInstance = nullptr, size_t cmdQueueSize = 20); /** - * This function is a core component and is called periodically. - * General sequence: - * If the State is SEND_WRITE: - * 1. Set the cookie state to COOKIE_UNUSED and read the command queue - * 2. Handles Device State Modes by calling doStateMachine(). - * This function calls callChildStatemachine() which calls the abstract functions - * doStartUp() and doShutDown() - * 3. Check switch states by calling checkSwitchStates() - * 4. Decrements counter for timeout of replies by calling decrementDeviceReplyMap() - * 5. Performs FDIR check for failures - * 6. Calls hkSwitcher.performOperation() - * 7. If the device mode is MODE_OFF, return RETURN_OK. Otherwise, perform the Action property - * and performs depending on value specified - * by input value counter. The child class tells base class what to do by setting this value. - * - SEND_WRITE: Send data or commands to device by calling doSendWrite() - * Calls abstract funtions buildNomalDeviceCommand() - * or buildTransitionDeviceCommand() - * - GET_WRITE: Get ackknowledgement for sending by calling doGetWrite(). - * Calls abstract functions scanForReply() and interpretDeviceReply(). - * - SEND_READ: Request reading data from device by calling doSendRead() - * - GET_READ: Access requested reading data by calling doGetRead() - * @param counter Specifies which Action to perform - * @return RETURN_OK for successful execution - */ + * @brief This function is the device handler base core component and is called periodically. + * @details + * General sequence, showing where abstract virtual functions are called: + * If the State is SEND_WRITE: + * 1. Set the cookie state to COOKIE_UNUSED and read the command queue + * 2. Handles Device State Modes by calling doStateMachine(). + * This function calls callChildStatemachine() which calls the abstract functions + * doStartUp() and doShutDown() + * 3. Check switch states by calling checkSwitchStates() + * 4. Decrements counter for timeout of replies by calling decrementDeviceReplyMap() + * 5. Performs FDIR check for failures + * 6. Calls hkSwitcher.performOperation() + * 7. If the device mode is MODE_OFF, return RETURN_OK. Otherwise, perform the Action property + * and performs depending on value specified + * by input value counter. The child class tells base class what to do by setting this value. + * - SEND_WRITE: Send data or commands to device by calling doSendWrite() which calls + * sendMessage function of #communicationInterface + * and calls buildInternalCommand if the cookie state is COOKIE_UNUSED + * - GET_WRITE: Get ackknowledgement for sending by calling doGetWrite() which calls + * getSendSuccess of #communicationInterface. + * Calls abstract functions scanForReply() and interpretDeviceReply(). + * - SEND_READ: Request reading data from device by calling doSendRead() which calls + * requestReceiveMessage of #communcationInterface + * - GET_READ: Access requested reading data by calling doGetRead() which calls + * readReceivedMessage of #communicationInterface + * @param counter Specifies which Action to perform + * @return RETURN_OK for successful execution + */ virtual ReturnValue_t performOperation(uint8_t counter); + /** + * @brief Initializes the device handler + * @details + * Initialize Device Handler as system object and + * initializes all important helper classes. + * Calls fillCommandAndReplyMap(). + * @return + */ virtual ReturnValue_t initialize(); - /** - * - * @param parentQueueId - */ - virtual void setParentQueue(MessageQueueId_t parentQueueId); /** * Destructor. */ virtual ~DeviceHandlerBase(); - - ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size); - Mode_t getTransitionSourceMode() const; - Submode_t getTransitionSourceSubMode() const; - virtual void getMode(Mode_t *mode, Submode_t *submode); - HealthState getHealth(); - ReturnValue_t setHealth(HealthState health); - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - /** - * Implementation of ExecutableObjectIF function - * - * 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_); protected: - /** - * The Returnvalues id of this class, required by HasReturnvaluesIF - */ - static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; - - static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(4); - static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(5); - static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(6); -// static const ReturnValue_t ONE_SWITCH = MAKE_RETURN_CODE(8); -// static const ReturnValue_t TWO_SWITCHES = MAKE_RETURN_CODE(9); - static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(10); - static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(11); - static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(12); - - //Mode handling error Codes - static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE1); - static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE2); - - static const DeviceCommandId_t RAW_COMMAND_ID = -1; - static const DeviceCommandId_t NO_COMMAND_ID = -2; - static const MessageQueueId_t NO_COMMANDER = 0; - - /** - * Pointer to the raw packet that will be sent. - */ - uint8_t *rawPacket; - /** - * Size of the #rawPacket. - */ - uint32_t rawPacketLen; - - /** - * The mode the device handler is currently in. - * - * This should never be changed directly but only with setMode() - */ - Mode_t mode; - - /** - * The submode the device handler is currently in. - * - * This should never be changed directly but only with setMode() - */ - Submode_t submode; - - /** - * This is the counter value from performOperation(). - */ - uint8_t pstStep; - - /** - * This will be used in the RMAP getRead command as expected length, is set by the constructor, can be modiefied at will. - */ - const uint32_t maxDeviceReplyLen; - - /** - * wiretapping flag: - * - * indicates either that all raw messages to and from the device should be sent to #theOneWhoWantsToReadRawTraffic - * or that all device TM should be downlinked to #theOneWhoWantsToReadRawTraffic - */ - enum WiretappingMode { - OFF = 0, RAW = 1, TM = 2 - } wiretappingMode; - - /** - * A message queue that accepts raw replies - * - * Statically initialized in initialize() to a configurable object. Used when there is no method - * of finding a recipient, ie raw mode and reporting erreonous replies - */ - MessageQueueId_t defaultRawReceiver; - - store_address_t storedRawData; - - /** - * the message queue which wants to read all raw traffic - * - * if #isWiretappingActive all raw communication from and to the device will be sent to this queue - */ - MessageQueueId_t requestedRawTraffic; - - /** - * the object used to set power switches - */ - PowerSwitchIF *powerSwitcher; - - /** - * Pointer to the IPCStore. - * - * This caches the pointer received from the objectManager in the constructor. - */ - StorageManagerIF *IPCStore; - - /** - * cached for init - */ - object_id_t deviceCommunicationId; - - /** - * Communication object used for device communication - */ - DeviceCommunicationIF *communicationInterface; - - /** - * Cookie used for communication - */ - Cookie *cookie; - - /** - * The MessageQueue used to receive device handler commands and to send replies. - */ - MessageQueueIF* commandQueue; - - /** - * this is the datapool variable with the thermal state of the device - * - * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking - */ - uint32_t deviceThermalStatePoolId; - - /** - * this is the datapool variable with the thermal request of the device - * - * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking - */ - uint32_t deviceThermalRequestPoolId; - - /** - * Taking care of the health - */ - HealthHelper healthHelper; - - ModeHelper modeHelper; - - ParameterHelper parameterHelper; - - /** - * Optional Error code - * Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure. - */ - ReturnValue_t childTransitionFailure; - - uint32_t ignoreMissedRepliesCount; //!< Counts if communication channel lost a reply, so some missed replys can be ignored. - - FailureIsolationBase* fdirInstance; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated. - - HkSwitchHelper hkSwitcher; - - bool defaultFDIRUsed; //!< To correctly delete the default instance. - - bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. - - PeriodicTaskIF* executingTask;//!< Pointer to the task which executes this component, is invalid before setTaskIF was called. - - static object_id_t powerSwitcherId; //!< Object which switches power on and off. - - static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. - - static object_id_t defaultFDIRParentId; //!< Object which may be the root cause of an identified fault. - /** - * Helper function to report a missed reply - * - * Can be overwritten by children to act on missed replies or to fake reporting Id. - * - * @param id of the missed reply - */ - virtual void missedReply(DeviceCommandId_t id); - - /** - * Send a reply to a received device handler command. - * - * This also resets #DeviceHandlerCommand to 0. - * - * @param reply the reply type - * @param parameter parameter for the reply - */ - void replyReturnvalueToCommand(ReturnValue_t status, - uint32_t parameter = 0); - - /** - * - - * @param parameter2 additional parameter - */ - void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); - - /** - * Set the device handler mode - * - * Sets #timeoutStart with every call. - * - * Sets #transitionTargetMode if necessary so transitional states can be entered from everywhere without breaking the state machine - * (which relies on a correct #transitionTargetMode). - * - * The submode is left unchanged. - * - * - * @param newMode - */ - void setMode(Mode_t newMode); - - /** - * @overload - * @param submode - */ - void setMode(Mode_t newMode, Submode_t submode); - /** * This is used to let the child class handle the transition from mode @c _MODE_START_UP to @c MODE_ON * @@ -380,6 +187,457 @@ protected: */ virtual void doShutDown() = 0; + /** + * Build the device command to send for normal mode. + * + * This is only called in @c MODE_NORMAL. If multiple submodes for @c MODE_NORMAL are supported, + * different commands can built returned depending on the submode. + * + * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. + * If variable command frequence is required, a counter can be used and + * the frequency in the reply map has to be set manually + * by calling updateReplyMap(). + * + * @param[out] id the device command id that has been built + * @return + * - @c RETURN_OK to send command after setting #rawPacket and #rawPacketLen. + * - @c NOTHING_TO_SEND when no command is to be sent. + * - Anything else triggers an even with the returnvalue as a parameter. + */ + virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; + + /** + * Build the device command to send for a transitional mode. + * + * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, + * @c _MODE_START_UP and @c _MODE_TO_POWER_DOWN. So it is used by doStartUp() and doShutDown() as well as doTransition() + * + * A good idea is to implement a flag indicating a command has to be built and a variable containing the command number to be built + * and filling them in doStartUp(), doShutDown() and doTransition() so no modes have to be checked here. + * + * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. + * + * @param[out] id the device command id built + * @return + * - @c RETURN_OK when a command is to be sent + * - @c NOTHING_TO_SEND when no command is to be sent + * - Anything else triggers an even with the returnvalue as a parameter + */ + virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) = 0; + + /** + * @brief Build a device command packet from data supplied by a direct command. + * + * @details + * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. + * The existence of the command in the command map and the command size check + * against 0 are done by the base class. + * + * @param deviceCommand the command to build, already checked against deviceCommandMap + * @param commandData pointer to the data from the direct command + * @param commandDataLen length of commandData + * @return + * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen have been set. + * - Anything else triggers an event with the returnvalue as a parameter + */ + virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t * commandData, size_t commandDataLen) = 0; + + /** + * @brief fill the #deviceCommandMap + * called by the initialize() of the base class + * @details + * This is used to let the base class know which replies are expected. + * There are different scenarios regarding this: + * - "Normal" commands. These are commands, that trigger a direct reply from the device. + * In this case, the id of the command should be added to the command map + * with a commandData_t where maxDelayCycles is set to the maximum expected + * number of PST cycles the reply will take. Then, scanForReply returns + * the id of the command and the base class can handle time-out and missing replies. + * - Periodic, unrequested replies. These are replies that, once enabled, are sent by the device + * on its own in a defined interval. In this case, the id of the reply + * or a placeholder id should be added to the deviceCommandMap with a commandData_t + * where maxDelayCycles is set to the maximum expected number of PST cycles between + * two replies (also a tolerance should be added, as an FDIR message will be generated if it is missed). + * As soon as the replies are enabled, DeviceCommandInfo.periodic must be set to 1, + * DeviceCommandInfo.delayCycles to DeviceCommandInfo.MaxDelayCycles. + * From then on, the base class handles the reception. + * Then, scanForReply returns the id of the reply or the placeholder id and the base class will + * take care of checking that all replies are received and the interval is correct. + * When the replies are disabled, DeviceCommandInfo.periodic must be set to 0, + * DeviceCommandInfo.delayCycles to 0; + * - Aperiodic, unrequested replies. These are replies that are sent + * by the device without any preceding command and not in a defined interval. + * These are not entered in the deviceCommandMap but handled by returning @c APERIODIC_REPLY in scanForReply(). + * + */ + virtual void fillCommandAndReplyMap() = 0; + + /** + * @brief Scans a buffer for a valid reply. + * @details + * This is used by the base class to check the data received for valid packets. + * It only checks if a valid packet starts at @c start. + * It also only checks the structural validy of the packet, + * e.g. checksums lengths and protocol data. + * No information check is done, e.g. range checks etc. + * + * Errors should be reported directly, the base class does NOT report + * any errors based on the returnvalue of this function. + * + * @param start start of remaining buffer to be scanned + * @param len length of remaining buffer to be scanned + * @param[out] foundId the id of the data found in the buffer. + * @param[out] foundLen length of the data found. Is to be set in function, + * buffer is scanned at previous position + foundLen. + * @return + * - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid + * - @c RETURN_FAILED no reply could be found starting at @c start, + * implies @c foundLen is not valid, + * base class will call scanForReply() again with ++start + * - @c DeviceHandlerIF::INVALID_DATA a packet was found but it is invalid, + * e.g. checksum error, implies @c foundLen is valid, can be used to skip some bytes + * - @c DeviceHandlerIF::LENGTH_MISSMATCH @c len is invalid + * - @c DeviceHandlerIF::IGNORE_REPLY_DATA Ignore this specific part of the packet + * - @c DeviceHandlerIF::IGNORE_FULL_PACKET Ignore the packet + * - @c APERIODIC_REPLY if a valid reply is received that has not been + * requested by a command, but should be handled anyway + * (@see also fillCommandAndCookieMap() ) + */ + virtual ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize, + DeviceCommandId_t *foundId, size_t *foundLen) = 0; + + /** + * @brief Interpret a reply from the device. + * @details + * This is called after scanForReply() found a valid packet, it can be assumed that the length and structure is valid. + * This routine extracts the data from the packet into a DataSet and then calls handleDeviceTM(), which either sends + * a TM packet or stores the data in the DataPool depending on whether the it was an external command. + * No packet length is given, as it should be defined implicitly by the id. + * + * @param id the id found by scanForReply() + * @param packet + * @return + * - @c RETURN_OK when the reply was interpreted. + * - @c RETURN_FAILED when the reply could not be interpreted, eg. logical errors or range violations occurred + */ + virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) = 0; + + /** + * set all datapool variables that are update periodically in normal mode invalid + * + * Child classes should provide an implementation which sets all those variables invalid + * which are set periodically during any normal mode. + */ + virtual void setNormalDatapoolEntriesInvalid() = 0; + + /** + * @brief Can be implemented by child handler to + * perform debugging + * @details Example: Calling this in performOperation + * to track values like mode. + * @param positionTracker Provide the child handler a way to know where the debugInterface was called + * @param objectId Provide the child handler object Id to specify actions for spefic devices + * @param parameter Supply a parameter of interest + * Please delete all debugInterface calls in DHB after debugging is finished ! + */ + virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0, uint32_t parameter = 0); + + /** + * Get the time needed to transit from modeFrom to modeTo. + * + * Used for the following transitions: + * modeFrom -> modeTo: + * - MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * - MODE_NORMAL -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * - MODE_RAW -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] + * - _MODE_START_UP -> MODE_ON (do not include time to set the switches, the base class got you covered) + * + * The default implementation returns 0 ! + * @param modeFrom + * @param modeTo + * @return time in ms + */ + virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo); + + /** + * Return the switches connected to the device. + * + * The default implementation returns one switch set in the ctor. + * + * @param[out] switches pointer to an array of switches + * @param[out] numberOfSwitches length of returned array + * @return + * - @c RETURN_OK if the parameters were set + * - @c NO_SWITCH or any other returnvalue if no switches exist + */ + virtual ReturnValue_t getSwitches(const uint8_t **switches, + uint8_t *numberOfSwitches); + + /** + * Can be used to perform device specific periodic operations. + * This is called on the SEND_READ step of the performOperation() call + */ + virtual void performOperationHook(); + + /** + * The Returnvalues id of this class, required by HasReturnvaluesIF + */ + static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; + +public: + /** + * @param parentQueueId + */ + virtual void setParentQueue(MessageQueueId_t parentQueueId); + + /** + * This function call handles the execution of external commands as required + * by the HasActionIF. + * @param actionId + * @param commandedBy + * @param data + * @param size + * @return + */ + ReturnValue_t executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, size_t size); + + Mode_t getTransitionSourceMode() const; + Submode_t getTransitionSourceSubMode() const; + virtual void getMode(Mode_t *mode, Submode_t *submode); + HealthState getHealth(); + ReturnValue_t setHealth(HealthState health); + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); + /** + * Implementation of ExecutableObjectIF function + * + * 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_); + virtual MessageQueueId_t getCommandQueue(void) const; + +protected: + //Mode handling error Codes + static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE1); + static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE2); + + static const DeviceCommandId_t RAW_COMMAND_ID = -1; + static const DeviceCommandId_t NO_COMMAND_ID = -2; + static const MessageQueueId_t NO_COMMANDER = 0; + + /** + * Pointer to the raw packet that will be sent. + */ + uint8_t *rawPacket = nullptr; + /** + * Size of the #rawPacket. + */ + size_t rawPacketLen = 0; + + /** + * The mode the device handler is currently in. + * + * This should never be changed directly but only with setMode() + */ + Mode_t mode; + + /** + * The submode the device handler is currently in. + * + * This should never be changed directly but only with setMode() + */ + Submode_t submode; + + /** + * This is the counter value from performOperation(). + */ + uint8_t pstStep = 0; + + /** + * wiretapping flag: + * + * indicates either that all raw messages to and from the device should be sent to #theOneWhoWantsToReadRawTraffic + * or that all device TM should be downlinked to #theOneWhoWantsToReadRawTraffic + */ + enum WiretappingMode: uint8_t { + OFF = 0, RAW = 1, TM = 2 + } wiretappingMode; + + /** + * A message queue that accepts raw replies + * + * Statically initialized in initialize() to a configurable object. Used when there is no method + * of finding a recipient, ie raw mode and reporting erreonous replies + */ + MessageQueueId_t defaultRawReceiver = 0; + + store_address_t storedRawData; + + /** + * the message queue which wants to read all raw traffic + * + * if #isWiretappingActive all raw communication from and to the device will be sent to this queue + */ + MessageQueueId_t requestedRawTraffic = 0; + + /** + * the object used to set power switches + */ + PowerSwitchIF *powerSwitcher = nullptr; + + /** + * Pointer to the IPCStore. + * + * This caches the pointer received from the objectManager in the constructor. + */ + StorageManagerIF *IPCStore = nullptr; + + /** + * cached for init + */ + object_id_t deviceCommunicationId; + + /** + * Communication object used for device communication + */ + DeviceCommunicationIF *communicationInterface = nullptr; + + /** + * Cookie used for communication. This is passed to the communication + * interface. + */ + CookieIF *comCookie; + + struct DeviceCommandInfo { + bool isExecuting; //!< Indicates if the command is already executing. + uint8_t expectedReplies; //!< Dynamic value to indicate how many replies are expected. Inititated with 0. + MessageQueueId_t sendReplyTo; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander. + }; + typedef std::map DeviceCommandMap; + typedef DeviceCommandMap::iterator DeviceCommandIter; + + /** + * @brief Information about expected replies + * + * This is used to keep track of pending replies + */ + struct DeviceReplyInfo { + uint16_t maxDelayCycles; //!< The maximum number of cycles the handler should wait for a reply to this command. + uint16_t delayCycles; //!< The currently remaining cycles the handler should wait for a reply, 0 means there is no reply expected + size_t replyLen = 0; //!< Expected size of the reply. + uint8_t periodic; //!< if this is !=0, the delayCycles will not be reset to 0 but to maxDelayCycles + DeviceCommandMap::iterator command; //!< The command that expects this reply. + }; + + typedef std::map DeviceReplyMap; + typedef DeviceReplyMap::iterator DeviceReplyIter; + + /** + * The MessageQueue used to receive device handler commands and to send replies. + */ + MessageQueueIF* commandQueue = nullptr; + + /** + * this is the datapool variable with the thermal state of the device + * + * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking + */ + uint32_t deviceThermalStatePoolId; + + /** + * this is the datapool variable with the thermal request of the device + * + * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking + */ + uint32_t deviceThermalRequestPoolId; + + /** + * Taking care of the health + */ + HealthHelper healthHelper; + + ModeHelper modeHelper; + + ParameterHelper parameterHelper; + + /** + * Optional Error code + * Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure. + */ + ReturnValue_t childTransitionFailure = RETURN_OK; + + uint32_t ignoreMissedRepliesCount = 0; //!< Counts if communication channel lost a reply, so some missed replys can be ignored. + + FailureIsolationBase* fdirInstance; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated. + + HkSwitchHelper hkSwitcher; + + bool defaultFDIRUsed; //!< To correctly delete the default instance. + + bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. + + PeriodicTaskIF* executingTask;//!< Pointer to the task which executes this component, is invalid before setTaskIF was called. + + static object_id_t powerSwitcherId; //!< Object which switches power on and off. + + static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. + + static object_id_t defaultFDIRParentId; //!< Object which may be the root cause of an identified fault. + + /** + * Set the device handler mode + * + * Sets #timeoutStart with every call. + * + * Sets #transitionTargetMode if necessary so transitional states can be entered from everywhere without breaking the state machine + * (which relies on a correct #transitionTargetMode). + * + * The submode is left unchanged. + * + * + * @param newMode + */ + void setMode(Mode_t newMode); + + /** + * @overload + * @param submode + */ + void setMode(Mode_t newMode, Submode_t submode); + + /** + * Helper function to report a missed reply + * + * Can be overwritten by children to act on missed replies or to fake reporting Id. + * + * @param id of the missed reply + */ + virtual void missedReply(DeviceCommandId_t id); + + /** + * Send a reply to a received device handler command. + * + * This also resets #DeviceHandlerCommand to 0. + * + * @param reply the reply type + * @param parameter parameter for the reply + */ + void replyReturnvalueToCommand(ReturnValue_t status, + uint32_t parameter = 0); + + /** + * Send reply to a command, differentiate between raw command + * and normal command. + * @param status + * @param parameter + */ + void replyToCommand(ReturnValue_t status, uint32_t parameter = 0); + /** * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). * @@ -409,144 +667,18 @@ protected: */ virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); - /** - * Get the time needed to transit from modeFrom to modeTo. - * - * Used for the following transitions: - * modeFrom -> modeTo: - * MODE_ON -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * MODE_NORMAL -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * MODE_RAW -> [MODE_ON, MODE_NORMAL, MODE_RAW, _MODE_POWER_DOWN] - * _MODE_START_UP -> MODE_ON (do not include time to set the switches, the base class got you covered) - * - * The default implementation returns 0; - * - * @param modeFrom - * @param modeTo - * @return time in ms - */ - virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo); - - /** - * Is the combination of mode and submode valid? - * - * @param mode - * @param submode - * @return - * - @c RETURN_OK if valid - * - @c RETURN_FAILED if invalid - */ - virtual ReturnValue_t isModeCombinationValid(Mode_t mode, - Submode_t submode); - - /** - * Get the Rmap action for the current step. - * - * The step number can be read from #pstStep. - * - * @return The Rmap action to execute in this step - */ - virtual RmapAction_t getRmapAction(); - - /** - * Build the device command to send for normal mode. - * - * This is only called in @c MODE_NORMAL. If multiple submodes for @c MODE_NORMAL are supported, - * different commands can built returned depending on the submode. - * - * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. - * - * @param[out] id the device command id that has been built - * @return - * - @c RETURN_OK when a command is to be sent - * - not @c RETURN_OK when no command is to be sent - */ - virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; - - /** - * Build the device command to send for a transitional mode. - * - * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, - * @c _MODE_START_UP and @c _MODE_TO_POWER_DOWN. So it is used by doStartUp() and doShutDown() as well as doTransition() - * - * A good idea is to implement a flag indicating a command has to be built and a variable containing the command number to be built - * and filling them in doStartUp(), doShutDown() and doTransition() so no modes have to be checked here. - * - * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. - * - * @param[out] id the device command id built - * @return - * - @c RETURN_OK when a command is to be sent - * - not @c RETURN_OK when no command is to be sent - */ - virtual ReturnValue_t buildTransitionDeviceCommand( - DeviceCommandId_t * id) = 0; - - /** - * Build the device command to send for raw mode. - * - * This is only called in @c MODE_RAW. It is for the rare case that in raw mode packets - * are to be sent by the handler itself. It is NOT needed for the raw commanding service. - * Its only current use is in the STR handler which gets its raw packets from a different - * source. - * Also it can be used for transitional commands, to get the device ready for @c MODE_RAW - * - * As it is almost never used, there is a default implementation returning @c NOTHING_TO_SEND. - * - * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. - * - * @param[out] id the device command id built - * @return - * - @c RETURN_OK when a command is to be sent - * - not @c NOTHING_TO_SEND when no command is to be sent - */ - virtual ReturnValue_t buildChildRawCommand(); - - /** - * Build a device command packet from data supplied by a direct command. - * - * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. - * - * @param deviceCommand the command to build, already checked against deviceCommandMap - * @param commandData pointer to the data from the direct command - * @param commandDataLen length of commandData - * @return - * - @c RETURN_OK when #rawPacket is valid - * - @c RETURN_FAILED when #rawPacket is invalid and no data should be sent - */ - virtual ReturnValue_t buildCommandFromCommand( - DeviceCommandId_t deviceCommand, const uint8_t * commandData, - size_t commandDataLen) = 0; - - /** - * fill the #deviceCommandMap - * - * called by the initialize() of the base class - * - * This is used to let the base class know which replies are expected. - * There are different scenarios regarding this: - * - "Normal" commands. These are commands, that trigger a direct reply from the device. In this case, the id of the command should be added to the command map - * with a commandData_t where maxDelayCycles is set to the maximum expected number of PST cycles the reply will take. Then, scanForReply returns the id of the command and the base class can handle time-out and missing replies. - * - Periodic, unrequested replies. These are replies that, once enabled, are sent by the device on its own in a defined interval. In this case, the id of the reply or a placeholder id should be added to the deviceCommandMap - * with a commandData_t where maxDelayCycles is set to the maximum expected number of PST cycles between two replies (also a tolerance should be added, as an FDIR message will be generated if it is missed). - * As soon as the replies are enabled, DeviceCommandInfo.periodic must be set to 1, DeviceCommandInfo.delayCycles to DeviceCommandInfo.MaxDelayCycles. From then on, the base class handles the reception. - * Then, scanForReply returns the id of the reply or the placeholder id and the base class will take care of checking that all replies are received and the interval is correct. - * When the replies are disabled, DeviceCommandInfo.periodic must be set to 0, DeviceCommandInfo.delayCycles to 0; - * - Aperiodic, unrequested replies. These are replies that are sent by the device without any preceding command and not in a defined interval. These are not entered in the deviceCommandMap but handled by returning @c APERIODIC_REPLY in scanForReply(). - * - */ - virtual void fillCommandAndReplyMap() = 0; - /** * This is a helper method to facilitate inserting entries in the command map. * @param deviceCommand Identifier of the command to add. * @param maxDelayCycles The maximum number of delay cycles the command waits until it times out. - * @param periodic Indicates if the command is periodic (i.e. it is sent by the device repeatedly without request) or not. + * @param periodic Indicates if the reply is periodic (i.e. it is sent by the device repeatedly without request) or not. * Default is aperiodic (0) + * @param hasDifferentReplyId + * @param replyId * @return RETURN_OK when the command was successfully inserted, COMMAND_MAP_ERROR else. */ ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, uint8_t periodic = 0, + uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0, bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); /** * This is a helper method to insert replies in the reply map. @@ -557,7 +689,7 @@ protected: * @return RETURN_OK when the command was successfully inserted, COMMAND_MAP_ERROR else. */ ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, uint8_t periodic = 0); + uint16_t maxDelayCycles, size_t replyLen = 0, uint8_t periodic = 0); /** * A simple command to add a command to the commandList. * @param deviceCommand The command to add @@ -583,48 +715,47 @@ protected: * @return The current delay count. If the command does not exist (should never happen) it returns 0. */ uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); - /** - * Scans a buffer for a valid reply. - * - * This is used by the base class to check the data received from the RMAP stack for valid packets. - * It only checks if a valid packet starts at @c start. - * It also only checks the structural validy of the packet, eg checksums lengths and protocol data. No - * information check is done, eg range checks etc. - * - * Errors should be reported directly, the base class does NOT report any errors based on the return - * value of this function. - * - * @param start start of data - * @param len length of data - * @param[out] foundId the id of the packet starting at @c start - * @param[out] foundLen length of the packet found - * @return - * - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid - * - @c NO_VALID_REPLY no reply could be found starting at @c start, implies @c foundLen is not valid, base class will call scanForReply() again with ++start - * - @c INVALID_REPLY a packet was found but it is invalid, eg checksum error, implies @c foundLen is valid, can be used to skip some bytes - * - @c TOO_SHORT @c len is too short for any valid packet - * - @c APERIODIC_REPLY if a valid reply is received that has not been requested by a command, but should be handled anyway (@see also fillCommandAndCookieMap() ) - */ - virtual ReturnValue_t scanForReply(const uint8_t *start, uint32_t len, - DeviceCommandId_t *foundId, uint32_t *foundLen) = 0; /** - * Interpret a reply from the device. + * Is the combination of mode and submode valid? * - * This is called after scanForReply() found a valid packet, it can be assumed that the length and structure is valid. - * This routine extracts the data from the packet into a DataSet and then calls handleDeviceTM(), which either sends - * a TM packet or stores the data in the DataPool depending on whether the it was an external command. - * No packet length is given, as it should be defined implicitly by the id. - * - * @param id the id found by scanForReply() - * @param packet - * @param commander the one who initiated the command, is 0 if not external commanded + * @param mode + * @param submode * @return - * - @c RETURN_OK when the reply was interpreted. - * - @c RETURN_FAILED when the reply could not be interpreted, eg. logical errors or range violations occurred + * - @c RETURN_OK if valid + * - @c RETURN_FAILED if invalid */ - virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) = 0; + virtual ReturnValue_t isModeCombinationValid(Mode_t mode, + Submode_t submode); + + /** + * Get the Rmap action for the current step. + * + * The step number can be read from #pstStep. + * + * @return The Rmap action to execute in this step + */ + virtual CommunicationAction_t getComAction(); + + /** + * Build the device command to send for raw mode. + * + * This is only called in @c MODE_RAW. It is for the rare case that in raw mode packets + * are to be sent by the handler itself. It is NOT needed for the raw commanding service. + * Its only current use is in the STR handler which gets its raw packets from a different + * source. + * Also it can be used for transitional commands, to get the device ready for @c MODE_RAW + * + * As it is almost never used, there is a default implementation returning @c NOTHING_TO_SEND. + * + * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. + * + * @param[out] id the device command id built + * @return + * - @c RETURN_OK when a command is to be sent + * - not @c NOTHING_TO_SEND when no command is to be sent + */ + virtual ReturnValue_t buildChildRawCommand(); /** * Construct a command reply containing a raw reply. @@ -649,33 +780,11 @@ protected: */ void replyRawReplyIfnotWiretapped(const uint8_t *data, size_t len); - /** - * Return the switches connected to the device. - * - * The default implementation returns one switch set in the ctor. - * - * - * @param[out] switches pointer to an array of switches - * @param[out] numberOfSwitches length of returned array - * @return - * - @c RETURN_OK if the parameters were set - * - @c RETURN_FAILED if no switches exist - */ - virtual ReturnValue_t getSwitches(const uint8_t **switches, - uint8_t *numberOfSwitches); - /** * notify child about mode change */ virtual void modeChanged(void); - struct DeviceCommandInfo { - bool isExecuting; //!< Indicates if the command is already executing. - uint8_t expectedReplies; //!< Dynamic value to indicate how many replies are expected. - MessageQueueId_t sendReplyTo; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander. - }; - - typedef std::map DeviceCommandMap; /** * Enable the reply checking for a command * @@ -686,16 +795,16 @@ protected: * When found, copies maxDelayCycles to delayCycles in the reply information and sets the command to * expect one reply. * - * Can be overwritten by the child, if a command activates multiple replies or replyId differs from - * commandId. + * Can be overwritten by the child, if a command activates multiple replies + * or replyId differs from commandId. * Notes for child implementations: * - If the command was not found in the reply map, NO_REPLY_EXPECTED MUST be returned. * - A failure code may be returned if something went fundamentally wrong. * * @param deviceCommand * @return - RETURN_OK if a reply was activated. - * - NO_REPLY_EXPECTED if there was no reply found. This is not an error case as many commands - * do not expect a reply. + * - NO_REPLY_EXPECTED if there was no reply found. This is not an + * error case as many commands do not expect a reply. */ virtual ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator cmd, uint8_t expectedReplies = 1, bool useAlternateId = false, @@ -711,14 +820,6 @@ protected: */ ReturnValue_t getStateOfSwitches(void); - /** - * set all datapool variables that are update periodically in normal mode invalid - * - * Child classes should provide an implementation which sets all those variables invalid - * which are set periodically during any normal mode. - */ - virtual void setNormalDatapoolEntriesInvalid() = 0; - /** * build a list of sids and pass it to the #hkSwitcher */ @@ -747,7 +848,6 @@ protected: virtual void startTransition(Mode_t mode, Submode_t submode); virtual void setToExternalControl(); virtual void announceMode(bool recursive); - virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); /** @@ -794,22 +894,6 @@ protected: bool commandIsExecuting(DeviceCommandId_t commandId); - /** - * Information about expected replies - * - * This is used to keep track of pending replies - */ - struct DeviceReplyInfo { - uint16_t maxDelayCycles; //!< The maximum number of cycles the handler should wait for a reply to this command. - uint16_t delayCycles; //!< The currently remaining cycles the handler should wait for a reply, 0 means there is no reply expected - uint8_t periodic; //!< if this is !=0, the delayCycles will not be reset to 0 but to maxDelayCycles - DeviceCommandMap::iterator command; //!< The command that expects this reply. - }; - - /** - * Definition for the important reply Map. - */ - typedef std::map DeviceReplyMap; /** * This map is used to check and track correct reception of all replies. * @@ -829,12 +913,13 @@ protected: DeviceCommandMap deviceCommandMap; ActionHelper actionHelper; + private: /** * State a cookie is in. * - * Used to keep track of the state of the RMAP communication. + * Used to keep track of the state of the communication. */ enum CookieState_t { COOKIE_UNUSED, //!< The Cookie is unused @@ -861,17 +946,12 @@ private: */ CookieInfo cookieInfo; - /** - * cached from ctor for initialize() - */ - const uint32_t ioBoardAddress; - /** * Used for timing out mode transitions. * * Set when setMode() is called. */ - uint32_t timeoutStart; + uint32_t timeoutStart = 0; /** * Delay for the current mode transition, used for time out @@ -913,22 +993,20 @@ private: * - checks whether commanded mode transitions are required and calls handleCommandedModeTransition() * - does the necessary action for the current mode or calls doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF * - actions that happen in transitions (eg setting a timeout) are handled in setMode() + * - Maybe export this into own class to increase modularity of software + * and reduce the massive class size ? */ void doStateMachine(void); void buildRawDeviceCommand(CommandMessage* message); void buildInternalCommand(void); -// /** -// * Send a reply with the current mode and submode. -// */ -// void announceMode(void); - /** * Decrement the counter for the timout of replies. * * This is called at the beginning of each cycle. It checks whether a reply has timed out (that means a reply was expected * but not received). + * In case the reply is periodic, the counter is simply set back to a specified value. */ void decrementDeviceReplyMap(void); @@ -995,8 +1073,8 @@ private: * - @c RETURN_FAILED IPCStore is NULL * - the return value from the IPCStore if it was not @c RETURN_OK */ - ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, - uint32_t *len); + ReturnValue_t getStorageData(store_address_t storageAddress, + uint8_t ** data, size_t * len); /** * set all switches returned by getSwitches() @@ -1025,9 +1103,16 @@ private: * - @c RETURN_FAILED when cookies could not be changed, eg because the newChannel is not enabled * - @c returnvalues of RMAPChannelIF::isActive() */ - ReturnValue_t switchCookieChannel(object_id_t newChannelId); + //ReturnValue_t switchCookieChannel(object_id_t newChannelId); + /** + * Handle device handler messages (e.g. commands sent by PUS Service 2) + * @param message + * @return + */ ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); + + }; #endif /* DEVICEHANDLERBASE_H_ */ diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index fe0ee8e8..34aa4114 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -8,7 +8,8 @@ #include /** - * This is the Interface used to communicate with a device handler. + * @brief This is the Interface used to communicate with a device handler. + * @details Includes all expected return values, events and modes. * */ class DeviceHandlerIF { @@ -22,80 +23,95 @@ public: * * @details The mode of the device handler must not be confused with the mode the device is in. * The mode of the device itself is transparent to the user but related to the mode of the handler. + * MODE_ON and MODE_OFF are included in hasModesIF.h */ -// MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted -// MODE_OFF = 1, //!< The device is powered off. The only command accepted in this mode is a mode change to on. - static const Mode_t MODE_NORMAL = 2; //!< The device is powered on and the device handler periodically sends commands. The commands to be sent are selected by the handler according to the submode. - static const Mode_t MODE_RAW = 3; //!< The device is powered on and ready to perform operations. In this mode, raw commands can be sent. The device handler will send all replies received from the command back to the commanding object. - static const Mode_t MODE_ERROR_ON = 4; //!4< The device is shut down but the switch could not be turned off, so the device still is powered. In this mode, only a mode change to @c MODE_OFF can be commanded, which tries to switch off the device again. - static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5; //!< This is a transitional state which can not be commanded. The device handler performs all commands to get the device in a state ready to perform commands. When this is completed, the mode changes to @c MODE_ON. - static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6; //!< This is a transitional state which can not be commanded. The device handler performs all actions and commands to get the device shut down. When the device is off, the mode changes to @c MODE_OFF. - static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON; - static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW; - static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL; - static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1; //!< This is a transitional state which can not be commanded. The device is shut down and ready to be switched off. After the command to set the switch off has been sent, the mode changes to @c MODE_WAIT_OFF - static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2; //!< This is a transitional state which can not be commanded. The device will be switched on in this state. After the command to set the switch on has been sent, the mode changes to @c MODE_WAIT_ON - static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3; //!< This is a transitional state which can not be commanded. The switch has been commanded off and the handler waits for it to be off. When the switch is off, the mode changes to @c MODE_OFF. - static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4; //!< This is a transitional state which can not be commanded. The switch has been commanded on and the handler waits for it to be on. When the switch is on, the mode changes to @c MODE_TO_ON. - static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5; //!< This is a transitional state which can not be commanded. The switch has been commanded off and is off now. This state is only to do an RMAP cycle once more where the doSendRead() function will set the mode to MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; - static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); - static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, SEVERITY::LOW); - static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, SEVERITY::LOW); - static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, SEVERITY::LOW); - static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, SEVERITY::LOW); - static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, SEVERITY::LOW); - static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, SEVERITY::LOW); - static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, SEVERITY::LOW); - static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, SEVERITY::LOW); //!< Indicates a SW bug in child class. - static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, SEVERITY::LOW); - static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, SEVERITY::HIGH); + // MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted + // MODE_OFF = 1, //!< The device is powered off. The only command accepted in this mode is a mode change to on. + static const Mode_t MODE_NORMAL = 2; //!< The device is powered on and the device handler periodically sends commands. The commands to be sent are selected by the handler according to the submode. + static const Mode_t MODE_RAW = 3; //!< The device is powered on and ready to perform operations. In this mode, raw commands can be sent. The device handler will send all replies received from the command back to the commanding object. + static const Mode_t MODE_ERROR_ON = 4; //!4< The device is shut down but the switch could not be turned off, so the device still is powered. In this mode, only a mode change to @c MODE_OFF can be commanded, which tries to switch off the device again. + static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5; //!< This is a transitional state which can not be commanded. The device handler performs all commands to get the device in a state ready to perform commands. When this is completed, the mode changes to @c MODE_ON. + static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6; //!< This is a transitional state which can not be commanded. The device handler performs all actions and commands to get the device shut down. When the device is off, the mode changes to @c MODE_OFF. + static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON; //!< It is possible to set the mode to _MODE_TO_ON to use the to on transition if available. + static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW; + static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL; + static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1; //!< This is a transitional state which can not be commanded. The device is shut down and ready to be switched off. After the command to set the switch off has been sent, the mode changes to @c MODE_WAIT_OFF + static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2; //!< This is a transitional state which can not be commanded. The device will be switched on in this state. After the command to set the switch on has been sent, the mode changes to @c MODE_WAIT_ON + static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3; //!< This is a transitional state which can not be commanded. The switch has been commanded off and the handler waits for it to be off. When the switch is off, the mode changes to @c MODE_OFF. + static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4; //!< This is a transitional state which can not be commanded. The switch has been commanded on and the handler waits for it to be on. When the switch is on, the mode changes to @c MODE_TO_ON. + static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5; //!< This is a transitional state which can not be commanded. The switch has been commanded off and is off now. This state is only to do an RMAP cycle once more where the doSendRead() function will set the mode to MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board - static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF; - static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA0); - static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA1); - static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA2); - static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA3); - static const ReturnValue_t CANT_SWITCH_IOBOARD = MAKE_RETURN_CODE(0xA4); - static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); - static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); - static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. - static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); - static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; + static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); + static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, SEVERITY::LOW); + static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, SEVERITY::LOW); + static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, SEVERITY::LOW); + static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, SEVERITY::LOW); + static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, SEVERITY::LOW); + static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, SEVERITY::LOW); + static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, SEVERITY::LOW); + static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, SEVERITY::LOW); //!< Indicates a SW bug in child class. + static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, SEVERITY::LOW); + static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, SEVERITY::HIGH); - //standard codes used in scan for reply - // static const ReturnValue_t TOO_SHORT = MAKE_RETURN_CODE(0xB1); - static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB2); - static const ReturnValue_t LENGTH_MISSMATCH = MAKE_RETURN_CODE(0xB3); - static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(0xB4); - static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0xB5); + static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF; - //standard codes used in interpret device reply - static const ReturnValue_t DEVICE_DID_NOT_EXECUTE = MAKE_RETURN_CODE(0xC1); //the device reported, that it did not execute the command - static const ReturnValue_t DEVICE_REPORTED_ERROR = MAKE_RETURN_CODE(0xC2); - static const ReturnValue_t UNKNOW_DEVICE_REPLY = MAKE_RETURN_CODE(0xC3); //the deviceCommandId reported by scanforReply is unknown - static const ReturnValue_t DEVICE_REPLY_INVALID = MAKE_RETURN_CODE(0xC4); //syntax etc is correct but still not ok, eg parameters where none are expected + // Standard codes used when building commands. + static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE(0xA0); //!< Return this if no command sending in required + // Mostly used for internal handling. + static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA2); //!< If the command size is 0. Checked in DHB + static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA3); //!< Used to indicate that this is a command-only command. + static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA4); //!< Command ID not in commandMap. Checked in DHB + static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA5); //!< Command was already executed. Checked in DHB + static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA6); + static const ReturnValue_t CANT_SWITCH_ADDRESS = MAKE_RETURN_CODE(0xA7); + static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA8); + static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA9); + static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xAA); + static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xAB); + static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAC); - //Standard codes used in buildCommandFromCommand - static const ReturnValue_t INVALID_COMMAND_PARAMETER = MAKE_RETURN_CODE( - 0xD0); - static const ReturnValue_t INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS = - MAKE_RETURN_CODE(0xD1); + // Standard codes used in scanForReply + static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(0xB1); //!< This is used to specify for replies from a device which are not replies to requests + static const ReturnValue_t LENGTH_MISSMATCH = MAKE_RETURN_CODE(0xB2); + static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(0xB3); //!< Ignore parts of the received packet + static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE(0xB4); //!< Ignore full received packet + static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB5); + static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(0xB6); + static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0xB7); + + // Standard codes used in interpretDeviceReply + static const ReturnValue_t DEVICE_DID_NOT_EXECUTE = MAKE_RETURN_CODE(0xC1); //the device reported, that it did not execute the command + static const ReturnValue_t DEVICE_REPORTED_ERROR = MAKE_RETURN_CODE(0xC2); + static const ReturnValue_t UNKNOW_DEVICE_REPLY = MAKE_RETURN_CODE(0xC3); //the deviceCommandId reported by scanforReply is unknown + static const ReturnValue_t DEVICE_REPLY_INVALID = MAKE_RETURN_CODE(0xC4); //syntax etc is correct but still not ok, eg parameters where none are expected + + // Standard codes used in buildCommandFromCommand + static const ReturnValue_t INVALID_COMMAND_PARAMETER = MAKE_RETURN_CODE(0xD0); + static const ReturnValue_t INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS = MAKE_RETURN_CODE(0xD1); + + // Standard codes used in getSwitches + static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE(0xE1); //!< Return in getSwitches() to specify there are no switches + + // static const ReturnValue_t ONE_SWITCH = MAKE_RETURN_CODE(8); + // static const ReturnValue_t TWO_SWITCHES = MAKE_RETURN_CODE(9); + // where is this used? + // static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE(11); + + /** + * Communication action that will be executed. + * + * This is used by the child class to tell the base class what to do. + */ + enum CommunicationAction_t: uint8_t { + SEND_WRITE,//!< Send write + GET_WRITE, //!< Get write + SEND_READ, //!< Send read + GET_READ, //!< Get read + NOTHING //!< Do nothing. + }; - /** - * RMAP Action that will be executed. - * - * This is used by the child class to tell the base class what to do. - */ - enum RmapAction_t { - SEND_WRITE,//!< RMAP send write - GET_WRITE, //!< RMAP get write - SEND_READ, //!< RMAP send read - GET_READ, //!< RMAP get read - NOTHING //!< Do nothing. - }; /** * Default Destructor */ diff --git a/devicehandlers/DeviceHandlerMessage.cpp b/devicehandlers/DeviceHandlerMessage.cpp index 58a6d312..97abcac5 100644 --- a/devicehandlers/DeviceHandlerMessage.cpp +++ b/devicehandlers/DeviceHandlerMessage.cpp @@ -47,7 +47,7 @@ void DeviceHandlerMessage::setDeviceHandlerWiretappingMessage( void DeviceHandlerMessage::setDeviceHandlerSwitchIoBoardMessage( CommandMessage* message, uint32_t ioBoardIdentifier) { - message->setCommand(CMD_SWITCH_IOBOARD); + message->setCommand(CMD_SWITCH_ADDRESS); message->setParameter(ioBoardIdentifier); } @@ -90,7 +90,7 @@ void DeviceHandlerMessage::clear(CommandMessage* message) { } } /* NO BREAK falls through*/ - case CMD_SWITCH_IOBOARD: + case CMD_SWITCH_ADDRESS: case CMD_WIRETAPPING: message->setCommand(CommandMessage::CMD_NONE); message->setParameter(0); diff --git a/devicehandlers/DeviceHandlerMessage.h b/devicehandlers/DeviceHandlerMessage.h index fad0f1b1..c91bb0a4 100644 --- a/devicehandlers/DeviceHandlerMessage.h +++ b/devicehandlers/DeviceHandlerMessage.h @@ -28,7 +28,7 @@ public: static const uint8_t MESSAGE_ID = MESSAGE_TYPE::DEVICE_HANDLER_COMMAND; static const Command_t CMD_RAW = MAKE_COMMAND_ID( 1 ); //!< Sends a raw command, setParameter is a ::store_id_t containing the raw packet to send // static const Command_t CMD_DIRECT = MAKE_COMMAND_ID( 2 ); //!< Sends a direct command, setParameter is a ::DeviceCommandId_t, setParameter2 is a ::store_id_t containing the data needed for the command - static const Command_t CMD_SWITCH_IOBOARD = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier + static const Command_t CMD_SWITCH_ADDRESS = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier static const Command_t CMD_WIRETAPPING = MAKE_COMMAND_ID( 4 ); //!< (De)Activates the monitoring of all raw traffic in DeviceHandlers, setParameter is 0 to deactivate, 1 to activate /*static const Command_t REPLY_SWITCHED_IOBOARD = MAKE_COMMAND_ID(1 );//!< Reply to a @c CMD_SWITCH_IOBOARD, indicates switch was successful, getParameter() contains the board switched to (0: nominal, 1: redundant) diff --git a/devicehandlers/DeviceTmReportingWrapper.cpp b/devicehandlers/DeviceTmReportingWrapper.cpp index 2c9e820f..4987c7fb 100644 --- a/devicehandlers/DeviceTmReportingWrapper.cpp +++ b/devicehandlers/DeviceTmReportingWrapper.cpp @@ -12,7 +12,7 @@ DeviceTmReportingWrapper::~DeviceTmReportingWrapper() { } ReturnValue_t DeviceTmReportingWrapper::serialize(uint8_t** buffer, - uint32_t* size, const uint32_t max_size, bool bigEndian) const { + size_t* size, const size_t max_size, bool bigEndian) const { ReturnValue_t result = SerializeAdapter::serialize(&objectId, buffer, size, max_size, bigEndian); if (result != HasReturnvaluesIF::RETURN_OK) { @@ -26,12 +26,12 @@ ReturnValue_t DeviceTmReportingWrapper::serialize(uint8_t** buffer, return data->serialize(buffer, size, max_size, bigEndian); } -uint32_t DeviceTmReportingWrapper::getSerializedSize() const { +size_t DeviceTmReportingWrapper::getSerializedSize() const { return sizeof(objectId) + sizeof(ActionId_t) + data->getSerializedSize(); } ReturnValue_t DeviceTmReportingWrapper::deSerialize(const uint8_t** buffer, - int32_t* size, bool bigEndian) { + ssize_t* size, bool bigEndian) { ReturnValue_t result = SerializeAdapter::deSerialize(&objectId, buffer, size, bigEndian); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/devicehandlers/DeviceTmReportingWrapper.h b/devicehandlers/DeviceTmReportingWrapper.h index 1cd9470d..fce74814 100644 --- a/devicehandlers/DeviceTmReportingWrapper.h +++ b/devicehandlers/DeviceTmReportingWrapper.h @@ -11,12 +11,12 @@ public: SerializeIF *data); virtual ~DeviceTmReportingWrapper(); - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; - virtual uint32_t getSerializedSize() const; + virtual size_t getSerializedSize() const; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian); private: object_id_t objectId; diff --git a/devicehandlers/FixedSequenceSlot.h b/devicehandlers/FixedSequenceSlot.h index 5aff0f4f..b3bac08f 100644 --- a/devicehandlers/FixedSequenceSlot.h +++ b/devicehandlers/FixedSequenceSlot.h @@ -19,29 +19,34 @@ class PeriodicTaskIF; */ class FixedSequenceSlot { public: - FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, int8_t setSequenceId, PeriodicTaskIF* executingTask ); + FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, + int8_t setSequenceId, PeriodicTaskIF* executingTask ); virtual ~FixedSequenceSlot(); /** - * \brief \c handler identifies which device handler object is executed in this slot. + * @brief Handler identifies which device handler object is executed in this slot. */ ExecutableObjectIF* handler; /** - * \brief This attribute defines when a device handler object is executed. + * @brief This attribute defines when a device handler object is executed. * - * \details The pollingTime attribute identifies the time the handler is executed in ms. It must be - * smaller than the period length of the polling sequence, what is ensured by automated calculation - * from a database. + * @details The pollingTime attribute identifies the time the handler is executed in ms. + * It must be smaller than the period length of the polling sequence. */ uint32_t pollingTimeMs; /** * \brief This value defines the type of device communication. * - * \details The state of this value decides what communication routine is called in the PST executable or the device handler object. + * \details The state of this value decides what communication routine is + * called in the PST executable or the device handler object. */ uint8_t opcode; + + bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { + return pollingTimeMs < fixedSequenceSlot.pollingTimeMs; + } }; diff --git a/devicehandlers/FixedSlotSequence.cpp b/devicehandlers/FixedSlotSequence.cpp index a65dd929..23bb0e78 100644 --- a/devicehandlers/FixedSlotSequence.cpp +++ b/devicehandlers/FixedSlotSequence.cpp @@ -2,22 +2,23 @@ #include FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : - lengthMs(setLengthMs) { + slotLengthMs(setLengthMs) { current = slotList.begin(); } FixedSlotSequence::~FixedSlotSequence() { - std::list::iterator slotIt; - //Iterate through slotList and delete all entries. - slotIt = this->slotList.begin(); - while (slotIt != this->slotList.end()) { - delete (*slotIt); - slotIt++; - } + // This should call the destructor on each list entry. + slotList.clear(); +// SlotListIter slotListIter = this->slotList.begin(); +// //Iterate through slotList and delete all entries. +// while (slotListIter != this->slotList.end()) { +// delete (*slotIt); +// slotIt++; +// } } void FixedSlotSequence::executeAndAdvance() { - (*this->current)->handler->performOperation((*this->current)->opcode); + current->handler->performOperation(current->opcode); // if (returnValue != RETURN_OK) { // this->sendErrorMessage( returnValue ); // } @@ -31,53 +32,50 @@ void FixedSlotSequence::executeAndAdvance() { uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { uint32_t oldTime; - std::list::iterator it; - it = current; + SlotListIter slotListIter = current; // Get the pollingTimeMs of the current slot object. - oldTime = (*it)->pollingTimeMs; + oldTime = slotListIter->pollingTimeMs; // Advance to the next object. - it++; + slotListIter++; // Find the next interval which is not 0. - while (it != slotList.end()) { - if (oldTime != (*it)->pollingTimeMs) { - return (*it)->pollingTimeMs - oldTime; + while (slotListIter != slotList.end()) { + if (oldTime != slotListIter->pollingTimeMs) { + return slotListIter->pollingTimeMs - oldTime; } else { - it++; + slotListIter++; } } // If the list end is reached (this is definitely an interval != 0), // the interval is calculated by subtracting the remaining time of the PST // and adding the start time of the first handler in the list. - it = slotList.begin(); - return lengthMs - oldTime + (*it)->pollingTimeMs; + slotListIter = slotList.begin(); + return slotLengthMs - oldTime + slotListIter->pollingTimeMs; } uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { uint32_t currentTime; - std::list::iterator it; - it = current; + SlotListIter slotListIter = current; // Get the pollingTimeMs of the current slot object. - currentTime = (*it)->pollingTimeMs; + currentTime = slotListIter->pollingTimeMs; //if it is the first slot, calculate difference to last slot - if (it == slotList.begin()){ - return lengthMs - (*(--slotList.end()))->pollingTimeMs + currentTime; + if (slotListIter == slotList.begin()){ + return slotLengthMs - (--slotList.end())->pollingTimeMs + currentTime; } // get previous slot - it--; + slotListIter--; - return currentTime - (*it)->pollingTimeMs; + return currentTime - slotListIter->pollingTimeMs; } bool FixedSlotSequence::slotFollowsImmediately() { - uint32_t currentTime = (*current)->pollingTimeMs; - std::list::iterator it; - it = this->current; + uint32_t currentTime = current->pollingTimeMs; + SlotListIter fixedSequenceIter = this->current; // Get the pollingTimeMs of the current slot object. - if (it == slotList.begin()) + if (fixedSequenceIter == slotList.begin()) return false; - it--; - if ((*it)->pollingTimeMs == currentTime) { + fixedSequenceIter--; + if (fixedSequenceIter->pollingTimeMs == currentTime) { return true; } else { return false; @@ -85,31 +83,35 @@ bool FixedSlotSequence::slotFollowsImmediately() { } uint32_t FixedSlotSequence::getLengthMs() const { - return this->lengthMs; + return this->slotLengthMs; } ReturnValue_t FixedSlotSequence::checkSequence() const { - //Iterate through slotList and check successful creation. Checks if timing is ok (must be ascending) and if all handlers were found. + // Iterate through slotList and check successful creation. + // Checks if timing is ok (must be ascending) and if all handlers were found. auto slotIt = slotList.begin(); uint32_t count = 0; uint32_t time = 0; while (slotIt != slotList.end()) { - if ((*slotIt)->handler == NULL) { + if (slotIt->handler == NULL) { error << "FixedSlotSequene::initialize: ObjectId does not exist!" << std::endl; count++; - } else if ((*slotIt)->pollingTimeMs < time) { + } else if (slotIt->pollingTimeMs < time) { error << "FixedSlotSequence::initialize: Time: " - << (*slotIt)->pollingTimeMs + << slotIt->pollingTimeMs << " is smaller than previous with " << time << std::endl; count++; } else { - //All ok, print slot. -// (*slotIt)->print(); + // All ok, print slot. + //info << "Current slot polling time: " << std::endl; + //info << std::dec << slotIt->pollingTimeMs << std::endl; } - time = (*slotIt)->pollingTimeMs; + time = slotIt->pollingTimeMs; slotIt++; } + //info << "Number of elements in slot list: " + // << slotList.size() << std::endl; if (count > 0) { return HasReturnvaluesIF::RETURN_FAILED; } @@ -118,8 +120,7 @@ ReturnValue_t FixedSlotSequence::checkSequence() const { void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep, PeriodicTaskIF* executingTask) { - this->slotList.push_back( - new FixedSequenceSlot(componentId, slotTimeMs, executionStep, - executingTask)); + this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep, + executingTask)); this->current = slotList.begin(); } diff --git a/devicehandlers/FixedSlotSequence.h b/devicehandlers/FixedSlotSequence.h index f8fd9a36..813d2fce 100644 --- a/devicehandlers/FixedSlotSequence.h +++ b/devicehandlers/FixedSlotSequence.h @@ -4,11 +4,15 @@ #include #include #include +#include + +using SlotList = std::multiset; +using SlotListIter = std::multiset::iterator; /** - * \brief This class is the representation of a Polling Sequence Table in software. + * @brief This class is the representation of a Polling Sequence Table in software. * - * \details The FixedSlotSequence object maintains the dynamic execution of device handler objects. + * @details The FixedSlotSequence object maintains the dynamic execution of device handler objects. * The main idea is to create a list of device handlers, to announce all handlers to the * polling sequence and to maintain a list of polling slot objects. This slot list represents the * Polling Sequence Table in software. Each polling slot contains information to indicate when and @@ -19,29 +23,37 @@ class FixedSlotSequence { public: + /** - * \brief The constructor of the FixedSlotSequence object. + * @brief The constructor of the FixedSlotSequence object. * - * \details The constructor takes two arguments, the period length and the init function. + * @details The constructor takes two arguments, the period length and the init function. * - * \param setLength The period length, expressed in ms. + * @param setLength The period length, expressed in ms. */ FixedSlotSequence(uint32_t setLengthMs); /** - * \brief The destructor of the FixedSlotSequence object. + * @brief The destructor of the FixedSlotSequence object. * - * \details The destructor frees all allocated memory by iterating through the slotList + * @details The destructor frees all allocated memory by iterating through the slotList * and deleting all allocated resources. */ virtual ~FixedSlotSequence(); /** - * \brief This is a method to add an PollingSlot object to slotList. + * @brief This is a method to add an PollingSlot object to slotList. * - * \details Here, a polling slot object is added to the slot list. It is appended + * @details Here, a polling slot object is added to the slot list. It is appended * to the end of the list. The list is currently NOT reordered. * Afterwards, the iterator current is set to the beginning of the list. + * @param Object ID of the object to add + * @param setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask + * will be called inside the slot period. + * @param setSequenceId ID which can be used to distinguish + * different task operations + * @param + * @param */ void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId, PeriodicTaskIF* executingTask); @@ -57,11 +69,14 @@ public: /** * \brief This method returns the time until the next software component is invoked. * - * \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 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. + * \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 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 getIntervalToNextSlotMs(); @@ -75,12 +90,12 @@ public: uint32_t getIntervalToPreviousSlotMs(); /** - * \brief This method returns the length of this FixedSlotSequence instance. + * @brief This method returns the length of this FixedSlotSequence instance. */ uint32_t getLengthMs() const; /** - * \brief The method to execute the device handler entered in the current OPUSPollingSlot object. + * \brief The method to execute the device handler entered in the current PollingSlot object. * * \details Within this method the device handler object to be executed is chosen by looking up the * handler address of the current slot in the handlerMap. Either the device handler's @@ -91,27 +106,27 @@ public: void executeAndAdvance(); /** - * \brief An iterator that indicates the current polling slot to execute. + * @brief An iterator that indicates the current polling slot to execute. * - * \details This is an iterator for slotList and always points to the polling slot which is executed next. + * @details This is an iterator for slotList and always points to the polling slot which is executed next. */ - std::list::iterator current; + SlotListIter current; - ReturnValue_t checkSequence() const; + virtual ReturnValue_t checkSequence() const; protected: /** - * \brief This list contains all OPUSPollingSlot objects, defining order and execution time of the + * @brief This list contains all PollingSlot objects, defining order and execution time of the * device handler objects. * - * \details The slot list is a std:list object that contains all created OPUSPollingSlot instances. + * @details The slot list is a std:list object that contains all created PollingSlot instances. * They are NOT ordered automatically, so by adding entries, the correct order needs to be ensured. * By iterating through this list the polling sequence is executed. Two entries with identical * polling times are executed immediately one after another. */ - std::list slotList; + SlotList slotList; - uint32_t lengthMs; + uint32_t slotLengthMs; }; #endif /* FIXEDSLOTSEQUENCE_H_ */ diff --git a/events/EventManager.cpp b/events/EventManager.cpp index 01334bac..46c53752 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -137,9 +137,10 @@ void EventManager::printEvent(EventMessage* message) { error << "0x" << std::hex << message->getReporter() << std::dec; } error << " reported " << translateEvents(message->getEvent()) << " (" - << std::dec << message->getEventId() << std::hex << ") P1: 0x" - << message->getParameter1() << " P2: 0x" - << message->getParameter2() << std::dec << std::endl; + << std::dec << message->getEventId() << ") " << std::endl; + + error << std::hex << "P1 Hex: 0x" << message->getParameter1() << ", P1 Dec: " << std::dec << message->getParameter1() << std::endl; + error << std::hex << "P2 Hex: 0x" << message->getParameter2() << ", P2 Dec: " << std::dec << message->getParameter2() << std::endl; break; } diff --git a/events/eventmatching/EventRangeMatcherBase.h b/events/eventmatching/EventRangeMatcherBase.h index 921a5d6a..8dea3e10 100644 --- a/events/eventmatching/EventRangeMatcherBase.h +++ b/events/eventmatching/EventRangeMatcherBase.h @@ -11,14 +11,14 @@ class EventRangeMatcherBase: public SerializeableMatcherIF { public: EventRangeMatcherBase(T from, T till, bool inverted) : rangeMatcher(from, till, inverted) { } virtual ~EventRangeMatcherBase() { } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { return rangeMatcher.serialize(buffer, size, max_size, bigEndian); } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { return rangeMatcher.getSerializedSize(); } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return rangeMatcher.deSerialize(buffer, size, bigEndian); } diff --git a/fdir/FailureIsolationBase.cpp b/fdir/FailureIsolationBase.cpp index 4b7caac5..c65640c2 100644 --- a/fdir/FailureIsolationBase.cpp +++ b/fdir/FailureIsolationBase.cpp @@ -5,9 +5,10 @@ #include #include -FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) : - eventQueue(NULL), ownerId( - owner), owner(NULL), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) { +FailureIsolationBase::FailureIsolationBase(object_id_t owner, + object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) : + eventQueue(NULL), ownerId(owner), owner(NULL), + faultTreeParent(parent), parameterDomainBase(parameterDomainBase) { eventQueue = QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE); } diff --git a/fdir/FailureIsolationBase.h b/fdir/FailureIsolationBase.h index cd582e39..894f6356 100644 --- a/fdir/FailureIsolationBase.h +++ b/fdir/FailureIsolationBase.h @@ -21,6 +21,10 @@ public: uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0); virtual ~FailureIsolationBase(); virtual ReturnValue_t initialize(); + + /** + * This is called by the DHB in performOperation() + */ void checkForFailures(); MessageQueueId_t getEventReceptionQueue(); virtual void triggerEvent(Event event, uint32_t parameter1 = 0, diff --git a/globalfunctions/Type.cpp b/globalfunctions/Type.cpp index 814d26f4..ea2ad896 100644 --- a/globalfunctions/Type.cpp +++ b/globalfunctions/Type.cpp @@ -1,4 +1,3 @@ -#include #include #include @@ -59,8 +58,8 @@ uint8_t Type::getSize() const { } } -ReturnValue_t Type::serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { +ReturnValue_t Type::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { uint8_t ptc; uint8_t pfc; ReturnValue_t result = getPtcPfc(&ptc, &pfc); @@ -81,12 +80,12 @@ ReturnValue_t Type::serialize(uint8_t** buffer, uint32_t* size, } -uint32_t Type::getSerializedSize() const { +size_t Type::getSerializedSize() const { uint8_t dontcare = 0; return 2 * SerializeAdapter::getSerializedSize(&dontcare); } -ReturnValue_t Type::deSerialize(const uint8_t** buffer, int32_t* size, +ReturnValue_t Type::deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { uint8_t ptc; uint8_t pfc; diff --git a/globalfunctions/Type.h b/globalfunctions/Type.h index 88df07b6..244091f7 100644 --- a/globalfunctions/Type.h +++ b/globalfunctions/Type.h @@ -39,12 +39,12 @@ public: static ActualType_t getActualType(uint8_t ptc, uint8_t pfc); - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; - virtual uint32_t getSerializedSize() const; + virtual size_t getSerializedSize() const; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian); private: diff --git a/globalfunctions/matching/MatchTree.h b/globalfunctions/matching/MatchTree.h index 398cf3f0..498fe860 100644 --- a/globalfunctions/matching/MatchTree.h +++ b/globalfunctions/matching/MatchTree.h @@ -45,8 +45,8 @@ public: return matchSubtree(iter, number); } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { iterator iter = this->begin(); uint8_t count = this->countRight(iter); ReturnValue_t result = SerializeAdapter::serialize(&count, @@ -86,7 +86,7 @@ public: return result; } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { //Analogous to serialize! uint32_t size = 1; //One for count iterator iter = this->begin(); @@ -115,7 +115,7 @@ public: return size; } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return HasReturnvaluesIF::RETURN_OK; } diff --git a/globalfunctions/matching/RangeMatcher.h b/globalfunctions/matching/RangeMatcher.h index 10e07173..c0980255 100644 --- a/globalfunctions/matching/RangeMatcher.h +++ b/globalfunctions/matching/RangeMatcher.h @@ -27,8 +27,8 @@ public: } } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result = SerializeAdapter::serialize(&lowerBound, buffer, size, max_size, bigEndian); if (result != HasReturnvaluesIF::RETURN_OK) { return result; @@ -40,11 +40,11 @@ public: return SerializeAdapter::serialize(&inverted, buffer, size, max_size, bigEndian); } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { return sizeof(lowerBound) + sizeof(upperBound) + sizeof(bool); } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { ReturnValue_t result = SerializeAdapter::deSerialize(&lowerBound, buffer, size, bigEndian); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/health/HealthHelper.h b/health/HealthHelper.h index a1ca2c52..24fd0d14 100644 --- a/health/HealthHelper.h +++ b/health/HealthHelper.h @@ -27,8 +27,8 @@ public: /** * ctor * + * @param owner * @param objectId the object Id to use when communication with the HealthTable - * @param useAsFrom id to use as from id when sending replies, can be set to 0 */ HealthHelper(HasHealthIF* owner, object_id_t objectId); diff --git a/health/HealthTable.cpp b/health/HealthTable.cpp index a575b282..94b7cf0b 100644 --- a/health/HealthTable.cpp +++ b/health/HealthTable.cpp @@ -65,7 +65,7 @@ bool HealthTable::hasHealth(object_id_t object) { void HealthTable::printAll(uint8_t* pointer, uint32_t maxSize) { mutex->lockMutex(MutexIF::NO_TIMEOUT); - uint32_t size = 0; + size_t size = 0; uint16_t count = healthMap.size(); ReturnValue_t result = SerializeAdapter::serialize(&count, &pointer, &size, maxSize, true); diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index 9a8ede00..81c4a0e5 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -8,10 +8,9 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t queuePoolId, uint32_t tmPoolId, uint32_t storePoolId) : - SystemObject(setObjectId), mutex(NULL), queuePoolId(queuePoolId), tmPoolId( - tmPoolId), storePoolId( - storePoolId), queueHits(0), tmHits(0), storeHits( - 0) { + SystemObject(setObjectId), mutex(NULL), queuePoolId(queuePoolId), + tmPoolId(tmPoolId),storePoolId(storePoolId), queueHits(0), tmHits(0), + storeHits(0) { mutex = MutexFactory::instance()->createMutex(); } diff --git a/ipc/CommandMessage.h b/ipc/CommandMessage.h index 2d966063..21c393e5 100644 --- a/ipc/CommandMessage.h +++ b/ipc/CommandMessage.h @@ -17,6 +17,9 @@ #define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) typedef ReturnValue_t Command_t; +/** + * @brief Used to pass command messages between tasks + */ class CommandMessage : public MessageQueueMessage { public: static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index 18e2d99a..47da694c 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -3,12 +3,16 @@ // COULDDO: We could support blocking calls +/** + * @defgroup message_queue Message Queue + * @brief Message Queue related software components + */ + #include #include #include class MessageQueueIF { public: - static const MessageQueueId_t NO_QUEUE = MessageQueueSenderIF::NO_QUEUE; //!< Ugly hack. static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; @@ -54,6 +58,8 @@ public: * 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. + * @return -@c RETURN_OK on success + * -@c MessageQueueIF::EMPTY if queue is empty */ virtual ReturnValue_t receiveMessage(MessageQueueMessage* message) = 0; /** @@ -72,33 +78,38 @@ public: virtual MessageQueueId_t getId() const = 0; /** - * \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 + * @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. + * @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 (if implemented). + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full (if implemented). + * @return -@c RETURN_OK on success + * -@c MessageQueueIF::FULL if queue is full */ virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; + /** - * @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. - */ + * @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. + */ virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault = false ) = 0; /** - * \brief The sendToDefaultFrom 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. + * @brief The sendToDefaultFrom 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. + * @return -@c RETURN_OK on success + * -@c MessageQueueIF::FULL if queue is full */ virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; /** @@ -106,6 +117,8 @@ public: * @details As in the sendMessage method, this function uses the sendToDefault call of the * Implementation class and adds its queue id as "sentFrom" information. * @param message A pointer to a previously created message, which is sent. + * @return -@c RETURN_OK on success + * -@c MessageQueueIF::FULL if queue is full */ virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ) = 0; /** diff --git a/ipc/MessageQueueSenderIF.h b/ipc/MessageQueueSenderIF.h index 9e7e11c0..6eb7733d 100644 --- a/ipc/MessageQueueSenderIF.h +++ b/ipc/MessageQueueSenderIF.h @@ -26,8 +26,8 @@ public: * Must be implemented by a subclass. */ static ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom = - MessageQueueSenderIF::NO_QUEUE, bool ignoreFault=false); + MessageQueueMessage* message, MessageQueueId_t sentFrom = MessageQueueSenderIF::NO_QUEUE, + bool ignoreFault=false); private: MessageQueueSenderIF() {} }; diff --git a/ipc/MutexIF.h b/ipc/MutexIF.h index 35786d6a..a4aff1cd 100644 --- a/ipc/MutexIF.h +++ b/ipc/MutexIF.h @@ -3,6 +3,13 @@ #include +/** + * @brief Common interface for OS Mutex objects which provide MUTual EXclusion. + * + * @details https://en.wikipedia.org/wiki/Lock_(computer_science) + * @ingroup osal + * @ingroup interface + */ class MutexIF { public: static const uint32_t NO_TIMEOUT; //!< Needs to be defined in implementation. diff --git a/memory/MemoryHelper.cpp b/memory/MemoryHelper.cpp index 4905875e..9bebb597 100644 --- a/memory/MemoryHelper.cpp +++ b/memory/MemoryHelper.cpp @@ -152,7 +152,7 @@ void MemoryHelper::handleMemoryLoad(CommandMessage* message) { ipcAddress = MemoryMessage::getStoreID(message); const uint8_t* p_data = NULL; uint8_t* dataPointer = NULL; - uint32_t size = 0; + size_t size = 0; ReturnValue_t returnCode = ipcStore->getData(ipcAddress, &p_data, &size); if (returnCode == RETURN_OK) { returnCode = workOnThis->handleMemoryLoad(address, p_data, size, diff --git a/modes/ModeHelper.cpp b/modes/ModeHelper.cpp index 7b98bdc6..d9266c35 100644 --- a/modes/ModeHelper.cpp +++ b/modes/ModeHelper.cpp @@ -1,6 +1,7 @@ #include #include #include +#include ModeHelper::ModeHelper(HasModesIF *owner) : theOneWhoCommandedAMode(0), commandedMode(HasModesIF::MODE_OFF), commandedSubmode( @@ -42,7 +43,6 @@ ReturnValue_t ModeHelper::handleModeCommand(CommandMessage* message) { } countdown.setTimeout(timeout); - owner->startTransition(mode, submode); } break; diff --git a/modes/ModeMessage.cpp b/modes/ModeMessage.cpp index 62fea7e4..1d3baad5 100644 --- a/modes/ModeMessage.cpp +++ b/modes/ModeMessage.cpp @@ -16,6 +16,10 @@ ReturnValue_t ModeMessage::setModeMessage(CommandMessage* message, Command_t com return HasReturnvaluesIF::RETURN_OK; } +ReturnValue_t ModeMessage::getCantReachModeReason(const CommandMessage* message) { + return message->getParameter(); +} + void ModeMessage::clear(CommandMessage* message) { message->setCommand(CommandMessage::CMD_NONE); } diff --git a/modes/ModeMessage.h b/modes/ModeMessage.h index fad34726..0a72aee0 100644 --- a/modes/ModeMessage.h +++ b/modes/ModeMessage.h @@ -24,6 +24,7 @@ public: static const Command_t REPLY_MODE_INFO = MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to inform their container of a changed mode) static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0 //SHOULDDO is there a way we can transmit a returnvalue when responding that the mode is wrong, so we can give a nice failure code when commanded by PUS? + // shouldn't that possible with parameter 2 when submode only takes 1 byte? static const Command_t REPLY_WRONG_MODE_REPLY = MAKE_COMMAND_ID(0x05);//!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded and a transition started but was aborted; the parameters contain the mode that was reached static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(0x06);//!> Command to read the current mode and reply with a REPLY_MODE_REPLY static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(0x07);//!> Command to trigger an ModeInfo Event. This command does NOT have a reply. @@ -34,6 +35,7 @@ public: static ReturnValue_t setModeMessage(CommandMessage* message, Command_t command, Mode_t mode, Submode_t submode); static void cantReachMode(CommandMessage* message, ReturnValue_t reason); + static ReturnValue_t getCantReachModeReason(const CommandMessage* message); static void clear(CommandMessage* message); }; diff --git a/monitoring/LimitMonitor.h b/monitoring/LimitMonitor.h index 45abe48b..c24629a3 100644 --- a/monitoring/LimitMonitor.h +++ b/monitoring/LimitMonitor.h @@ -16,12 +16,13 @@ public: uint16_t confirmationLimit, T lowerLimit, T upperLimit, Event belowLowEvent = MonitoringIF::VALUE_BELOW_LOW_LIMIT, Event aboveHighEvent = MonitoringIF::VALUE_ABOVE_HIGH_LIMIT) : - MonitorBase(reporterId, monitorId, parameterId, confirmationLimit), lowerLimit( - lowerLimit), upperLimit(upperLimit), belowLowEvent( - belowLowEvent), aboveHighEvent(aboveHighEvent) { - } - virtual ~LimitMonitor() { + MonitorBase(reporterId, monitorId, parameterId, confirmationLimit), + lowerLimit(lowerLimit), upperLimit(upperLimit), belowLowEvent(belowLowEvent), + aboveHighEvent(aboveHighEvent) { } + + virtual ~LimitMonitor() {} + virtual ReturnValue_t checkSample(T sample, T* crossedLimit) { *crossedLimit = 0.0; if (sample > upperLimit) { diff --git a/monitoring/LimitViolationReporter.cpp b/monitoring/LimitViolationReporter.cpp index 760e8b93..234a0bff 100644 --- a/monitoring/LimitViolationReporter.cpp +++ b/monitoring/LimitViolationReporter.cpp @@ -17,7 +17,7 @@ ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF } store_address_t storeId; uint8_t* dataTarget = NULL; - uint32_t maxSize = data->getSerializedSize(); + size_t maxSize = data->getSerializedSize(); if (maxSize > MonitoringIF::VIOLATION_REPORT_MAX_SIZE) { return MonitoringIF::INVALID_SIZE; } @@ -26,7 +26,7 @@ ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - uint32_t size = 0; + size_t size = 0; result = data->serialize(&dataTarget, &size, maxSize, true); if (result != HasReturnvaluesIF::RETURN_OK) { return result; diff --git a/objectmanager/ObjectManagerIF.h b/objectmanager/ObjectManagerIF.h index aca24a24..1d7674c6 100644 --- a/objectmanager/ObjectManagerIF.h +++ b/objectmanager/ObjectManagerIF.h @@ -78,6 +78,8 @@ public: virtual void printList() = 0; }; + +/*Documentation can be found in the class method declaration above.*/ template T* ObjectManagerIF::get( object_id_t id ) { SystemObjectIF* temp = this->getSystemObject(id); diff --git a/osal/Endiness.h b/osal/Endiness.h index 65cc0a10..55d0aeb3 100644 --- a/osal/Endiness.h +++ b/osal/Endiness.h @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_OSAL_ENDINESS_H_ #define FRAMEWORK_OSAL_ENDINESS_H_ +/** + * @defgroup osal Operating System Abstraction Layer + * @brief Provides clean interfaces to use OS functionalities + */ /* * BSD-style endian declaration diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp new file mode 100644 index 00000000..546c5a46 --- /dev/null +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -0,0 +1,109 @@ +/** + * @file BinarySemaphore.cpp + * + * @date 25.02.2020 + */ +#include +#include + +#include +#include "portmacro.h" +#include "task.h" + +BinarySemaphore::BinarySemaphore() { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } +} + +BinarySemaphore::~BinarySemaphore() { + vSemaphoreDelete(handle); +} + +ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { + if(handle == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + TickType_t timeout = portMAX_DELAY; + if(timeoutMs != 0) { + timeout = pdMS_TO_TICKS(timeoutMs); + } + + BaseType_t returncode = xSemaphoreTake(handle, timeout); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_FOUND; + } +} + +ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks) { + if(handle == nullptr) { + return SEMAPHORE_NOT_FOUND; + } + + BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::giveBinarySemaphore() { + if (handle == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + BaseType_t returncode = xSemaphoreGive(handle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} + +SemaphoreHandle_t BinarySemaphore::getSemaphore() { + return handle; +} + +ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { + if (semaphore == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + BaseType_t returncode = xSemaphoreGive(semaphore); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +void BinarySemaphore::resetSemaphore() { + if(handle != nullptr) { + vSemaphoreDelete(handle); + xSemaphoreCreateBinary(handle); + } +} + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, + BaseType_t * higherPriorityTaskWoken) { + if (semaphore == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); + if (returncode == pdPASS) { + if(*higherPriorityTaskWoken == pdPASS) { + // Request context switch + // TODO: I don't know if this will ever happen but if it does, + // I want to to know in case this causes issues. If it doesn't + // we should remove this. + TRACE_INFO("Binary Semaphore: Higher priority task unblocked!"); + TaskManagement::requestContextSwitch(CallContext::isr); + } + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h new file mode 100644 index 00000000..a809f0bb --- /dev/null +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -0,0 +1,103 @@ +/** + * @file BinarySempahore.h + * + * @date 25.02.2020 + */ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ + +#include +#include +#include "semphr.h" + +/** + * @brief OS Tool to achieve synchronization of between tasks or between task and ISR + * @details + * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html + * @ingroup osal + */ +class BinarySemaphore: public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + /** Semaphore object not found */ + static const ReturnValue_t SEMAPHORE_NOT_FOUND = MAKE_RETURN_CODE(1); + /** Semaphore timeout */ + static const ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(2); + /** The current semaphore can not be given, because it is not owned */ + static const ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(3); + + /** + * Create a binary semaphore + */ + BinarySemaphore(); + + /** + * Delete the binary semaphore to prevent a memory leak + */ + ~BinarySemaphore(); + + /** + * Take the binary semaphore. + * If the semaphore has already been taken, the task will be blocked for a maximum + * of #timeoutMs or until the semaphore is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs); + + /** + * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks); + + /** + * Give back the binary semaphore + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + ReturnValue_t giveBinarySemaphore(); + + /** + * Get Handle to the semaphore. + * @return + */ + SemaphoreHandle_t getSemaphore(); + + /** + * Reset the semaphore. + */ + void resetSemaphore(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphore(SemaphoreHandle_t semaphore); + + /** + * Wrapper function to give back semaphore from handle when called from an ISR + * @param semaphore + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority + * was unblocked + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, + BaseType_t * higherPriorityTaskWoken); +private: + SemaphoreHandle_t handle; +}; + + + + + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index 00fd73d3..b1c97420 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -19,8 +19,7 @@ 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)); + 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. @@ -58,8 +57,19 @@ ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); - return HasReturnvaluesIF::RETURN_OK; + if (objectManager->get(componentId) != NULL) { + if(slotTimeMs == 0) { + // TODO: FreeRTOS throws errors for zero values. + // maybe there is a better solution than this. + slotTimeMs = 1; + } + pst.addSlot(componentId, slotTimeMs, executionStep, this); + return HasReturnvaluesIF::RETURN_OK; + } + + error << "Component " << std::hex << componentId + << " not found, not adding it to pst" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; } uint32_t FixedTimeslotTask::getPeriodMs() const { @@ -72,10 +82,10 @@ 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. - std::list::iterator it = pst.current; + SlotListIter slotListIter = pst.current; //The start time for the first entry is read. - uint32_t intervalMs = (*it)->pollingTimeMs; + uint32_t intervalMs = slotListIter->pollingTimeMs; TickType_t interval = pdMS_TO_TICKS(intervalMs); TickType_t xLastWakeTime; @@ -110,4 +120,3 @@ 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 bed13051..1ab8724f 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -51,6 +51,7 @@ public: ReturnValue_t checkSequence() const; ReturnValue_t sleepFor(uint32_t ms); + protected: bool started; TaskHandle_t handle; diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index f3aebcd1..cc38e77d 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -3,9 +3,10 @@ #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 - +// As a first step towards this, introduces system context variable which needs to be switched manually +// Haven't found function to find system context. MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : -defaultDestination(0),lastPartner(0) { +defaultDestination(0),lastPartner(0), callContext(CallContext::task) { handle = xQueueCreate(message_depth, max_message_size); if (handle == NULL) { error << "MessageQueue creation failed" << std::endl; @@ -18,6 +19,10 @@ MessageQueue::~MessageQueue() { } } +void MessageQueue::switchSystemContext(CallContext callContext) { + this->callContext = callContext; +} + ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault) { return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); @@ -27,6 +32,11 @@ ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { return sendToDefaultFrom(message, this->getId()); } +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); +} + ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { if (this->lastPartner != 0) { return sendMessageFrom(this->lastPartner, message, this->getId()); @@ -35,10 +45,54 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { } } +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault, callContext); +} + +ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessage *message, MessageQueueId_t sentFrom, + bool ignoreFault, CallContext callContext) { + message->setSender(sentFrom); + BaseType_t result; + if(callContext == CallContext::task) { + result = xQueueSendToBack(reinterpret_cast(sendTo), + reinterpret_cast(message->getBuffer()), 0); + } + else { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + result = xQueueSendFromISR(reinterpret_cast(sendTo), + reinterpret_cast(message->getBuffer()), &xHigherPriorityTaskWoken); + if(xHigherPriorityTaskWoken == pdTRUE) { + TaskManagement::requestContextSwitch(callContext); + } + } + return handleSendResult(result, ignoreFault); +} + + + +ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { + if (result != pdPASS) { + if (!ignoreFault) { + InternalErrorReporterIF* internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != NULL) { + internalErrorReporter->queueMessageNotSent(); + } + } + return MessageQueueIF::FULL; + } + return HasReturnvaluesIF::RETURN_OK; +} + ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, MessageQueueId_t* receivedFrom) { ReturnValue_t status = this->receiveMessage(message); - *receivedFrom = this->lastPartner; + if(status == HasReturnvaluesIF::RETURN_OK) { + *receivedFrom = this->lastPartner; + } return status; } @@ -71,17 +125,6 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { this->defaultDestination = defaultDestination; } -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); -} - MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; } @@ -89,23 +132,6 @@ MessageQueueId_t MessageQueue::getDefaultDestination() const { bool MessageQueue::isDefaultDestinationSet() const { return 0; } -ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessage *message, MessageQueueId_t sentFrom, - bool ignoreFault) { - message->setSender(sentFrom); - BaseType_t result = xQueueSendToBack(reinterpret_cast(sendTo),reinterpret_cast(message->getBuffer()), 0); - if (result != pdPASS) { - if (!ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != NULL) { - internalErrorReporter->queueMessageNotSent(); - } - } - return MessageQueueIF::FULL; - } - return HasReturnvaluesIF::RETURN_OK; -} diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index 32f41b44..8edfed10 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -4,9 +4,11 @@ #include #include #include +#include #include -#include +#include "queue.h" + //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/ @@ -21,11 +23,17 @@ * 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 + * + * Please keep in mind that FreeRTOS offers + * different calls for message queue operations if called from an ISR. + * For now, the system context needs to be switched manually. + * @ingroup osal + * @ingroup message_queue */ class MessageQueue : public MessageQueueIF { friend class MessageQueueSenderIF; @@ -43,11 +51,15 @@ public: * 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(); + + void switchSystemContext(CallContext callContext); + /** * @brief This operation sends a message to the given destination. * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its @@ -74,6 +86,29 @@ public: */ ReturnValue_t reply( MessageQueueMessage* message ); + /** + * \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 sendMessageFrom( 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 sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** * @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 @@ -107,26 +142,7 @@ public: * @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 sendMessageFrom( 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 sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** * \brief This method is a simple setter for the default destination. */ @@ -148,12 +164,20 @@ protected: * \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. + * \param context */ - static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE,bool ignoreFault=false); + static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault=false, CallContext callContex = CallContext::task); + + static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); + + private: QueueHandle_t handle; MessageQueueId_t defaultDestination; MessageQueueId_t lastPartner; + CallContext callContext; //!< Stores the current system context }; #endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/Mutex.cpp b/osal/FreeRTOS/Mutex.cpp index 7c511091..616ef7b8 100644 --- a/osal/FreeRTOS/Mutex.cpp +++ b/osal/FreeRTOS/Mutex.cpp @@ -6,7 +6,9 @@ const uint32_t MutexIF::NO_TIMEOUT = 0; Mutex::Mutex() { handle = xSemaphoreCreateMutex(); - //TODO print error + if(handle == NULL) { + error << "Mutex creation failure" << std::endl; + } } Mutex::~Mutex() { @@ -18,8 +20,7 @@ Mutex::~Mutex() { ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { if (handle == 0) { - //TODO Does not exist - return HasReturnvaluesIF::RETURN_FAILED; + return MutexIF::MUTEX_NOT_FOUND; } TickType_t timeout = portMAX_DELAY; if (timeoutMs != NO_TIMEOUT) { @@ -30,21 +31,18 @@ ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; } else { - //TODO could not be acquired/timeout - return HasReturnvaluesIF::RETURN_FAILED; + return MutexIF::MUTEX_TIMEOUT; } } ReturnValue_t Mutex::unlockMutex() { if (handle == 0) { - //TODO Does not exist - return HasReturnvaluesIF::RETURN_FAILED; + return MutexIF::MUTEX_NOT_FOUND; } BaseType_t returncode = xSemaphoreGive(handle); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; } else { - //TODO is not owner - return HasReturnvaluesIF::RETURN_FAILED; + return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX; } } diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h index 91f29585..2703df4e 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/osal/FreeRTOS/Mutex.h @@ -1,5 +1,5 @@ -#ifndef OS_RTEMS_MUTEX_H_ -#define OS_RTEMS_MUTEX_H_ +#ifndef FRAMEWORK_FREERTOS_MUTEX_H_ +#define FRAMEWORK_FREERTOS_MUTEX_H_ #include @@ -7,8 +7,14 @@ #include #include "semphr.h" - - +/** + * @brief OS component to implement MUTual EXclusion + * + * @details + * Mutexes are binary semaphores which include a priority inheritance mechanism. + * Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html + * @ingroup osal + */ class Mutex : public MutexIF { public: Mutex(); @@ -19,4 +25,4 @@ private: SemaphoreHandle_t handle; }; -#endif /* OS_RTEMS_MUTEX_H_ */ +#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */ diff --git a/osal/FreeRTOS/MutexFactory.cpp b/osal/FreeRTOS/MutexFactory.cpp index cadb54fb..b3e3f02c 100644 --- a/osal/FreeRTOS/MutexFactory.cpp +++ b/osal/FreeRTOS/MutexFactory.cpp @@ -1,6 +1,5 @@ #include - -#include "../FreeRTOS/Mutex.h" +#include //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(); diff --git a/osal/FreeRTOS/PeriodicTask.h b/osal/FreeRTOS/PeriodicTask.h index e7ba8dd2..4cbffd5a 100644 --- a/osal/FreeRTOS/PeriodicTask.h +++ b/osal/FreeRTOS/PeriodicTask.h @@ -1,5 +1,5 @@ -#ifndef MULTIOBJECTTASK_H_ -#define MULTIOBJECTTASK_H_ +#ifndef PERIODICTASK_H_ +#define PERIODICTASK_H_ #include #include @@ -107,4 +107,4 @@ protected: void taskFunctionality(void); }; -#endif /* MULTIOBJECTTASK_H_ */ +#endif /* PERIODICTASK_H_ */ diff --git a/osal/FreeRTOS/QueueFactory.cpp b/osal/FreeRTOS/QueueFactory.cpp index 5c7087de..eaf245d3 100644 --- a/osal/FreeRTOS/QueueFactory.cpp +++ b/osal/FreeRTOS/QueueFactory.cpp @@ -1,6 +1,6 @@ #include -#include "../FreeRTOS/MessageQueue.h" +#include QueueFactory* QueueFactory::factoryInstance = NULL; diff --git a/osal/FreeRTOS/TaskFactory.cpp b/osal/FreeRTOS/TaskFactory.cpp index 7b2f70a3..753da60f 100644 --- a/osal/FreeRTOS/TaskFactory.cpp +++ b/osal/FreeRTOS/TaskFactory.cpp @@ -15,6 +15,7 @@ TaskFactory* TaskFactory::instance() { } /*** * Keep in Mind that you need to call before this vTaskStartScheduler()! + * High taskPriority_ number means high priority. */ PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp new file mode 100644 index 00000000..9946833d --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -0,0 +1,32 @@ +/** + * @file TaskManagement.cpp + * + * @date 26.02.2020 + * + */ +#include +#include +#include "portmacro.h" +#include "task.h" + +/** + * TODO: This stuff is hardware and architecture and mission dependant... + * Some FreeRTOS implementations might be able to determine their own task context for example. + * If not ISRs are used, or task preemption is enabled, some of this stuff might + * not be necessary anyway. Maybe there is a better solution? + */ +void TaskManagement::requestContextSwitchFromTask() { + vTaskDelay(0); +} + +void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::task) { + if(callContext == CallContext::isr) { + // This function depends on the partmacro.h definition for the specific device + portYIELD_FROM_ISR(); + } else { + requestContextSwitchFromTask(); + } +} + + + diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h new file mode 100644 index 00000000..fd2bfc0b --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.h @@ -0,0 +1,38 @@ +/** + * @file TaskManagement.h + * + * @date 26.02.2020 + */ + +#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ + +/*! + * Used by functions to tell if they are being called from + * within an ISR or from a regular task. This is required because FreeRTOS + * has different functions for handling semaphores and messages from within an ISR and task. + */ + +enum CallContext { + task = 0x00,//!< task_context + isr = 0xFF //!< isr_context +}; + +class TaskManagement { +public: + /** + * In this function, a function dependant on the portmacro.h header function calls + * to request a context switch can be specified. + * This can be used if sending to the queue from an ISR caused a task to unblock + * and a context switch is required. + */ + static void requestContextSwitch(CallContext callContext); + + /** + * If task preemption in FreeRTOS is disabled, a context switch + * can be requested manually by calling this function. + */ + static void requestContextSwitchFromTask(void); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ diff --git a/osal/linux/FixedTimeslotTask.cpp b/osal/linux/FixedTimeslotTask.cpp index 99cbf818..21040e6e 100644 --- a/osal/linux/FixedTimeslotTask.cpp +++ b/osal/linux/FixedTimeslotTask.cpp @@ -40,6 +40,11 @@ uint32_t FixedTimeslotTask::getPeriodMs() const { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { + if (!objectManager->get(componentId)) { + error << "Component " << std::hex << componentId << " not found, not adding it to pst" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + pst.addSlot(componentId, slotTimeMs, executionStep, this); return HasReturnvaluesIF::RETURN_OK; } diff --git a/parameters/ParameterHelper.cpp b/parameters/ParameterHelper.cpp index 75b71a7e..4ba2a1d9 100644 --- a/parameters/ParameterHelper.cpp +++ b/parameters/ParameterHelper.cpp @@ -3,7 +3,7 @@ #include ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner) : - owner(owner), storage(NULL) { + owner(owner), ownerQueueId(0), storage(NULL){ } @@ -37,7 +37,7 @@ ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) { ParameterMessage::getParameterId(message)); const uint8_t *storedStream; - uint32_t storedStreamSize; + size_t storedStreamSize; result = storage->getData( ParameterMessage::getStoreId(message), &storedStream, &storedStreamSize); @@ -94,7 +94,7 @@ ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id, return result; } - uint32_t storeElementSize = 0; + size_t storeElementSize = 0; result = description->serialize(&storeElement, &storeElementSize, serializedSize, true); diff --git a/parameters/ParameterWrapper.cpp b/parameters/ParameterWrapper.cpp index 8f661bb3..1420c076 100644 --- a/parameters/ParameterWrapper.cpp +++ b/parameters/ParameterWrapper.cpp @@ -20,8 +20,8 @@ ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, ParameterWrapper::~ParameterWrapper() { } -ReturnValue_t ParameterWrapper::serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { +ReturnValue_t ParameterWrapper::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result; result = SerializeAdapter::serialize(&type, buffer, size, max_size, @@ -77,7 +77,7 @@ ReturnValue_t ParameterWrapper::serialize(uint8_t** buffer, uint32_t* size, return result; } -uint32_t ParameterWrapper::getSerializedSize() const { +size_t ParameterWrapper::getSerializedSize() const { uint32_t serializedSize = 0; serializedSize += type.getSerializedSize(); serializedSize += sizeof(rows); @@ -88,8 +88,8 @@ uint32_t ParameterWrapper::getSerializedSize() const { } template -ReturnValue_t ParameterWrapper::serializeData(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { +ReturnValue_t ParameterWrapper::serializeData(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { const T *element = (const T*) readonlyData; ReturnValue_t result; uint16_t dataSize = columns * rows; @@ -112,7 +112,7 @@ ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow, //treat from as a continuous Stream as we copy all of it const uint8_t *fromAsStream = (const uint8_t *) from; - int32_t streamSize = fromRows * fromColumns * sizeof(T); + ssize_t streamSize = fromRows * fromColumns * sizeof(T); ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; @@ -137,12 +137,12 @@ ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow, } ReturnValue_t ParameterWrapper::deSerialize(const uint8_t** buffer, - int32_t* size, bool bigEndian) { + ssize_t* size, bool bigEndian) { return deSerialize(buffer, size, bigEndian, 0); } ReturnValue_t ParameterWrapper::deSerialize(const uint8_t** buffer, - int32_t* size, bool bigEndian, uint16_t startWritingAtIndex) { + ssize_t* size, bool bigEndian, uint16_t startWritingAtIndex) { ParameterWrapper streamDescription; ReturnValue_t result = streamDescription.set(*buffer, *size, buffer, size); @@ -153,8 +153,8 @@ ReturnValue_t ParameterWrapper::deSerialize(const uint8_t** buffer, return copyFrom(&streamDescription, startWritingAtIndex); } -ReturnValue_t ParameterWrapper::set(const uint8_t* stream, int32_t streamSize, - const uint8_t **remainingStream, int32_t *remainingSize) { +ReturnValue_t ParameterWrapper::set(const uint8_t* stream, ssize_t streamSize, + const uint8_t **remainingStream, ssize_t *remainingSize) { ReturnValue_t result = SerializeAdapter::deSerialize(&type, &stream, &streamSize, true); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/parameters/ParameterWrapper.h b/parameters/ParameterWrapper.h index f61786b8..6f8f6fc9 100644 --- a/parameters/ParameterWrapper.h +++ b/parameters/ParameterWrapper.h @@ -25,15 +25,15 @@ public: const void *data); virtual ~ParameterWrapper(); - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; - virtual uint32_t getSerializedSize() const; + virtual size_t getSerializedSize() const; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian); - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian, uint16_t startWritingAtIndex = 0); template @@ -111,8 +111,8 @@ public: void setMatrix(const T& member) { this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0])); } - ReturnValue_t set(const uint8_t *stream, int32_t streamSize, - const uint8_t **remainingStream = NULL, int32_t *remainingSize = + ReturnValue_t set(const uint8_t *stream, ssize_t streamSize, + const uint8_t **remainingStream = NULL, ssize_t *remainingSize = NULL); ReturnValue_t copyFrom(const ParameterWrapper *from, @@ -128,8 +128,8 @@ private: const void *readonlyData; template - ReturnValue_t serializeData(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + ReturnValue_t serializeData(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; template ReturnValue_t deSerializeData(uint8_t startingRow, uint8_t startingColumn, diff --git a/power/Fuse.cpp b/power/Fuse.cpp index dd5d3e3f..6a4e6caf 100644 --- a/power/Fuse.cpp +++ b/power/Fuse.cpp @@ -86,8 +86,8 @@ ReturnValue_t Fuse::check() { return result; } -ReturnValue_t Fuse::serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { +ReturnValue_t Fuse::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result = RETURN_FAILED; for (DeviceList::const_iterator iter = devices.begin(); iter != devices.end(); iter++) { @@ -100,7 +100,7 @@ ReturnValue_t Fuse::serialize(uint8_t** buffer, uint32_t* size, } uint32_t Fuse::getSerializedSize() const { - uint32_t size = 0; + size_t size = 0; for (DeviceList::const_iterator iter = devices.begin(); iter != devices.end(); iter++) { size += (*iter)->getSerializedSize(); @@ -108,7 +108,7 @@ uint32_t Fuse::getSerializedSize() const { return size; } -ReturnValue_t Fuse::deSerialize(const uint8_t** buffer, int32_t* size, +ReturnValue_t Fuse::deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { ReturnValue_t result = RETURN_FAILED; for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); diff --git a/power/Fuse.h b/power/Fuse.h index 6da24178..b3c9547a 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -49,11 +49,11 @@ public: uint8_t getFuseId() const; ReturnValue_t initialize(); DeviceList devices; - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; uint32_t getSerializedSize() const; - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, - bool bigEndian); + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, + bool bigEndian); void setAllMonitorsToUnchecked(); ReturnValue_t performOperation(uint8_t opCode); MessageQueueId_t getCommandQueue() const; diff --git a/power/PowerComponent.cpp b/power/PowerComponent.cpp index 6a87d88b..77e60d0e 100644 --- a/power/PowerComponent.cpp +++ b/power/PowerComponent.cpp @@ -17,8 +17,8 @@ PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min, f twoSwitches), min(min), max(max), moduleId(moduleId) { } -ReturnValue_t PowerComponent::serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { +ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result = SerializeAdapter::serialize(&min, buffer, size, max_size, bigEndian); if (result != HasReturnvaluesIF::RETURN_OK) { @@ -28,7 +28,7 @@ ReturnValue_t PowerComponent::serialize(uint8_t** buffer, uint32_t* size, bigEndian); } -uint32_t PowerComponent::getSerializedSize() const { +size_t PowerComponent::getSerializedSize() const { return sizeof(min) + sizeof(max); } @@ -56,8 +56,8 @@ float PowerComponent::getMax() { return max; } -ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, int32_t* size, -bool bigEndian) { +ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, ssize_t* size, + bool bigEndian) { ReturnValue_t result = SerializeAdapter::deSerialize(&min, buffer, size, bigEndian); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/power/PowerComponent.h b/power/PowerComponent.h index a82fe1d7..1410e69d 100644 --- a/power/PowerComponent.h +++ b/power/PowerComponent.h @@ -19,12 +19,12 @@ public: float getMin(); float getMax(); - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; - uint32_t getSerializedSize() const; + size_t getSerializedSize() const; - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian); ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, diff --git a/power/PowerSwitchIF.h b/power/PowerSwitchIF.h index 1c4c06f7..f25589c4 100644 --- a/power/PowerSwitchIF.h +++ b/power/PowerSwitchIF.h @@ -11,8 +11,13 @@ #include #include /** - * This interface defines a connection to a device that is capable of turning on and off - * switches of devices identified by a switch ID. + * + * @brief This interface defines a connection to a device that is capable of turning on and off + * switches of devices identified by a switch ID. + * @details The virtual functions of this interface do not allow to make any assignments + * because they can be called asynchronosuly (const ending). + * + * @ingroup interfaces */ class PowerSwitchIF : public HasReturnvaluesIF { public: diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index d21861c0..120d8b8c 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -24,6 +24,7 @@ enum { MEMORY_HELPER, //MH SERIALIZE_IF, //SE FIXED_MAP, //FM + FIXED_MULTIMAP, //FMM HAS_HEALTH_IF, //HHI FIFO_CLASS, //FF MESSAGE_PROXY, //MQP @@ -59,6 +60,7 @@ enum { SGP4PROPAGATOR_CLASS, //SGP4 53 MUTEX_IF, //MUX 54 MESSAGE_QUEUE_IF,//MQI 55 + SEMAPHORE_IF, //SPH 56 FW_CLASS_ID_COUNT //is actually count + 1 ! }; diff --git a/returnvalues/HasReturnvaluesIF.h b/returnvalues/HasReturnvaluesIF.h index 5adbca3f..d84fc757 100644 --- a/returnvalues/HasReturnvaluesIF.h +++ b/returnvalues/HasReturnvaluesIF.h @@ -1,27 +1,21 @@ #ifndef HASRETURNVALUESIF_H_ #define HASRETURNVALUESIF_H_ -#include #include #include +#include #define MAKE_RETURN_CODE( number ) ((INTERFACE_ID << 8) + (number)) typedef uint16_t ReturnValue_t; - - - - class HasReturnvaluesIF { public: static const ReturnValue_t RETURN_OK = 0; - static const ReturnValue_t RETURN_FAILED = 1; + static const ReturnValue_t RETURN_FAILED = 0xFFFF; virtual ~HasReturnvaluesIF() { } }; - - #endif /* HASRETURNVALUESIF_H_ */ diff --git a/rmap/RMAP.cpp b/rmap/RMAP.cpp index 4c95f6c9..927fe746 100644 --- a/rmap/RMAP.cpp +++ b/rmap/RMAP.cpp @@ -12,8 +12,8 @@ RMAP::RMAP(){ } -ReturnValue_t RMAP::sendWriteCommand(RMAPCookie *cookie, uint8_t* buffer, - uint32_t length) { +ReturnValue_t RMAP::sendWriteCommand(RMAPCookie *cookie, const uint8_t* buffer, + size_t length) { uint8_t instruction; if ((buffer == NULL) && (length != 0)) { @@ -61,7 +61,7 @@ ReturnValue_t RMAP::sendReadCommand(RMAPCookie *cookie, uint32_t expLength) { } ReturnValue_t RMAP::getReadReply(RMAPCookie *cookie, uint8_t **buffer, - uint32_t *size) { + size_t *size) { if (cookie->getChannel() == NULL) { return COMMAND_NO_CHANNEL; } diff --git a/rmap/RMAP.h b/rmap/RMAP.h index 195574f8..91aa123e 100644 --- a/rmap/RMAP.h +++ b/rmap/RMAP.h @@ -153,8 +153,8 @@ public: * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write command * - return codes of RMAPChannelIF::sendCommand() */ - static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, uint8_t* buffer, - uint32_t length); + static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t* buffer, + size_t length); /** * get the reply to a write command @@ -204,7 +204,7 @@ public: * - return codes of RMAPChannelIF::getReply() */ static ReturnValue_t getReadReply(RMAPCookie *cookie, uint8_t **buffer, - uint32_t *size); + size_t *size); /** * @see sendReadCommand() diff --git a/rmap/RMAPChannelIF.h b/rmap/RMAPChannelIF.h index 6549c8ef..34623bb3 100644 --- a/rmap/RMAPChannelIF.h +++ b/rmap/RMAPChannelIF.h @@ -3,6 +3,7 @@ #include #include +#include class RMAPChannelIF { public: @@ -73,7 +74,7 @@ public: * - @c NOT_SUPPORTED if you dont feel like implementing something... */ virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, - uint8_t *data, uint32_t datalen)=0; + const uint8_t *data, size_t datalen)=0; /** * get the reply to an rmap command @@ -92,7 +93,7 @@ public: * - all RMAP standard replies */ virtual ReturnValue_t getReply(RMAPCookie *cookie, uint8_t **databuffer, - uint32_t *len)=0; + size_t *len)=0; /** * diff --git a/rmap/RMAPCookie.cpp b/rmap/RMAPCookie.cpp index 5bf2ba9f..223b5165 100644 --- a/rmap/RMAPCookie.cpp +++ b/rmap/RMAPCookie.cpp @@ -93,11 +93,11 @@ RMAPCookie::~RMAPCookie() { } -uint32_t RMAPCookie::getMaxReplyLen() const { +size_t RMAPCookie::getMaxReplyLen() const { return maxReplyLen; } -void RMAPCookie::setMaxReplyLen(uint32_t maxReplyLen) { +void RMAPCookie::setMaxReplyLen(size_t maxReplyLen) { this->maxReplyLen = maxReplyLen; } diff --git a/rmap/RMAPCookie.h b/rmap/RMAPCookie.h index c091ba18..99ebd6a2 100644 --- a/rmap/RMAPCookie.h +++ b/rmap/RMAPCookie.h @@ -1,12 +1,13 @@ #ifndef RMAPCOOKIE_H_ #define RMAPCOOKIE_H_ -#include +#include #include +#include class RMAPChannelIF; -class RMAPCookie : public Cookie{ +class RMAPCookie : public CookieIF { public: //To Uli: Sorry, I need an empty ctor to initialize an array of cookies. RMAPCookie(); @@ -28,8 +29,8 @@ public: void setCommandMask(uint8_t commandMask); uint8_t getCommandMask(); - uint32_t getMaxReplyLen() const; - void setMaxReplyLen(uint32_t maxReplyLen); + size_t getMaxReplyLen() const; + void setMaxReplyLen(size_t maxReplyLen); uint16_t getTransactionIdentifier() const; void setTransactionIdentifier(uint16_t id_); diff --git a/rmap/RmapDeviceCommunicationIF.cpp b/rmap/RmapDeviceCommunicationIF.cpp index 4958b3ed..6dc91339 100644 --- a/rmap/RmapDeviceCommunicationIF.cpp +++ b/rmap/RmapDeviceCommunicationIF.cpp @@ -5,43 +5,43 @@ RmapDeviceCommunicationIF::~RmapDeviceCommunicationIF() { } -ReturnValue_t RmapDeviceCommunicationIF::sendMessage(Cookie* cookie, - uint8_t* data, uint32_t len) { - return RMAP::sendWriteCommand((RMAPCookie *) cookie, data, len); +ReturnValue_t RmapDeviceCommunicationIF::sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) { + return RMAP::sendWriteCommand((RMAPCookie *) cookie, sendData, sendLen); } -ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(Cookie* cookie) { +ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(CookieIF* cookie) { return RMAP::getWriteReply((RMAPCookie *) cookie); } ReturnValue_t RmapDeviceCommunicationIF::requestReceiveMessage( - Cookie* cookie) { + CookieIF *cookie, size_t requestLen) { return RMAP::sendReadCommand((RMAPCookie *) cookie, ((RMAPCookie *) cookie)->getMaxReplyLen()); } -ReturnValue_t RmapDeviceCommunicationIF::readReceivedMessage(Cookie* cookie, - uint8_t** buffer, uint32_t* size) { +ReturnValue_t RmapDeviceCommunicationIF::readReceivedMessage(CookieIF* cookie, + uint8_t** buffer, size_t * size) { return RMAP::getReadReply((RMAPCookie *) cookie, buffer, size); } -ReturnValue_t RmapDeviceCommunicationIF::setAddress(Cookie* cookie, +ReturnValue_t RmapDeviceCommunicationIF::setAddress(CookieIF* cookie, uint32_t address) { ((RMAPCookie *) cookie)->setAddress(address); return HasReturnvaluesIF::RETURN_OK; } -uint32_t RmapDeviceCommunicationIF::getAddress(Cookie* cookie) { +uint32_t RmapDeviceCommunicationIF::getAddress(CookieIF* cookie) { return ((RMAPCookie *) cookie)->getAddress(); } -ReturnValue_t RmapDeviceCommunicationIF::setParameter(Cookie* cookie, +ReturnValue_t RmapDeviceCommunicationIF::setParameter(CookieIF* cookie, uint32_t parameter) { //TODO Empty? return HasReturnvaluesIF::RETURN_FAILED; } -uint32_t RmapDeviceCommunicationIF::getParameter(Cookie* cookie) { +uint32_t RmapDeviceCommunicationIF::getParameter(CookieIF* cookie) { return 0; } diff --git a/rmap/RmapDeviceCommunicationIF.h b/rmap/RmapDeviceCommunicationIF.h index 12ae67e4..12bac57a 100644 --- a/rmap/RmapDeviceCommunicationIF.h +++ b/rmap/RmapDeviceCommunicationIF.h @@ -4,7 +4,8 @@ #include /** - * @brief This class is a implementation of a DeviceCommunicationIF for RMAP calls. It expects RMAPCookies or a derived class of RMAPCookies + * @brief This class is a implementation of a DeviceCommunicationIF for RMAP calls. + * It expects RMAPCookies or a derived class of RMAPCookies * * @details The open, close and reOpen calls are mission specific * The open call might return any child of RMAPCookies @@ -16,65 +17,73 @@ class RmapDeviceCommunicationIF: public DeviceCommunicationIF { public: virtual ~RmapDeviceCommunicationIF(); - /** - * This method is mission specific as the open call will return a mission specific cookie - * - * @param cookie A cookie, can be mission specific subclass of RMAP Cookie - * @param address The address of the RMAP Cookie - * @param maxReplyLen Maximum length of expected reply - * @return + * @brief Device specific initialization, using the cookie. + * @details + * The cookie is already prepared in the factory. If the communication + * interface needs to be set up in some way and requires cookie information, + * this can be performed in this function, which is called on device handler + * initialization. + * @param cookie + * @return -@c RETURN_OK if initialization was successfull + * - Everything else triggers failure event with returnvalue as parameter 1 */ - virtual ReturnValue_t open(Cookie **cookie, uint32_t address, - uint32_t maxReplyLen) = 0; + virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; /** - * Use an existing cookie to open a connection to a new DeviceCommunication. - * The previous connection must not be closed. - * If the returnvalue is not RETURN_OK, the cookie is unchanged and - * can be used with the previous connection. + * Called by DHB in the SEND_WRITE doSendWrite(). + * This function is used to send data to the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param data + * @param len + * @return -@c RETURN_OK for successfull send + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen); + + /** + * Called by DHB in the GET_WRITE doGetWrite(). + * Get send confirmation that the data in sendMessage() was sent successfully. + * @param cookie + * @return -@c RETURN_OK if data was sent successfull + * - Everything else triggers falure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t getSendSuccess(CookieIF *cookie); + + /** + * Called by DHB in the SEND_WRITE doSendRead(). + * It is assumed that it is always possible to request a reply + * from a device. * * @param cookie - * @param address - * @param maxReplyLen - * @return + * @return -@c RETURN_OK to confirm the request for data has been sent. + * -@c NO_READ_REQUEST if no request shall be made. readReceivedMessage() + * will not be called in the respective communication cycle. + * - Everything else triggers failure event with returnvalue as parameter 1 */ - virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, - uint32_t maxReplyLen) = 0; - + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen); /** - * Closing call of connection and memory free of cookie. Mission dependent call + * Called by DHB in the GET_WRITE doGetRead(). + * This function is used to receive data from the physical device + * by implementing and calling related drivers or wrapper functions. * @param cookie + * @param data + * @param len + * @return @c RETURN_OK for successfull receive + * - Everything else triggers failure event with returnvalue as parameter 1 */ - virtual void close(Cookie *cookie) = 0; + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size); - //SHOULDDO can data be const? - /** - * - * - * @param cookie Expects an RMAPCookie or derived from RMAPCookie Class - * @param data Data to be send - * @param len Length of the data to be send - * @return - Return codes of RMAP::sendWriteCommand() - */ - virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, - uint32_t len); - - virtual ReturnValue_t getSendSuccess(Cookie *cookie); - - virtual ReturnValue_t requestReceiveMessage(Cookie *cookie); - - virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, - uint32_t *size); - - virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address); - - virtual uint32_t getAddress(Cookie *cookie); - - virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter); - - virtual uint32_t getParameter(Cookie *cookie); + ReturnValue_t setAddress(CookieIF* cookie, + uint32_t address); + uint32_t getAddress(CookieIF* cookie); + ReturnValue_t setParameter(CookieIF* cookie, + uint32_t parameter); + uint32_t getParameter(CookieIF* cookie); }; #endif /* MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ */ diff --git a/serialize/EndianSwapper.h b/serialize/EndianSwapper.h index 6ff54444..25fb681e 100644 --- a/serialize/EndianSwapper.h +++ b/serialize/EndianSwapper.h @@ -5,6 +5,10 @@ #include #include +/** + * @brief Can be used to swap endianness of data + * into big endian + */ class EndianSwapper { private: EndianSwapper() { @@ -40,6 +44,32 @@ public: #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(out, in, size); return; +#endif + } + + /** + * Swap endianness of buffer entries + * Template argument specifies buffer type + * @param out + * @param in + * @param size + */ + template + static void swap(T * out, const T * in, uint32_t size) { +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + const uint8_t * in_buffer = reinterpret_cast(in); + uint8_t * out_buffer = reinterpret_cast(out); + for (uint8_t count = 0; count < size; count++) { + for(uint8_t i = 0; i < sizeof(T);i++) { + out_buffer[sizeof(T)* (count + 1) - i - 1] = in_buffer[count * sizeof(T) + i]; + } + } + return; +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN + memcpy(out, in, size*sizeof(T)); + return; #endif } }; diff --git a/serialize/SerialArrayListAdapter.h b/serialize/SerialArrayListAdapter.h index 5ffbc375..21a669c2 100644 --- a/serialize/SerialArrayListAdapter.h +++ b/serialize/SerialArrayListAdapter.h @@ -12,6 +12,7 @@ #include /** + * Also serializes length field ! * \ingroup serialize */ template @@ -20,13 +21,15 @@ public: SerialArrayListAdapter(ArrayList *adaptee) : adaptee(adaptee) { } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { return serialize(adaptee, buffer, size, max_size, bigEndian); } - static ReturnValue_t serialize(const ArrayList* list, uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) { + static ReturnValue_t serialize(const ArrayList* list, + uint8_t** buffer, size_t* size, const size_t max_size, + bool bigEndian) { + // Serialize length field first ReturnValue_t result = SerializeAdapter::serialize(&list->size, buffer, size, max_size, bigEndian); count_t i = 0; @@ -38,7 +41,7 @@ public: return result; } - virtual uint32_t getSerializedSize() const { + virtual size_t getSerializedSize() const { return getSerializedSize(adaptee); } @@ -53,13 +56,13 @@ public: return printSize; } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return deSerialize(adaptee, buffer, size, bigEndian); } - static ReturnValue_t deSerialize(ArrayList* list, const uint8_t** buffer, int32_t* size, - bool bigEndian) { + static ReturnValue_t deSerialize(ArrayList* list, + const uint8_t** buffer, ssize_t* size, bool bigEndian) { count_t tempSize = 0; ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize, buffer, size, bigEndian); @@ -76,6 +79,11 @@ public: } return result; } + + + static void swapArrayListEndianness(ArrayList* list) { + list->swapArrayListEndianness(); + } private: ArrayList *adaptee; }; diff --git a/serialize/SerialBufferAdapter.cpp b/serialize/SerialBufferAdapter.cpp index 3ed083bf..618e8a15 100644 --- a/serialize/SerialBufferAdapter.cpp +++ b/serialize/SerialBufferAdapter.cpp @@ -1,71 +1,80 @@ #include +#include #include +template +SerialBufferAdapter::SerialBufferAdapter(const void* buffer, + count_t bufferLength, bool serializeLength) : + m_serialize_length(serializeLength), + m_const_buffer(static_cast(buffer)), m_buffer(nullptr), + m_buffer_length(bufferLength) { - -template -SerialBufferAdapter::SerialBufferAdapter(const uint8_t* buffer, - T bufferLength, bool serializeLenght) : - serializeLength(serializeLenght), constBuffer(buffer), buffer(NULL), bufferLength( - bufferLength) { } -template -SerialBufferAdapter::SerialBufferAdapter(uint8_t* buffer, T bufferLength, - bool serializeLenght) : - serializeLength(serializeLenght), constBuffer(NULL), buffer(buffer), bufferLength( - bufferLength) { +template +SerialBufferAdapter::SerialBufferAdapter(void* buffer, count_t bufferLength, + bool serializeLength) : + m_serialize_length(serializeLength), m_buffer_length(bufferLength) { + uint8_t * member_buffer = static_cast(buffer); + m_buffer = member_buffer; + m_const_buffer = member_buffer; } -template -SerialBufferAdapter::~SerialBufferAdapter() { + +template +SerialBufferAdapter::~SerialBufferAdapter() { } -template -ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - uint32_t serializedLength = bufferLength; - if (serializeLength) { +template +ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + uint32_t serializedLength = m_buffer_length; + if (m_serialize_length) { serializedLength += AutoSerializeAdapter::getSerializedSize( - &bufferLength); + &m_buffer_length); } if (*size + serializedLength > max_size) { return BUFFER_TOO_SHORT; } else { - if (serializeLength) { - AutoSerializeAdapter::serialize(&bufferLength, buffer, size, + if (m_serialize_length) { + AutoSerializeAdapter::serialize(&m_buffer_length, buffer, size, max_size, bigEndian); } - if (this->constBuffer != NULL) { - memcpy(*buffer, this->constBuffer, bufferLength); - } else if (this->buffer != NULL) { - memcpy(*buffer, this->buffer, bufferLength); + if (m_const_buffer != nullptr) { + memcpy(*buffer, m_const_buffer, m_buffer_length); + } else if (m_buffer != nullptr) { + memcpy(*buffer, m_buffer, m_buffer_length); } else { return HasReturnvaluesIF::RETURN_FAILED; } - *size += bufferLength; - (*buffer) += bufferLength; + *size += m_buffer_length; + (*buffer) += m_buffer_length; return HasReturnvaluesIF::RETURN_OK; } } -template -uint32_t SerialBufferAdapter::getSerializedSize() const { - if (serializeLength) { - return bufferLength + AutoSerializeAdapter::getSerializedSize(&bufferLength); +template +size_t SerialBufferAdapter::getSerializedSize() const { + if (m_serialize_length) { + return m_buffer_length + AutoSerializeAdapter::getSerializedSize(&m_buffer_length); } else { - return bufferLength; + return m_buffer_length; } } -template -ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, - int32_t* size, bool bigEndian) { +template +ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, + ssize_t* size, bool bigEndian) { //TODO Ignores Endian flag! if (buffer != NULL) { - if(serializeLength){ - T serializedSize = AutoSerializeAdapter::getSerializedSize( - &bufferLength); - if((*size - bufferLength - serializedSize) >= 0){ + if(m_serialize_length){ + // Suggestion (would require removing rest of the block inside this if clause !): + //ReturnValue_t result = AutoSerializeAdapter::deSerialize(&bufferLength,buffer,size,bigEndian); + //if (result != HasReturnvaluesIF::RETURN_OK) { + // return result; + //} + count_t serializedSize = AutoSerializeAdapter::getSerializedSize( + &m_buffer_length); + if((*size - m_buffer_length - serializedSize) >= 0){ *buffer += serializedSize; *size -= serializedSize; }else{ @@ -73,10 +82,10 @@ ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, } } //No Else If, go on with buffer - if (*size - bufferLength >= 0) { - *size -= bufferLength; - memcpy(this->buffer, *buffer, bufferLength); - (*buffer) += bufferLength; + if (*size - m_buffer_length >= 0) { + *size -= m_buffer_length; + memcpy(m_buffer, *buffer, m_buffer_length); + (*buffer) += m_buffer_length; return HasReturnvaluesIF::RETURN_OK; } else { return STREAM_TOO_SHORT; @@ -86,6 +95,30 @@ ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, } } +template +uint8_t * SerialBufferAdapter::getBuffer() { + if(m_buffer == nullptr) { + error << "Wrong access function for stored type ! Use getConstBuffer()" << std::endl; + return nullptr; + } + return m_buffer; +} + +template +const uint8_t * SerialBufferAdapter::getConstBuffer() { + if(m_const_buffer == nullptr) { + error << "Wrong access function for stored type ! Use getBuffer()" << std::endl; + return nullptr; + } + return m_const_buffer; +} + +template +void SerialBufferAdapter::setBuffer(void * buffer, count_t buffer_length) { + m_buffer = static_cast(buffer); + m_buffer_length = buffer_length; +} + //forward Template declaration for linker template class SerialBufferAdapter; diff --git a/serialize/SerialBufferAdapter.h b/serialize/SerialBufferAdapter.h index 7cd75d55..ff2083de 100644 --- a/serialize/SerialBufferAdapter.h +++ b/serialize/SerialBufferAdapter.h @@ -5,29 +5,57 @@ #include /** + * This adapter provides an interface for SerializeIF to serialize or deserialize + * buffers with no length header but a known size. + * + * Additionally, the buffer length can be serialized too and will be put in front of the serialized buffer. + * + * Can be used with SerialLinkedListAdapter by declaring a SerializeElement with + * SerialElement> serialBufferElement. + * Right now, the SerialBufferAdapter must always be initialized with the buffer and size ! + * * \ingroup serialize */ -template +template class SerialBufferAdapter: public SerializeIF { public: - SerialBufferAdapter(const uint8_t * buffer, T bufferLength, bool serializeLenght = false); - SerialBufferAdapter(uint8_t* buffer, T bufferLength, - bool serializeLenght = false); + + /** + * Constructor for constant uint8_t buffer. Length field can be serialized optionally. + * Type of length can be supplied as template type. + * @param buffer + * @param bufferLength + * @param serializeLength + */ + SerialBufferAdapter(const void* buffer, count_t bufferLength, bool serializeLength = false); + + /** + * Constructor for non-constant uint8_t buffer. Length field can be serialized optionally. + * Type of length can be supplied as template type. + * @param buffer + * @param bufferLength + * @param serializeLength + */ + SerialBufferAdapter(void* buffer, count_t bufferLength, bool serializeLength = false); virtual ~SerialBufferAdapter(); - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const; - virtual uint32_t getSerializedSize() const; + virtual size_t getSerializedSize() const; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian); + + uint8_t * getBuffer(); + const uint8_t * getConstBuffer(); + void setBuffer(void* buffer_, count_t bufferLength_); private: - bool serializeLength; - const uint8_t *constBuffer; - uint8_t *buffer; - T bufferLength; + bool m_serialize_length = false; + const uint8_t *m_const_buffer = nullptr; + uint8_t *m_buffer = nullptr; + count_t m_buffer_length = 0; }; diff --git a/serialize/SerialFixedArrayListAdapter.h b/serialize/SerialFixedArrayListAdapter.h index 16919b62..8bcbf09e 100644 --- a/serialize/SerialFixedArrayListAdapter.h +++ b/serialize/SerialFixedArrayListAdapter.h @@ -5,24 +5,49 @@ #include /** - * \ingroup serialize + * @brief This adapter provides an interface for SerializeIF to serialize and deserialize + * buffers with a header containing the buffer length. + * @details + * + * Can be used by SerialLinkedListAdapter by declaring + * as a linked element with SerializeElement>. + * The sequence of objects is defined in the constructor by using the setStart and setNext functions. + * + * 1. Buffers with a size header inside that class can be declared with + * SerialFixedArrayListAdapter. + * 2. MAX_BUFFER_LENGTH specifies the maximum allowed number of elements in FixedArrayList + * 3. LENGTH_FIELD_TYPE specifies the data type of the buffer header containing the buffer size + * (defaults to 1 byte length field) that follows + * + * @ingroup serialize */ -template -class SerialFixedArrayListAdapter : public FixedArrayList, public SerializeIF { +template +class SerialFixedArrayListAdapter : public FixedArrayList, public SerializeIF { public: + /** + * Constructor Arguments are forwarded to FixedArrayList constructor + * @param args + */ template - SerialFixedArrayListAdapter(Args... args) : FixedArrayList(std::forward(args)...) { + SerialFixedArrayListAdapter(Args... args) : FixedArrayList(std::forward(args)...) { } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - return SerialArrayListAdapter::serialize(this, buffer, size, max_size, bigEndian); + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + return SerialArrayListAdapter::serialize(this, buffer, size, max_size, bigEndian); } - uint32_t getSerializedSize() const { - return SerialArrayListAdapter::getSerializedSize(this); + + size_t getSerializedSize() const { + return SerialArrayListAdapter::getSerializedSize(this); } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { - return SerialArrayListAdapter::deSerialize(this, buffer, size, bigEndian); + return SerialArrayListAdapter::deSerialize(this, + buffer, size, bigEndian); + } + + void swapArrayListEndianness() { + SerialArrayListAdapter::swapArrayListEndianness(this); } }; diff --git a/serialize/SerialLinkedListAdapter.h b/serialize/SerialLinkedListAdapter.h index 29952c4a..b5c06a16 100644 --- a/serialize/SerialLinkedListAdapter.h +++ b/serialize/SerialLinkedListAdapter.h @@ -13,12 +13,44 @@ #include //This is where we need the SerializeAdapter! -/** - * \ingroup serialize + /** + * @brief Implement the conversion of object data to data streams + * or vice-versa, using linked lists. + * @details + * An alternative to the AutoSerializeAdapter functions + * - All object members with a datatype are declared as SerializeElement + * members inside the class implementing this adapter. + * - The element type can also be a SerialBufferAdapter to de-/serialize buffers, + * with a known size, where the size can also be serialized + * - The element type can also be a SerialFixedArrayListAdapter to de-/serialize buffers + * with a size header, which is scanned automatically + * + * The sequence of objects is defined in the constructor by using + * the setStart and setNext functions. + * + * - The serialization process is done by instantiating the class and + * calling serializ after all SerializeElement entries have been set by + * using the constructor or setter functions. An additional size variable can be supplied + * which is calculated/incremented automatically + * - The deserialization process is done by instantiating the class and supplying + * a buffer with the data which is converted into an object. The size of + * data to serialize can be supplied and is decremented in the function + * + * @ingroup serialize */ template class SerialLinkedListAdapter: public SinglyLinkedList, public SerializeIF { public: + /** + * Copying is forbidden by deleting the copy constructor and the copy + * assignment operator because of the pointers to the linked list members. + * Unless the child class implements an own copy constructor or + * copy assignment operator, these operation will throw a compiler error. + * @param + */ + SerialLinkedListAdapter(const SerialLinkedListAdapter &) = delete; + SerialLinkedListAdapter& operator=(const SerialLinkedListAdapter&) = delete; + SerialLinkedListAdapter(typename LinkedElement::Iterator start, bool printCount = false) : SinglyLinkedList(start), printCount(printCount) { @@ -31,8 +63,18 @@ public: SinglyLinkedList(), printCount(printCount) { } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + /** + * Serialize object implementing this adapter into the supplied buffer + * and calculate the serialized size + * @param buffer [out] Object is serialized into this buffer. Note that the buffer pointer + * *buffer is incremented automatically inside the respective serialize functions + * @param size [out] Calculated serialized size. Don't forget to set to 0. + * @param max_size + * @param bigEndian Specify endianness + * @return + */ + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { if (printCount) { count_t mySize = SinglyLinkedList::getSize(); ReturnValue_t result = SerializeAdapter::serialize(&mySize, @@ -46,7 +88,7 @@ public: } static ReturnValue_t serialize(const LinkedElement* element, - uint8_t** buffer, uint32_t* size, const uint32_t max_size, + uint8_t** buffer, size_t* size, const size_t max_size, bool bigEndian) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { @@ -56,7 +98,7 @@ public: } return result; } - virtual uint32_t getSerializedSize() const { + virtual size_t getSerializedSize() const { if (printCount) { return SerialLinkedListAdapter::getSerializedSize() + sizeof(count_t); @@ -73,13 +115,20 @@ public: return size; } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + /** + * Deserialize supplied buffer with supplied size into object implementing this adapter + * @param buffer + * @param size Decremented in respective deSerialize functions automatically + * @param bigEndian Specify endianness + * @return + */ + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return deSerialize(SinglyLinkedList::start, buffer, size, bigEndian); } static ReturnValue_t deSerialize(LinkedElement* element, - const uint8_t** buffer, int32_t* size, bool bigEndian) { + const uint8_t** buffer, ssize_t* size, bool bigEndian) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { result = element->value->deSerialize(buffer, size, bigEndian); diff --git a/serialize/SerializeAdapter.h b/serialize/SerializeAdapter.h index fd9e1b6a..81a3730f 100644 --- a/serialize/SerializeAdapter.h +++ b/serialize/SerializeAdapter.h @@ -7,15 +7,60 @@ #include #include -/** - * \ingroup serialize + /** + * @brief This adapter provides an interface to use the SerializeIF functions + * with arbitrary template objects to facilitate and simplify the serialization of classes + * with different multiple different data types into buffers and vice-versa. + * @details + * Examples: + * A report class is converted into a TM buffer. The report class implements a serialize functions and calls + * the AutoSerializeAdapter::serialize function repeatedly on all object data fields. + * The getSerializedSize function is implemented by calling the + * AutoSerializeAdapter::getSerializedSize function repeatedly on all data fields. + * + * The AutoSerializeAdapter functions can also be used as an alternative to memcpy + * to retrieve data out of a buffer directly into a class variable with data type T while being able to specify endianness. + * The boolean bigEndian specifies whether an endian swap is performed on the data before + * serialization or deserialization. + * + * If the target architecture is little endian (ARM), any data types created might + * have the wrong endiness if they are to be used for the FSFW. + * There are three ways to retrieve data out of a buffer to be used in the FSFW + * to use regular aligned (big endian) data. + * This can also be applied to uint32_t and uint64_t: + * + * 1. Use the AutoSerializeAdapter::deSerialize function + * The pointer *buffer will be incremented automatically by the typeSize of the object, + * so this function can be called on &buffer repeatedly without adjusting pointer position. + * Set bigEndian parameter to true to perform endian swapping. + * + * uint16_t data; + * int32_t dataLen = sizeof(data); + * ReturnValue_t result = AutoSerializeAdapter::deSerialize(&data,&buffer,&dataLen,true); + * + * 2. Perform a bitshift operation. Perform endian swapping if necessary: + * + * uint16_t data; + * data = buffer[targetByte1] << 8 | buffer[targetByte2]; + * data = EndianSwapper::swap(data); + * + * 3. Memcpy can be used when data is little-endian. Perform endian-swapping if necessary. + * + * uint16_t data; + * memcpy(&data,buffer + positionOfTargetByte1,sizeof(data)); + * data = EndianSwapper::swap(data); + * + * When serializing for downlink, the packets are generally serialized assuming big endian data format + * like seen in TmPacketStored.cpp for example. + * + * @ingroup serialize */ template class SerializeAdapter_ { public: static ReturnValue_t serialize(const T* object, uint8_t** buffer, - uint32_t* size, const uint32_t max_size, bool bigEndian) { - uint32_t ignoredSize = 0; + size_t* size, const size_t max_size, bool bigEndian) { + size_t ignoredSize = 0; if (size == NULL) { size = &ignoredSize; } @@ -35,7 +80,15 @@ public: } } - ReturnValue_t deSerialize(T* object, const uint8_t** buffer, int32_t* size, + /** + * Deserialize buffer into object + * @param object [out] Object to be deserialized with buffer data + * @param buffer buffer containing the data. Non-Const pointer to non-const pointer to const buffer. + * @param size int32_t type to allow value to be values smaller than 0, needed for range/size checking + * @param bigEndian Specify endianness + * @return + */ + ReturnValue_t deSerialize(T* object, const uint8_t** buffer, ssize_t* size, bool bigEndian) { T tmp; *size -= sizeof(T); @@ -62,9 +115,9 @@ public: template class SerializeAdapter_ { public: - ReturnValue_t serialize(const T* object, uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - uint32_t ignoredSize = 0; + ReturnValue_t serialize(const T* object, uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + size_t ignoredSize = 0; if (size == NULL) { size = &ignoredSize; } @@ -74,7 +127,7 @@ public: return object->getSerializedSize(); } - ReturnValue_t deSerialize(T* object, const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(T* object, const uint8_t** buffer, ssize_t* size, bool bigEndian) { return object->deSerialize(buffer, size, bigEndian); } @@ -84,7 +137,7 @@ template class SerializeAdapter { public: static ReturnValue_t serialize(const T* object, uint8_t** buffer, - uint32_t* size, const uint32_t max_size, bool bigEndian) { + size_t* size, const size_t max_size, bool bigEndian) { SerializeAdapter_::Is> adapter; return adapter.serialize(object, buffer, size, max_size, bigEndian); } @@ -94,18 +147,18 @@ public: } static ReturnValue_t deSerialize(T* object, const uint8_t** buffer, - int32_t* size, bool bigEndian) { + ssize_t* size, bool bigEndian) { SerializeAdapter_::Is> adapter; return adapter.deSerialize(object, buffer, size, bigEndian); } }; - +// No type specification necessary here. class AutoSerializeAdapter { public: template static ReturnValue_t serialize(const T* object, uint8_t** buffer, - uint32_t* size, const uint32_t max_size, bool bigEndian) { + size_t* size, const size_t max_size, bool bigEndian) { SerializeAdapter_::Is> adapter; return adapter.serialize(object, buffer, size, max_size, bigEndian); } @@ -116,7 +169,7 @@ public: } template static ReturnValue_t deSerialize(T* object, const uint8_t** buffer, - int32_t* size, bool bigEndian) { + ssize_t* size, bool bigEndian) { SerializeAdapter_::Is> adapter; return adapter.deSerialize(object, buffer, size, bigEndian); } diff --git a/serialize/SerializeElement.h b/serialize/SerializeElement.h index db7db20a..e2da5c14 100644 --- a/serialize/SerializeElement.h +++ b/serialize/SerializeElement.h @@ -6,31 +6,46 @@ #include /** - * \ingroup serialize + * @brief This class is used to mark datatypes for serialization with the + * SerialLinkedListAdapter + * @details + * Used by declaring any arbitrary datatype with SerializeElement myVariable, + * inside a SerialLinkedListAdapter implementation and setting the sequence + * of objects with setNext() and setStart(). + * Serilization and Deserialization is then performed automatically in + * specified sequence order. + * @ingroup serialize */ template class SerializeElement : public SerializeIF, public LinkedElement { public: + /** + * Arguments are forwarded to the element datatype constructor + * @param args + */ template SerializeElement(Args... args) : LinkedElement(this), entry(std::forward(args)...) { } SerializeElement() : LinkedElement(this) { } + T entry; - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { return SerializeAdapter::serialize(&entry, buffer, size, max_size, bigEndian); } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { return SerializeAdapter::getSerializedSize(&entry); } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return SerializeAdapter::deSerialize(&entry, buffer, size, bigEndian); } + operator T() { return entry; } diff --git a/serialize/SerializeIF.h b/serialize/SerializeIF.h index 701fbf56..da401b2f 100644 --- a/serialize/SerializeIF.h +++ b/serialize/SerializeIF.h @@ -2,15 +2,35 @@ #define SERIALIZEIF_H_ #include +#include +#include + +#ifndef ssize_t +typedef std::make_signed::type ssize_t; +#endif /** - * \defgroup serialize Serialization + * @defgroup serialize Serialization * Contains serialisation services. */ /** - * Translation of objects into data streams. - * \ingroup serialize + * @brief An interface for alle classes which require + * translation of objects data into data streams and vice-versa. + * @details + * If the target architecture is little endian (e.g. ARM), any data types created might + * have the wrong endiness if they are to be used for the FSFW. + * There are three ways to retrieve data out of a buffer to be used in the FSFW to use + * regular aligned (big endian) data. This can also be applied to uint32_t and uint64_t: + * + * 1. Use the @c AutoSerializeAdapter::deSerialize function with @c bigEndian = true + * 2. Perform a bitshift operation + * 3. @c memcpy can be used when data is in little-endian format. Otherwise, @c EndianSwapper has to be used in conjuction. + * + * When serializing for downlink, the packets are generally serialized assuming big endian data format + * like seen in TmPacketStored.cpp for example. + * + * @ingroup serialize */ class SerializeIF { public: @@ -22,12 +42,12 @@ public: virtual ~SerializeIF() { } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const = 0; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const = 0; - virtual uint32_t getSerializedSize() const = 0; + virtual size_t getSerializedSize() const = 0; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) = 0; }; diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index 58065994..6798b776 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -1,10 +1,13 @@ #include #include #include +#include // to be implemented by bsp extern "C" void printChar(const char*); + + int ServiceInterfaceBuffer::overflow(int c) { // Handle output putChars(pbase(), pptr()); @@ -24,11 +27,12 @@ int ServiceInterfaceBuffer::sync(void) { Clock::TimeOfDay_t loggerTime; Clock::getDateAndTime(&loggerTime); char preamble[96] = { 0 }; - sprintf(preamble, "%s: | %lu:%02lu:%02lu.%03lu | ", - this->log_message.c_str(), (unsigned long) loggerTime.hour, - (unsigned long) loggerTime.minute, - (unsigned long) loggerTime.second, - (unsigned long) loggerTime.usecond /1000); + sprintf(preamble, "%s: | %" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ".%03" PRIu32 " | ", + this->log_message.c_str(), + loggerTime.hour, + loggerTime.minute, + loggerTime.second, + loggerTime.usecond /1000); // Write log_message and time this->putChars(preamble, preamble + sizeof(preamble)); // Handle output diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index 08cb017f..c2fab82b 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -39,7 +39,95 @@ public: * @brief This definition generally sets the number of different sized pools. * @details This must be less than the maximum number of pools (currently 0xff). */ -// static const uint32_t NUMBER_OF_POOLS; + // static const uint32_t NUMBER_OF_POOLS; + /** + * @brief This is the default constructor for a pool manager instance. + * @details By passing two arrays of size NUMBER_OF_POOLS, the constructor + * allocates memory (with \c new) for store and size_list. These + * regions are all set to zero on start up. + * @param setObjectId The object identifier to be set. This allows for + * multiple instances of LocalPool in the system. + * @param element_sizes An array of size NUMBER_OF_POOLS in which the size + * of a single element in each pool is determined. + * The sizes must be provided in ascending order. + * + * @param n_elements An array of size NUMBER_OF_POOLS in which the + * number of elements for each pool is determined. + * The position of these values correspond to those in + * element_sizes. + * @param registered Register the pool in object manager or not. Default is false (local pool). + * @param spillsToHigherPools + * A variable to determine whether higher n pools are used if the store is full. + */ + LocalPool(object_id_t setObjectId, + const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS], + bool registered = false, + bool spillsToHigherPools = false); + /** + * @brief In the LocalPool's destructor all allocated memory is freed. + */ + virtual ~LocalPool(void); + + /** + * Add data to local data pool, performs range check + * @param storageId [out] Store ID in which the data will be stored + * @param data + * @param size + * @param ignoreFault + * @return @c RETURN_OK if write was successful + */ + ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, + uint32_t size, bool ignoreFault = false); + + /** + * With this helper method, a free element of \c size is reserved. + * @param storageId [out] storeID of the free element + * @param size The minimum packet size that shall be reserved. + * @param p_data [out] pointer to the pointer of free element + * @param ignoreFault + * @return Returns the storage identifier within the storage or + * StorageManagerIF::INVALID_ADDRESS (in raw). + */ + ReturnValue_t getFreeElement(store_address_t* storageId, + const uint32_t size, uint8_t** p_data, bool ignoreFault = false); + + /** + * Retrieve data from local pool + * @param packet_id + * @param packet_ptr + * @param size [out] Size of retrieved data + * @return @c RETURN_OK if data retrieval was successfull + */ + ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, + size_t * size); + + /** + * Modify data by supplying a packet pointer and using that packet pointer + * to access and modify the pool entry (via *pointer call) + * @param packet_id Store ID of data to modify + * @param packet_ptr [out] pointer to the pool entry to modify + * @param size [out] size of pool entry + * @return + */ + ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, + size_t * size); + virtual ReturnValue_t deleteData(store_address_t); + virtual ReturnValue_t deleteData(uint8_t* ptr, uint32_t size, + store_address_t* storeId = NULL); + void clearStore(); + ReturnValue_t initialize(); +protected: + /** + * With this helper method, a free element of \c size is reserved. + * @param size The minimum packet size that shall be reserved. + * @param[out] address Storage ID of the reserved data. + * @return - #RETURN_OK on success, + * - the return codes of #getPoolIndex or #findEmpty otherwise. + */ + virtual ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault); + + InternalErrorReporterIF *internalErrorReporter; private: /** * Indicates that this element is free. @@ -121,65 +209,6 @@ private: * - #DATA_STORAGE_FULL if the store is full */ ReturnValue_t findEmpty(uint16_t pool_index, uint16_t* element); -protected: - /** - * With this helper method, a free element of \c size is reserved. - * @param size The minimum packet size that shall be reserved. - * @param[out] address Storage ID of the reserved data. - * @return - #RETURN_OK on success, - * - the return codes of #getPoolIndex or #findEmpty otherwise. - */ - virtual ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault); - - InternalErrorReporterIF *internalErrorReporter; -public: - /** - * @brief This is the default constructor for a pool manager instance. - * @details By passing two arrays of size NUMBER_OF_POOLS, the constructor - * allocates memory (with \c new) for store and size_list. These - * regions are all set to zero on start up. - * @param setObjectId The object identifier to be set. This allows for - * multiple instances of LocalPool in the system. - * @param element_sizes An array of size NUMBER_OF_POOLS in which the size - * of a single element in each pool is determined. - * The sizes must be provided in ascending order. - * - * @param n_elements An array of size NUMBER_OF_POOLS in which the - * number of elements for each pool is determined. - * The position of these values correspond to those in - * element_sizes. - * @param registered Register the pool in object manager or not. Default is false (local pool). - */ - LocalPool(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS], - bool registered = false, - bool spillsToHigherPools = false); - /** - * @brief In the LocalPool's destructor all allocated memory is freed. - */ - virtual ~LocalPool(void); - ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, - uint32_t size, bool ignoreFault = false); - - /** - * With this helper method, a free element of \c size is reserved. - * - * @param size The minimum packet size that shall be reserved. - * @return Returns the storage identifier within the storage or - * StorageManagerIF::INVALID_ADDRESS (in raw). - */ - ReturnValue_t getFreeElement(store_address_t* storageId, - const uint32_t size, uint8_t** p_data, bool ignoreFault = false); - ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, - uint32_t* size); - ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, - uint32_t* size); - virtual ReturnValue_t deleteData(store_address_t); - virtual ReturnValue_t deleteData(uint8_t* ptr, uint32_t size, - store_address_t* storeId = NULL); - void clearStore(); - ReturnValue_t initialize(); }; template @@ -266,8 +295,8 @@ inline ReturnValue_t LocalPool::reserveSpace( if (!ignoreFault) { internalErrorReporter->storeFull(); } -// error << "LocalPool( " << std::hex << getObjectId() << std::dec -// << " )::reserveSpace: Packet store is full." << std::endl; + error << "LocalPool( " << std::hex << getObjectId() << std::dec + << " )::reserveSpace: Packet store is full." << std::endl; } return status; } @@ -276,7 +305,7 @@ template inline LocalPool::LocalPool(object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], const uint16_t n_elements[NUMBER_OF_POOLS], bool registered, bool spillsToHigherPools) : - SystemObject(setObjectId, registered), spillsToHigherPools(spillsToHigherPools), internalErrorReporter(NULL) { + SystemObject(setObjectId, registered), internalErrorReporter(NULL), spillsToHigherPools(spillsToHigherPools){ for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { this->element_sizes[n] = element_sizes[n]; this->n_elements[n] = n_elements[n]; @@ -319,7 +348,7 @@ inline ReturnValue_t LocalPool::getFreeElement( template inline ReturnValue_t LocalPool::getData( - store_address_t packet_id, const uint8_t** packet_ptr, uint32_t* size) { + store_address_t packet_id, const uint8_t** packet_ptr, size_t * size) { uint8_t* tempData = NULL; ReturnValue_t status = modifyData(packet_id, &tempData, size); *packet_ptr = tempData; @@ -328,7 +357,7 @@ inline ReturnValue_t LocalPool::getData( template inline ReturnValue_t LocalPool::modifyData(store_address_t packet_id, - uint8_t** packet_ptr, uint32_t* size) { + uint8_t** packet_ptr, size_t * size) { ReturnValue_t status = RETURN_FAILED; if (packet_id.pool_index >= NUMBER_OF_POOLS) { return ILLEGAL_STORAGE_ID; diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 575e9caa..e8d8b413 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -125,12 +125,12 @@ public: * (e.g. an illegal packet_id was passed). */ virtual ReturnValue_t getData(store_address_t packet_id, - const uint8_t** packet_ptr, uint32_t* size) = 0; + const uint8_t** packet_ptr, size_t * size) = 0; /** * Same as above, but not const and therefore modifiable. */ virtual ReturnValue_t modifyData(store_address_t packet_id, - uint8_t** packet_ptr, uint32_t* size) = 0; + uint8_t** packet_ptr, size_t * size) = 0; /** * This method reserves an element of \c size. * diff --git a/subsystem/Subsystem.cpp b/subsystem/Subsystem.cpp index e1ec544b..e4a682ba 100644 --- a/subsystem/Subsystem.cpp +++ b/subsystem/Subsystem.cpp @@ -162,13 +162,13 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage* message) { case ModeSequenceMessage::ADD_SEQUENCE: { FixedArrayList sequence; const uint8_t *pointer; - uint32_t sizeRead; + size_t sizeRead; result = IPCStore->getData( ModeSequenceMessage::getStoreAddress(message), &pointer, &sizeRead); if (result == RETURN_OK) { Mode_t fallbackId; - int32_t size = sizeRead; + ssize_t size = sizeRead; result = SerializeAdapter::deSerialize(&fallbackId, &pointer, &size, true); if (result == RETURN_OK) { @@ -188,12 +188,12 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage* message) { case ModeSequenceMessage::ADD_TABLE: { FixedArrayList table; const uint8_t *pointer; - uint32_t sizeRead; + size_t sizeRead; result = IPCStore->getData( ModeSequenceMessage::getStoreAddress(message), &pointer, &sizeRead); if (result == RETURN_OK) { - int32_t size = sizeRead; + ssize_t size = sizeRead; result = SerialArrayListAdapter::deSerialize(&table, &pointer, &size, true); if (result == RETURN_OK) { @@ -601,13 +601,13 @@ void Subsystem::transitionFailed(ReturnValue_t failureCode, void Subsystem::sendSerializablesAsCommandMessage(Command_t command, SerializeIF** elements, uint8_t count) { ReturnValue_t result; - uint32_t maxSize = 0; + size_t maxSize = 0; for (uint8_t i = 0; i < count; i++) { maxSize += elements[i]->getSerializedSize(); } uint8_t *storeBuffer; store_address_t address; - uint32_t size = 0; + size_t size = 0; result = IPCStore->getFreeElement(&address, maxSize, &storeBuffer); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/subsystem/SubsystemBase.h b/subsystem/SubsystemBase.h index 3294c46d..1a050a9a 100644 --- a/subsystem/SubsystemBase.h +++ b/subsystem/SubsystemBase.h @@ -12,6 +12,10 @@ #include #include +/** + * @defgroup subsystems Subsystem Objects + * Contains all Subsystem and Assemblies + */ class SubsystemBase: public SystemObject, public HasModesIF, public HasHealthIF, diff --git a/subsystem/modes/ModeDefinitions.h b/subsystem/modes/ModeDefinitions.h index 8e7531f3..4c0c4a26 100644 --- a/subsystem/modes/ModeDefinitions.h +++ b/subsystem/modes/ModeDefinitions.h @@ -18,8 +18,8 @@ public: uint8_t value3; uint8_t value4; - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result; @@ -49,11 +49,11 @@ public: } - virtual uint32_t getSerializedSize() const { + virtual size_t getSerializedSize() const { return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4); } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { ReturnValue_t result; diff --git a/tasks/FixedTimeslotTaskIF.h b/tasks/FixedTimeslotTaskIF.h index 3a3582fb..7edd6751 100644 --- a/tasks/FixedTimeslotTaskIF.h +++ b/tasks/FixedTimeslotTaskIF.h @@ -5,12 +5,15 @@ #include /** - * Following the same principle as the base class IF. This is the interface for a Fixed timeslot task + * @brief Following the same principle as the base class IF. + * This is the interface for a Fixed timeslot task */ class FixedTimeslotTaskIF : public PeriodicTaskIF { public: virtual ~FixedTimeslotTaskIF() {} - virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) = 0; + + virtual ReturnValue_t addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) = 0; virtual ReturnValue_t checkSequence() const = 0; }; diff --git a/tcdistribution/CCSDSDistributor.cpp b/tcdistribution/CCSDSDistributor.cpp index ecd7702e..878b8f7d 100644 --- a/tcdistribution/CCSDSDistributor.cpp +++ b/tcdistribution/CCSDSDistributor.cpp @@ -13,7 +13,7 @@ CCSDSDistributor::~CCSDSDistributor() { iterator_t CCSDSDistributor::selectDestination() { // debug << "CCSDSDistributor::selectDestination received: " << this->currentMessage.getStorageId().pool_index << ", " << this->currentMessage.getStorageId().packet_index << std::endl; const uint8_t* p_packet = NULL; - uint32_t size = 0; + size_t size = 0; //TODO check returncode? this->tcStore->getData( this->currentMessage.getStorageId(), &p_packet, &size ); SpacePacketBase current_packet( p_packet ); diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index a209620f..7b413eab 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -31,7 +31,7 @@ iterator_t PUSDistributor::selectDestination() { } if (tcStatus != RETURN_OK) { - debug << "PUSDistributor::handlePacket: error with " << (int) tcStatus + debug << "PUSDistributor::handlePacket: error with 0x" << std::hex << (int) tcStatus << std::endl; return this->queueMap.end(); } else { @@ -48,6 +48,7 @@ ReturnValue_t PUSDistributor::registerService(AcceptsTelecommandsIF* service) { ReturnValue_t returnValue = RETURN_OK; bool errorCode = true; uint16_t serviceId = service->getIdentifier(); + //info << "Service ID: " << (int)serviceId << std::endl; MessageQueueId_t queue = service->getRequestQueue(); errorCode = this->queueMap.insert( std::pair(serviceId, queue)).second; diff --git a/thermal/AbstractTemperatureSensor.h b/thermal/AbstractTemperatureSensor.h index 75437dca..4b869365 100644 --- a/thermal/AbstractTemperatureSensor.h +++ b/thermal/AbstractTemperatureSensor.h @@ -10,6 +10,16 @@ #include "ThermalModuleIF.h" #include "tcsDefinitions.h" +/** + * @defgroup thermal Thermal Components + * @brief Contains all components related to thermal tasks (sensors, heaters) + */ + +/** + * @brief Base class for Temperature Sensor, implements all important interfaces. + * Please use the TemperatureSensor class to implement the actual sensors. + * @ingroup thermal + */ class AbstractTemperatureSensor: public HasHealthIF, public SystemObject, public ExecutableObjectIF, diff --git a/thermal/AcceptsThermalMessagesIF.h b/thermal/AcceptsThermalMessagesIF.h new file mode 100644 index 00000000..28c62af6 --- /dev/null +++ b/thermal/AcceptsThermalMessagesIF.h @@ -0,0 +1,22 @@ +/** + * \file AcceptsThermalMessagesIF.h + * + * \date 16.02.2020 + */ + +#ifndef FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ +#define FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ +#include + +class AcceptsThermalMessagesIF { +public: + + /** + * @brief This is the empty virtual destructor as required for C++ interfaces. + */ + virtual ~AcceptsThermalMessagesIF() { } + + virtual MessageQueueId_t getReceptionQueue() const = 0; +}; + +#endif /* FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ */ diff --git a/thermal/CoreComponent.h b/thermal/CoreComponent.h index f7e7aff8..da77c65b 100644 --- a/thermal/CoreComponent.h +++ b/thermal/CoreComponent.h @@ -8,6 +8,7 @@ #include #include +// TODO: Documentaiton, how to use this? only use Thermal Component, which inherits core component? class CoreComponent: public ThermalComponentIF { public: struct Parameters { diff --git a/thermal/RedundantHeater.h b/thermal/RedundantHeater.h index 29791a9a..55d402d7 100644 --- a/thermal/RedundantHeater.h +++ b/thermal/RedundantHeater.h @@ -10,15 +10,14 @@ public: Parameters(uint32_t objectIdHeater0, uint32_t objectIdHeater1, uint8_t switch0Heater0, uint8_t switch1Heater0, uint8_t switch0Heater1, uint8_t switch1Heater1) : - objectIdHeater0(objectIdHeater0), objectIdHeater1( - objectIdHeater1), switch0Heater0(switch0Heater0), switch1Heater0( - switch1Heater0), switch0Heater1(switch0Heater1), switch1Heater1( - switch1Heater1) { + objectIdHeater0(objectIdHeater0), objectIdHeater1(objectIdHeater1), + switch0Heater0(switch0Heater0),switch1Heater0(switch1Heater0), + switch0Heater1(switch0Heater1), switch1Heater1(switch1Heater1) { } Parameters() : - objectIdHeater0(0), objectIdHeater1(0), switch0Heater0(0), switch1Heater0( - 0), switch0Heater1(0), switch1Heater1(0) { + objectIdHeater0(0), objectIdHeater1(0), switch0Heater0(0), + switch1Heater0(0), switch0Heater1(0), switch1Heater1(0) { } uint32_t objectIdHeater0; diff --git a/thermal/TemperatureSensor.h b/thermal/TemperatureSensor.h index de280d87..b4172670 100644 --- a/thermal/TemperatureSensor.h +++ b/thermal/TemperatureSensor.h @@ -1,40 +1,100 @@ #ifndef TEMPERATURESENSOR_H_ #define TEMPERATURESENSOR_H_ +#include #include -#include "AbstractTemperatureSensor.h" #include -template +/** + * @brief This building block handles non-linear value conversion and + * range checks for analog temperature sensors. + * @details This class can be used to perform all necessary tasks for temperature sensors. + * A sensor can be instantiated by calling the constructor. + * The temperature is calculated from an input value with + * the calculateOutputTemperature() function. Range checking and + * limit monitoring is performed automatically. + * The inputType specifies the type of the raw input while the + * limitType specifies the type of the upper and lower limit to check against. + * @ingroup thermal + */ + +template class TemperatureSensor: public AbstractTemperatureSensor { public: + /** + * This structure contains parameters required for range checking + * and the conversion from the input value to the output temperature. + * a, b and c can be any parameters required to calculate the output + * temperature from the input value, depending on the formula used. + * + * The parameters a,b and c are used in the calculateOutputTemperature() call. + * + * The lower and upper limits can be specified in any type, for example float for C° values + * or any other type for raw values. + */ struct Parameters { float a; float b; float c; - T lowerLimit; - T upperLimit; - float gradient; + limitType lowerLimit; + limitType upperLimit; + float maxGradient; }; + + /** + * Forward declaration for explicit instantiation of used parameters. + */ struct UsedParameters { UsedParameters(Parameters parameters) : - a(parameters.a), b(parameters.b), c(parameters.c), gradient( - parameters.gradient) { - } + a(parameters.a), b(parameters.b), c(parameters.c), + gradient(parameters.maxGradient) {} float a; float b; float c; float gradient; }; - static const uint16_t ADDRESS_A = 0; - static const uint16_t ADDRESS_B = 1; - static const uint16_t ADDRESS_C = 2; - static const uint16_t ADDRESS_GRADIENT = 3; + /** + * Instantiate Temperature Sensor Object. + * @param setObjectid objectId of the sensor object + * @param inputValue Input value which is converted to a temperature + * @param poolVariable Pool Variable to store the temperature value + * @param vectorIndex Vector Index for the sensor monitor + * @param parameters Calculation parameters, temperature limits, gradient limit + * @param datapoolId Datapool ID of the output temperature + * @param outputSet Output dataset for the output temperature to fetch it with read() + * @param thermalModule respective thermal module, if it has one + */ + TemperatureSensor(object_id_t setObjectid, + inputType *inputValue, PoolVariableIF *poolVariable, + uint8_t vectorIndex, uint32_t datapoolId, Parameters parameters = {0, 0, 0, 0, 0, 0}, + DataSet *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) : + AbstractTemperatureSensor(setObjectid, thermalModule), parameters(parameters), + inputValue(inputValue), poolVariable(poolVariable), + outputTemperature(datapoolId, outputSet, PoolVariableIF::VAR_WRITE), + sensorMonitor(setObjectid, DOMAIN_ID_SENSOR, + DataPool::poolIdAndPositionToPid(poolVariable->getDataPoolId(), vectorIndex), + DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, parameters.upperLimit, + TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), + oldTemperature(20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) { + } + + +protected: + /** + * This formula is used to calculate the temperature from an input value + * with an arbitrary type. + * A default implementation is provided but can be replaced depending + * on the required calculation. + * @param inputTemperature + * @return + */ + virtual float calculateOutputTemperature(inputType inputValue) { + return parameters.a * inputValue * inputValue + + parameters.b * inputValue + parameters.c; + } - static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.) - static const uint8_t DOMAIN_ID_SENSOR = 1; private: void setInvalid() { outputTemperature = INVALID_TEMPERATURE; @@ -47,22 +107,17 @@ protected: UsedParameters parameters; - T *inputTemperature; + inputType * inputValue; PoolVariableIF *poolVariable; PoolVariable outputTemperature; - LimitMonitor sensorMonitor; + LimitMonitor sensorMonitor; float oldTemperature; timeval uptimeOfOldTemperature; - virtual float calculateOutputTemperature(T inputTemperature) { - return parameters.a * inputTemperature * inputTemperature - + parameters.b * inputTemperature + parameters.c; - } - void doChildOperation() { if (!poolVariable->isValid() || !healthHelper.healthTable->isHealthy(getObjectId())) { @@ -70,7 +125,7 @@ protected: return; } - outputTemperature = calculateOutputTemperature(*inputTemperature); + outputTemperature = calculateOutputTemperature(*inputValue); outputTemperature.setValid(PoolVariableIF::VALID); timeval uptime; @@ -78,7 +133,7 @@ protected: if (uptimeOfOldTemperature.tv_sec != INVALID_UPTIME) { //In theory, we could use an AbsValueMonitor to monitor the gradient. - //But this would require storing the gradient in DP and quite some overhead. + //But this would require storing the maxGradient in DP and quite some overhead. //The concept of delta limits is a bit strange anyway. float deltaTime; float deltaTemp; @@ -96,8 +151,8 @@ protected: } } - //Check is done against raw limits. SHOULDDO: Why? Using °C would be more easy to handle. - sensorMonitor.doCheck(*inputTemperature); + //Check is done against raw limits. SHOULDDO: Why? Using °C would be more easy to handle. + sensorMonitor.doCheck(outputTemperature.value); if (sensorMonitor.isOutOfLimits()) { uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; @@ -110,23 +165,6 @@ protected: } public: - TemperatureSensor(object_id_t setObjectid, - T *inputTemperature, PoolVariableIF *poolVariable, - uint8_t vectorIndex, Parameters parameters, uint32_t datapoolId, - DataSet *outputSet, ThermalModuleIF *thermalModule) : - AbstractTemperatureSensor(setObjectid, thermalModule), parameters( - parameters), inputTemperature(inputTemperature), poolVariable( - poolVariable), outputTemperature(datapoolId, outputSet, - PoolVariableIF::VAR_WRITE), sensorMonitor(setObjectid, - DOMAIN_ID_SENSOR, - DataPool::poolIdAndPositionToPid( - poolVariable->getDataPoolId(), vectorIndex), - DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, - parameters.upperLimit, TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), oldTemperature( - 20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) { - - } - float getTemperature() { return outputTemperature; } @@ -135,6 +173,15 @@ public: return outputTemperature.isValid(); } + static const uint16_t ADDRESS_A = 0; + static const uint16_t ADDRESS_B = 1; + static const uint16_t ADDRESS_C = 2; + static const uint16_t ADDRESS_GRADIENT = 3; + + static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.) + + static const uint8_t DOMAIN_ID_SENSOR = 1; + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex) { diff --git a/thermal/ThermalComponent.cpp b/thermal/ThermalComponent.cpp index bf6f7398..737ffd2e 100644 --- a/thermal/ThermalComponent.cpp +++ b/thermal/ThermalComponent.cpp @@ -12,12 +12,10 @@ ThermalComponent::ThermalComponent(object_id_t reportingObjectId, CoreComponent(reportingObjectId, domainId, temperaturePoolId, targetStatePoolId, currentStatePoolId, requestPoolId, dataSet, sensor, firstRedundantSensor, secondRedundantSensor, - thermalModule, - { parameters.lowerOpLimit, parameters.upperOpLimit, - parameters.heaterOn, parameters.hysteresis, - parameters.heaterSwitchoff }, priority, - ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL), nopParameters( - { parameters.lowerNopLimit, parameters.upperNopLimit }) { + thermalModule,{ parameters.lowerOpLimit, parameters.upperOpLimit, + parameters.heaterOn, parameters.hysteresis, parameters.heaterSwitchoff }, + priority, ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL), + nopParameters({ parameters.lowerNopLimit, parameters.upperNopLimit }) { } ThermalComponent::~ThermalComponent() { @@ -42,11 +40,11 @@ ReturnValue_t ThermalComponent::setTargetState(int8_t newState) { } } -ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, uint32_t size) { +ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, ssize_t size) { if (size != 4 * sizeof(parameters.lowerOpLimit)) { return MonitoringIF::INVALID_SIZE; } - int32_t readSize = size; + ssize_t readSize = size; SerializeAdapter::deSerialize(&nopParameters.lowerNopLimit, &data, &readSize, true); SerializeAdapter::deSerialize(¶meters.lowerOpLimit, &data, diff --git a/thermal/ThermalComponent.h b/thermal/ThermalComponent.h index 93243868..37ed01c0 100644 --- a/thermal/ThermalComponent.h +++ b/thermal/ThermalComponent.h @@ -3,6 +3,9 @@ #include "CoreComponent.h" +/** + * What is it. How to use + */ class ThermalComponent: public CoreComponent { public: struct Parameters { @@ -14,10 +17,31 @@ public: float hysteresis; float heaterSwitchoff; }; + + /** + * Non-Operational Temperatures + */ struct NopParameters { float lowerNopLimit; float upperNopLimit; }; + + /** + * How to use. + * @param reportingObjectId + * @param domainId + * @param temperaturePoolId + * @param targetStatePoolId + * @param currentStatePoolId + * @param requestPoolId + * @param dataSet + * @param sensor + * @param firstRedundantSensor + * @param secondRedundantSensor + * @param thermalModule + * @param parameters + * @param priority + */ ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, uint32_t currentStatePoolId, uint32_t requestPoolId, DataSet *dataSet, AbstractTemperatureSensor *sensor, @@ -29,7 +53,7 @@ public: ReturnValue_t setTargetState(int8_t newState); - virtual ReturnValue_t setLimits( const uint8_t* data, uint32_t size); + virtual ReturnValue_t setLimits( const uint8_t* data, ssize_t size); virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper *parameterWrapper, diff --git a/thermal/ThermalModule.h b/thermal/ThermalModule.h index d8ac7d73..e65560cd 100644 --- a/thermal/ThermalModule.h +++ b/thermal/ThermalModule.h @@ -11,6 +11,9 @@ #include "RedundantHeater.h" class PowerSwitchIF; +/** + * @brief Allows creation of different thermal control domains within a system. + */ class ThermalModule: public ThermalModuleIF { friend class ThermalController; public: diff --git a/thermal/ThermalMonitor.h b/thermal/ThermalMonitor.h index 6aca55ab..a38889d0 100644 --- a/thermal/ThermalMonitor.h +++ b/thermal/ThermalMonitor.h @@ -4,6 +4,9 @@ #include #include +/** + * What does it do. How to use it. + */ class ThermalMonitor: public MonitorReporter { public: template diff --git a/timemanager/CCSDSTime.cpp b/timemanager/CCSDSTime.cpp index 32032716..29aafb68 100644 --- a/timemanager/CCSDSTime.cpp +++ b/timemanager/CCSDSTime.cpp @@ -1,5 +1,6 @@ #include #include +#include #include CCSDSTime::CCSDSTime() { @@ -154,15 +155,58 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* if (length < 19) { return RETURN_FAILED; } +// Newlib nano can't parse uint8, see SCNu8 documentation and https://sourceware.org/newlib/README +// Suggestion: use uint16 all the time. This should work on all systems. +#ifdef NEWLIB_NANO_NO_C99_IO + uint16_t year; + uint16_t month; + uint16_t day; + uint16_t hour; + uint16_t minute; + float second; + int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, + &month, &day, &hour, &minute, &second); + if (count == 6) { + to->year = year; + to->month = month; + to->day = day; + to->hour = hour; + to->minute = minute; + to->second = second; + to->usecond = (second - floor(second)) * 1000000; + return RETURN_OK; + } + + // try Code B (yyyy-ddd) + count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day, + &hour, &minute, &second); + if (count == 5) { + uint8_t tempDay; + ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, + reinterpret_cast(&month), reinterpret_cast(&tempDay)); + if (result != RETURN_OK) { + return RETURN_FAILED; + } + to->year = year; + to->month = month; + to->day = tempDay; + to->hour = hour; + to->minute = minute; + to->second = second; + to->usecond = (second - floor(second)) * 1000000; + return RETURN_OK; + } +// Warning: Compiler/Linker fails ambiguously if library does not implement C99 I/O +#else uint16_t year; uint8_t month; uint16_t day; uint8_t hour; uint8_t minute; float second; -//try Code A (yyyy-mm-dd) + //try Code A (yyyy-mm-dd) int count = sscanf((char *) from, "%4hi-%2hhi-%2hiT%2hhi:%2hhi:%fZ", &year, - &month, &day, &hour, &minute, &second); + &month, &day, &hour, &minute, &second); if (count == 6) { to->year = year; to->month = month; @@ -193,6 +237,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* to->usecond = (second - floor(second)) * 1000000; return RETURN_OK; } +#endif return UNSUPPORTED_TIME_FORMAT; } diff --git a/timemanager/ReceivesTimeInfoIF.h b/timemanager/ReceivesTimeInfoIF.h index 14a750c5..f65f9dad 100644 --- a/timemanager/ReceivesTimeInfoIF.h +++ b/timemanager/ReceivesTimeInfoIF.h @@ -7,6 +7,7 @@ #ifndef RECEIVESTIMEINFOIF_H_ #define RECEIVESTIMEINFOIF_H_ +#include /** * This is a Interface for classes that receive timing information diff --git a/tmstorage/TmStoreBackendIF.h b/tmstorage/TmStoreBackendIF.h index 162bd766..9b913b35 100644 --- a/tmstorage/TmStoreBackendIF.h +++ b/tmstorage/TmStoreBackendIF.h @@ -49,14 +49,33 @@ public: static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, SEVERITY::INFO);//!< Info that the a auto catalog report failed virtual ~TmStoreBackendIF() {} + + /** + * What do I need to implement here ? + * @param opCode + * @return + */ virtual ReturnValue_t performOperation(uint8_t opCode) = 0; virtual ReturnValue_t initialize() = 0; + + /** + * Implement the storage of TM packets to mass memory + * @param tmPacket + * @return + */ virtual ReturnValue_t storePacket(TmPacketMinimal* tmPacket) = 0; virtual ReturnValue_t setFetchLimitTime(const timeval* loverLimit, const timeval* upperLimit) = 0; virtual ReturnValue_t setFetchLimitBlocks(uint32_t startAddress, uint32_t endAddress) = 0; virtual ReturnValue_t fetchPackets(bool fromBegin = false) = 0; virtual ReturnValue_t initializeStore(object_id_t dumpTarget) = 0; virtual ReturnValue_t dumpIndex(store_address_t* storeId) = 0; + + /** + * TODO: Adapt for file management system? + * @param startAddress + * @param endAddress + * @return + */ virtual ReturnValue_t deleteBlocks(uint32_t startAddress, uint32_t endAddress) = 0; virtual ReturnValue_t deleteTime(const timeval* timeUntil, uint32_t* deletedPackets) = 0; diff --git a/tmstorage/TmStoreFrontendIF.h b/tmstorage/TmStoreFrontendIF.h index 787c3597..7d38cfc6 100644 --- a/tmstorage/TmStoreFrontendIF.h +++ b/tmstorage/TmStoreFrontendIF.h @@ -11,6 +11,14 @@ class TmStoreBackendIF; class TmStoreFrontendIF { public: virtual TmStoreBackendIF* getBackend() const = 0; + + /** + * What do I need to implement here? + * This is propably used by PUS Service 15 so we should propably check for messages.. + * Provide base implementation? + * @param opCode + * @return + */ virtual ReturnValue_t performOperation(uint8_t opCode) = 0; /** * Callback from the back-end to indicate a certain packet was received. diff --git a/tmstorage/TmStorePackets.h b/tmstorage/TmStorePackets.h index 6eea6f58..4e7bc94b 100644 --- a/tmstorage/TmStorePackets.h +++ b/tmstorage/TmStorePackets.h @@ -32,8 +32,8 @@ public: } uint16_t apid; uint16_t ssc; - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result = SerializeAdapter::serialize(&apid, buffer, size, max_size, bigEndian); if (result != HasReturnvaluesIF::RETURN_OK) { @@ -44,11 +44,11 @@ public: } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { return sizeof(apid) + sizeof(ssc); } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { ReturnValue_t result = SerializeAdapter::deSerialize(&apid, buffer, size, bigEndian); @@ -218,8 +218,8 @@ public: } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { ReturnValue_t result = AutoSerializeAdapter::serialize(&apid,buffer,size,max_size,bigEndian); if(result!=HasReturnvaluesIF::RETURN_OK){ return result; @@ -244,7 +244,7 @@ public: return adapter.serialize(buffer,size,max_size,bigEndian); } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { uint32_t size = 0; size += AutoSerializeAdapter::getSerializedSize(&apid); size += AutoSerializeAdapter::getSerializedSize(&sourceSequenceCount); @@ -257,7 +257,7 @@ public: }; - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { ReturnValue_t result = AutoSerializeAdapter::deSerialize(&apid, buffer, size, bigEndian); diff --git a/tmtcpacket/packetmatcher/ApidMatcher.h b/tmtcpacket/packetmatcher/ApidMatcher.h index 1f194968..1ee44476 100644 --- a/tmtcpacket/packetmatcher/ApidMatcher.h +++ b/tmtcpacket/packetmatcher/ApidMatcher.h @@ -22,14 +22,15 @@ public: return false; } } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - return SerializeAdapter::serialize(&apid, buffer, size, max_size, bigEndian); + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + return SerializeAdapter::serialize(&apid, buffer, + size, max_size, bigEndian); } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { return SerializeAdapter::getSerializedSize(&apid); } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return SerializeAdapter::deSerialize(&apid, buffer, size, bigEndian); } diff --git a/tmtcpacket/packetmatcher/ServiceMatcher.h b/tmtcpacket/packetmatcher/ServiceMatcher.h index 1a6781b4..b69ac7a5 100644 --- a/tmtcpacket/packetmatcher/ServiceMatcher.h +++ b/tmtcpacket/packetmatcher/ServiceMatcher.h @@ -22,14 +22,15 @@ public: return false; } } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - return SerializeAdapter::serialize(&service, buffer, size, max_size, bigEndian); + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + return SerializeAdapter::serialize(&service, buffer, + size, max_size, bigEndian); } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { return SerializeAdapter::getSerializedSize(&service); } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return SerializeAdapter::deSerialize(&service, buffer, size, bigEndian); } diff --git a/tmtcpacket/packetmatcher/SubserviceMatcher.h b/tmtcpacket/packetmatcher/SubserviceMatcher.h index 1b589b20..9c93af64 100644 --- a/tmtcpacket/packetmatcher/SubserviceMatcher.h +++ b/tmtcpacket/packetmatcher/SubserviceMatcher.h @@ -20,14 +20,15 @@ public: return false; } } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - return SerializeAdapter::serialize(&subService, buffer, size, max_size, bigEndian); + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + return SerializeAdapter::serialize(&subService, buffer, size, + max_size, bigEndian); } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { return SerializeAdapter::getSerializedSize(&subService); } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + ReturnValue_t deSerialize(const uint8_t** buffer, ssize_t* size, bool bigEndian) { return SerializeAdapter::deSerialize(&subService, buffer, size, bigEndian); } diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp index 1f31a763..4bfd0e37 100644 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ b/tmtcpacket/pus/TcPacketStored.cpp @@ -59,7 +59,7 @@ bool TcPacketStored::checkAndSetStore() { void TcPacketStored::setStoreAddress(store_address_t setAddress) { this->storeAddress = setAddress; const uint8_t* temp_data = NULL; - uint32_t temp_size; + size_t temp_size; ReturnValue_t status = StorageManagerIF::RETURN_FAILED; if (this->checkAndSetStore()) { status = this->store->getData(this->storeAddress, &temp_data, @@ -79,7 +79,7 @@ store_address_t TcPacketStored::getStoreAddress() { bool TcPacketStored::isSizeCorrect() { const uint8_t* temp_data = NULL; - uint32_t temp_size; + size_t temp_size; ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, &temp_size); if (status == StorageManagerIF::RETURN_OK) { diff --git a/tmtcpacket/pus/TmPacketStored.cpp b/tmtcpacket/pus/TmPacketStored.cpp index f2c1eb28..b60f6c7e 100644 --- a/tmtcpacket/pus/TmPacketStored.cpp +++ b/tmtcpacket/pus/TmPacketStored.cpp @@ -22,6 +22,7 @@ TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, (TmPacketBase::TM_PACKET_MIN_SIZE + size + headerSize), &pData); if (returnValue != store->RETURN_OK) { + debug << "TM Packet Stored: Issue getting free storage" << std::endl; checkAndReportLostTm(); return; } @@ -41,7 +42,7 @@ TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, if (!checkAndSetStore()) { return; } - uint32_t sourceDataSize = 0; + size_t sourceDataSize = 0; if (content != NULL) { sourceDataSize += content->getSerializedSize(); } @@ -57,7 +58,7 @@ TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, setData(p_data); initializeTmPacket(apid, service, subservice, packetSubcounter); uint8_t* putDataHere = getSourceData(); - uint32_t size = 0; + size_t size = 0; if (header != NULL) { header->serialize(&putDataHere, &size, sourceDataSize, true); } @@ -81,7 +82,7 @@ void TmPacketStored::deletePacket() { void TmPacketStored::setStoreAddress(store_address_t setAddress) { storeAddress = setAddress; const uint8_t* temp_data = NULL; - uint32_t temp_size; + size_t temp_size; if (!checkAndSetStore()) { return; } diff --git a/tmtcservices/AcceptsTelecommandsIF.h b/tmtcservices/AcceptsTelecommandsIF.h index 03a57aae..0952d3a6 100644 --- a/tmtcservices/AcceptsTelecommandsIF.h +++ b/tmtcservices/AcceptsTelecommandsIF.h @@ -12,7 +12,7 @@ class AcceptsTelecommandsIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::ACCEPTS_TELECOMMANDS_IF; - static const ReturnValue_t ACTIVITY_STARTED = MAKE_RETURN_CODE(1); + static const ReturnValue_t ACTIVITY_STARTED = MAKE_RETURN_CODE(1); // is this used anywhere or can it be removed? static const ReturnValue_t INVALID_SUBSERVICE = MAKE_RETURN_CODE(2); static const ReturnValue_t ILLEGAL_APPLICATION_DATA = MAKE_RETURN_CODE(3); static const ReturnValue_t SEND_TM_FAILED = MAKE_RETURN_CODE(4); diff --git a/tmtcservices/CommandingServiceBase.cpp b/tmtcservices/CommandingServiceBase.cpp index d70b9042..5b397756 100644 --- a/tmtcservices/CommandingServiceBase.cpp +++ b/tmtcservices/CommandingServiceBase.cpp @@ -219,8 +219,8 @@ void CommandingServiceBase::handleRequestQueue() { void CommandingServiceBase::sendTmPacket(uint8_t subservice, - const uint8_t* data, uint32_t dataLen, const uint8_t* headerData, - uint32_t headerSize) { + const uint8_t* data, size_t dataLen, const uint8_t* headerData, + size_t headerSize) { TmPacketStored tmPacketStored(this->apid, this->service, subservice, this->tmPacketCounter, data, dataLen, headerData, headerSize); ReturnValue_t result = tmPacketStored.sendPacket( @@ -232,10 +232,10 @@ void CommandingServiceBase::sendTmPacket(uint8_t subservice, void CommandingServiceBase::sendTmPacket(uint8_t subservice, - object_id_t objectId, const uint8_t *data, uint32_t dataLen) { + object_id_t objectId, const uint8_t *data, size_t dataLen) { uint8_t buffer[sizeof(object_id_t)]; uint8_t* pBuffer = buffer; - uint32_t size = 0; + size_t size = 0; SerializeAdapter::serialize(&objectId, &pBuffer, &size, sizeof(object_id_t), true); TmPacketStored tmPacketStored(this->apid, this->service, subservice, diff --git a/tmtcservices/CommandingServiceBase.h b/tmtcservices/CommandingServiceBase.h index ee59ffe4..56e9b87d 100644 --- a/tmtcservices/CommandingServiceBase.h +++ b/tmtcservices/CommandingServiceBase.h @@ -64,7 +64,7 @@ public: virtual ~CommandingServiceBase(); /*** - * This is the periodic called function + * This is the periodically called function. * Handle request queue for external commands. * Handle command Queue for internal commands. * @param opCode is unused here at the moment @@ -104,6 +104,66 @@ public: }; protected: + /** + * Check the target subservice + * @param subservice + * @return + */ + virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; + + /** + * Once a TC Request is valid, the existence of the destination and its target interface is checked and retrieved. + * The target message queue ID can then be acquired by using the target interface. + * @param subservice + * @param tcData Application Data of TC Packet + * @param tcDataLen + * @param id MessageQueue ID is stored here + * @param objectId Object ID is extracted and stored here + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED + * - @c CSB or implementation specific return codes + */ + virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, + object_id_t *objectId) = 0; + + /** + * After the Message Queue and Object ID are determined, + * the command is prepared by using an implementation specific CommandMessage type + * which is sent to the target object. + * It contains all necessary information for the device to execute telecommands. + * @param message + * @param subservice + * @param tcData + * @param tcDataLen + * @param state + * @param objectId Target object ID + * @return + */ + virtual ReturnValue_t prepareCommand(CommandMessage *message, + uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, + uint32_t *state, object_id_t objectId) = 0; + + /** + * This function is responsible for the communication between the Command Service Base + * and the respective PUS Commanding Service once the execution has started. + * The PUS Commanding Service receives replies from the target device and forwards them by calling this function. + * There are different translations of these replies to specify how the Command Service proceeds. + * @param reply[out] Command Message which contains information about the command + * @param previousCommand [out] + * @param state + * @param optionalNextCommand + * @param objectId Source object ID + * @param isStep Flag value to mark steps of command execution + * @return - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to generate TC verification success + * - @c INVALID_REPLY can handle unrequested replies + * - Anything else triggers a TC verification failure + */ + virtual ReturnValue_t handleReply(const CommandMessage *reply, + Command_t previousCommand, uint32_t *state, + CommandMessage *optionalNextCommand, object_id_t objectId, + bool *isStep) = 0; + struct CommandInfo { struct tcInfo { uint8_t ackFlags; @@ -159,8 +219,8 @@ protected: * @param headerData HeaderData will be placed before data * @param headerSize Size of HeaderData */ - void sendTmPacket(uint8_t subservice, const uint8_t *data, uint32_t dataLen, - const uint8_t* headerData = NULL, uint32_t headerSize = 0); + void sendTmPacket(uint8_t subservice, const uint8_t *data, size_t dataLen, + const uint8_t* headerData = nullptr,size_t headerSize = 0); /** * To send TM packets of objects that still need to be serialized and consist of an object ID with appended data @@ -170,7 +230,7 @@ protected: * @param dataLen Length of Data */ void sendTmPacket(uint8_t subservice, object_id_t objectId, - const uint8_t *data, uint32_t dataLen); + const uint8_t *data, size_t dataLen); /** * To send packets has data which is in form of a SerializeIF or Adapters implementing it @@ -179,21 +239,7 @@ protected: * @param header Serialize IF header which will be placed before content */ void sendTmPacket(uint8_t subservice, SerializeIF* content, - SerializeIF* header = NULL); - virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; - - virtual ReturnValue_t prepareCommand(CommandMessage *message, - uint8_t subservice, const uint8_t *tcData, uint32_t tcDataLen, - uint32_t *state, object_id_t objectId) = 0; - - virtual ReturnValue_t handleReply(const CommandMessage *reply, - Command_t previousCommand, uint32_t *state, - CommandMessage *optionalNextCommand, object_id_t objectId, - bool *isStep) = 0; - - virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, - const uint8_t *tcData, uint32_t tcDataLen, MessageQueueId_t *id, - object_id_t *objectId) = 0; + SerializeIF* header = nullptr); virtual void handleUnrequestedReply(CommandMessage *reply); @@ -209,7 +255,8 @@ private: * It handles replies generated by the devices and relayed by the specific service implementation. * This means that it determines further course of action depending on the return values specified * in the service implementation. - * This includes the generation of TC verification messages: + * This includes the generation of TC verification messages. Note that + * the static framework object ID @c VerificationReporter::messageReceiver needs to be set. * - TM[1,5] Step Successs * - TM[1,6] Step Failure * - TM[1,7] Completion Success diff --git a/tmtcservices/PusServiceBase.cpp b/tmtcservices/PusServiceBase.cpp index c8f6accf..a0ab1768 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/tmtcservices/PusServiceBase.cpp @@ -23,14 +23,14 @@ ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { TmTcMessage message; for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { ReturnValue_t status = this->requestQueue->receiveMessage(&message); - // debug << "PusServiceBase::performOperation: Receiving from MQ ID: " << std::hex << this->requestQueue.getId() << std::dec << " returned: " << status << std::endl; + // debug << "PusServiceBase::performOperation: Receiving from MQ ID: " << std::hex << this->requestQueue.getId() + // << std::dec << " returned: " << status << std::endl; if (status == RETURN_OK) { this->currentPacket.setStoreAddress(message.getStorageId()); -// info << "Service " << (uint16_t) this->serviceId << ": new packet!" -// << std::endl; + // info << "Service " << (uint16_t) this->serviceId << ": new packet!" << std::endl; - ReturnValue_t return_code = this->handleRequest(); - // debug << "Service " << (uint16_t)this->serviceId << ": handleRequest returned: " << (int)return_code << std::endl; + ReturnValue_t return_code = this->handleRequest(currentPacket.getSubService()); + // debug << "Service " << (uint16_t)this->serviceId << ": handleRequest returned: " << (int)return_code << std::endl; if (return_code == RETURN_OK) { this->verifyReporter.sendSuccessReport( TC_VERIFY::COMPLETION_SUCCESS, &this->currentPacket); @@ -44,7 +44,7 @@ ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { errorParameter2 = 0; } else if (status == MessageQueueIF::EMPTY) { status = RETURN_OK; - // debug << "PusService " << (uint16_t)this->serviceId << ": no new packet." << std::endl; + // debug << "PusService " << (uint16_t)this->serviceId << ": no new packet." << std::endl; break; } else { diff --git a/tmtcservices/PusServiceBase.h b/tmtcservices/PusServiceBase.h index 782d375f..de16ebe2 100644 --- a/tmtcservices/PusServiceBase.h +++ b/tmtcservices/PusServiceBase.h @@ -30,7 +30,10 @@ void setStaticFrameworkObjectIds(); * All PUS Services are System Objects, so an Object ID needs to be specified on construction. * \ingroup pus_services */ -class PusServiceBase : public ExecutableObjectIF, public AcceptsTelecommandsIF, public SystemObject, public HasReturnvaluesIF { +class PusServiceBase : public ExecutableObjectIF, + public AcceptsTelecommandsIF, + public SystemObject, + public HasReturnvaluesIF { friend void (Factory::setStaticFrameworkObjectIds)(); public: /** @@ -46,17 +49,24 @@ public: */ virtual ~PusServiceBase(); /** - * The handleRequest method shall handle any kind of Telecommand Request immediately. + * @brief The handleRequest method shall handle any kind of Telecommand Request immediately. + * @details * Implemetations can take the Telecommand in currentPacket and perform any kind of operation. * They may send additional "Start Success (1,3)" messages with the verifyReporter, but Completion * Success or Failure Reports are generated automatically after execution of this method. - * If a Telecommand can not be executed within one call cycle, this Base class is not the right parent. - * The child class may add additional error information in #errorParameters which are attached to the generated - * verification message. + * + * If a Telecommand can not be executed within one call cycle, + * this Base class is not the right parent. + * + * The child class may add additional error information by setting #errorParameters which are + * attached to the generated verification message. + * + * Subservice checking should be implemented in this method. + * * @return The returned status_code is directly taken as main error code in the Verification Report. * On success, RETURN_OK shall be returned. */ - virtual ReturnValue_t handleRequest() = 0; + virtual ReturnValue_t handleRequest(uint8_t subservice) = 0; /** * In performService, implementations can handle periodic, non-TC-triggered activities. * The performService method is always called. @@ -68,8 +78,8 @@ public: * It checks for new requests, and, if found, calls handleRequest, sends completion verification messages and deletes * the TC requests afterwards. * performService is always executed afterwards. - * @return - \c RETURN_OK if the periodic performService was successful. - * - \c RETURN_FAILED else. + * @return \c RETURN_OK if the periodic performService was successful. + * \c RETURN_FAILED else. */ ReturnValue_t performOperation(uint8_t opCode); virtual uint16_t getIdentifier(); @@ -91,7 +101,8 @@ protected: /** * One of two error parameters for additional error information. */ - uint8_t errorParameter2; + // shouldn't this be uint32_t ? The PUS Verification Message structure param2 has the size 4 + uint32_t errorParameter2; /** * This is a complete instance of the Telecommand reception queue of the class. * It is initialized on construction of the class. diff --git a/tmtcservices/PusVerificationReport.h b/tmtcservices/PusVerificationReport.h index 7a173be9..f8913627 100644 --- a/tmtcservices/PusVerificationReport.h +++ b/tmtcservices/PusVerificationReport.h @@ -49,7 +49,7 @@ class PusSuccessReport { private: static const uint16_t MAX_SIZE = 7; uint8_t reportBuffer[MAX_SIZE]; - uint32_t reportSize; + size_t reportSize; uint8_t * pBuffer; public: PusSuccessReport(uint16_t setPacketId, uint16_t setSequenceControl, @@ -63,7 +63,7 @@ class PusFailureReport { private: static const uint16_t MAX_SIZE = 16; uint8_t reportBuffer[MAX_SIZE]; - uint32_t reportSize; + size_t reportSize; uint8_t * pBuffer; public: PusFailureReport(uint16_t setPacketId, uint16_t setSequenceControl, diff --git a/tmtcservices/TmTcBridge.cpp b/tmtcservices/TmTcBridge.cpp new file mode 100644 index 00000000..6b563f98 --- /dev/null +++ b/tmtcservices/TmTcBridge.cpp @@ -0,0 +1,175 @@ +/** + * @file TmTcBridge.cpp + * + * @date 26.12.2019 + * @author R. Mueller + */ + +#include + +#include +#include +#include + +TmTcBridge::TmTcBridge(object_id_t objectId_, object_id_t ccsdsPacketDistributor_): + SystemObject(objectId_),tcStore(NULL), tmStore(NULL), + ccsdsPacketDistributor(ccsdsPacketDistributor_), communicationLinkUp(false), + tmStored(false),recvBuffer(NULL), size(0) { + TmTcReceptionQueue = QueueFactory::instance()-> + createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH); + +} + +TmTcBridge::~TmTcBridge() { +} + +ReturnValue_t TmTcBridge::initialize() { + tcStore = objectManager->get(objects::TC_STORE); + if (tcStore == NULL) { + return RETURN_FAILED; + } + tmStore = objectManager->get(objects::TM_STORE); + if (tmStore == NULL) { + return RETURN_FAILED; + } + AcceptsTelecommandsIF* tcDistributor = + objectManager->get(ccsdsPacketDistributor); + if (tcDistributor == NULL) { + return RETURN_FAILED; + } + TmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue()); + return RETURN_OK; +} + +ReturnValue_t TmTcBridge::performOperation(uint8_t operationCode) { + ReturnValue_t result; + result = handleTc(); + if(result != RETURN_OK) { + error << "TMTC Bridge: Error handling TCs" << std::endl; + } + result = handleTm(); + if (result != RETURN_OK) { + error << "TMTC Bridge: Error handling TMs" << std::endl; + } + return result; +} + +ReturnValue_t TmTcBridge::handleTc() { + ReturnValue_t result = receiveTc(&recvBuffer, &size); + return result; +} + +ReturnValue_t TmTcBridge::handleTm() { + ReturnValue_t result = readTmQueue(); + if(result != RETURN_OK) { + error << "TMTC Bridge: Reading TM Queue failed" << std::endl; + return RETURN_FAILED; + } + + if(tmStored && communicationLinkUp) { + result = sendStoredTm(); + } + return result; + +} + +ReturnValue_t TmTcBridge::readTmQueue() { + TmTcMessage message; + const uint8_t* data = NULL; + size_t size = 0; + for (ReturnValue_t result = TmTcReceptionQueue->receiveMessage(&message); + result == RETURN_OK; result = TmTcReceptionQueue->receiveMessage(&message)) + { + if(communicationLinkUp == false) { + result = storeDownlinkData(&message); + return result; + } + + result = tmStore->getData(message.getStorageId(), &data, &size); + if (result != HasReturnvaluesIF::RETURN_OK) { + continue; + } + + result = sendTm(data, size); + if (result != RETURN_OK) { + error << "TMTC Bridge: Could not send TM packet"<< std::endl; + tmStore->deleteData(message.getStorageId()); + return result; + + } + tmStore->deleteData(message.getStorageId()); + } + return RETURN_OK; +} + +ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { + info << "TMTC Bridge: Comm Link down. " + "Saving packet ID to be sent later " << std::endl; + store_address_t storeId; + + if(fifo.full()) { + info << "TMTC Bridge: TM downlink max. number of stored packet IDs reached." + " Overwriting old data" << std::endl; + fifo.retrieve(&storeId); + tmStore->deleteData(storeId); + } + storeId = message->getStorageId(); + fifo.insert(storeId); + tmStored = true; + return RETURN_OK; +} + +ReturnValue_t TmTcBridge::sendStoredTm() { + uint8_t counter = 0; + ReturnValue_t result = RETURN_OK; + while(!fifo.empty() && counter < MAX_STORED_DATA_SENT_PER_CYCLE) { + info << "UDP Server: Sending stored TM data. There are " + << (int) fifo.size() << " left to send" << std::endl; + store_address_t storeId; + const uint8_t* data = NULL; + size_t size = 0; + fifo.retrieve(&storeId); + result = tmStore->getData(storeId, &data, &size); + sendTm(data,size); + if(result != RETURN_OK) { + error << "UDP Server: Could not send stored downlink data" << std::endl; + result = RETURN_FAILED; + } + counter ++; + + if(fifo.empty()) { + tmStored = false; + } + tmStore->deleteData(storeId); + } + return result; +} + +void TmTcBridge::registerCommConnect() { + if(!communicationLinkUp) { + info << "TMTC Bridge: Registered Comm Link Connect" << std::endl; + communicationLinkUp = true; + } +} + +void TmTcBridge::registerCommDisconnect() { + info << "TMTC Bridge: Registered Comm Link Disconnect" << std::endl; + if(communicationLinkUp) { + communicationLinkUp = false; + } +} + +MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) { + return TmTcReceptionQueue->getId(); +} + +void TmTcBridge::printData(uint8_t * data, uint32_t dataLen) { + info << "TMTC Bridge: Printing data: ["; + for(uint32_t i=0;i +#include +#include +#include +#include + +#include +#include + +class TmTcBridge : public AcceptsTelemetryIF, + public ExecutableObjectIF, + public HasReturnvaluesIF, + public SystemObject { +public: + TmTcBridge(object_id_t objectId_, object_id_t ccsdsPacketDistributor_); + virtual ~TmTcBridge(); + + /** + * Initializes basic FSFW components for the TMTC Bridge + * @return + */ + virtual ReturnValue_t initialize(); + + /** + * @brief The performOperation method is executed in a task. + * @details There are no restrictions for calls within this method, so any + * other member of the class can be used. + * @return Currently, the return value is ignored. + */ + virtual ReturnValue_t performOperation(uint8_t operationCode = 0); + + /** + * Return TMTC Reception Queue + * @param virtualChannel + * @return + */ + virtual MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0); + + void registerCommConnect(); + void registerCommDisconnect(); +protected: + MessageQueueIF* TmTcReceptionQueue; //!< Used to send and receive TMTC messages. TmTcMessage is used to transport messages between tasks. + StorageManagerIF* tcStore; + StorageManagerIF* tmStore; + object_id_t ccsdsPacketDistributor; + bool communicationLinkUp; //!< Used to specify whether communication link is up + bool tmStored; + + /** + * Handle TC reception. Default implementation provided + * @return + */ + virtual ReturnValue_t handleTc(); + + /** + * Implemented by child class. Perform receiving of Telecommand, for example by implementing + * specific drivers or wrappers, e.g. UART Communication or lwIP stack + * @param recvBuffer [out] Received data + * @param size [out] Size of received data + * @return + */ + virtual ReturnValue_t receiveTc(uint8_t ** recvBuffer, uint32_t * size) = 0; + + /** + * Handle Telemetry. Default implementation provided. + * Calls sendTm() + * @return + */ + virtual ReturnValue_t handleTm(); + + /** + * Read the TM Queue and send TM if necessary. Default implementation provided + * @return + */ + virtual ReturnValue_t readTmQueue(); + + /** + * Implemented by child class. Perform sending of Telemetry by implementing + * communication drivers or wrappers, e.g. UART communication or lwIP stack. + * @param data + * @param dataLen + * @return + */ + virtual ReturnValue_t sendTm(const uint8_t * data, uint32_t dataLen) = 0; + + /** + * Store data to be sent later if communication link is not up. + * @param message + * @return + */ + ReturnValue_t storeDownlinkData(TmTcMessage * message); + + /** + * Send stored data if communication link is active + * @return + */ + ReturnValue_t sendStoredTm(); + + /** + * Print data as hexidecimal array + * @param data + * @param dataLen + */ + void printData(uint8_t * data, uint32_t dataLen); + +private: + static const uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20; + static const uint8_t MAX_STORED_DATA_SENT_PER_CYCLE = 10; + static const uint8_t MAX_DOWNLINK_PACKETS_STORED = 15; + + FIFO fifo; + uint8_t * recvBuffer; + uint32_t size; +}; + + +#endif /* FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ */