From 8af5a32f1d3f3376cb229b85a3d742b51bec0ef3 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:37:46 +0200 Subject: [PATCH 01/53] new store accessor classes implementation of local pool and pool manager extracted into tpp file. store_address_t definition extracted in separate file to avoid circular includes by using forward declarations --- storagemanager/LocalPool.h | 389 ++++++----------------------- storagemanager/LocalPool.tpp | 300 ++++++++++++++++++++++ storagemanager/PoolManager.h | 96 ++----- storagemanager/PoolManager.tpp | 47 ++++ storagemanager/StorageAccessor.cpp | 155 ++++++++++++ storagemanager/StorageAccessor.h | 151 +++++++++++ storagemanager/StorageManagerIF.h | 118 ++++----- storagemanager/storeAddress.h | 54 ++++ 8 files changed, 868 insertions(+), 442 deletions(-) create mode 100644 storagemanager/LocalPool.tpp create mode 100644 storagemanager/PoolManager.tpp create mode 100644 storagemanager/StorageAccessor.cpp create mode 100644 storagemanager/StorageAccessor.h create mode 100644 storagemanager/storeAddress.h diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index 5104be2e..c155f918 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -1,26 +1,18 @@ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -/** - * @file LocalPool - * - * @date 02.02.2012 - * @author Bastian Baetz - * - * @brief This file contains the definition of the LocalPool class. - */ - #include #include #include #include #include -#include +#include +#include /** * @brief The LocalPool class provides an intermediate data storage with * a fixed pool size policy. - * \details The class implements the StorageManagerIF interface. While the + * @details The class implements the StorageManagerIF interface. While the * total number of pools is fixed, the element sizes in one pool and * the number of pool elements per pool are set on construction. * The full amount of memory is allocated on construction. @@ -39,7 +31,71 @@ 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); + + /** + * Documentation: See StorageManagerIF.h + */ + ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, + size_t size, bool ignoreFault = false) override; + ReturnValue_t getFreeElement(store_address_t* storageId,const size_t size, + uint8_t** p_data, bool ignoreFault = false) override; + + ConstAccessorPair getData(store_address_t packet_id) override; + ReturnValue_t getData(store_address_t packet_id, ConstStorageAccessor&) override; + ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, + size_t * size) override; + + AccessorPair modifyData(store_address_t packet_id) override; + ReturnValue_t modifyData(store_address_t packet_id, StorageAccessor&) override; + ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, + size_t * size) override; + + virtual ReturnValue_t deleteData(store_address_t) override; + virtual ReturnValue_t deleteData(uint8_t* ptr, size_t size, + store_address_t* storeId = NULL) override; + void clearStore() override; + ReturnValue_t initialize() override; +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. @@ -78,7 +134,7 @@ private: * @param data The data to be stored. * @param size The size of the data to be stored. */ - void write(store_address_t packet_id, const uint8_t* data, uint32_t size); + void write(store_address_t packet_id, const uint8_t* data, size_t size); /** * @brief A helper method to read the element size of a certain pool. * @param pool_index The pool in which to look. @@ -101,7 +157,8 @@ private: * @return - #RETURN_OK on success, * - #DATA_TOO_LARGE otherwise. */ - ReturnValue_t getPoolIndex(uint32_t packet_size, uint16_t* poolIndex, uint16_t startAtIndex = 0); + ReturnValue_t getPoolIndex(size_t packet_size, uint16_t* poolIndex, + uint16_t startAtIndex = 0); /** * @brief This helper method calculates the true array position in store * of a given packet id. @@ -121,310 +178,8 @@ 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 -inline ReturnValue_t LocalPool::findEmpty(uint16_t pool_index, - uint16_t* element) { - ReturnValue_t status = DATA_STORAGE_FULL; - for (uint16_t foundElement = 0; foundElement < n_elements[pool_index]; - foundElement++) { - if (size_list[pool_index][foundElement] == STORAGE_FREE) { - *element = foundElement; - status = RETURN_OK; - break; - } - } - return status; -} - -template -inline void LocalPool::write(store_address_t packet_id, - const uint8_t* data, uint32_t size) { - uint8_t* ptr; - uint32_t packet_position = getRawPosition(packet_id); - - //check size? -> Not necessary, because size is checked before calling this function. - ptr = &store[packet_id.pool_index][packet_position]; - memcpy(ptr, data, size); - size_list[packet_id.pool_index][packet_id.packet_index] = size; -} - -//Returns page size of 0 in case store_index is illegal -template -inline uint32_t LocalPool::getPageSize(uint16_t pool_index) { - if (pool_index < NUMBER_OF_POOLS) { - return element_sizes[pool_index]; - } else { - return 0; - } -} - -template -inline ReturnValue_t LocalPool::getPoolIndex( - uint32_t packet_size, uint16_t* poolIndex, uint16_t startAtIndex) { - for (uint16_t n = startAtIndex; n < NUMBER_OF_POOLS; n++) { -// debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << n << ", Element Size: " << element_sizes[n] << std::endl; - if (element_sizes[n] >= packet_size) { - *poolIndex = n; - return RETURN_OK; - } - } - return DATA_TOO_LARGE; -} - -template -inline uint32_t LocalPool::getRawPosition( - store_address_t packet_id) { - return packet_id.packet_index * element_sizes[packet_id.pool_index]; -} - -template -inline ReturnValue_t LocalPool::reserveSpace( - const uint32_t size, store_address_t* address, bool ignoreFault) { - ReturnValue_t status = getPoolIndex(size, &address->pool_index); - if (status != RETURN_OK) { - sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec - << " )::reserveSpace: Packet too large." << std::endl; - return status; - } - status = findEmpty(address->pool_index, &address->packet_index); - while (status != RETURN_OK && spillsToHigherPools) { - status = getPoolIndex(size, &address->pool_index, address->pool_index + 1); - if (status != RETURN_OK) { - //We don't find any fitting pool anymore. - break; - } - status = findEmpty(address->pool_index, &address->packet_index); - } - if (status == RETURN_OK) { -// if (getObjectId() == objects::IPC_STORE && address->pool_index >= 3) { -// debug << "Reserve: Pool: " << std::dec << address->pool_index << " Index: " << address->packet_index << std::endl; -// } - - size_list[address->pool_index][address->packet_index] = size; - } else { - if (!ignoreFault) { - internalErrorReporter->storeFull(); - } -// error << "LocalPool( " << std::hex << getObjectId() << std::dec -// << " )::reserveSpace: Packet store is full." << std::endl; - } - return status; -} - -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) { - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - this->element_sizes[n] = element_sizes[n]; - this->n_elements[n] = n_elements[n]; - store[n] = new uint8_t[n_elements[n] * element_sizes[n]]; - size_list[n] = new uint32_t[n_elements[n]]; - memset(store[n], 0x00, (n_elements[n] * element_sizes[n])); - memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list))); //TODO checkme - } -} - -template -inline LocalPool::~LocalPool(void) { - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - delete[] store[n]; - delete[] size_list[n]; - } -} - -template -inline ReturnValue_t LocalPool::addData( - store_address_t* storageId, const uint8_t* data, uint32_t size, bool ignoreFault) { - ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); - if (status == RETURN_OK) { - write(*storageId, data, size); - } - return status; -} - -template -inline ReturnValue_t LocalPool::getFreeElement( - store_address_t* storageId, const uint32_t size, uint8_t** p_data, bool ignoreFault) { - ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); - if (status == RETURN_OK) { - *p_data = &store[storageId->pool_index][getRawPosition(*storageId)]; - } else { - *p_data = NULL; - } - return status; -} - -template -inline ReturnValue_t LocalPool::getData( - store_address_t packet_id, const uint8_t** packet_ptr, uint32_t* size) { - uint8_t* tempData = NULL; - ReturnValue_t status = modifyData(packet_id, &tempData, size); - *packet_ptr = tempData; - return status; -} - -template -inline ReturnValue_t LocalPool::modifyData(store_address_t packet_id, - uint8_t** packet_ptr, uint32_t* size) { - ReturnValue_t status = RETURN_FAILED; - if (packet_id.pool_index >= NUMBER_OF_POOLS) { - return ILLEGAL_STORAGE_ID; - } - if ((packet_id.packet_index >= n_elements[packet_id.pool_index])) { - return ILLEGAL_STORAGE_ID; - } - if (size_list[packet_id.pool_index][packet_id.packet_index] - != STORAGE_FREE) { - uint32_t packet_position = getRawPosition(packet_id); - *packet_ptr = &store[packet_id.pool_index][packet_position]; - *size = size_list[packet_id.pool_index][packet_id.packet_index]; - status = RETURN_OK; - } else { - status = DATA_DOES_NOT_EXIST; - } - return status; -} - -template -inline ReturnValue_t LocalPool::deleteData( - store_address_t packet_id) { - -// if (getObjectId() == objects::IPC_STORE && packet_id.pool_index >= 3) { -// debug << "Delete: Pool: " << std::dec << packet_id.pool_index << " Index: " << packet_id.packet_index << std::endl; -// } - ReturnValue_t status = RETURN_OK; - uint32_t page_size = getPageSize(packet_id.pool_index); - if ((page_size != 0) - && (packet_id.packet_index < n_elements[packet_id.pool_index])) { - uint16_t packet_position = getRawPosition(packet_id); - uint8_t* ptr = &store[packet_id.pool_index][packet_position]; - memset(ptr, 0, page_size); - //Set free list - size_list[packet_id.pool_index][packet_id.packet_index] = STORAGE_FREE; - } else { - //pool_index or packet_index is too large - sif::error << "LocalPool:deleteData failed." << std::endl; - status = ILLEGAL_STORAGE_ID; - } - return status; -} - -template -inline void LocalPool::clearStore() { - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list)));//TODO checkme - } -} - -template -inline ReturnValue_t LocalPool::deleteData(uint8_t* ptr, - uint32_t size, store_address_t* storeId) { - store_address_t localId; - ReturnValue_t result = ILLEGAL_ADDRESS; - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - //Not sure if new allocates all stores in order. so better be careful. - if ((store[n] <= ptr) && (&store[n][n_elements[n]*element_sizes[n]]) > ptr) { - localId.pool_index = n; - uint32_t deltaAddress = ptr - store[n]; - //Getting any data from the right "block" is ok. This is necessary, as IF's sometimes don't point to the first element of an object. - localId.packet_index = deltaAddress / element_sizes[n]; - result = deleteData(localId); -// if (deltaAddress % element_sizes[n] != 0) { -// error << "Pool::deleteData: address not aligned!" << std::endl; -// } - break; - } - } - if (storeId != NULL) { - *storeId = localId; - } - return result; -} - -template -inline ReturnValue_t LocalPool::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - internalErrorReporter = objectManager->get(objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter == NULL){ - return RETURN_FAILED; - } - - //Check if any pool size is large than the maximum allowed. - for (uint8_t count = 0; count < NUMBER_OF_POOLS; count++) { - if (element_sizes[count] >= STORAGE_FREE) { - sif::error - << "LocalPool::initialize: Pool is too large! Max. allowed size is: " - << (STORAGE_FREE - 1) << std::endl; - return RETURN_FAILED; - } - } - return RETURN_OK; -} +#include #endif /* FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ */ diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp new file mode 100644 index 00000000..32724bd8 --- /dev/null +++ b/storagemanager/LocalPool.tpp @@ -0,0 +1,300 @@ +#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ +#define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ + +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), internalErrorReporter(nullptr), + 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]; + store[n] = new uint8_t[n_elements[n] * element_sizes[n]]; + size_list[n] = new uint32_t[n_elements[n]]; + memset(store[n], 0x00, (n_elements[n] * element_sizes[n])); + //TODO checkme + memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list))); + } +} + + +template +inline ReturnValue_t LocalPool::findEmpty(uint16_t pool_index, + uint16_t* element) { + ReturnValue_t status = DATA_STORAGE_FULL; + for (uint16_t foundElement = 0; foundElement < n_elements[pool_index]; + foundElement++) { + if (size_list[pool_index][foundElement] == STORAGE_FREE) { + *element = foundElement; + status = RETURN_OK; + break; + } + } + return status; +} + +template +inline void LocalPool::write(store_address_t packet_id, + const uint8_t* data, size_t size) { + uint8_t* ptr; + uint32_t packet_position = getRawPosition(packet_id); + + //check size? -> Not necessary, because size is checked before calling this function. + ptr = &store[packet_id.pool_index][packet_position]; + memcpy(ptr, data, size); + size_list[packet_id.pool_index][packet_id.packet_index] = size; +} + +//Returns page size of 0 in case store_index is illegal +template +inline uint32_t LocalPool::getPageSize(uint16_t pool_index) { + if (pool_index < NUMBER_OF_POOLS) { + return element_sizes[pool_index]; + } else { + return 0; + } +} + +template +inline ReturnValue_t LocalPool::getPoolIndex( + size_t packet_size, uint16_t* poolIndex, uint16_t startAtIndex) { + for (uint16_t n = startAtIndex; n < NUMBER_OF_POOLS; n++) { + //debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << + // n << ", Element Size: " << element_sizes[n] << std::endl; + if (element_sizes[n] >= packet_size) { + *poolIndex = n; + return RETURN_OK; + } + } + return DATA_TOO_LARGE; +} + +template +inline uint32_t LocalPool::getRawPosition( + store_address_t packet_id) { + return packet_id.packet_index * element_sizes[packet_id.pool_index]; +} + +template +inline ReturnValue_t LocalPool::reserveSpace( + const uint32_t size, store_address_t* address, bool ignoreFault) { + ReturnValue_t status = getPoolIndex(size, &address->pool_index); + if (status != RETURN_OK) { + sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec + << " )::reserveSpace: Packet too large." << std::endl; + return status; + } + status = findEmpty(address->pool_index, &address->packet_index); + while (status != RETURN_OK && spillsToHigherPools) { + status = getPoolIndex(size, &address->pool_index, address->pool_index + 1); + if (status != RETURN_OK) { + //We don't find any fitting pool anymore. + break; + } + status = findEmpty(address->pool_index, &address->packet_index); + } + if (status == RETURN_OK) { + // if (getObjectId() == objects::IPC_STORE && address->pool_index >= 3) { + // debug << "Reserve: Pool: " << std::dec << address->pool_index << + // " Index: " << address->packet_index << std::endl; + // } + + size_list[address->pool_index][address->packet_index] = size; + } else { + if (!ignoreFault and internalErrorReporter != nullptr) { + internalErrorReporter->storeFull(); + } + // error << "LocalPool( " << std::hex << getObjectId() << std::dec + // << " )::reserveSpace: Packet store is full." << std::endl; + } + return status; +} + +template +inline LocalPool::~LocalPool(void) { + for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { + delete[] store[n]; + delete[] size_list[n]; + } +} + +template inline +ReturnValue_t LocalPool::addData(store_address_t* storageId, + const uint8_t* data, size_t size, bool ignoreFault) { + ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); + if (status == RETURN_OK) { + write(*storageId, data, size); + } + return status; +} + +template +inline ReturnValue_t LocalPool::getFreeElement( + store_address_t* storageId, const size_t size, + uint8_t** p_data, bool ignoreFault) { + ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); + if (status == RETURN_OK) { + *p_data = &store[storageId->pool_index][getRawPosition(*storageId)]; + } else { + *p_data = NULL; + } + return status; +} + +template +inline ConstAccessorPair LocalPool::getData( + store_address_t storeId) { + uint8_t* tempData = nullptr; + ConstStorageAccessor constAccessor(storeId, this); + ReturnValue_t status = modifyData(storeId, &tempData, &constAccessor.size_); + constAccessor.constDataPointer = tempData; + return ConstAccessorPair(status, std::move(constAccessor)); +} + +template +inline ReturnValue_t LocalPool::getData(store_address_t storeId, + ConstStorageAccessor& storeAccessor) { + uint8_t* tempData = nullptr; + ReturnValue_t status = modifyData(storeId, &tempData, &storeAccessor.size_); + storeAccessor.assignStore(this); + storeAccessor.constDataPointer = tempData; + return status; +} + +template +inline ReturnValue_t LocalPool::getData( + 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; + return status; +} + +template +inline AccessorPair LocalPool::modifyData( + store_address_t storeId) { + StorageAccessor accessor(storeId, this); + ReturnValue_t status = modifyData(storeId, &accessor.dataPointer, + &accessor.size_); + accessor.assignConstPointer(); + return AccessorPair(status, std::move(accessor)); +} + +template +inline ReturnValue_t LocalPool::modifyData( + store_address_t storeId, StorageAccessor& storeAccessor) { + storeAccessor.assignStore(this); + ReturnValue_t status = modifyData(storeId, &storeAccessor.dataPointer, + &storeAccessor.size_); + storeAccessor.assignConstPointer(); + return status; +} + +template +inline ReturnValue_t LocalPool::modifyData( + store_address_t packet_id, uint8_t** packet_ptr, size_t* size) { + ReturnValue_t status = RETURN_FAILED; + if (packet_id.pool_index >= NUMBER_OF_POOLS) { + return ILLEGAL_STORAGE_ID; + } + if ((packet_id.packet_index >= n_elements[packet_id.pool_index])) { + return ILLEGAL_STORAGE_ID; + } + if (size_list[packet_id.pool_index][packet_id.packet_index] + != STORAGE_FREE) { + uint32_t packet_position = getRawPosition(packet_id); + *packet_ptr = &store[packet_id.pool_index][packet_position]; + *size = size_list[packet_id.pool_index][packet_id.packet_index]; + status = RETURN_OK; + } else { + status = DATA_DOES_NOT_EXIST; + } + return status; +} + +template +inline ReturnValue_t LocalPool::deleteData( + store_address_t packet_id) { + //if (getObjectId() == objects::IPC_STORE && packet_id.pool_index >= 3) { + // debug << "Delete: Pool: " << std::dec << packet_id.pool_index << " Index: " + // << packet_id.packet_index << std::endl; + //} + ReturnValue_t status = RETURN_OK; + uint32_t page_size = getPageSize(packet_id.pool_index); + if ((page_size != 0) + && (packet_id.packet_index < n_elements[packet_id.pool_index])) { + uint16_t packet_position = getRawPosition(packet_id); + uint8_t* ptr = &store[packet_id.pool_index][packet_position]; + memset(ptr, 0, page_size); + //Set free list + size_list[packet_id.pool_index][packet_id.packet_index] = STORAGE_FREE; + } else { + //pool_index or packet_index is too large + sif::error << "LocalPool:deleteData failed." << std::endl; + status = ILLEGAL_STORAGE_ID; + } + return status; +} + +template +inline void LocalPool::clearStore() { + for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { + //TODO checkme + memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list))); + } +} + +template +inline ReturnValue_t LocalPool::deleteData(uint8_t* ptr, + size_t size, store_address_t* storeId) { + store_address_t localId; + ReturnValue_t result = ILLEGAL_ADDRESS; + for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { + //Not sure if new allocates all stores in order. so better be careful. + if ((store[n] <= ptr) && (&store[n][n_elements[n]*element_sizes[n]]) > ptr) { + localId.pool_index = n; + uint32_t deltaAddress = ptr - store[n]; + // Getting any data from the right "block" is ok. + // This is necessary, as IF's sometimes don't point to the first + // element of an object. + localId.packet_index = deltaAddress / element_sizes[n]; + result = deleteData(localId); + //if (deltaAddress % element_sizes[n] != 0) { + // error << "Pool::deleteData: address not aligned!" << std::endl; + //} + break; + } + } + if (storeId != NULL) { + *storeId = localId; + } + return result; +} + +template +inline ReturnValue_t LocalPool::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter == nullptr){ + return ObjectManagerIF::INTERNAL_ERR_REPORTER_UNINIT; + } + + //Check if any pool size is large than the maximum allowed. + for (uint8_t count = 0; count < NUMBER_OF_POOLS; count++) { + if (element_sizes[count] >= STORAGE_FREE) { + sif::error << "LocalPool::initialize: Pool is too large! " + "Max. allowed size is: " << (STORAGE_FREE - 1) << std::endl; + return StorageManagerIF::POOL_TOO_LARGE; + } + } + return RETURN_OK; +} + +#endif diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 68a7addc..6e353de2 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -1,86 +1,44 @@ -/** - * @file PoolManager - * - * @date 02.02.2012 - * @author Bastian Baetz - * - * @brief This file contains the definition of the PoolManager class. - */ - -#ifndef POOLMANAGER_H_ -#define POOLMANAGER_H_ - +#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ +#define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ #include #include +#include /** * @brief The PoolManager class provides an intermediate data storage with * a fixed pool size policy for inter-process communication. - * \details Uses local pool, but is thread-safe. + * @details Uses local pool calls but is thread safe by protecting the call + * with a lock. */ - -template +template class PoolManager : public LocalPool { +public: + PoolManager(object_id_t setObjectId, + const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS]); + + //! @brief In the PoolManager's destructor all allocated memory is freed. + virtual ~PoolManager(); + + //! @brief LocalPool overrides for thread-safety. Decorator function which + //! wraps LocalPool calls with a mutex protection. + ReturnValue_t deleteData(store_address_t) override; + ReturnValue_t deleteData(uint8_t* buffer, size_t size, + store_address_t* storeId = nullptr) override; protected: - /** - * Overwritten for thread safety. - * Locks during execution. - */ - virtual ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault); + ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, + bool ignoreFault) override; /** - * \brief The mutex is created in the constructor and makes access mutual exclusive. - * \details Locking and unlocking is done during searching for free slots and deleting existing slots. + * @brief The mutex is created in the constructor and makes + * access mutual exclusive. + * @details Locking and unlocking is done during searching for free slots + * and deleting existing slots. */ - MutexIF* mutex; -public: - PoolManager( object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], const uint16_t n_elements[NUMBER_OF_POOLS] ); - /** - * @brief In the PoolManager's destructor all allocated memory is freed. - */ - virtual ~PoolManager( void ); - /** - * Overwritten for thread safety. - */ - virtual ReturnValue_t deleteData(store_address_t); - virtual ReturnValue_t deleteData(uint8_t* buffer, uint32_t size, store_address_t* storeId = NULL); + MutexIF* mutex; }; -template -inline ReturnValue_t PoolManager::reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault) { - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); - ReturnValue_t status = LocalPool::reserveSpace(size,address,ignoreFault); - return status; -} - -template -inline PoolManager::PoolManager(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS]) : LocalPool(setObjectId, element_sizes, n_elements, true) { - mutex = MutexFactory::instance()->createMutex(); -} - -template -inline PoolManager::~PoolManager(void) { - MutexFactory::instance()->deleteMutex(mutex); -} - -template -inline ReturnValue_t PoolManager::deleteData( - store_address_t packet_id) { - // debug << "PoolManager( " << translateObject(getObjectId()) << " )::deleteData from store " << packet_id.pool_index << ". id is " << packet_id.packet_index << std::endl; - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); - ReturnValue_t status = LocalPool::deleteData(packet_id); - return status; -} - -template -inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, uint32_t size, - store_address_t* storeId) { - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); - ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId); - return status; -} +#include "PoolManager.tpp" #endif /* POOLMANAGER_H_ */ diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp new file mode 100644 index 00000000..854e22da --- /dev/null +++ b/storagemanager/PoolManager.tpp @@ -0,0 +1,47 @@ +#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ +#define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ + +template +inline PoolManager::PoolManager(object_id_t setObjectId, + const uint16_t element_sizes[NUMBER_OF_POOLS], + const uint16_t n_elements[NUMBER_OF_POOLS]) : + LocalPool(setObjectId, element_sizes, n_elements, true) { + mutex = MutexFactory::instance()->createMutex(); +} + +template +inline PoolManager::~PoolManager(void) { + MutexFactory::instance()->deleteMutex(mutex); +} + +template +inline ReturnValue_t PoolManager::reserveSpace( + const uint32_t size, store_address_t* address, bool ignoreFault) { + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::reserveSpace(size, + address,ignoreFault); + return status; +} + +template +inline ReturnValue_t PoolManager::deleteData( + store_address_t packet_id) { + // debug << "PoolManager( " << translateObject(getObjectId()) << + // " )::deleteData from store " << packet_id.pool_index << + // ". id is "<< packet_id.packet_index << std::endl; + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::deleteData(packet_id); + return status; +} + +template +inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, + size_t size, store_address_t* storeId) { + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::deleteData(buffer, + size, storeId); + return status; +} + +#endif + diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp new file mode 100644 index 00000000..c0c8126b --- /dev/null +++ b/storagemanager/StorageAccessor.cpp @@ -0,0 +1,155 @@ +#include +#include + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): + storeId(storeId) {} + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, + StorageManagerIF* store): + storeId(storeId), store(store) { + internalState = AccessState::ASSIGNED; +} + +ConstStorageAccessor::~ConstStorageAccessor() { + if(deleteData and store != nullptr) { + sif::debug << "deleting store data" << std::endl; + store->deleteData(storeId); + } +} + +ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): + constDataPointer(other.constDataPointer), storeId(other.storeId), + size_(other.size_), store(other.store), deleteData(other.deleteData), + internalState(other.internalState) { + // This prevent premature deletion + other.store = nullptr; +} + +ConstStorageAccessor& ConstStorageAccessor::operator=( + ConstStorageAccessor&& other) { + constDataPointer = other.constDataPointer; + storeId = other.storeId; + store = other.store; + size_ = other.size_; + deleteData = other.deleteData; + this->store = other.store; + // This prevents premature deletion + other.store = nullptr; + return *this; +} + +const uint8_t* ConstStorageAccessor::data() const { + return constDataPointer; +} + +size_t ConstStorageAccessor::size() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return size_; +} + +ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, + size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(constDataPointer, constDataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +void ConstStorageAccessor::release() { + deleteData = false; +} + +store_address_t ConstStorageAccessor::getId() const { + return storeId; +} + +void ConstStorageAccessor::print() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return; + } + sif::info << "StorageAccessor: Printing data: ["; + for(uint16_t iPool = 0; iPool < size_; iPool++) { + sif::info << std::hex << (int)constDataPointer[iPool]; + if(iPool < size_ - 1){ + sif::info << " , "; + } + } + sif::info << " ] " << std::endl; +} + +void ConstStorageAccessor::assignStore(StorageManagerIF* store) { + internalState = AccessState::ASSIGNED; + this->store = store; +} + + +StorageAccessor::StorageAccessor(store_address_t storeId): + ConstStorageAccessor(storeId) { +} + +StorageAccessor::StorageAccessor(store_address_t storeId, + StorageManagerIF* store): + ConstStorageAccessor(storeId, store) { +} + +StorageAccessor& StorageAccessor::operator =( + StorageAccessor&& other) { + // Call the parent move assignment and also assign own member. + dataPointer = other.dataPointer; + StorageAccessor::operator=(std::move(other)); + return * this; +} + +// Call the parent move ctor and also transfer own member. +StorageAccessor::StorageAccessor(StorageAccessor&& other): + ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { +} + +ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(dataPointer, dataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t* StorageAccessor::data() { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return dataPointer; +} + +ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, + uint16_t offset) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(offset + size > size_) { + sif::error << "StorageAccessor: Data too large for pool entry!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(data, data + size, dataPointer + offset); + return HasReturnvaluesIF::RETURN_OK; +} + +void StorageAccessor::assignConstPointer() { + constDataPointer = dataPointer; +} + + diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h new file mode 100644 index 00000000..57c9369c --- /dev/null +++ b/storagemanager/StorageAccessor.h @@ -0,0 +1,151 @@ +#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ + +#include +#include + +class StorageManagerIF; + +/** + * @brief Helper classes to facilitate safe access to storages which is also + * conforming to RAII principles + * @details + * Accessor class which can be returned by pool manager or passed and set by + * pool managers to have safe access to the pool resources. + * + * These helper can be used together with the StorageManager classes to manage + * access to a storage. It can take care of thread-safety while also providing + * mechanisms to automatically clear storage data. + */ +class ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + /** + * @brief Simple constructor which takes the store ID of the storage + * entry to access. + * @param storeId + */ + ConstStorageAccessor(store_address_t storeId); + ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief The destructor in default configuration takes care of + * deleting the accessed pool entry and unlocking the mutex + */ + virtual ~ConstStorageAccessor(); + + /** + * @brief Returns a pointer to the read-only data + * @return + */ + const uint8_t* data() const; + + /** + * @brief Copies the read-only data to the supplied pointer + * @param pointer + */ + virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); + + /** + * @brief Calling this will prevent the Accessor from deleting the data + * when the destructor is called. + */ + void release(); + + /** + * Get the size of the data + * @return + */ + size_t size() const; + + /** + * Get the storage ID. + * @return + */ + store_address_t getId() const; + + void print() const; + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + ConstStorageAccessor& operator= (ConstStorageAccessor&&); + ConstStorageAccessor (ConstStorageAccessor&&); + + //! The copy ctor and copy assignemnt should be deleted implicitely + //! according to https://foonathan.net/2019/02/special-member-functions/ + //! but I still deleted them to make it more explicit. (remember rule of 5). + ConstStorageAccessor& operator= (ConstStorageAccessor&) = delete; + ConstStorageAccessor (ConstStorageAccessor&) = delete; +protected: + const uint8_t* constDataPointer = nullptr; + store_address_t storeId; + size_t size_ = 0; + //! Managing pool, has to assign itself. + StorageManagerIF* store = nullptr; + bool deleteData = true; + + enum class AccessState { + UNINIT, + ASSIGNED + }; + //! Internal state for safety reasons. + AccessState internalState = AccessState::UNINIT; + /** + * Used by the pool manager instances to assign themselves to the + * accessor. This is necessary to delete the data when the acessor + * exits the scope ! The internal state will be considered read + * when this function is called, so take care all data is set properly as + * well. + * @param + */ + void assignStore(StorageManagerIF*); +}; + + +/** + * @brief Child class for modifyable data. Also has a normal pointer member. + */ +class StorageAccessor: public ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + StorageAccessor(store_address_t storeId); + StorageAccessor(store_address_t storeId, StorageManagerIF* store); + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + StorageAccessor& operator= (StorageAccessor&&); + StorageAccessor (StorageAccessor&&); + + ReturnValue_t write(uint8_t *data, size_t size, + uint16_t offset = 0); + uint8_t* data(); + ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize) override; + +private: + //! Non-const pointer for modifyable data. + uint8_t* dataPointer = nullptr; + //! For modifyable data, the const pointer is assigned to the normal + //! pointer by the pool manager so both access functions can be used safely + void assignConstPointer(); +}; + +#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index a0c2b23d..d5ac5818 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -3,56 +3,14 @@ #include #include -#include +#include +#include +#include +#include -/** - * This union defines the type that identifies where a data packet is stored in the store. - * It comprises of a raw part to read it as raw value and a structured part to use it in - * pool-like stores. - */ -union store_address_t { - /** - * Default Constructor, initializing to INVALID_ADDRESS - */ - store_address_t():raw(0xFFFFFFFF){} - /** - * Constructor to create an address object using the raw address - * - * @param rawAddress - */ - store_address_t(uint32_t rawAddress):raw(rawAddress){} +using AccessorPair = std::pair; +using ConstAccessorPair = std::pair; - /** - * Constructor to create an address object using pool - * and packet indices - * - * @param poolIndex - * @param packetIndex - */ - store_address_t(uint16_t poolIndex, uint16_t packetIndex): - pool_index(poolIndex),packet_index(packetIndex){} - /** - * A structure with two elements to access the store address pool-like. - */ - struct { - /** - * The index in which pool the packet lies. - */ - uint16_t pool_index; - /** - * The position in the chosen pool. - */ - uint16_t packet_index; - }; - /** - * Alternative access to the raw value. - */ - uint32_t raw; - - bool operator==(const store_address_t& other) const { - return raw == other.raw; - } -}; /** * @brief This class provides an interface for intermediate data storage. @@ -75,6 +33,7 @@ public: static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); + static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); @@ -98,7 +57,8 @@ public: * @li RETURN_FAILED if data could not be added. * storageId is unchanged then. */ - virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, uint32_t size, bool ignoreFault = false) = 0; + virtual ReturnValue_t addData(store_address_t* storageId, + const uint8_t * data, size_t size, bool ignoreFault = false) = 0; /** * @brief With deleteData, the storageManager frees the memory region * identified by packet_id. @@ -109,14 +69,37 @@ public: */ virtual ReturnValue_t deleteData(store_address_t packet_id) = 0; /** - * @brief Another deleteData which uses the pointer and size of the stored data to delete the content. + * @brief Another deleteData which uses the pointer and size of the + * stored data to delete the content. * @param buffer Pointer to the data. * @param size Size of data to be stored. * @param storeId Store id of the deleted element (optional) * @return @li RETURN_OK on success. * @li failure code if deletion did not work */ - virtual ReturnValue_t deleteData(uint8_t* buffer, uint32_t size, store_address_t* storeId = NULL) = 0; + virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, + store_address_t* storeId = nullptr) = 0; + + /** + * @brief Access the data by supplying a store ID. + * @details + * A pair consisting of the retrieval result and an instance of a + * ConstStorageAccessor class is returned + * @param storeId + * @return Pair of return value and a ConstStorageAccessor instance + */ + virtual ConstAccessorPair getData(store_address_t storeId) = 0; + + /** + * @brief Access the data by supplying a store ID and a helper + * instance + * @param storeId + * @param constAccessor Wrapper function to access store data. + * @return + */ + virtual ReturnValue_t getData(store_address_t storeId, + ConstStorageAccessor& constAccessor) = 0; + /** * @brief getData returns an address to data and the size of the data * for a given packet_id. @@ -129,12 +112,34 @@ 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. + * Modify data by supplying a store ID + * @param storeId + * @return Pair of return value and StorageAccessor helper + */ + virtual AccessorPair modifyData(store_address_t storeId) = 0; + + /** + * Modify data by supplying a store ID and a StorageAccessor helper instance. + * @param storeId + * @param accessor Helper class to access the modifiable data. + * @return + */ + virtual ReturnValue_t modifyData(store_address_t storeId, + StorageAccessor& accessor) = 0; + + /** + * Get pointer and size of modifiable data by supplying the storeId + * @param packet_id + * @param packet_ptr [out] Pointer to pointer of data to set + * @param size [out] Pointer to size to set + * @return */ 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. * @@ -148,13 +153,14 @@ public: * @li RETURN_FAILED if data could not be added. * storageId is unchanged then. */ - virtual ReturnValue_t getFreeElement(store_address_t* storageId, const uint32_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; + virtual ReturnValue_t getFreeElement(store_address_t* storageId, + const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; + /** * Clears the whole store. * Use with care! */ virtual void clearStore() = 0; - }; #endif /* STORAGEMANAGERIF_H_ */ diff --git a/storagemanager/storeAddress.h b/storagemanager/storeAddress.h new file mode 100644 index 00000000..5dd785a3 --- /dev/null +++ b/storagemanager/storeAddress.h @@ -0,0 +1,54 @@ +#ifndef FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ +#define FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ +#include + +/** + * This union defines the type that identifies where a data packet is + * stored in the store. It comprises of a raw part to read it as raw value and + * a structured part to use it in pool-like stores. + */ +union store_address_t { + /** + * Default Constructor, initializing to INVALID_ADDRESS + */ + store_address_t():raw(0xFFFFFFFF){} + /** + * Constructor to create an address object using the raw address + * + * @param rawAddress + */ + store_address_t(uint32_t rawAddress):raw(rawAddress){} + + /** + * Constructor to create an address object using pool + * and packet indices + * + * @param poolIndex + * @param packetIndex + */ + store_address_t(uint16_t poolIndex, uint16_t packetIndex): + pool_index(poolIndex),packet_index(packetIndex){} + /** + * A structure with two elements to access the store address pool-like. + */ + struct { + /** + * The index in which pool the packet lies. + */ + uint16_t pool_index; + /** + * The position in the chosen pool. + */ + uint16_t packet_index; + }; + /** + * Alternative access to the raw value. + */ + uint32_t raw; + + bool operator==(const store_address_t& other) const { + return raw == other.raw; + } +}; + +#endif /* FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ */ From d83181cb0fddcb9ad8f2572151058ca97c2e0a96 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:41:23 +0200 Subject: [PATCH 02/53] added author tag --- storagemanager/LocalPool.h | 1 + 1 file changed, 1 insertion(+) diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index c155f918..2d61dea5 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -22,6 +22,7 @@ * 0xFFFF-1 bytes. * It is possible to store empty packets in the pool. * The local pool is NOT thread-safe. + * @author Bastian Baetz */ template From a993223f6e32ed278b5739d407411466bea83c47 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:44:31 +0200 Subject: [PATCH 03/53] added include protection --- storagemanager/LocalPool.tpp | 4 ++++ storagemanager/PoolManager.tpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index 32724bd8..dd360a0a 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ +#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ +#error Include LocalPool.h instead of LocalPool.tpp!. +#endif + template inline LocalPool::LocalPool(object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index 854e22da..bdc73ec2 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ +#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ +#error Include LocalPool.h instead of LocalPool.tpp!. +#endif + template inline PoolManager::PoolManager(object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], From ab17e284052297a4ab94852ecbc331a7add97159 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:45:52 +0200 Subject: [PATCH 04/53] include protection output fix --- storagemanager/LocalPool.tpp | 2 +- storagemanager/PoolManager.tpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index dd360a0a..b7fa0da9 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -2,7 +2,7 @@ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -#error Include LocalPool.h instead of LocalPool.tpp!. +#error Include LocalPool.h instead of LocalPool.tpp! #endif template diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index bdc73ec2..97603246 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -2,7 +2,7 @@ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ -#error Include LocalPool.h instead of LocalPool.tpp!. +#error Include LocalPool.h instead of LocalPool.tpp! #endif template From acf037614ff9795ee1bea4875d76415a61388835 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:48:53 +0200 Subject: [PATCH 05/53] added another author tag --- storagemanager/PoolManager.h | 1 + 1 file changed, 1 insertion(+) diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 6e353de2..c74e95c0 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -10,6 +10,7 @@ * a fixed pool size policy for inter-process communication. * @details Uses local pool calls but is thread safe by protecting the call * with a lock. + * @author Bastian Baetz */ template class PoolManager : public LocalPool { From a3f379e149dd32e4ac90e1fd58038138d8a65701 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 16:50:37 +0200 Subject: [PATCH 06/53] and another little include guard fix --- storagemanager/LocalPool.tpp | 2 +- storagemanager/PoolManager.tpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index b7fa0da9..764bd7be 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -2,7 +2,7 @@ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -#error Include LocalPool.h instead of LocalPool.tpp! +#error Include LocalPool.h before LocalPool.tpp! #endif template diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index 97603246..29b2b82a 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -2,7 +2,7 @@ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ -#error Include LocalPool.h instead of LocalPool.tpp! +#error Include PoolManager.h before PoolManager.tpp! #endif template From f871f75e1c8fd5f625e4a2067492eb92f3b82289 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 17:10:57 +0200 Subject: [PATCH 07/53] added back default value for pool manager.h --- storagemanager/PoolManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index c74e95c0..144d073d 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -12,7 +12,7 @@ * with a lock. * @author Bastian Baetz */ -template +template class PoolManager : public LocalPool { public: PoolManager(object_id_t setObjectId, From 8e3f99a350be66308d9afabae8069426f67ce8e6 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 4 Jun 2020 14:59:14 +0200 Subject: [PATCH 08/53] removed object manager changes for now --- objectmanager/ObjectManagerIF.h | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/objectmanager/ObjectManagerIF.h b/objectmanager/ObjectManagerIF.h index b5cab408..aca24a24 100644 --- a/objectmanager/ObjectManagerIF.h +++ b/objectmanager/ObjectManagerIF.h @@ -8,11 +8,10 @@ #ifndef OBJECTMANAGERIF_H_ #define OBJECTMANAGERIF_H_ -#include "systemObjectList.h" #include +#include #include #include -#include /** * @brief This class provides an interface to the global object manager. @@ -25,12 +24,9 @@ */ class ObjectManagerIF : public HasReturnvaluesIF { public: - static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; - static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); - static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); - static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); - static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 ); - + static const uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; + static const ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); + static const ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); protected: /** * @brief This method is used to hide the template-based get call from @@ -82,22 +78,15 @@ public: virtual void printList() = 0; }; +template +T* ObjectManagerIF::get( object_id_t id ) { + SystemObjectIF* temp = this->getSystemObject(id); + return dynamic_cast(temp); +} /** * @brief This is the forward declaration of the global objectManager instance. */ extern ObjectManagerIF *objectManager; -/*Documentation can be found in the class method declaration above.*/ -template -T* ObjectManagerIF::get( object_id_t id ) { - if(objectManager == nullptr) { - sif::error << "ObjectManagerIF: Global object manager has not " - "been initialized yet!" << std::endl; - std::exit(0); - } - SystemObjectIF* temp = this->getSystemObject(id); - return dynamic_cast(temp); -} - #endif /* OBJECTMANAGERIF_H_ */ From 1d99a99bbd79942b5f034705fd74f4e599b47444 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 4 Jun 2020 15:00:05 +0200 Subject: [PATCH 09/53] I now remember why I included object manager IF changes --- objectmanager/ObjectManagerIF.h | 42 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/objectmanager/ObjectManagerIF.h b/objectmanager/ObjectManagerIF.h index aca24a24..0dfb7f30 100644 --- a/objectmanager/ObjectManagerIF.h +++ b/objectmanager/ObjectManagerIF.h @@ -1,17 +1,10 @@ -/** - * @file ObjectManagerIF.h - * @brief This file contains the implementation of the ObjectManagerIF interface - * @date 19.09.2012 - * @author Bastian Baetz - */ - -#ifndef OBJECTMANAGERIF_H_ -#define OBJECTMANAGERIF_H_ +#ifndef FRAMEWORK_OBJECTMANAGER_OBJECTMANAGERIF_H_ +#define FRAMEWORK_OBJECTMANAGER_OBJECTMANAGERIF_H_ #include -#include #include #include +#include /** * @brief This class provides an interface to the global object manager. @@ -20,13 +13,17 @@ * inserted, removed and retrieved from the list. On getting the * object, the call checks if the object implements the requested * interface. - * \ingroup system_objects + * @author Bastian Baetz + * @ingroup system_objects */ class ObjectManagerIF : public HasReturnvaluesIF { public: - static const uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; - static const ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); - static const ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); + static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; + static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); + static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); + static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); + static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 ); + protected: /** * @brief This method is used to hide the template-based get call from @@ -78,15 +75,22 @@ public: virtual void printList() = 0; }; -template -T* ObjectManagerIF::get( object_id_t id ) { - SystemObjectIF* temp = this->getSystemObject(id); - return dynamic_cast(temp); -} /** * @brief This is the forward declaration of the global objectManager instance. */ extern ObjectManagerIF *objectManager; +/*Documentation can be found in the class method declaration above.*/ +template +T* ObjectManagerIF::get( object_id_t id ) { + if(objectManager == nullptr) { + sif::error << "ObjectManagerIF: Global object manager has not " + "been initialized yet!" << std::endl; + std::exit(1); + } + SystemObjectIF* temp = this->getSystemObject(id); + return dynamic_cast(temp); +} + #endif /* OBJECTMANAGERIF_H_ */ From 3d175f603c0cfdb1a8b1c7185ab15ad248f164a6 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 4 Jun 2020 15:02:14 +0200 Subject: [PATCH 10/53] removed conflict markers --- storagemanager/LocalPool.h | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index d842294c..7e349dcd 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -1,12 +1,3 @@ -<<<<<<< HEAD -======= -/** - * @file LocalPool - * @date 02.02.2012 - * @author Bastian Baetz - * @brief This file contains the definition of the LocalPool class. - */ ->>>>>>> upstream/master #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ @@ -44,7 +35,7 @@ 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 + * 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. @@ -96,7 +87,7 @@ public: ReturnValue_t initialize() override; protected: /** - * With this helper method, a free element of \c size is reserved. + * 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, @@ -109,7 +100,8 @@ protected: private: /** * Indicates that this element is free. - * This value limits the maximum size of a pool. Change to larger data type if increase is required. + * This value limits the maximum size of a pool. Change to larger data type + * if increase is required. */ static const uint32_t STORAGE_FREE = 0xFFFFFFFF; /** @@ -135,7 +127,9 @@ private: * is also dynamically allocated there. */ uint32_t* size_list[NUMBER_OF_POOLS]; - bool spillsToHigherPools; //!< A variable to determine whether higher n pools are used if the store is full. + //! A variable to determine whether higher n pools are used if + //! the store is full. + bool spillsToHigherPools; /** * @brief This method safely stores the given data in the given packet_id. * @details It also sets the size in size_list. The method does not perform From a6a31801960dca7a5949daece14c1843caaa9baf Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 4 Jun 2020 15:03:29 +0200 Subject: [PATCH 11/53] removed conflict markers --- storagemanager/PoolManager.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index cbb5d54b..7c2e8a71 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -22,20 +22,12 @@ public: //! @brief In the PoolManager's destructor all allocated memory is freed. virtual ~PoolManager(); -<<<<<<< HEAD //! @brief LocalPool overrides for thread-safety. Decorator function which //! wraps LocalPool calls with a mutex protection. ReturnValue_t deleteData(store_address_t) override; ReturnValue_t deleteData(uint8_t* buffer, size_t size, store_address_t* storeId = nullptr) override; -======= - //! @brief LocalPool overrides for thread-safety. - ReturnValue_t deleteData(store_address_t) override; - ReturnValue_t deleteData(uint8_t* buffer, size_t size, - store_address_t* storeId = NULL) override; - ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, - size_t* size) override; ->>>>>>> upstream/master + protected: ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault) override; From 4c59b043e13aa8f21949d9adf9662e75ecb98611 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 23 Jun 2020 10:57:14 +0200 Subject: [PATCH 12/53] const store accessor in separate file now --- storagemanager/ConstStoreAccessor.cpp | 93 +++++++++++++++++++++ storagemanager/ConstStoreAccessor.h | 116 ++++++++++++++++++++++++++ storagemanager/StorageAccessor.cpp | 98 ++-------------------- storagemanager/StorageAccessor.h | 109 +----------------------- 4 files changed, 215 insertions(+), 201 deletions(-) create mode 100644 storagemanager/ConstStoreAccessor.cpp create mode 100644 storagemanager/ConstStoreAccessor.h diff --git a/storagemanager/ConstStoreAccessor.cpp b/storagemanager/ConstStoreAccessor.cpp new file mode 100644 index 00000000..84f40053 --- /dev/null +++ b/storagemanager/ConstStoreAccessor.cpp @@ -0,0 +1,93 @@ +#include +#include +#include + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): + storeId(storeId) {} + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, + StorageManagerIF* store): + storeId(storeId), store(store) { + internalState = AccessState::ASSIGNED; +} + +ConstStorageAccessor::~ConstStorageAccessor() { + if(deleteData and store != nullptr) { + sif::debug << "deleting store data" << std::endl; + store->deleteData(storeId); + } +} + +ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): + constDataPointer(other.constDataPointer), storeId(other.storeId), + size_(other.size_), store(other.store), deleteData(other.deleteData), + internalState(other.internalState) { + // This prevent premature deletion + other.store = nullptr; +} + +ConstStorageAccessor& ConstStorageAccessor::operator=( + ConstStorageAccessor&& other) { + constDataPointer = other.constDataPointer; + storeId = other.storeId; + store = other.store; + size_ = other.size_; + deleteData = other.deleteData; + this->store = other.store; + // This prevents premature deletion + other.store = nullptr; + return *this; +} + +const uint8_t* ConstStorageAccessor::data() const { + return constDataPointer; +} + +size_t ConstStorageAccessor::size() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return size_; +} + +ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, + size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(constDataPointer, constDataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +void ConstStorageAccessor::release() { + deleteData = false; +} + +store_address_t ConstStorageAccessor::getId() const { + return storeId; +} + +void ConstStorageAccessor::print() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return; + } + sif::info << "StorageAccessor: Printing data: ["; + for(uint16_t iPool = 0; iPool < size_; iPool++) { + sif::info << std::hex << (int)constDataPointer[iPool]; + if(iPool < size_ - 1){ + sif::info << " , "; + } + } + sif::info << " ] " << std::endl; +} + +void ConstStorageAccessor::assignStore(StorageManagerIF* store) { + internalState = AccessState::ASSIGNED; + this->store = store; +} diff --git a/storagemanager/ConstStoreAccessor.h b/storagemanager/ConstStoreAccessor.h new file mode 100644 index 00000000..2420893c --- /dev/null +++ b/storagemanager/ConstStoreAccessor.h @@ -0,0 +1,116 @@ +#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTOREACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_CONSTSTOREACCESSOR_H_ + +#include +#include +#include + +class StorageManagerIF; + +/** + * @brief Helper classes to facilitate safe access to storages which is also + * conforming to RAII principles + * @details + * Accessor class which can be returned by pool manager or passed and set by + * pool managers to have safe access to the pool resources. + * + * These helper can be used together with the StorageManager classes to manage + * access to a storage. It can take care of thread-safety while also providing + * mechanisms to automatically clear storage data. + */ +class ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + /** + * @brief Simple constructor which takes the store ID of the storage + * entry to access. + * @param storeId + */ + ConstStorageAccessor(store_address_t storeId); + ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief The destructor in default configuration takes care of + * deleting the accessed pool entry and unlocking the mutex + */ + virtual ~ConstStorageAccessor(); + + /** + * @brief Returns a pointer to the read-only data + * @return + */ + const uint8_t* data() const; + + /** + * @brief Copies the read-only data to the supplied pointer + * @param pointer + */ + virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); + + /** + * @brief Calling this will prevent the Accessor from deleting the data + * when the destructor is called. + */ + void release(); + + /** + * Get the size of the data + * @return + */ + size_t size() const; + + /** + * Get the storage ID. + * @return + */ + store_address_t getId() const; + + void print() const; + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + ConstStorageAccessor& operator= (ConstStorageAccessor&&); + ConstStorageAccessor (ConstStorageAccessor&&); + + //! The copy ctor and copy assignemnt should be deleted implicitely + //! according to https://foonathan.net/2019/02/special-member-functions/ + //! but I still deleted them to make it more explicit. (remember rule of 5). + ConstStorageAccessor& operator= (ConstStorageAccessor&) = delete; + ConstStorageAccessor (ConstStorageAccessor&) = delete; +protected: + const uint8_t* constDataPointer = nullptr; + store_address_t storeId; + size_t size_ = 0; + //! Managing pool, has to assign itself. + StorageManagerIF* store = nullptr; + bool deleteData = true; + + enum class AccessState { + UNINIT, + ASSIGNED + }; + //! Internal state for safety reasons. + AccessState internalState = AccessState::UNINIT; + /** + * Used by the pool manager instances to assign themselves to the + * accessor. This is necessary to delete the data when the acessor + * exits the scope ! The internal state will be considered read + * when this function is called, so take care all data is set properly as + * well. + * @param + */ + void assignStore(StorageManagerIF*); +}; + + +#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTOREACCESSOR_H_ */ diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp index c0c8126b..b827b9c0 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/storagemanager/StorageAccessor.cpp @@ -1,96 +1,6 @@ #include #include - -ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): - storeId(storeId) {} - -ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, - StorageManagerIF* store): - storeId(storeId), store(store) { - internalState = AccessState::ASSIGNED; -} - -ConstStorageAccessor::~ConstStorageAccessor() { - if(deleteData and store != nullptr) { - sif::debug << "deleting store data" << std::endl; - store->deleteData(storeId); - } -} - -ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): - constDataPointer(other.constDataPointer), storeId(other.storeId), - size_(other.size_), store(other.store), deleteData(other.deleteData), - internalState(other.internalState) { - // This prevent premature deletion - other.store = nullptr; -} - -ConstStorageAccessor& ConstStorageAccessor::operator=( - ConstStorageAccessor&& other) { - constDataPointer = other.constDataPointer; - storeId = other.storeId; - store = other.store; - size_ = other.size_; - deleteData = other.deleteData; - this->store = other.store; - // This prevents premature deletion - other.store = nullptr; - return *this; -} - -const uint8_t* ConstStorageAccessor::data() const { - return constDataPointer; -} - -size_t ConstStorageAccessor::size() const { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - } - return size_; -} - -ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, - size_t maxSize) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(constDataPointer, constDataPointer + size_, pointer); - return HasReturnvaluesIF::RETURN_OK; -} - -void ConstStorageAccessor::release() { - deleteData = false; -} - -store_address_t ConstStorageAccessor::getId() const { - return storeId; -} - -void ConstStorageAccessor::print() const { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return; - } - sif::info << "StorageAccessor: Printing data: ["; - for(uint16_t iPool = 0; iPool < size_; iPool++) { - sif::info << std::hex << (int)constDataPointer[iPool]; - if(iPool < size_ - 1){ - sif::info << " , "; - } - } - sif::info << " ] " << std::endl; -} - -void ConstStorageAccessor::assignStore(StorageManagerIF* store) { - internalState = AccessState::ASSIGNED; - this->store = store; -} - +#include StorageAccessor::StorageAccessor(store_address_t storeId): ConstStorageAccessor(storeId) { @@ -120,7 +30,8 @@ ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { return HasReturnvaluesIF::RETURN_FAILED; } if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; + sif::error << "StorageAccessor: Supplied buffer not large " + "enough" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } std::copy(dataPointer, dataPointer + size_, pointer); @@ -141,7 +52,8 @@ ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, return HasReturnvaluesIF::RETURN_FAILED; } if(offset + size > size_) { - sif::error << "StorageAccessor: Data too large for pool entry!" << std::endl; + sif::error << "StorageAccessor: Data too large for pool " + "entry!" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } std::copy(data, data + size, dataPointer + offset); diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index 57c9369c..bcefe24d 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -1,117 +1,10 @@ #ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ #define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ -#include -#include +#include class StorageManagerIF; -/** - * @brief Helper classes to facilitate safe access to storages which is also - * conforming to RAII principles - * @details - * Accessor class which can be returned by pool manager or passed and set by - * pool managers to have safe access to the pool resources. - * - * These helper can be used together with the StorageManager classes to manage - * access to a storage. It can take care of thread-safety while also providing - * mechanisms to automatically clear storage data. - */ -class ConstStorageAccessor { - //! StorageManager classes have exclusive access to private variables. - template - friend class PoolManager; - template - friend class LocalPool; -public: - /** - * @brief Simple constructor which takes the store ID of the storage - * entry to access. - * @param storeId - */ - ConstStorageAccessor(store_address_t storeId); - ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); - - /** - * @brief The destructor in default configuration takes care of - * deleting the accessed pool entry and unlocking the mutex - */ - virtual ~ConstStorageAccessor(); - - /** - * @brief Returns a pointer to the read-only data - * @return - */ - const uint8_t* data() const; - - /** - * @brief Copies the read-only data to the supplied pointer - * @param pointer - */ - virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); - - /** - * @brief Calling this will prevent the Accessor from deleting the data - * when the destructor is called. - */ - void release(); - - /** - * Get the size of the data - * @return - */ - size_t size() const; - - /** - * Get the storage ID. - * @return - */ - store_address_t getId() const; - - void print() const; - - /** - * @brief Move ctor and move assignment allow returning accessors as - * a returnvalue. They prevent resource being free prematurely. - * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ - * move-constructors-and-move-assignment-operators-cpp.md - * @param - * @return - */ - ConstStorageAccessor& operator= (ConstStorageAccessor&&); - ConstStorageAccessor (ConstStorageAccessor&&); - - //! The copy ctor and copy assignemnt should be deleted implicitely - //! according to https://foonathan.net/2019/02/special-member-functions/ - //! but I still deleted them to make it more explicit. (remember rule of 5). - ConstStorageAccessor& operator= (ConstStorageAccessor&) = delete; - ConstStorageAccessor (ConstStorageAccessor&) = delete; -protected: - const uint8_t* constDataPointer = nullptr; - store_address_t storeId; - size_t size_ = 0; - //! Managing pool, has to assign itself. - StorageManagerIF* store = nullptr; - bool deleteData = true; - - enum class AccessState { - UNINIT, - ASSIGNED - }; - //! Internal state for safety reasons. - AccessState internalState = AccessState::UNINIT; - /** - * Used by the pool manager instances to assign themselves to the - * accessor. This is necessary to delete the data when the acessor - * exits the scope ! The internal state will be considered read - * when this function is called, so take care all data is set properly as - * well. - * @param - */ - void assignStore(StorageManagerIF*); -}; - - /** * @brief Child class for modifyable data. Also has a normal pointer member. */ From a589be7c746d9f44b3ef3b47fceaa2ae3cd8412e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 23 Jun 2020 11:06:54 +0200 Subject: [PATCH 13/53] took over imrpvements --- ...tStoreAccessor.cpp => ConstStorageAccessor.cpp} | 14 ++++---------- ...ConstStoreAccessor.h => ConstStorageAccessor.h} | 6 +++--- storagemanager/PoolManager.h | 3 +++ storagemanager/PoolManager.tpp | 6 +++--- storagemanager/StorageAccessor.h | 2 +- 5 files changed, 14 insertions(+), 17 deletions(-) rename storagemanager/{ConstStoreAccessor.cpp => ConstStorageAccessor.cpp} (87%) rename storagemanager/{ConstStoreAccessor.h => ConstStorageAccessor.h} (94%) diff --git a/storagemanager/ConstStoreAccessor.cpp b/storagemanager/ConstStorageAccessor.cpp similarity index 87% rename from storagemanager/ConstStoreAccessor.cpp rename to storagemanager/ConstStorageAccessor.cpp index 84f40053..0bfde58c 100644 --- a/storagemanager/ConstStoreAccessor.cpp +++ b/storagemanager/ConstStorageAccessor.cpp @@ -1,6 +1,7 @@ -#include #include +#include #include +#include ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): storeId(storeId) {} @@ -73,18 +74,11 @@ store_address_t ConstStorageAccessor::getId() const { } void ConstStorageAccessor::print() const { - if(internalState == AccessState::UNINIT) { + if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { sif::warning << "StorageAccessor: Not initialized!" << std::endl; return; } - sif::info << "StorageAccessor: Printing data: ["; - for(uint16_t iPool = 0; iPool < size_; iPool++) { - sif::info << std::hex << (int)constDataPointer[iPool]; - if(iPool < size_ - 1){ - sif::info << " , "; - } - } - sif::info << " ] " << std::endl; + arrayprinter::print(constDataPointer, size_); } void ConstStorageAccessor::assignStore(StorageManagerIF* store) { diff --git a/storagemanager/ConstStoreAccessor.h b/storagemanager/ConstStorageAccessor.h similarity index 94% rename from storagemanager/ConstStoreAccessor.h rename to storagemanager/ConstStorageAccessor.h index 2420893c..cf8ca08f 100644 --- a/storagemanager/ConstStoreAccessor.h +++ b/storagemanager/ConstStorageAccessor.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTOREACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_CONSTSTOREACCESSOR_H_ +#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ #include #include @@ -113,4 +113,4 @@ protected: }; -#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTOREACCESSOR_H_ */ +#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 7c2e8a71..3c1c1217 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -29,6 +29,9 @@ public: store_address_t* storeId = nullptr) override; protected: + //! Default mutex timeout value to prevent permanent blocking. + static constexpr uint32_t mutexTimeout = 50; + ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault) override; diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index a364f5a2..4ca22b85 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -21,7 +21,7 @@ inline PoolManager::~PoolManager(void) { template inline ReturnValue_t PoolManager::reserveSpace( const uint32_t size, store_address_t* address, bool ignoreFault) { - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + MutexHelper mutexHelper(mutex, mutexTimeout); ReturnValue_t status = LocalPool::reserveSpace(size, address,ignoreFault); return status; @@ -33,7 +33,7 @@ inline ReturnValue_t PoolManager::deleteData( // debug << "PoolManager( " << translateObject(getObjectId()) << // " )::deleteData from store " << packet_id.pool_index << // ". id is "<< packet_id.packet_index << std::endl; - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + MutexHelper mutexHelper(mutex, mutexTimeout); ReturnValue_t status = LocalPool::deleteData(packet_id); return status; } @@ -41,7 +41,7 @@ inline ReturnValue_t PoolManager::deleteData( template inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, size_t size, store_address_t* storeId) { - MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + MutexHelper mutexHelper(mutex, mutexTimeout); ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId); return status; diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index bcefe24d..c5e38306 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -1,7 +1,7 @@ #ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ #define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ -#include +#include class StorageManagerIF; From 549ad97bd3b2ee6b05af2383e7a30ef1ac846f5c Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 18 Aug 2020 11:25:57 +0200 Subject: [PATCH 14/53] shared ring buffer pull request --- container/SharedRingBuffer.cpp | 30 +++++++++++++++ container/SharedRingBuffer.h | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 container/SharedRingBuffer.cpp create mode 100644 container/SharedRingBuffer.h diff --git a/container/SharedRingBuffer.cpp b/container/SharedRingBuffer.cpp new file mode 100644 index 00000000..001a21ed --- /dev/null +++ b/container/SharedRingBuffer.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, + bool overwriteOld, size_t maxExcessBytes): + SystemObject(objectId), SimpleRingBuffer(size, overwriteOld, + maxExcessBytes) { + mutex = MutexFactory::instance()->createMutex(); +} + +SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer, + const size_t size, bool overwriteOld, size_t maxExcessBytes): + SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld, + maxExcessBytes) { + mutex = MutexFactory::instance()->createMutex(); +} + +ReturnValue_t SharedRingBuffer::lockRingBufferMutex( + MutexIF::TimeoutType timeoutType, dur_millis_t timeout) { + return mutex->lockMutex(timeoutType, timeout); +} + +ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() { + return mutex->unlockMutex(); +} + +MutexIF* SharedRingBuffer::getMutexHandle() const { + return mutex; +} diff --git a/container/SharedRingBuffer.h b/container/SharedRingBuffer.h new file mode 100644 index 00000000..0b5be052 --- /dev/null +++ b/container/SharedRingBuffer.h @@ -0,0 +1,68 @@ +#ifndef FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ +#define FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ + +#include +#include +#include +#include + +/** + * @brief Ring buffer which can be shared among multiple objects + * @details + * This class offers a mutex to perform thread-safe operation on the ring + * buffer. It is still up to the developer to actually perform the lock + * and unlock operations. + */ +class SharedRingBuffer: public SystemObject, + public SimpleRingBuffer { +public: + /** + * This constructor allocates a new internal buffer with the supplied size. + * @param size + * @param overwriteOld + * If the ring buffer is overflowing at a write operartion, the oldest data + * will be overwritten. + */ + SharedRingBuffer(object_id_t objectId, const size_t size, + bool overwriteOld, size_t maxExcessBytes); + + /** + * This constructor takes an external buffer with the specified size. + * @param buffer + * @param size + * @param overwriteOld + * If the ring buffer is overflowing at a write operartion, the oldest data + * will be overwritten. + */ + SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size, + bool overwriteOld, size_t maxExcessBytes); + + /** + * Unless a read-only constant value is read, all operations on the + * shared ring buffer should be protected by calling this function. + * @param timeoutType + * @param timeout + * @return + */ + virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType, + dur_millis_t timeout); + /** + * Any locked mutex also has to be unlocked, otherwise, access to the + * shared ring buffer will be blocked. + * @return + */ + virtual ReturnValue_t unlockRingBufferMutex(); + + /** + * The mutex handle can be accessed directly, for example to perform + * the lock with the #MutexHelper for a RAII compliant lock operation. + * @return + */ + MutexIF* getMutexHandle() const; +private: + MutexIF* mutex = nullptr; +}; + + + +#endif /* FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ */ From b7612bee37fdcfefa879ae80b71fdd8ebeaf198e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 24 Aug 2020 14:55:32 +0200 Subject: [PATCH 15/53] getFreeELement function added --- container/SimpleRingBuffer.cpp | 203 ++++++++++++++++++++++----------- container/SimpleRingBuffer.h | 149 ++++++++++++++++++++---- 2 files changed, 263 insertions(+), 89 deletions(-) diff --git a/container/SimpleRingBuffer.cpp b/container/SimpleRingBuffer.cpp index ee087643..7ed019b2 100644 --- a/container/SimpleRingBuffer.cpp +++ b/container/SimpleRingBuffer.cpp @@ -1,68 +1,135 @@ -#include "SimpleRingBuffer.h" -#include - -SimpleRingBuffer::SimpleRingBuffer(uint32_t size, bool overwriteOld) : - RingBufferBase<>(0, size, overwriteOld), buffer(NULL) { - buffer = new uint8_t[size]; -} - -SimpleRingBuffer::~SimpleRingBuffer() { - delete[] buffer; -} - -ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, - uint32_t amount) { - if (availableWriteSpace() >= amount || overwriteOld) { - uint32_t amountTillWrap = writeTillWrap(); - if (amountTillWrap >= amount) { - memcpy(&buffer[write], data, amount); - } else { - memcpy(&buffer[write], data, amountTillWrap); - memcpy(buffer, data + amountTillWrap, amount - amountTillWrap); - } - incrementWrite(amount); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, uint32_t amount, - bool readRemaining, uint32_t* trueAmount) { - uint32_t availableData = availableReadData(READ_PTR); - uint32_t amountTillWrap = readTillWrap(READ_PTR); - if (availableData < amount) { - if (readRemaining) { - amount = availableData; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - if (trueAmount != NULL) { - *trueAmount = amount; - } - if (amountTillWrap >= amount) { - memcpy(data, &buffer[read[READ_PTR]], amount); - } else { - memcpy(data, &buffer[read[READ_PTR]], amountTillWrap); - memcpy(data + amountTillWrap, buffer, amount - amountTillWrap); - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount, - bool deleteRemaining, uint32_t* trueAmount) { - uint32_t availableData = availableReadData(READ_PTR); - if (availableData < amount) { - if (deleteRemaining) { - amount = availableData; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - if (trueAmount != NULL) { - *trueAmount = amount; - } - incrementRead(amount, READ_PTR); - return HasReturnvaluesIF::RETURN_OK; -} +#include "../container/SimpleRingBuffer.h" +#include + +SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, + size_t maxExcessBytes) : + RingBufferBase<>(0, size, overwriteOld), + maxExcessBytes(maxExcessBytes) { + if(maxExcessBytes > size) { + this->maxExcessBytes = size; + } + else { + this->maxExcessBytes = maxExcessBytes; + } + buffer = new uint8_t[size + maxExcessBytes]; +} + +SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size, + bool overwriteOld, size_t maxExcessBytes): + RingBufferBase<>(0, size, overwriteOld), buffer(buffer) { + if(maxExcessBytes > size) { + this->maxExcessBytes = size; + } + else { + this->maxExcessBytes = maxExcessBytes; + } +} + + +SimpleRingBuffer::~SimpleRingBuffer() { + delete[] buffer; +} + + +ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer, + size_t amount) { + if (availableWriteSpace() >= amount or overwriteOld) { + size_t amountTillWrap = writeTillWrap(); + if (amountTillWrap < amount) { + if((amount - amountTillWrap + excessBytes) > maxExcessBytes) { + return HasReturnvaluesIF::RETURN_FAILED; + } + excessBytes = amount - amountTillWrap; + } + *writePointer = &buffer[write]; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +void SimpleRingBuffer::confirmBytesWritten(size_t amount) { + if(getExcessBytes() > 0) { + moveExcessBytesToStart(); + } + incrementWrite(amount); + +} + +ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, + size_t amount) { + if (availableWriteSpace() >= amount or overwriteOld) { + size_t amountTillWrap = writeTillWrap(); + if (amountTillWrap >= amount) { + // remaining size in buffer is sufficient to fit full amount. + memcpy(&buffer[write], data, amount); + } + else { + memcpy(&buffer[write], data, amountTillWrap); + memcpy(buffer, data + amountTillWrap, amount - amountTillWrap); + } + incrementWrite(amount); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount, + bool incrementReadPtr, bool readRemaining, size_t* trueAmount) { + size_t availableData = getAvailableReadData(READ_PTR); + size_t amountTillWrap = readTillWrap(READ_PTR); + if (availableData < amount) { + if (readRemaining) { + // more data available than amount specified. + amount = availableData; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + if (trueAmount != nullptr) { + *trueAmount = amount; + } + if (amountTillWrap >= amount) { + memcpy(data, &buffer[read[READ_PTR]], amount); + } else { + memcpy(data, &buffer[read[READ_PTR]], amountTillWrap); + memcpy(data + amountTillWrap, buffer, amount - amountTillWrap); + } + + if(incrementReadPtr) { + deleteData(amount, readRemaining); + } + return HasReturnvaluesIF::RETURN_OK; +} + +size_t SimpleRingBuffer::getExcessBytes() const { + return excessBytes; +} + +void SimpleRingBuffer::moveExcessBytesToStart() { + if(excessBytes > 0) { + std::memcpy(buffer, &buffer[size], excessBytes); + excessBytes = 0; + } +} + +ReturnValue_t SimpleRingBuffer::deleteData(size_t amount, + bool deleteRemaining, size_t* trueAmount) { + size_t availableData = getAvailableReadData(READ_PTR); + if (availableData < amount) { + if (deleteRemaining) { + amount = availableData; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + if (trueAmount != nullptr) { + *trueAmount = amount; + } + incrementRead(amount, READ_PTR); + return HasReturnvaluesIF::RETURN_OK; +} + + diff --git a/container/SimpleRingBuffer.h b/container/SimpleRingBuffer.h index 5d4fecab..b13e9f2a 100644 --- a/container/SimpleRingBuffer.h +++ b/container/SimpleRingBuffer.h @@ -1,21 +1,128 @@ -#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ -#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ - -#include "RingBufferBase.h" -#include - -class SimpleRingBuffer: public RingBufferBase<> { -public: - SimpleRingBuffer(uint32_t size, bool overwriteOld); - virtual ~SimpleRingBuffer(); - ReturnValue_t writeData(const uint8_t* data, uint32_t amount); - ReturnValue_t readData(uint8_t* data, uint32_t amount, bool readRemaining = false, uint32_t* trueAmount = NULL); - ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, uint32_t* trueAmount = NULL); -private: -// static const uint8_t TEMP_READ_PTR = 1; - static const uint8_t READ_PTR = 0; - uint8_t* buffer; -}; - -#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ - +#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ +#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ + +#include "../container/RingBufferBase.h" +#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. + * This class allocated dynamically, so + * @ingroup containers + */ +class SimpleRingBuffer: public RingBufferBase<> { +public: + /** + * This constructor allocates a new internal buffer with the supplied size. + * + * @param size + * @param overwriteOld If the ring buffer is overflowing at a write + * operation, the oldest data will be overwritten. + * @param maxExcessBytes These additional bytes will be allocated in addtion + * to the specified size to accomodate contiguous write operations + * with getFreeElement. + * + */ + SimpleRingBuffer(const size_t size, bool overwriteOld, + size_t maxExcessBytes = 0); + /** + * This constructor takes an external buffer with the specified size. + * @param buffer + * @param size + * @param overwriteOld + * If the ring buffer is overflowing at a write operartion, the oldest data + * will be overwritten. + * @param maxExcessBytes + * If the buffer can accomodate additional bytes for contigous write + * operations with getFreeElement, this is the maximum allowed additional + * size + */ + SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld, + size_t maxExcessBytes = 0); + + virtual ~SimpleRingBuffer(); + + /** + * Write to circular buffer and increment write pointer by amount. + * @param data + * @param amount + * @return -@c RETURN_OK if write operation was successfull + * -@c RETURN_FAILED if + */ + ReturnValue_t writeData(const uint8_t* data, size_t amount); + + /** + * Returns a pointer to a free element. If the remaining buffer is + * not large enough, the data will be written past the actual size + * and the amount of excess bytes will be cached. This function + * does not increment the write pointer! + * @param writePointer Pointer to a pointer which can be used to write + * contiguous blocks into the ring buffer + * @param amount + * @return + */ + ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount); + + /** + * This increments the write pointer and also copies the excess bytes + * to the beginning. It should be called if the write operation + * conducted after calling getFreeElement() was performed. + * @return + */ + void confirmBytesWritten(size_t amount); + + virtual size_t getExcessBytes() const; + /** + * Helper functions which moves any excess bytes to the start + * of the ring buffer. + * @return + */ + virtual void moveExcessBytesToStart(); + + /** + * Read from circular buffer at read pointer. + * @param data + * @param amount + * @param incrementReadPtr + * If this is set to true, the read pointer will be incremented. + * If readRemaining is set to true, the read pointer will be incremented + * accordingly. + * @param readRemaining + * If this is set to true, the data will be read even if the amount + * specified exceeds the read data available. + * @param trueAmount [out] + * If readRemaining was set to true, the true amount read will be assigned + * to the passed value. + * @return + * - @c RETURN_OK if data was read successfully + * - @c RETURN_FAILED if not enough data was available and readRemaining + * was set to false. + */ + ReturnValue_t readData(uint8_t* data, size_t amount, + bool incrementReadPtr = false, bool readRemaining = false, + size_t* trueAmount = nullptr); + + /** + * Delete data by incrementing read pointer. + * @param amount + * @param deleteRemaining + * If the amount specified is larger than the remaing size to read and this + * is set to true, the remaining amount will be deleted as well + * @param trueAmount [out] + * If deleteRemaining was set to true, the amount deleted will be assigned + * to the passed value. + * @return + */ + ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false, + size_t* trueAmount = nullptr); +private: + static const uint8_t READ_PTR = 0; + uint8_t* buffer = nullptr; + size_t maxExcessBytes; + size_t excessBytes = 0; +}; + +#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ + From 84d99a6f04b5ccd6d544c6e633247e0d10bb1fd7 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 24 Aug 2020 14:56:50 +0200 Subject: [PATCH 16/53] added brackets for boolean expressions --- container/SimpleRingBuffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/container/SimpleRingBuffer.cpp b/container/SimpleRingBuffer.cpp index 7ed019b2..2a19d619 100644 --- a/container/SimpleRingBuffer.cpp +++ b/container/SimpleRingBuffer.cpp @@ -33,7 +33,7 @@ SimpleRingBuffer::~SimpleRingBuffer() { ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer, size_t amount) { - if (availableWriteSpace() >= amount or overwriteOld) { + if ((availableWriteSpace() >= amount) or overwriteOld) { size_t amountTillWrap = writeTillWrap(); if (amountTillWrap < amount) { if((amount - amountTillWrap + excessBytes) > maxExcessBytes) { @@ -59,7 +59,7 @@ void SimpleRingBuffer::confirmBytesWritten(size_t amount) { ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, size_t amount) { - if (availableWriteSpace() >= amount or overwriteOld) { + if ((availableWriteSpace() >= amount) or overwriteOld) { size_t amountTillWrap = writeTillWrap(); if (amountTillWrap >= amount) { // remaining size in buffer is sufficient to fit full amount. From 3001911d69522c3fb44a2483c25d129e6cfef98e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 25 Aug 2020 14:00:27 +0200 Subject: [PATCH 17/53] taken over interface changes --- storagemanager/ConstStorageAccessor.cpp | 174 ++++++------ storagemanager/ConstStorageAccessor.h | 232 ++++++++-------- storagemanager/StorageAccessor.cpp | 134 +++++----- storagemanager/StorageAccessor.h | 89 +++---- storagemanager/StorageManagerIF.h | 335 ++++++++++++------------ 5 files changed, 482 insertions(+), 482 deletions(-) diff --git a/storagemanager/ConstStorageAccessor.cpp b/storagemanager/ConstStorageAccessor.cpp index 0bfde58c..ea9f2e44 100644 --- a/storagemanager/ConstStorageAccessor.cpp +++ b/storagemanager/ConstStorageAccessor.cpp @@ -1,87 +1,87 @@ -#include -#include -#include -#include - -ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): - storeId(storeId) {} - -ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, - StorageManagerIF* store): - storeId(storeId), store(store) { - internalState = AccessState::ASSIGNED; -} - -ConstStorageAccessor::~ConstStorageAccessor() { - if(deleteData and store != nullptr) { - sif::debug << "deleting store data" << std::endl; - store->deleteData(storeId); - } -} - -ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): - constDataPointer(other.constDataPointer), storeId(other.storeId), - size_(other.size_), store(other.store), deleteData(other.deleteData), - internalState(other.internalState) { - // This prevent premature deletion - other.store = nullptr; -} - -ConstStorageAccessor& ConstStorageAccessor::operator=( - ConstStorageAccessor&& other) { - constDataPointer = other.constDataPointer; - storeId = other.storeId; - store = other.store; - size_ = other.size_; - deleteData = other.deleteData; - this->store = other.store; - // This prevents premature deletion - other.store = nullptr; - return *this; -} - -const uint8_t* ConstStorageAccessor::data() const { - return constDataPointer; -} - -size_t ConstStorageAccessor::size() const { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - } - return size_; -} - -ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, - size_t maxSize) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(constDataPointer, constDataPointer + size_, pointer); - return HasReturnvaluesIF::RETURN_OK; -} - -void ConstStorageAccessor::release() { - deleteData = false; -} - -store_address_t ConstStorageAccessor::getId() const { - return storeId; -} - -void ConstStorageAccessor::print() const { - if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return; - } - arrayprinter::print(constDataPointer, size_); -} - -void ConstStorageAccessor::assignStore(StorageManagerIF* store) { - internalState = AccessState::ASSIGNED; - this->store = store; -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../storagemanager/ConstStorageAccessor.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../globalfunctions/arrayprinter.h" + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): + storeId(storeId) {} + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, + StorageManagerIF* store): + storeId(storeId), store(store) { + internalState = AccessState::ASSIGNED; +} + +ConstStorageAccessor::~ConstStorageAccessor() { + if(deleteData and store != nullptr) { + sif::debug << "deleting store data" << std::endl; + store->deleteData(storeId); + } +} + +ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): + constDataPointer(other.constDataPointer), storeId(other.storeId), + size_(other.size_), store(other.store), deleteData(other.deleteData), + internalState(other.internalState) { + // This prevent premature deletion + other.store = nullptr; +} + +ConstStorageAccessor& ConstStorageAccessor::operator=( + ConstStorageAccessor&& other) { + constDataPointer = other.constDataPointer; + storeId = other.storeId; + store = other.store; + size_ = other.size_; + deleteData = other.deleteData; + this->store = other.store; + // This prevents premature deletion + other.store = nullptr; + return *this; +} + +const uint8_t* ConstStorageAccessor::data() const { + return constDataPointer; +} + +size_t ConstStorageAccessor::size() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return size_; +} + +ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, + size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(constDataPointer, constDataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +void ConstStorageAccessor::release() { + deleteData = false; +} + +store_address_t ConstStorageAccessor::getId() const { + return storeId; +} + +void ConstStorageAccessor::print() const { + if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return; + } + arrayprinter::print(constDataPointer, size_); +} + +void ConstStorageAccessor::assignStore(StorageManagerIF* store) { + internalState = AccessState::ASSIGNED; + this->store = store; +} diff --git a/storagemanager/ConstStorageAccessor.h b/storagemanager/ConstStorageAccessor.h index bb003f55..ec2da8ce 100644 --- a/storagemanager/ConstStorageAccessor.h +++ b/storagemanager/ConstStorageAccessor.h @@ -1,116 +1,116 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ - -#include "storeAddress.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include - -class StorageManagerIF; - -/** - * @brief Helper classes to facilitate safe access to storages which is also - * conforming to RAII principles - * @details - * Accessor class which can be returned by pool manager or passed and set by - * pool managers to have safe access to the pool resources. - * - * These helper can be used together with the StorageManager classes to manage - * access to a storage. It can take care of thread-safety while also providing - * mechanisms to automatically clear storage data. - */ -class ConstStorageAccessor { - //! StorageManager classes have exclusive access to private variables. - template - friend class PoolManager; - template - friend class LocalPool; -public: - /** - * @brief Simple constructor which takes the store ID of the storage - * entry to access. - * @param storeId - */ - ConstStorageAccessor(store_address_t storeId); - ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); - - /** - * @brief The destructor in default configuration takes care of - * deleting the accessed pool entry and unlocking the mutex - */ - virtual ~ConstStorageAccessor(); - - /** - * @brief Returns a pointer to the read-only data - * @return - */ - const uint8_t* data() const; - - /** - * @brief Copies the read-only data to the supplied pointer - * @param pointer - */ - virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); - - /** - * @brief Calling this will prevent the Accessor from deleting the data - * when the destructor is called. - */ - void release(); - - /** - * Get the size of the data - * @return - */ - size_t size() const; - - /** - * Get the storage ID. - * @return - */ - store_address_t getId() const; - - void print() const; - - /** - * @brief Move ctor and move assignment allow returning accessors as - * a returnvalue. They prevent resource being free prematurely. - * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ - * move-constructors-and-move-assignment-operators-cpp.md - * @param - * @return - */ - ConstStorageAccessor& operator= (ConstStorageAccessor&&); - ConstStorageAccessor (ConstStorageAccessor&&); - - //! The copy ctor and copy assignemnt should be deleted implicitely - //! according to https://foonathan.net/2019/02/special-member-functions/ - //! but I still deleted them to make it more explicit. (remember rule of 5). - ConstStorageAccessor& operator= (ConstStorageAccessor&) = delete; - ConstStorageAccessor (ConstStorageAccessor&) = delete; -protected: - const uint8_t* constDataPointer = nullptr; - store_address_t storeId; - size_t size_ = 0; - //! Managing pool, has to assign itself. - StorageManagerIF* store = nullptr; - bool deleteData = true; - - enum class AccessState { - UNINIT, - ASSIGNED - }; - //! Internal state for safety reasons. - AccessState internalState = AccessState::UNINIT; - /** - * Used by the pool manager instances to assign themselves to the - * accessor. This is necessary to delete the data when the acessor - * exits the scope ! The internal state will be considered read - * when this function is called, so take care all data is set properly as - * well. - * @param - */ - void assignStore(StorageManagerIF*); -}; - - -#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ +#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ + +#include "../storagemanager/storeAddress.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +class StorageManagerIF; + +/** + * @brief Helper classes to facilitate safe access to storages which is also + * conforming to RAII principles + * @details + * Accessor class which can be returned by pool manager or passed and set by + * pool managers to have safe access to the pool resources. + * + * These helper can be used together with the StorageManager classes to manage + * access to a storage. It can take care of thread-safety while also providing + * mechanisms to automatically clear storage data. + */ +class ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + /** + * @brief Simple constructor which takes the store ID of the storage + * entry to access. + * @param storeId + */ + ConstStorageAccessor(store_address_t storeId); + ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief The destructor in default configuration takes care of + * deleting the accessed pool entry and unlocking the mutex + */ + virtual ~ConstStorageAccessor(); + + /** + * @brief Returns a pointer to the read-only data + * @return + */ + const uint8_t* data() const; + + /** + * @brief Copies the read-only data to the supplied pointer + * @param pointer + */ + virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); + + /** + * @brief Calling this will prevent the Accessor from deleting the data + * when the destructor is called. + */ + void release(); + + /** + * Get the size of the data + * @return + */ + size_t size() const; + + /** + * Get the storage ID. + * @return + */ + store_address_t getId() const; + + void print() const; + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + ConstStorageAccessor& operator= (ConstStorageAccessor&&); + ConstStorageAccessor(ConstStorageAccessor&&); + + //! The copy ctor and copy assignemnt should be deleted implicitely + //! according to https://foonathan.net/2019/02/special-member-functions/ + //! but I still deleted them to make it more explicit. (remember rule of 5). + ConstStorageAccessor& operator=(const ConstStorageAccessor&) = delete; + ConstStorageAccessor(const ConstStorageAccessor&) = delete; +protected: + const uint8_t* constDataPointer = nullptr; + store_address_t storeId; + size_t size_ = 0; + //! Managing pool, has to assign itself. + StorageManagerIF* store = nullptr; + bool deleteData = true; + + enum class AccessState { + UNINIT, + ASSIGNED + }; + //! Internal state for safety reasons. + AccessState internalState = AccessState::UNINIT; + /** + * Used by the pool manager instances to assign themselves to the + * accessor. This is necessary to delete the data when the acessor + * exits the scope ! The internal state will be considered read + * when this function is called, so take care all data is set properly as + * well. + * @param + */ + void assignStore(StorageManagerIF*); +}; + + +#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp index 9c2f936a..d4d2a54d 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/storagemanager/StorageAccessor.cpp @@ -1,67 +1,67 @@ -#include "StorageAccessor.h" -#include "StorageManagerIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -StorageAccessor::StorageAccessor(store_address_t storeId): - ConstStorageAccessor(storeId) { -} - -StorageAccessor::StorageAccessor(store_address_t storeId, - StorageManagerIF* store): - ConstStorageAccessor(storeId, store) { -} - -StorageAccessor& StorageAccessor::operator =( - StorageAccessor&& other) { - // Call the parent move assignment and also assign own member. - dataPointer = other.dataPointer; - StorageAccessor::operator=(std::move(other)); - return * this; -} - -// Call the parent move ctor and also transfer own member. -StorageAccessor::StorageAccessor(StorageAccessor&& other): - ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { -} - -ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large " - "enough" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(dataPointer, dataPointer + size_, pointer); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t* StorageAccessor::data() { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - } - return dataPointer; -} - -ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, - uint16_t offset) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(offset + size > size_) { - sif::error << "StorageAccessor: Data too large for pool " - "entry!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(data, data + size, dataPointer + offset); - return HasReturnvaluesIF::RETURN_OK; -} - -void StorageAccessor::assignConstPointer() { - constDataPointer = dataPointer; -} - - +#include "../storagemanager/StorageAccessor.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +StorageAccessor::StorageAccessor(store_address_t storeId): + ConstStorageAccessor(storeId) { +} + +StorageAccessor::StorageAccessor(store_address_t storeId, + StorageManagerIF* store): + ConstStorageAccessor(storeId, store) { +} + +StorageAccessor& StorageAccessor::operator =( + StorageAccessor&& other) { + // Call the parent move assignment and also assign own member. + dataPointer = other.dataPointer; + StorageAccessor::operator=(std::move(other)); + return * this; +} + +// Call the parent move ctor and also transfer own member. +StorageAccessor::StorageAccessor(StorageAccessor&& other): + ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { +} + +ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large " + "enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(dataPointer, dataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t* StorageAccessor::data() { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return dataPointer; +} + +ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, + uint16_t offset) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(offset + size > size_) { + sif::error << "StorageAccessor: Data too large for pool " + "entry!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(data, data + size, dataPointer + offset); + return HasReturnvaluesIF::RETURN_OK; +} + +void StorageAccessor::assignConstPointer() { + constDataPointer = dataPointer; +} + + diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index 5cdd82a7..1ca5f7dd 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -1,44 +1,45 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ - -#include "ConstStorageAccessor.h" - -class StorageManagerIF; - -/** - * @brief Child class for modifyable data. Also has a normal pointer member. - */ -class StorageAccessor: public ConstStorageAccessor { - //! StorageManager classes have exclusive access to private variables. - template - friend class PoolManager; - template - friend class LocalPool; -public: - StorageAccessor(store_address_t storeId); - StorageAccessor(store_address_t storeId, StorageManagerIF* store); - /** - * @brief Move ctor and move assignment allow returning accessors as - * a returnvalue. They prevent resource being free prematurely. - * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ - * move-constructors-and-move-assignment-operators-cpp.md - * @param - * @return - */ - StorageAccessor& operator= (StorageAccessor&&); - StorageAccessor (StorageAccessor&&); - - ReturnValue_t write(uint8_t *data, size_t size, - uint16_t offset = 0); - uint8_t* data(); - ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize) override; - -private: - //! Non-const pointer for modifyable data. - uint8_t* dataPointer = nullptr; - //! For modifyable data, the const pointer is assigned to the normal - //! pointer by the pool manager so both access functions can be used safely - void assignConstPointer(); -}; - -#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ +#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ + +#include "../storagemanager/ConstStorageAccessor.h" + +class StorageManagerIF; + +/** + * @brief Child class for modifyable data. Also has a normal pointer member. + */ +class StorageAccessor: public ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + StorageAccessor(store_address_t storeId); + StorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being freed prematurely. + * See: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + StorageAccessor& operator=(StorageAccessor&&); + StorageAccessor(StorageAccessor&&); + + ReturnValue_t write(uint8_t *data, size_t size, + uint16_t offset = 0); + uint8_t* data(); + ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize) override; + +private: + //! Non-const pointer for modifyable data. + uint8_t* dataPointer = nullptr; + //! For modifyable data, the const pointer is assigned to the normal + //! pointer by the pool manager so both access functions can be used safely + void assignConstPointer(); +}; + +#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index a36a714a..85341f2e 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -1,168 +1,167 @@ -#ifndef STORAGEMANAGERIF_H_H -#define STORAGEMANAGERIF_H_H - - -#include "../events/Event.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../storagemanager/StorageAccessor.h" -#include "../storagemanager/storeAddress.h" -#include -#include - -using AccessorPair = std::pair; -using ConstAccessorPair = std::pair; - -/** - * @brief This class provides an interface for intermediate data storage. - * @details The Storage manager classes shall be used to store larger chunks of - * data in RAM for exchange between tasks. This interface expects the - * data to be stored in one consecutive block of memory, so tasks can - * write directly to the destination pointer. - * For interprocess communication, the stores must be locked during - * insertion and deletion. If the receiving storage identifier is - * passed token-like between tasks, a lock during read and write - * operations is not necessary. - * @author Bastian Baetz - * @date 18.09.2012 - */ -class StorageManagerIF : public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::STORAGE_MANAGER_IF; //!< The unique ID for return codes for this interface. - static const ReturnValue_t DATA_TOO_LARGE = MAKE_RETURN_CODE(1); //!< This return code indicates that the data to be stored is too large for the store. - static const ReturnValue_t DATA_STORAGE_FULL = MAKE_RETURN_CODE(2); //!< This return code indicates that a data storage is full. - static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. - static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. - static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); - static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; - static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); - static const Event STORE_DATA_FAILED = MAKE_EVENT(1, SEVERITY::LOW); - - static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address. - /** - * @brief This is the empty virtual destructor as required for C++ interfaces. - */ - virtual ~StorageManagerIF() { - } - ; - /** - * @brief With addData, a free storage position is allocated and data - * stored there. - * @details During the allocation, the StorageManager is blocked. - * @param storageId A pointer to the storageId to retrieve. - * @param data The data to be stored in the StorageManager. - * @param size The amount of data to be stored. - * @return Returns @li RETURN_OK if data was added. - * @li RETURN_FAILED if data could not be added. - * storageId is unchanged then. - */ - virtual ReturnValue_t addData(store_address_t* storageId, - const uint8_t * data, size_t size, bool ignoreFault = false) = 0; - /** - * @brief With deleteData, the storageManager frees the memory region - * identified by packet_id. - * @param packet_id The identifier of the memory region to be freed. - * @return @li RETURN_OK on success. - * @li RETURN_FAILED if deletion did not work - * (e.g. an illegal packet_id was passed). - */ - virtual ReturnValue_t deleteData(store_address_t packet_id) = 0; - /** - * @brief Another deleteData which uses the pointer and size of the - * stored data to delete the content. - * @param buffer Pointer to the data. - * @param size Size of data to be stored. - * @param storeId Store id of the deleted element (optional) - * @return @li RETURN_OK on success. - * @li failure code if deletion did not work - */ - virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, - store_address_t* storeId = nullptr) = 0; - - - /** - * @brief Access the data by supplying a store ID. - * @details - * A pair consisting of the retrieval result and an instance of a - * ConstStorageAccessor class is returned - * @param storeId - * @return Pair of return value and a ConstStorageAccessor instance - */ - virtual ConstAccessorPair getData(store_address_t storeId) = 0; - - /** - * @brief Access the data by supplying a store ID and a helper - * instance - * @param storeId - * @param constAccessor Wrapper function to access store data. - * @return - */ - virtual ReturnValue_t getData(store_address_t storeId, - ConstStorageAccessor& constAccessor) = 0; - - - /** - * @brief getData returns an address to data and the size of the data - * for a given packet_id. - * @param packet_id The id of the data to be returned - * @param packet_ptr The passed pointer address is set to the the memory - * position - * @param size The exact size of the stored data is returned here. - * @return @li RETURN_OK on success. - * @li RETURN_FAILED if fetching data did not work - * (e.g. an illegal packet_id was passed). - */ - virtual ReturnValue_t getData(store_address_t packet_id, - const uint8_t** packet_ptr, size_t* size) = 0; - - - /** - * Modify data by supplying a store ID - * @param storeId - * @return Pair of return value and StorageAccessor helper - */ - virtual AccessorPair modifyData(store_address_t storeId) = 0; - - /** - * Modify data by supplying a store ID and a StorageAccessor helper instance. - * @param storeId - * @param accessor Helper class to access the modifiable data. - * @return - */ - virtual ReturnValue_t modifyData(store_address_t storeId, - StorageAccessor& accessor) = 0; - - /** - * Get pointer and size of modifiable data by supplying the storeId - * @param packet_id - * @param packet_ptr [out] Pointer to pointer of data to set - * @param size [out] Pointer to size to set - * @return - */ - virtual ReturnValue_t modifyData(store_address_t packet_id, - uint8_t** packet_ptr, size_t* size) = 0; - /** - * This method reserves an element of \c size. - * - * It returns the packet id of this element as well as a direct pointer to the - * data of the element. It must be assured that exactly \c size data is - * written to p_data! - * @param storageId A pointer to the storageId to retrieve. - * @param size The size of the space to be reserved. - * @param p_data A pointer to the element data is returned here. - * @return Returns @li RETURN_OK if data was added. - * @li RETURN_FAILED if data could not be added. - * storageId is unchanged then. - */ - virtual ReturnValue_t getFreeElement(store_address_t* storageId, - const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; - - /** - * Clears the whole store. - * Use with care! - */ - virtual void clearStore() = 0; -}; - -#endif /* STORAGEMANAGERIF_H_ */ +#ifndef STORAGEMANAGERIF_H_H +#define STORAGEMANAGERIF_H_H + +#include "../events/Event.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../storagemanager/StorageAccessor.h" +#include "../storagemanager/storeAddress.h" +#include +#include + +using AccessorPair = std::pair; +using ConstAccessorPair = std::pair; + +/** + * @brief This class provides an interface for intermediate data storage. + * @details The Storage manager classes shall be used to store larger chunks of + * data in RAM for exchange between tasks. This interface expects the + * data to be stored in one consecutive block of memory, so tasks can + * write directly to the destination pointer. + * For interprocess communication, the stores must be locked during + * insertion and deletion. If the receiving storage identifier is + * passed token-like between tasks, a lock during read and write + * operations is not necessary. + * @author Bastian Baetz + * @date 18.09.2012 + */ +class StorageManagerIF : public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::STORAGE_MANAGER_IF; //!< The unique ID for return codes for this interface. + static const ReturnValue_t DATA_TOO_LARGE = MAKE_RETURN_CODE(1); //!< This return code indicates that the data to be stored is too large for the store. + static const ReturnValue_t DATA_STORAGE_FULL = MAKE_RETURN_CODE(2); //!< This return code indicates that a data storage is full. + static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. + static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. + static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); + static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; + static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); + static const Event STORE_DATA_FAILED = MAKE_EVENT(1, SEVERITY::LOW); + + static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address. + /** + * @brief This is the empty virtual destructor as required for C++ interfaces. + */ + virtual ~StorageManagerIF() { + } + ; + /** + * @brief With addData, a free storage position is allocated and data + * stored there. + * @details During the allocation, the StorageManager is blocked. + * @param storageId A pointer to the storageId to retrieve. + * @param data The data to be stored in the StorageManager. + * @param size The amount of data to be stored. + * @return Returns @li RETURN_OK if data was added. + * @li RETURN_FAILED if data could not be added. + * storageId is unchanged then. + */ + virtual ReturnValue_t addData(store_address_t* storageId, + const uint8_t * data, size_t size, bool ignoreFault = false) = 0; + /** + * @brief With deleteData, the storageManager frees the memory region + * identified by packet_id. + * @param packet_id The identifier of the memory region to be freed. + * @return @li RETURN_OK on success. + * @li RETURN_FAILED if deletion did not work + * (e.g. an illegal packet_id was passed). + */ + virtual ReturnValue_t deleteData(store_address_t packet_id) = 0; + /** + * @brief Another deleteData which uses the pointer and size of the + * stored data to delete the content. + * @param buffer Pointer to the data. + * @param size Size of data to be stored. + * @param storeId Store id of the deleted element (optional) + * @return @li RETURN_OK on success. + * @li failure code if deletion did not work + */ + virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, + store_address_t* storeId = nullptr) = 0; + + + /** + * @brief Access the data by supplying a store ID. + * @details + * A pair consisting of the retrieval result and an instance of a + * ConstStorageAccessor class is returned + * @param storeId + * @return Pair of return value and a ConstStorageAccessor instance + */ + virtual ConstAccessorPair getData(store_address_t storeId) = 0; + + /** + * @brief Access the data by supplying a store ID and a helper + * instance + * @param storeId + * @param constAccessor Wrapper function to access store data. + * @return + */ + virtual ReturnValue_t getData(store_address_t storeId, + ConstStorageAccessor& constAccessor) = 0; + + + /** + * @brief getData returns an address to data and the size of the data + * for a given packet_id. + * @param packet_id The id of the data to be returned + * @param packet_ptr The passed pointer address is set to the the memory + * position + * @param size The exact size of the stored data is returned here. + * @return @li RETURN_OK on success. + * @li RETURN_FAILED if fetching data did not work + * (e.g. an illegal packet_id was passed). + */ + virtual ReturnValue_t getData(store_address_t packet_id, + const uint8_t** packet_ptr, size_t* size) = 0; + + + /** + * Modify data by supplying a store ID + * @param storeId + * @return Pair of return value and StorageAccessor helper + */ + virtual AccessorPair modifyData(store_address_t storeId) = 0; + + /** + * Modify data by supplying a store ID and a StorageAccessor helper instance. + * @param storeId + * @param accessor Helper class to access the modifiable data. + * @return + */ + virtual ReturnValue_t modifyData(store_address_t storeId, + StorageAccessor& accessor) = 0; + + /** + * Get pointer and size of modifiable data by supplying the storeId + * @param packet_id + * @param packet_ptr [out] Pointer to pointer of data to set + * @param size [out] Pointer to size to set + * @return + */ + virtual ReturnValue_t modifyData(store_address_t packet_id, + uint8_t** packet_ptr, size_t* size) = 0; + /** + * This method reserves an element of \c size. + * + * It returns the packet id of this element as well as a direct pointer to the + * data of the element. It must be assured that exactly \c size data is + * written to p_data! + * @param storageId A pointer to the storageId to retrieve. + * @param size The size of the space to be reserved. + * @param p_data A pointer to the element data is returned here. + * @return Returns @li RETURN_OK if data was added. + * @li RETURN_FAILED if data could not be added. + * storageId is unchanged then. + */ + virtual ReturnValue_t getFreeElement(store_address_t* storageId, + const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; + + /** + * Clears the whole store. + * Use with care! + */ + virtual void clearStore() = 0; +}; + +#endif /* STORAGEMANAGERIF_H_ */ From 3f9d9b8770561a1487302d3f61e3e07aa012899d Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 25 Aug 2020 18:24:46 +0200 Subject: [PATCH 18/53] ipc update --- devicehandlers/HealthDevice.cpp | 2 +- ipc/CommandMessage.cpp | 242 +++++++++++++--------------- ipc/CommandMessage.h | 263 +++++++++++++++---------------- ipc/CommandMessageCleaner.cpp | 45 ++++++ ipc/CommandMessageCleaner.h | 16 ++ ipc/CommandMessageIF.h | 73 +++++++++ ipc/MessageQueueMessage.cpp | 149 ++++++++++-------- ipc/MessageQueueMessage.h | 268 ++++++++++++++++++-------------- ipc/MessageQueueMessageIF.h | 91 +++++++++++ 9 files changed, 700 insertions(+), 449 deletions(-) create mode 100644 ipc/CommandMessageCleaner.cpp create mode 100644 ipc/CommandMessageCleaner.h create mode 100644 ipc/CommandMessageIF.h create mode 100644 ipc/MessageQueueMessageIF.h diff --git a/devicehandlers/HealthDevice.cpp b/devicehandlers/HealthDevice.cpp index 411731dc..b15e5d2b 100644 --- a/devicehandlers/HealthDevice.cpp +++ b/devicehandlers/HealthDevice.cpp @@ -5,7 +5,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue) : SystemObject(setObjectId), lastHealth(HEALTHY), parentQueue( parentQueue), commandQueue(), healthHelper(this, setObjectId) { - commandQueue = QueueFactory::instance()->createMessageQueue(3, CommandMessage::COMMAND_MESSAGE_SIZE); + commandQueue = QueueFactory::instance()->createMessageQueue(3); } HealthDevice::~HealthDevice() { diff --git a/ipc/CommandMessage.cpp b/ipc/CommandMessage.cpp index dbea8533..16293608 100644 --- a/ipc/CommandMessage.cpp +++ b/ipc/CommandMessage.cpp @@ -1,131 +1,111 @@ -/** - * @file CommandMessage.cpp - * @brief This file defines the CommandMessage class. - * @date 20.06.2013 - * @author baetz - */ - -#include "../devicehandlers/DeviceHandlerMessage.h" -#include "../health/HealthMessage.h" -#include "CommandMessage.h" -#include "../memory/MemoryMessage.h" -#include "../modes/ModeMessage.h" -#include "../monitoring/MonitoringMessage.h" -#include "../subsystem/modes/ModeSequenceMessage.h" -#include "../tmstorage/TmStoreMessage.h" -#include "../parameters/ParameterMessage.h" - -namespace messagetypes { -void clearMissionMessage(CommandMessage* message); -} - - -CommandMessage::CommandMessage() { - this->messageSize = COMMAND_MESSAGE_SIZE; - setCommand(CMD_NONE); -} - -CommandMessage::CommandMessage(Command_t command, uint32_t parameter1, - uint32_t parameter2) { - this->messageSize = COMMAND_MESSAGE_SIZE; - setCommand(command); - setParameter(parameter1); - setParameter2(parameter2); -} - -Command_t CommandMessage::getCommand() const { - Command_t command; - memcpy(&command, getData(), sizeof(Command_t)); - return command; -} - -void CommandMessage::setCommand(Command_t command) { - memcpy(getData(), &command, sizeof(command)); -} - -uint32_t CommandMessage::getParameter() const { - uint32_t parameter1; - memcpy(¶meter1, getData() + sizeof(Command_t), sizeof(parameter1)); - return parameter1; -} - -void CommandMessage::setParameter(uint32_t parameter1) { - memcpy(getData() + sizeof(Command_t), ¶meter1, sizeof(parameter1)); -} - -uint32_t CommandMessage::getParameter2() const { - uint32_t parameter2; - memcpy(¶meter2, getData() + sizeof(Command_t) + sizeof(uint32_t), - sizeof(parameter2)); - return parameter2; -} - -void CommandMessage::setParameter2(uint32_t parameter2) { - memcpy(getData() + sizeof(Command_t) + sizeof(uint32_t), ¶meter2, - sizeof(parameter2)); -} - -void CommandMessage::clearCommandMessage() { - switch((getCommand()>>8) & 0xff){ - case messagetypes::MODE_COMMAND: - ModeMessage::clear(this); - break; - case messagetypes::HEALTH_COMMAND: - HealthMessage::clear(this); - break; - case messagetypes::MODE_SEQUENCE: - ModeSequenceMessage::clear(this); - break; - case messagetypes::ACTION: - ActionMessage::clear(this); - break; - case messagetypes::DEVICE_HANDLER_COMMAND: - DeviceHandlerMessage::clear(this); - break; - case messagetypes::MEMORY: - MemoryMessage::clear(this); - break; - case messagetypes::MONITORING: - MonitoringMessage::clear(this); - break; - case messagetypes::TM_STORE: - TmStoreMessage::clear(this); - break; - case messagetypes::PARAMETER: - ParameterMessage::clear(this); - break; - default: - messagetypes::clearMissionMessage(this); - break; - } -} - -bool CommandMessage::isClearedCommandMessage() { - return getCommand() == CMD_NONE; -} - -size_t CommandMessage::getMinimumMessageSize() const { - return COMMAND_MESSAGE_SIZE; -} - -void CommandMessage::setToUnknownCommand() { - Command_t initialCommand = getCommand(); - clearCommandMessage(); - setReplyRejected(UNKNOWN_COMMAND, initialCommand); -} - -void CommandMessage::setReplyRejected(ReturnValue_t reason, - Command_t initialCommand) { - setCommand(REPLY_REJECTED); - setParameter(reason); - setParameter2(initialCommand); -} - -ReturnValue_t CommandMessage::getReplyRejectedReason( - Command_t *initialCommand) const { - ReturnValue_t reason = getParameter(); - if(initialCommand != nullptr) { - *initialCommand = getParameter2(); - } - return reason; -} +#include "CommandMessage.h" +#include "CommandMessageCleaner.h" +#include + +CommandMessage::CommandMessage() { + MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); + setCommand(CMD_NONE); +} + +CommandMessage::CommandMessage(Command_t command, uint32_t parameter1, + uint32_t parameter2) { + MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); + setCommand(command); + setParameter(parameter1); + setParameter2(parameter2); +} + +Command_t CommandMessage::getCommand() const { + Command_t command; + std::memcpy(&command, MessageQueueMessage::getData(), sizeof(Command_t)); + return command; +} + +void CommandMessage::setCommand(Command_t command) { + std::memcpy(MessageQueueMessage::getData(), &command, sizeof(Command_t)); +} + +uint8_t CommandMessage::getMessageType() const { + // first byte of command ID. + return getCommand() >> 8 & 0xff; +} + +uint32_t CommandMessage::getParameter() const { + uint32_t parameter1; + std::memcpy(¶meter1, this->getData(), sizeof(parameter1)); + return parameter1; +} + +void CommandMessage::setParameter(uint32_t parameter1) { + std::memcpy(this->getData(), ¶meter1, sizeof(parameter1)); +} + +uint32_t CommandMessage::getParameter2() const { + uint32_t parameter2; + std::memcpy(¶meter2, this->getData() + sizeof(uint32_t), + sizeof(parameter2)); + return parameter2; +} + +void CommandMessage::setParameter2(uint32_t parameter2) { + std::memcpy(this->getData() + sizeof(uint32_t), ¶meter2, + sizeof(parameter2)); +} + +uint32_t CommandMessage::getParameter3() const { + uint32_t parameter3; + std::memcpy(¶meter3, this->getData() + 2 * sizeof(uint32_t), + sizeof(parameter3)); + return parameter3; +} + +void CommandMessage::setParameter3(uint32_t parameter3) { + std::memcpy(this->getData() + 2 * sizeof(uint32_t), ¶meter3, + sizeof(parameter3)); +} + +size_t CommandMessage::getMinimumMessageSize() const { + return MINIMUM_COMMAND_MESSAGE_SIZE; +} + +void CommandMessage::clearCommandMessage() { + clear(); +} + +void CommandMessage::clear() { + CommandMessageCleaner::clearCommandMessage(this); +} + +bool CommandMessage::isClearedCommandMessage() { + return getCommand() == CMD_NONE; +} + +void CommandMessage::setToUnknownCommand() { + Command_t initialCommand = getCommand(); + this->clear(); + setReplyRejected(UNKNOWN_COMMAND, initialCommand); +} + +void CommandMessage::setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) { + setCommand(REPLY_REJECTED); + setParameter(reason); + setParameter2(initialCommand); +} + +ReturnValue_t CommandMessage::getReplyRejectedReason( + Command_t *initialCommand) const { + ReturnValue_t reason = getParameter(); + if(initialCommand != nullptr) { + *initialCommand = getParameter2(); + } + return reason; +} + +uint8_t* CommandMessage::getData() { + return MessageQueueMessage::getData() + sizeof(Command_t); +} + +const uint8_t* CommandMessage::getData() const { + return MessageQueueMessage::getData() + sizeof(Command_t); +} diff --git a/ipc/CommandMessage.h b/ipc/CommandMessage.h index e984ad3d..3be9a120 100644 --- a/ipc/CommandMessage.h +++ b/ipc/CommandMessage.h @@ -1,134 +1,129 @@ -/** - * @file CommandMessage.h - * @brief This file defines the CommandMessage class. - * @date 20.06.2013 - * @author baetz - */ - -#ifndef COMMANDMESSAGE_H_ -#define COMMANDMESSAGE_H_ - - -#include "FwMessageTypes.h" -#include - -#include "MessageQueueMessage.h" - -#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) -typedef ReturnValue_t Command_t; - -class CommandMessage : public MessageQueueMessage { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; - static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); - - - static const uint8_t MESSAGE_ID = messagetypes::COMMAND; - static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 );//!< Used internally, will be ignored - static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 3 ); - static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 0xD1 );//!< Reply indicating that the current command was rejected, par1 should contain the error code - - /** - * This is the size of a message as it is seen by the MessageQueue - */ - static const size_t COMMAND_MESSAGE_SIZE = HEADER_SIZE - + sizeof(Command_t) + 2 * sizeof(uint32_t); - - /** - * Default Constructor, does not initialize anything. - * - * This constructor should be used when receiving a Message, as the content is filled by the MessageQueue. - */ - CommandMessage(); - /** - * This constructor creates a new message with all message content initialized - * - * @param command The DeviceHandlerCommand_t that will be sent - * @param parameter1 The first parameter - * @param parameter2 The second parameter - */ - CommandMessage(Command_t command, - uint32_t parameter1, uint32_t parameter2); - - /** - * Default Destructor - */ - virtual ~CommandMessage() { - } - - /** - * Read the DeviceHandlerCommand_t that is stored in the message, usually used after receiving - * - * @return the Command stored in the Message - */ - Command_t getCommand() const; - - /** - * Set the DeviceHandlerCOmmand_t of the message - * - * @param the Command to be sent - */ - void setCommand(Command_t command); - - /** - * Get the first parameter of the message - * - * @return the first Parameter of the message - */ - uint32_t getParameter() const; - - /** - * Set the first parameter of the message - * - * @param the first parameter of the message - */ - void setParameter(uint32_t parameter1); - - /** - * Get the second parameter of the message - * - * @return the second Parameter of the message - */ - uint32_t getParameter2() const; - - /** - * Set the second parameter of the message - * - * @param the second parameter of the message - */ - void setParameter2(uint32_t parameter2); - - /** - * Set the command to CMD_NONE and try to find - * the correct class to handle a more detailed - * clear. - * Also, calls a mission-specific clearMissionMessage - * function to separate between framework and mission - * messages. Not optimal, may be replaced by totally - * different auto-delete solution (e.g. smart pointers). - * - */ - void clearCommandMessage(); - - /** - * check if a message was cleared - * - * @return if the command is CMD_NONE - */ - bool isClearedCommandMessage(); - - - /** - * Sets the command to REPLY_REJECTED with parameter UNKNOWN_COMMAND. - * Is needed quite often, so we better code it once only. - */ - void setToUnknownCommand(); - void setReplyRejected(ReturnValue_t reason, Command_t initialCommand = CMD_NONE); - ReturnValue_t getReplyRejectedReason( - Command_t *initialCommand = nullptr) const; - - size_t getMinimumMessageSize() const; -}; - - -#endif /* COMMANDMESSAGE_H_ */ +#ifndef FSFW_IPC_COMMANDMESSAGE_H_ +#define FSFW_IPC_COMMANDMESSAGE_H_ + +#include "CommandMessageIF.h" +#include "MessageQueueMessage.h" +#include "FwMessageTypes.h" + +/** + * @brief Default command message used to pass command messages between tasks. + * Primary message type for IPC. Contains sender, 2-byte command ID + * field, and 2 4-byte parameters. + * @details + * It operates on an external memory which is contained inside a + * class implementing MessageQueueMessageIF by taking its address. + * This allows for a more flexible designs of message implementations. + * The pointer can be passed to different message implementations without + * the need of unnecessary copying. + * + * The command message is based of the generic MessageQueueMessage which + * currently has an internal message size of 28 bytes. + * @author Bastian Baetz + */ +class CommandMessage: public MessageQueueMessage, public CommandMessageIF { +public: + /** + * Default size can accomodate 2 4-byte parameters. + */ + static constexpr size_t DEFAULT_COMMAND_MESSAGE_SIZE = + CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE + sizeof(uint32_t); + + /** + * @brief Default Constructor, does not initialize anything. + * @details + * This constructor should be used when receiving a Message, as the + * content is filled by the MessageQueue. + */ + CommandMessage(); + /** + * This constructor creates a new message with all message content + * initialized + * + * @param command The DeviceHandlerCommand_t that will be sent + * @param parameter1 The first parameter + * @param parameter2 The second parameter + */ + CommandMessage(Command_t command, uint32_t parameter1, uint32_t parameter2); + + /** + * @brief Default Destructor + */ + virtual ~CommandMessage() {} + + /** + * Read the DeviceHandlerCommand_t that is stored in the message, + * usually used after receiving. + * + * @return the Command stored in the Message + */ + virtual Command_t getCommand() const override; + /** + * Set the command type of the message. Default implementation also + * sets the message type, which will be the first byte of the command ID. + * @param the Command to be sent + */ + virtual void setCommand(Command_t command); + + virtual uint8_t* getData() override; + virtual const uint8_t* getData() const override; + + /** + * Get the first parameter of the message + * @return the first Parameter of the message + */ + uint32_t getParameter() const; + /** + * Set the first parameter of the message + * @param the first parameter of the message + */ + void setParameter(uint32_t parameter1); + uint32_t getParameter2() const; + void setParameter2(uint32_t parameter2); + uint32_t getParameter3() const; + void setParameter3(uint32_t parameter3); + + /** + * check if a message was cleared + * + * @return if the command is CMD_NONE + */ + bool isClearedCommandMessage(); + + /** + * Sets the command to REPLY_REJECTED with parameter UNKNOWN_COMMAND. + * Is needed quite often, so we better code it once only. + */ + void setToUnknownCommand() override; + + /** + * A command message can be rejected and needs to offer a function + * to set a rejected reply + * @param reason + * @param initialCommand + */ + void setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) override; + /** + * Corrensonding getter function. + * @param initialCommand + * @return + */ + ReturnValue_t getReplyRejectedReason( + Command_t* initialCommand = nullptr) const override; + + + virtual void clear() override; + void clearCommandMessage(); + + /** + * Extract message ID, which is the first byte of the command ID for the + * default implementation. + * @return + */ + virtual uint8_t getMessageType() const override; + + /** MessageQueueMessageIF functions used for minimum size check. */ + size_t getMinimumMessageSize() const override; +}; + +#endif /* FSFW_IPC_COMMANDMESSAGE_H_ */ diff --git a/ipc/CommandMessageCleaner.cpp b/ipc/CommandMessageCleaner.cpp new file mode 100644 index 00000000..a4dec78d --- /dev/null +++ b/ipc/CommandMessageCleaner.cpp @@ -0,0 +1,45 @@ +#include "../ipc/CommandMessageCleaner.h" + +#include "../devicehandlers/DeviceHandlerMessage.h" +#include "../health/HealthMessage.h" +#include "../memory/MemoryMessage.h" +#include "../modes/ModeMessage.h" +#include "../monitoring/MonitoringMessage.h" +#include "../subsystem/modes/ModeSequenceMessage.h" +#include "../tmstorage/TmStoreMessage.h" +#include "../parameters/ParameterMessage.h" + +void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { + switch(message->getMessageType()){ + case messagetypes::MODE_COMMAND: + ModeMessage::clear(message); + break; + case messagetypes::HEALTH_COMMAND: + HealthMessage::clear(message); + break; + case messagetypes::MODE_SEQUENCE: + ModeSequenceMessage::clear(message); + break; + case messagetypes::ACTION: + ActionMessage::clear(message); + break; + case messagetypes::DEVICE_HANDLER_COMMAND: + DeviceHandlerMessage::clear(message); + break; + case messagetypes::MEMORY: + MemoryMessage::clear(message); + break; + case messagetypes::MONITORING: + MonitoringMessage::clear(message); + break; + case messagetypes::TM_STORE: + TmStoreMessage::clear(message); + break; + case messagetypes::PARAMETER: + ParameterMessage::clear(message); + break; + default: + messagetypes::clearMissionMessage(message); + break; + } +} diff --git a/ipc/CommandMessageCleaner.h b/ipc/CommandMessageCleaner.h new file mode 100644 index 00000000..f17bf282 --- /dev/null +++ b/ipc/CommandMessageCleaner.h @@ -0,0 +1,16 @@ +#ifndef FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ +#define FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ +#include "../ipc/CommandMessage.h" + +namespace messagetypes { +// Implemented in config. +void clearMissionMessage(CommandMessage* message); +} + +class CommandMessageCleaner { +public: + static void clearCommandMessage(CommandMessage* message); +}; + + +#endif /* FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ */ diff --git a/ipc/CommandMessageIF.h b/ipc/CommandMessageIF.h new file mode 100644 index 00000000..68a8d956 --- /dev/null +++ b/ipc/CommandMessageIF.h @@ -0,0 +1,73 @@ +#ifndef FSFW_IPC_COMMANDMESSAGEIF_H_ +#define FSFW_IPC_COMMANDMESSAGEIF_H_ + +#include "MessageQueueMessageIF.h" +#include "FwMessageTypes.h" +#include "../returnvalues/HasReturnvaluesIF.h" + +#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) +typedef uint16_t Command_t; + +class CommandMessageIF { +public: + /** + * Header consists of sender ID and command ID. + */ + static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE + + sizeof(Command_t); + /** + * This minimum size is derived from the interface requirement to be able + * to set a rejected reply, which contains a returnvalue and the initial + * command. + */ + static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE = + CommandMessageIF::HEADER_SIZE + sizeof(ReturnValue_t) + + sizeof(Command_t); + + static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; + static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); + + static const uint8_t MESSAGE_ID = messagetypes::COMMAND; + //! Used internally, shall be ignored + static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 ); + static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 ); + //! Reply indicating that the current command was rejected, + //! par1 should contain the error code + static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 ); + + virtual ~CommandMessageIF() {}; + + /** + * A command message shall have a uint16_t command ID field. + * @return + */ + virtual Command_t getCommand() const = 0; + /** + * A command message shall have a uint8_t message type ID field. + * @return + */ + virtual uint8_t getMessageType() const = 0; + + /** + * A command message can be rejected and needs to offer a function + * to set a rejected reply + * @param reason + * @param initialCommand + */ + virtual void setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) = 0; + /** + * Corrensonding getter function. + * @param initialCommand + * @return + */ + virtual ReturnValue_t getReplyRejectedReason( + Command_t* initialCommand = nullptr) const = 0; + + virtual void setToUnknownCommand() = 0; + + virtual void clear() = 0; + +}; + +#endif /* FSFW_IPC_COMMANDMESSAGEIF_H_ */ diff --git a/ipc/MessageQueueMessage.cpp b/ipc/MessageQueueMessage.cpp index 05dde1f5..2f79cb3b 100644 --- a/ipc/MessageQueueMessage.cpp +++ b/ipc/MessageQueueMessage.cpp @@ -1,65 +1,84 @@ -#include "MessageQueueMessage.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -#include - -MessageQueueMessage::MessageQueueMessage() : - messageSize(this->HEADER_SIZE) { - memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); -} - -MessageQueueMessage::~MessageQueueMessage() { -} - -const uint8_t* MessageQueueMessage::getBuffer() const { - return this->internalBuffer; -} - -uint8_t* MessageQueueMessage::getBuffer() { - return this->internalBuffer; -} - -const uint8_t* MessageQueueMessage::getData() const { - return this->internalBuffer + this->HEADER_SIZE; -} - -uint8_t* MessageQueueMessage::getData() { - return this->internalBuffer + this->HEADER_SIZE; -} - -MessageQueueId_t MessageQueueMessage::getSender() const { - MessageQueueId_t temp_id; - memcpy(&temp_id, this->internalBuffer, sizeof(MessageQueueId_t)); - return temp_id; -} - -void MessageQueueMessage::setSender(MessageQueueId_t setId) { - memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t)); -} - -MessageQueueMessage::MessageQueueMessage(uint8_t* data, uint32_t size) : - messageSize(this->HEADER_SIZE + size) { - if (size <= this->MAX_DATA_SIZE) { - memcpy(this->getData(), data, size); - } else { - memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); - this->messageSize = this->HEADER_SIZE; - } -} - -size_t MessageQueueMessage::getMinimumMessageSize() { - return this->HEADER_SIZE; -} - -void MessageQueueMessage::print() { - sif::debug << "MessageQueueMessage has size: " << this->messageSize << std::hex - << std::endl; - for (uint8_t count = 0; count < this->messageSize; count++) { - sif::debug << (uint32_t) this->internalBuffer[count] << ":"; - } - sif::debug << std::dec << std::endl; -} - -void MessageQueueMessage::clear() { - memset(this->getBuffer(), 0, this->MAX_MESSAGE_SIZE); -} +#include "MessageQueueMessage.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../globalfunctions/arrayprinter.h" +#include + +MessageQueueMessage::MessageQueueMessage() : + messageSize(getMinimumMessageSize()) { + memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); +} + +MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) : + messageSize(this->HEADER_SIZE + size) { + if (size <= this->MAX_DATA_SIZE) { + memcpy(this->getData(), data, size); + this->messageSize = this->HEADER_SIZE + size; + } + else { + sif::warning << "MessageQueueMessage: Passed size larger than maximum" + "allowed size! Setting content to 0" << std::endl; + memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); + this->messageSize = this->HEADER_SIZE; + } +} + +MessageQueueMessage::~MessageQueueMessage() { +} + +const uint8_t* MessageQueueMessage::getBuffer() const { + return this->internalBuffer; +} + +uint8_t* MessageQueueMessage::getBuffer() { + return this->internalBuffer; +} + +const uint8_t* MessageQueueMessage::getData() const { + return this->internalBuffer + this->HEADER_SIZE; +} + +uint8_t* MessageQueueMessage::getData() { + return this->internalBuffer + this->HEADER_SIZE; +} + +MessageQueueId_t MessageQueueMessage::getSender() const { + MessageQueueId_t temp_id; + memcpy(&temp_id, this->internalBuffer, sizeof(MessageQueueId_t)); + return temp_id; +} + +void MessageQueueMessage::setSender(MessageQueueId_t setId) { + memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t)); +} + +void MessageQueueMessage::print(bool printWholeMessage) { + sif::debug << "MessageQueueMessage content: " << std::endl; + if(printWholeMessage) { + arrayprinter::print(getData(), getMaximumMessageSize()); + } + else { + arrayprinter::print(getData(), getMessageSize()); + } + +} + +void MessageQueueMessage::clear() { + memset(this->getBuffer(), 0, this->MAX_MESSAGE_SIZE); +} + +size_t MessageQueueMessage::getMessageSize() const { + return this->messageSize; +} + +void MessageQueueMessage::setMessageSize(size_t messageSize) { + this->messageSize = messageSize; +} + +size_t MessageQueueMessage::getMinimumMessageSize() const { + return this->MIN_MESSAGE_SIZE; +} + +size_t MessageQueueMessage::getMaximumMessageSize() const { + return this->MAX_MESSAGE_SIZE; +} + diff --git a/ipc/MessageQueueMessage.h b/ipc/MessageQueueMessage.h index aa3559d6..da5c78cb 100644 --- a/ipc/MessageQueueMessage.h +++ b/ipc/MessageQueueMessage.h @@ -1,118 +1,150 @@ -#ifndef MESSAGEQUEUEMESSAGE_H_ -#define MESSAGEQUEUEMESSAGE_H_ - -#include "MessageQueueSenderIF.h" -#include - -/** - * \brief This class is the representation and data organizer for interprocess messages. - * - * \details To facilitate and standardize interprocess communication, this class was created - * to handle a lightweight "interprocess message protocol". It adds a header with the - * sender's queue id to every sent message and defines the maximum total message size. - * Specialized messages, such as device commanding messages, can be created by inheriting - * from this class and filling the buffer provided by getData with additional content. - * If larger amounts of data must be sent between processes, the data shall be stored in - * the IPC Store object and only the storage id is passed in a queue message. - * The class is used both to generate and send messages and to receive messages from - * other tasks. - * \ingroup message_queue - */ -class MessageQueueMessage { -public: - /** - * \brief This constant defines the maximum size of the data content, excluding the header. - * \details It may be changed if necessary, but in general should be kept as small as possible. - */ - static const size_t MAX_DATA_SIZE = 24; - /** - * \brief This constants defines the size of the header, which is added to every message. - */ - static const size_t HEADER_SIZE = sizeof(MessageQueueId_t); - /** - * \brief This constant defines the maximum total size in bytes of a sent message. - * \details It is the sum of the maximum data and the header size. Be aware that this constant - * is used to define the buffer sizes for every message queue in the system. So, a change - * here may have significant impact on the required resources. - */ - static const size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; -private: - /** - * \brief This is the internal buffer that contains the actual message data. - */ - uint8_t internalBuffer[MAX_MESSAGE_SIZE]; -public: - /** - * \brief The size information of each message is stored in this attribute. - * \details It is public to simplify usage and to allow for passing the variable's address as a - * pointer. Care must be taken when inheriting from this class, as every child class is - * responsible for managing the size information by itself. When using the class to - * receive a message, the size information is updated automatically. - */ - size_t messageSize; - /** - * \brief The class is initialized empty with this constructor. - * \details The messageSize attribute is set to the header's size and the whole content is set to - * zero. - */ - MessageQueueMessage(); - /** - * \brief With this constructor the class is initialized with the given content. - * \details If the passed message size fits into the buffer, the passed data is copied to the - * internal buffer and the messageSize information is set. Otherwise, messageSize - * is set to the header's size and the whole content is set to zero. - * \param data The data to be put in the message. - * \param size Size of the data to be copied. Must be smaller than MAX_MESSAGE_SIZE. - */ - MessageQueueMessage(uint8_t* data, uint32_t size); - /** - * \brief As no memory is allocated in this class, the destructor is empty. - */ - virtual ~MessageQueueMessage(); - /** - * \brief This method is used to get the complete data of the message. - */ - const uint8_t* getBuffer() const; - /** - * \brief This method is used to get the complete data of the message. - */ - uint8_t* getBuffer(); - /** - * \brief This method is used to fetch the data content of the message. - * \details It shall be used by child classes to add data at the right position. - */ - const uint8_t* getData() const; - /** - * \brief This method is used to fetch the data content of the message. - * \details It shall be used by child classes to add data at the right position. - */ - uint8_t* getData(); - /** - * \brief This method is used to extract the sender's message queue id information from a - * received message. - */ - MessageQueueId_t getSender() const; - /** - * \brief With this method, the whole content and the message size is set to zero. - */ - void clear(); - /** - * \brief This is a debug method that prints the content (till messageSize) to the debug output. - */ - void print(); - /** - * \brief This method is used to set the sender's message queue id information prior to - * sending the message. - * \param setId The message queue id that identifies the sending message queue. - */ - void setSender(MessageQueueId_t setId); - /** - * \brief This helper function is used by the MessageQueue class to check the size of an - * incoming message. - * \details The method must be overwritten by child classes if size checks shall be more strict. - * @return The default implementation returns HEADER_SIZE. - */ - virtual size_t getMinimumMessageSize(); -}; - -#endif /* MESSAGEQUEUEMESSAGE_H_ */ +#ifndef FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ +#define FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ + +#include "../ipc/MessageQueueMessageIF.h" +#include "../ipc/MessageQueueSenderIF.h" +#include + +/** + * @brief This class is the representation and data organizer + * for interprocess messages. + * @details + * To facilitate and standardize interprocess communication, this class was + * created to handle a lightweight "interprocess message protocol". + * + * It adds a header with the sender's queue id to every sent message and + * defines the maximum total message size. Specialized messages, such as + * device commanding messages, can be created by inheriting from this class + * and filling the buffer provided by getData with additional content. + * + * If larger amounts of data must be sent between processes, the data shall + * be stored in the IPC Store object and only the storage id is passed in a + * queue message.The class is used both to generate and send messages and to + * receive messages from other tasks. + * @ingroup message_queue + */ +class MessageQueueMessage: public MessageQueueMessageIF { +public: + /** + * @brief The class is initialized empty with this constructor. + * @details + * The messageSize attribute is set to the header's size and the whole + * content is set to zero. + */ + MessageQueueMessage(); + /** + * @brief With this constructor the class is initialized with + * the given content. + * @details + * If the passed message size fits into the buffer, the passed data is + * copied to the internal buffer and the messageSize information is set. + * Otherwise, messageSize is set to the header's size and the whole + * content is set to zero. + * @param data The data to be put in the message. + * @param size Size of the data to be copied. Must be smaller than + * MAX_MESSAGE_SIZE and larger than MIN_MESSAGE_SIZE. + */ + MessageQueueMessage(uint8_t* data, size_t size); + + /** + * @brief As no memory is allocated in this class, + * the destructor is empty. + */ + virtual ~MessageQueueMessage(); + + /** + * @brief The size information of each message is stored in + * this attribute. + * @details + * It is public to simplify usage and to allow for passing the size + * address as a pointer. Care must be taken when inheriting from this class, + * as every child class is responsible for managing the size information by + * itself. When using the class to receive a message, the size information + * is updated automatically. + * + * Please note that the minimum size is limited by the size of the header + * while the maximum size is limited by the maximum allowed message size. + */ + size_t messageSize; + /** + * @brief This constant defines the maximum size of the data content, + * excluding the header. + * @details + * It may be changed if necessary, but in general should be kept + * as small as possible. + */ + static const size_t MAX_DATA_SIZE = 24; + + /** + * @brief This constant defines the maximum total size in bytes + * of a sent message. + * @details + * It is the sum of the maximum data and the header size. Be aware that + * this constant is used to define the buffer sizes for every message + * queue in the system. So, a change here may have significant impact on + * the required resources. + */ + static constexpr size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; + /** + * @brief Defines the minimum size of a message where only the + * header is included + */ + static constexpr size_t MIN_MESSAGE_SIZE = HEADER_SIZE; +private: + /** + * @brief This is the internal buffer that contains the + * actual message data. + */ + uint8_t internalBuffer[MAX_MESSAGE_SIZE]; +public: + /** + * @brief This method is used to get the complete data of the message. + */ + const uint8_t* getBuffer() const override; + /** + * @brief This method is used to get the complete data of the message. + */ + uint8_t* getBuffer() override; + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + const uint8_t* getData() const override; + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + uint8_t* getData() override; + /** + * @brief This method is used to extract the sender's message + * queue id information from a received message. + */ + MessageQueueId_t getSender() const override; + /** + * @brief With this method, the whole content + * and the message size is set to zero. + */ + void clear() override; + + /** + * @brief This method is used to set the sender's message queue id + * information prior to ing the message. + * @param setId + * The message queue id that identifies the sending message queue. + */ + void setSender(MessageQueueId_t setId) override; + + virtual size_t getMessageSize() const override; + virtual void setMessageSize(size_t messageSize) override; + virtual size_t getMinimumMessageSize() const override; + virtual size_t getMaximumMessageSize() const override; + + /** + * @brief This is a debug method that prints the content. + */ + void print(bool printWholeMessage); +}; + +#endif /* FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ */ diff --git a/ipc/MessageQueueMessageIF.h b/ipc/MessageQueueMessageIF.h new file mode 100644 index 00000000..91753ced --- /dev/null +++ b/ipc/MessageQueueMessageIF.h @@ -0,0 +1,91 @@ +#ifndef FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ +#define FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ +#include +#include + +/* + * TODO: Actually, the definition of this ID to be a uint32_t is not ideal and + * breaks layering. However, it is difficult to keep layering, as the ID is + * stored in many places and sent around in MessageQueueMessage. + * Ideally, one would use the (current) object_id_t only, however, doing a + * lookup of queueIDs for every call does not sound ideal. + * In a first step, I'll circumvent the issue by not touching it, + * maybe in a second step. This also influences Interface design + * (getCommandQueue) and some other issues.. + */ + +typedef uint32_t MessageQueueId_t; + +class MessageQueueMessageIF { +public: + static const MessageQueueId_t NO_QUEUE = -1; + /** + * @brief This constants defines the size of the header, + * which is added to every message. + */ + static const size_t HEADER_SIZE = sizeof(MessageQueueId_t); + + virtual ~MessageQueueMessageIF() {}; + + /** + * @brief With this method, the whole content and the message + * size is set to zero. + * @details + * Implementations should also take care to clear data which is stored + * indirectly (e.g. storage data). + */ + virtual void clear() = 0; + + /** + * @brief Get read-only pointer to the complete data of the message. + * @return + */ + virtual const uint8_t* getBuffer() const = 0; + + /** + * @brief This method is used to get the complete data of the message. + */ + virtual uint8_t* getBuffer() = 0; + + /** + * @brief This method is used to set the sender's message queue id + * information prior to sending the message. + * @param setId + * The message queue id that identifies the sending message queue. + */ + virtual void setSender(MessageQueueId_t setId) = 0; + + /** + * @brief This method is used to extract the sender's message queue id + * information from a received message. + */ + virtual MessageQueueId_t getSender() const = 0; + + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + virtual const uint8_t* getData() const = 0; + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + virtual uint8_t* getData() = 0; + + /** + * Get constant message size of current message implementation. + * @return + */ + virtual size_t getMessageSize() const = 0; + + virtual void setMessageSize(size_t messageSize) = 0; + virtual size_t getMinimumMessageSize() const = 0; + virtual size_t getMaximumMessageSize() const = 0; + +}; + + + +#endif /* FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ */ From 66cf2d3559b93ff78ebb043dafc4ea2abb4d6efa Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 27 Aug 2020 16:05:31 +0200 Subject: [PATCH 19/53] timeslot update for FreeRTOS --- devicehandlers/FixedSequenceSlot.cpp | 20 -- osal/FreeRTOS/FixedTimeslotTask.cpp | 328 +++++++++--------- osal/FreeRTOS/FixedTimeslotTask.h | 203 ++++++----- tasks/FixedSequenceSlot.cpp | 17 + {devicehandlers => tasks}/FixedSequenceSlot.h | 117 +++---- .../FixedSlotSequence.cpp | 270 +++++++------- {devicehandlers => tasks}/FixedSlotSequence.h | 311 +++++++++-------- 7 files changed, 647 insertions(+), 619 deletions(-) delete mode 100644 devicehandlers/FixedSequenceSlot.cpp create mode 100644 tasks/FixedSequenceSlot.cpp rename {devicehandlers => tasks}/FixedSequenceSlot.h (56%) rename {devicehandlers => tasks}/FixedSlotSequence.cpp (61%) rename {devicehandlers => tasks}/FixedSlotSequence.h (90%) diff --git a/devicehandlers/FixedSequenceSlot.cpp b/devicehandlers/FixedSequenceSlot.cpp deleted file mode 100644 index 667aba1d..00000000 --- a/devicehandlers/FixedSequenceSlot.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file PollingSlot.cpp - * @brief This file defines the PollingSlot class. - * @date 19.12.2012 - * @author baetz - */ - -#include "FixedSequenceSlot.h" -#include "../objectmanager/SystemObjectIF.h" -#include - -FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, - int8_t setSequenceId, PeriodicTaskIF* executingTask) : - handler(NULL), pollingTimeMs(setTime), opcode(setSequenceId) { - handler = objectManager->get(handlerId); - handler->setTaskIF(executingTask); -} - -FixedSequenceSlot::~FixedSequenceSlot() {} - diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index 4873dde4..772c4bca 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -1,162 +1,166 @@ -#include "FixedTimeslotTask.h" - -#include "../../serviceinterface/ServiceInterfaceStream.h" - -uint32_t FixedTimeslotTask::deadlineMissedCount = 0; -const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; - -FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod overallPeriod, - void (*setDeadlineMissedFunc)()) : - started(false), handle(NULL), pst(overallPeriod * 1000) { - configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); - xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); - // All additional attributes are applied to the object. - this->deadlineMissedFunc = setDeadlineMissedFunc; -} - -FixedTimeslotTask::~FixedTimeslotTask() { -} - -void FixedTimeslotTask::taskEntryPoint(void* argument) { - - // The argument is re-interpreted as FixedTimeslotTask. The Task object is - // global, so it is found from any place. - FixedTimeslotTask *originalTask(reinterpret_cast(argument)); - /* Task should not start until explicitly requested, - * but in FreeRTOS, tasks start as soon as they are created if the scheduler - * is running but not if the scheduler is not running. - * To be able to accommodate both cases we check a member which is set in - * #startTask(). If it is not set and we get here, the scheduler was started - * before #startTask() was called and we need to suspend if it is set, - * the scheduler was not running before #startTask() was called and we - * can continue */ - - if (not originalTask->started) { - vTaskSuspend(NULL); - } - - originalTask->taskFunctionality(); - sif::debug << "Polling task " << originalTask->handle - << " returned from taskFunctionality." << std::endl; -} - -void FixedTimeslotTask::missedDeadlineCounter() { - FixedTimeslotTask::deadlineMissedCount++; - if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { - sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount - << " deadlines." << std::endl; - } -} - -ReturnValue_t FixedTimeslotTask::startTask() { - started = true; - - // We must not call resume if scheduler is not started yet - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - vTaskResume(handle); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, - uint32_t slotTimeMs, int8_t executionStep) { - if (objectManager->get(componentId) != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); - return HasReturnvaluesIF::RETURN_OK; - } - - sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; -} - -uint32_t FixedTimeslotTask::getPeriodMs() const { - return pst.getLengthMs(); -} - -ReturnValue_t FixedTimeslotTask::checkSequence() const { - return pst.checkSequence(); -} - -void FixedTimeslotTask::taskFunctionality() { - // A local iterator for the Polling Sequence Table is created to find the - // start time for the first entry. - auto slotListIter = pst.current; - - //The start time for the first entry is read. - uint32_t intervalMs = slotListIter->pollingTimeMs; - TickType_t interval = pdMS_TO_TICKS(intervalMs); - - TickType_t xLastWakeTime; - /* The xLastWakeTime variable needs to be initialized with the current tick - count. Note that this is the only time the variable is written to - explicitly. After this assignment, xLastWakeTime is updated automatically - internally within vTaskDelayUntil(). */ - xLastWakeTime = xTaskGetTickCount(); - - // wait for first entry's start time - if(interval > 0) { - vTaskDelayUntil(&xLastWakeTime, interval); - } - - /* Enter the loop that defines the task behavior. */ - for (;;) { - //The component for this slot is executed and the next one is chosen. - this->pst.executeAndAdvance(); - if (not pst.slotFollowsImmediately()) { - // Get the interval till execution of the next slot. - intervalMs = this->pst.getIntervalToPreviousSlotMs(); - interval = pdMS_TO_TICKS(intervalMs); - - checkMissedDeadline(xLastWakeTime, interval); - - // Wait for the interval. This exits immediately if a deadline was - // missed while also updating the last wake time. - vTaskDelayUntil(&xLastWakeTime, interval); - } - } -} - -void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval) { - /* Check whether deadline was missed while also taking overflows - * into account. Drawing this on paper with a timeline helps to understand - * it. */ - TickType_t currentTickCount = xTaskGetTickCount(); - TickType_t timeToWake = xLastWakeTime + interval; - // Time to wake has not overflown. - if(timeToWake > xLastWakeTime) { - /* If the current time has overflown exclusively or the current - * tick count is simply larger than the time to wake, a deadline was - * missed */ - if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } - } - /* Time to wake has overflown. A deadline was missed if the current time - * is larger than the time to wake */ - else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } -} - -void FixedTimeslotTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif - if(deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } -} - -ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { - vTaskDelay(pdMS_TO_TICKS(ms)); - return HasReturnvaluesIF::RETURN_OK; -} - -TaskHandle_t FixedTimeslotTask::getTaskHandle() { - return handle; -} +#include "FixedTimeslotTask.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" + +uint32_t FixedTimeslotTask::deadlineMissedCount = 0; +const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; + +FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod overallPeriod, + void (*setDeadlineMissedFunc)()) : + started(false), handle(nullptr), pst(overallPeriod * 1000) { + configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); + xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); + // All additional attributes are applied to the object. + this->deadlineMissedFunc = setDeadlineMissedFunc; +} + +FixedTimeslotTask::~FixedTimeslotTask() { +} + +void FixedTimeslotTask::taskEntryPoint(void* argument) { + + // The argument is re-interpreted as FixedTimeslotTask. The Task object is + // global, so it is found from any place. + FixedTimeslotTask *originalTask(reinterpret_cast(argument)); + /* Task should not start until explicitly requested, + * but in FreeRTOS, tasks start as soon as they are created if the scheduler + * is running but not if the scheduler is not running. + * To be able to accommodate both cases we check a member which is set in + * #startTask(). If it is not set and we get here, the scheduler was started + * before #startTask() was called and we need to suspend if it is set, + * the scheduler was not running before #startTask() was called and we + * can continue */ + + if (not originalTask->started) { + vTaskSuspend(NULL); + } + + originalTask->taskFunctionality(); + sif::debug << "Polling task " << originalTask->handle + << " returned from taskFunctionality." << std::endl; +} + +void FixedTimeslotTask::missedDeadlineCounter() { + FixedTimeslotTask::deadlineMissedCount++; + if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { + sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount + << " deadlines." << std::endl; + } +} + +ReturnValue_t FixedTimeslotTask::startTask() { + started = true; + + // We must not call resume if scheduler is not started yet + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + vTaskResume(handle); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) { + ExecutableObjectIF* handler = + objectManager->get(componentId); + if (handler != nullptr) { + pst.addSlot(componentId, slotTimeMs, executionStep, handler, this); + return HasReturnvaluesIF::RETURN_OK; + } + + sif::error << "Component " << std::hex << componentId << + " not found, not adding it to pst" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +} + +uint32_t FixedTimeslotTask::getPeriodMs() const { + return pst.getLengthMs(); +} + +ReturnValue_t FixedTimeslotTask::checkSequence() const { + return pst.checkSequence(); +} + +void FixedTimeslotTask::taskFunctionality() { + // A local iterator for the Polling Sequence Table is created to find the + // start time for the first entry. + auto slotListIter = pst.current; + + pst.intializeSequenceAfterTaskCreation(); + + //The start time for the first entry is read. + uint32_t intervalMs = slotListIter->pollingTimeMs; + TickType_t interval = pdMS_TO_TICKS(intervalMs); + + TickType_t xLastWakeTime; + /* The xLastWakeTime variable needs to be initialized with the current tick + count. Note that this is the only time the variable is written to + explicitly. After this assignment, xLastWakeTime is updated automatically + internally within vTaskDelayUntil(). */ + xLastWakeTime = xTaskGetTickCount(); + + // wait for first entry's start time + if(interval > 0) { + vTaskDelayUntil(&xLastWakeTime, interval); + } + + /* Enter the loop that defines the task behavior. */ + for (;;) { + //The component for this slot is executed and the next one is chosen. + this->pst.executeAndAdvance(); + if (not pst.slotFollowsImmediately()) { + // Get the interval till execution of the next slot. + intervalMs = this->pst.getIntervalToPreviousSlotMs(); + interval = pdMS_TO_TICKS(intervalMs); + + checkMissedDeadline(xLastWakeTime, interval); + + // Wait for the interval. This exits immediately if a deadline was + // missed while also updating the last wake time. + vTaskDelayUntil(&xLastWakeTime, interval); + } + } +} + +void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval) { + /* Check whether deadline was missed while also taking overflows + * into account. Drawing this on paper with a timeline helps to understand + * it. */ + TickType_t currentTickCount = xTaskGetTickCount(); + TickType_t timeToWake = xLastWakeTime + interval; + // Time to wake has not overflown. + if(timeToWake > xLastWakeTime) { + /* If the current time has overflown exclusively or the current + * tick count is simply larger than the time to wake, a deadline was + * missed */ + if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } + } + /* Time to wake has overflown. A deadline was missed if the current time + * is larger than the time to wake */ + else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } +} + +void FixedTimeslotTask::handleMissedDeadline() { +#ifdef DEBUG + sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << + " missed deadline!\n" << std::flush; +#endif + if(deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } +} + +ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +TaskHandle_t FixedTimeslotTask::getTaskHandle() { + return handle; +} diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/osal/FreeRTOS/FixedTimeslotTask.h index 84264c4c..42af14b8 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -1,102 +1,101 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ - -#include "FreeRTOSTaskIF.h" -#include "../../devicehandlers/FixedSlotSequence.h" -#include "../../tasks/FixedTimeslotTaskIF.h" -#include "../../tasks/Typedef.h" - - -#include -#include - -class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF { -public: - - /** - * Keep in mind that you need to call before vTaskStartScheduler()! - * A lot of task parameters are set in "FreeRTOSConfig.h". - * @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN - * @param setPriority Number of priorities specified by - * configMAX_PRIORITIES. High taskPriority_ number means high priority. - * @param setStack Stack size in words (not bytes!). - * Lower limit specified by configMINIMAL_STACK_SIZE - * @param overallPeriod Period in seconds. - * @param setDeadlineMissedFunc Callback if a deadline was missed. - * @return Pointer to the newly created task. - */ - FixedTimeslotTask(TaskName name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod overallPeriod, - void (*setDeadlineMissedFunc)()); - - /** - * @brief The destructor of the class. - * @details - * The destructor frees all heap memory that was allocated on thread - * initialization for the PST and the device handlers. This is done by - * calling the PST's destructor. - */ - virtual ~FixedTimeslotTask(void); - - ReturnValue_t startTask(void); - /** - * This static function can be used as #deadlineMissedFunc. - * It counts missedDeadlines and prints the number of missed deadlines - * every 10th time. - */ - static void missedDeadlineCounter(); - /** - * A helper variable to count missed deadlines. - */ - static uint32_t deadlineMissedCount; - - ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep) override; - - uint32_t getPeriodMs() const override; - - ReturnValue_t checkSequence() const override; - - ReturnValue_t sleepFor(uint32_t ms) override; - - TaskHandle_t getTaskHandle() override; - -protected: - bool started; - TaskHandle_t handle; - - FixedSlotSequence pst; - - /** - * @brief This attribute holds a function pointer that is executed when - * a deadline was missed. - * @details - * Another function may be announced to determine the actions to perform - * when a deadline was missed. Currently, only one function for missing - * any deadline is allowed. If not used, it shall be declared NULL. - */ - void (*deadlineMissedFunc)(void); - /** - * @brief This is the entry point for a new task. - * @details - * This method starts the task by calling taskFunctionality(), as soon as - * all requirements (task scheduler has started and startTask() - * has been called) are met. - */ - static void taskEntryPoint(void* argument); - - /** - * @brief This function holds the main functionality of the thread. - * @details - * Core function holding the main functionality of the task - * It links the functionalities provided by FixedSlotSequence with the - * OS's System Calls to keep the timing of the periods. - */ - void taskFunctionality(void); - - void checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval); - void handleMissedDeadline(); -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ + +#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" +#include "../../tasks/FixedSlotSequence.h" +#include "../../tasks/FixedTimeslotTaskIF.h" +#include "../../tasks/Typedef.h" + +#include +#include + +class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF { +public: + + /** + * Keep in mind that you need to call before vTaskStartScheduler()! + * A lot of task parameters are set in "FreeRTOSConfig.h". + * @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN + * @param setPriority Number of priorities specified by + * configMAX_PRIORITIES. High taskPriority_ number means high priority. + * @param setStack Stack size in words (not bytes!). + * Lower limit specified by configMINIMAL_STACK_SIZE + * @param overallPeriod Period in seconds. + * @param setDeadlineMissedFunc Callback if a deadline was missed. + * @return Pointer to the newly created task. + */ + FixedTimeslotTask(TaskName name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod overallPeriod, + void (*setDeadlineMissedFunc)()); + + /** + * @brief The destructor of the class. + * @details + * The destructor frees all heap memory that was allocated on thread + * initialization for the PST and the device handlers. This is done by + * calling the PST's destructor. + */ + virtual ~FixedTimeslotTask(void); + + ReturnValue_t startTask(void); + /** + * This static function can be used as #deadlineMissedFunc. + * It counts missedDeadlines and prints the number of missed deadlines + * every 10th time. + */ + static void missedDeadlineCounter(); + /** + * A helper variable to count missed deadlines. + */ + static uint32_t deadlineMissedCount; + + ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep) override; + + uint32_t getPeriodMs() const override; + + ReturnValue_t checkSequence() const override; + + ReturnValue_t sleepFor(uint32_t ms) override; + + TaskHandle_t getTaskHandle() override; + +protected: + bool started; + TaskHandle_t handle; + + FixedSlotSequence pst; + + /** + * @brief This attribute holds a function pointer that is executed when + * a deadline was missed. + * @details + * Another function may be announced to determine the actions to perform + * when a deadline was missed. Currently, only one function for missing + * any deadline is allowed. If not used, it shall be declared NULL. + */ + void (*deadlineMissedFunc)(void); + /** + * @brief This is the entry point for a new task. + * @details + * This method starts the task by calling taskFunctionality(), as soon as + * all requirements (task scheduler has started and startTask() + * has been called) are met. + */ + static void taskEntryPoint(void* argument); + + /** + * @brief This function holds the main functionality of the thread. + * @details + * Core function holding the main functionality of the task + * It links the functionalities provided by FixedSlotSequence with the + * OS's System Calls to keep the timing of the periods. + */ + void taskFunctionality(void); + + void checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval); + void handleMissedDeadline(); +}; + +#endif /* POLLINGTASK_H_ */ diff --git a/tasks/FixedSequenceSlot.cpp b/tasks/FixedSequenceSlot.cpp new file mode 100644 index 00000000..5fe49523 --- /dev/null +++ b/tasks/FixedSequenceSlot.cpp @@ -0,0 +1,17 @@ +#include "FixedSequenceSlot.h" +#include "../objectmanager/SystemObjectIF.h" +#include + +FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, + int8_t setSequenceId, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask) : + pollingTimeMs(setTime), opcode(setSequenceId) { + if(executableObject == nullptr) { + return; + } + this->executableObject = executableObject; + this->executableObject->setTaskIF(executingTask); +} + +FixedSequenceSlot::~FixedSequenceSlot() {} + diff --git a/devicehandlers/FixedSequenceSlot.h b/tasks/FixedSequenceSlot.h similarity index 56% rename from devicehandlers/FixedSequenceSlot.h rename to tasks/FixedSequenceSlot.h index 73504955..9cf5894c 100644 --- a/devicehandlers/FixedSequenceSlot.h +++ b/tasks/FixedSequenceSlot.h @@ -1,60 +1,57 @@ -/** - * @file FixedSequenceSlot.h - * @brief This file defines the PollingSlot class. - * @date 19.12.2012 - * @author baetz - */ - -#ifndef FIXEDSEQUENCESLOT_H_ -#define FIXEDSEQUENCESLOT_H_ - -#include "../objectmanager/ObjectManagerIF.h" -#include "../tasks/ExecutableObjectIF.h" -class PeriodicTaskIF; - -/** - * @brief This class is the representation of a single polling sequence table entry. - * - * @details The PollingSlot class is the representation of a single polling - * sequence table entry. - */ -class FixedSequenceSlot { -public: - FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, - int8_t setSequenceId, PeriodicTaskIF* executingTask ); - virtual ~FixedSequenceSlot(); - - /** - * @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. - * - * @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. - */ - uint8_t opcode; - - /** - * @brief Operator overload for the comparison operator to - * allow sorting by polling time. - * @param fixedSequenceSlot - * @return - */ - bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { - return pollingTimeMs < fixedSequenceSlot.pollingTimeMs; - } -}; - - -#endif /* FIXEDSEQUENCESLOT_H_ */ +#ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ +#define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../tasks/ExecutableObjectIF.h" +class PeriodicTaskIF; + +/** + * @brief This class is the representation of a single polling sequence + * table entry. + * @details + * The PollingSlot class is the representation of a single polling + * sequence table entry. + * @author baetz + */ +class FixedSequenceSlot { +public: + FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, + int8_t setSequenceId, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask); + virtual ~FixedSequenceSlot(); + + /** + * @brief Handler identifies which object is executed in this slot. + */ + ExecutableObjectIF* executableObject = nullptr; + + /** + * @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. + */ + 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. + */ + uint8_t opcode; + + /** + * @brief Operator overload for the comparison operator to + * allow sorting by polling time. + * @param fixedSequenceSlot + * @return + */ + bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { + return pollingTimeMs < fixedSequenceSlot.pollingTimeMs; + } +}; + + +#endif /* FIXEDSEQUENCESLOT_H_ */ diff --git a/devicehandlers/FixedSlotSequence.cpp b/tasks/FixedSlotSequence.cpp similarity index 61% rename from devicehandlers/FixedSlotSequence.cpp rename to tasks/FixedSlotSequence.cpp index 38d4dcea..78f512ca 100644 --- a/devicehandlers/FixedSlotSequence.cpp +++ b/tasks/FixedSlotSequence.cpp @@ -1,123 +1,147 @@ -#include "FixedSlotSequence.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : - lengthMs(setLengthMs) { - current = slotList.begin(); -} - -FixedSlotSequence::~FixedSlotSequence() { - // Call the destructor on each list entry. - slotList.clear(); -} - -void FixedSlotSequence::executeAndAdvance() { - current->handler->performOperation(current->opcode); -// if (returnValue != RETURN_OK) { -// this->sendErrorMessage( returnValue ); -// } - //Increment the polling Sequence iterator - this->current++; - //Set it to the beginning, if the list's end is reached. - if (this->current == this->slotList.end()) { - this->current = this->slotList.begin(); - } -} - -uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { - uint32_t oldTime; - SlotListIter slotListIter = current; - // Get the pollingTimeMs of the current slot object. - oldTime = slotListIter->pollingTimeMs; - // Advance to the next object. - slotListIter++; - // Find the next interval which is not 0. - while (slotListIter != slotList.end()) { - if (oldTime != slotListIter->pollingTimeMs) { - return slotListIter->pollingTimeMs - oldTime; - } else { - 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. - slotListIter = slotList.begin(); - return lengthMs - oldTime + slotListIter->pollingTimeMs; -} - -uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { - uint32_t currentTime; - SlotListIter slotListIter = current; - // Get the pollingTimeMs of the current slot object. - currentTime = slotListIter->pollingTimeMs; - - //if it is the first slot, calculate difference to last slot - if (slotListIter == slotList.begin()){ - return lengthMs - (--slotList.end())->pollingTimeMs + currentTime; - } - // get previous slot - slotListIter--; - - return currentTime - slotListIter->pollingTimeMs; -} - -bool FixedSlotSequence::slotFollowsImmediately() { - uint32_t currentTime = current->pollingTimeMs; - SlotListIter fixedSequenceIter = this->current; - // Get the pollingTimeMs of the current slot object. - if (fixedSequenceIter == slotList.begin()) - return false; - fixedSequenceIter--; - if (fixedSequenceIter->pollingTimeMs == currentTime) { - return true; - } else { - return false; - } -} - -uint32_t FixedSlotSequence::getLengthMs() const { - return this->lengthMs; -} - -ReturnValue_t FixedSlotSequence::checkSequence() const { - if(slotList.empty()) { - sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - auto slotIt = slotList.begin(); - uint32_t count = 0; - uint32_t time = 0; - while (slotIt != slotList.end()) { - if (slotIt->handler == nullptr) { - sif::error << "FixedSlotSequene::initialize: ObjectId does not exist!" - << std::endl; - count++; - } else if (slotIt->pollingTimeMs < time) { - sif::error << "FixedSlotSequence::initialize: Time: " - << slotIt->pollingTimeMs - << " is smaller than previous with " << time << std::endl; - count++; - } else { - // All ok, print slot. - //info << "Current slot polling time: " << std::endl; - //info << std::dec << slotIt->pollingTimeMs << std::endl; - } - time = slotIt->pollingTimeMs; - slotIt++; - } - //info << "Number of elements in slot list: " - // << slotList.size() << std::endl; - if (count > 0) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep, PeriodicTaskIF* executingTask) { - this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep, - executingTask)); - this->current = slotList.begin(); -} +#include "FixedSlotSequence.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include + +FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : + lengthMs(setLengthMs) { + current = slotList.begin(); +} + +FixedSlotSequence::~FixedSlotSequence() { + // Call the destructor on each list entry. + slotList.clear(); +} + +void FixedSlotSequence::executeAndAdvance() { + current->executableObject->performOperation(current->opcode); +// if (returnValue != RETURN_OK) { +// this->sendErrorMessage( returnValue ); +// } + //Increment the polling Sequence iterator + this->current++; + //Set it to the beginning, if the list's end is reached. + if (this->current == this->slotList.end()) { + this->current = this->slotList.begin(); + } +} + +uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { + uint32_t oldTime; + SlotListIter slotListIter = current; + // Get the pollingTimeMs of the current slot object. + oldTime = slotListIter->pollingTimeMs; + // Advance to the next object. + slotListIter++; + // Find the next interval which is not 0. + while (slotListIter != slotList.end()) { + if (oldTime != slotListIter->pollingTimeMs) { + return slotListIter->pollingTimeMs - oldTime; + } else { + 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. + slotListIter = slotList.begin(); + return lengthMs - oldTime + slotListIter->pollingTimeMs; +} + +uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { + uint32_t currentTime; + SlotListIter slotListIter = current; + // Get the pollingTimeMs of the current slot object. + currentTime = slotListIter->pollingTimeMs; + + //if it is the first slot, calculate difference to last slot + if (slotListIter == slotList.begin()){ + return lengthMs - (--slotList.end())->pollingTimeMs + currentTime; + } + // get previous slot + slotListIter--; + + return currentTime - slotListIter->pollingTimeMs; +} + +bool FixedSlotSequence::slotFollowsImmediately() { + uint32_t currentTime = current->pollingTimeMs; + SlotListIter fixedSequenceIter = this->current; + // Get the pollingTimeMs of the current slot object. + if (fixedSequenceIter == slotList.begin()) + return false; + fixedSequenceIter--; + if (fixedSequenceIter->pollingTimeMs == currentTime) { + return true; + } else { + return false; + } +} + +uint32_t FixedSlotSequence::getLengthMs() const { + return this->lengthMs; +} + +void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask) { + this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, + executionStep, executableObject, executingTask)); + this->current = slotList.begin(); +} + +ReturnValue_t FixedSlotSequence::checkSequence() const { + if(slotList.empty()) { + sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint32_t count = 0; + uint32_t time = 0; + for(const auto& slot: slotList) { + if (slot.executableObject == nullptr) { + count++; + } + else if (slot.pollingTimeMs < time) { + sif::error << "FixedSlotSequence::initialize: Time: " + << slot.pollingTimeMs << " is smaller than previous with " + << time << std::endl; + count++; + } + else { + // All ok, print slot. + //sif::info << "Current slot polling time: " << std::endl; + //sif::info << std::dec << slotIt->pollingTimeMs << std::endl; + } + time = slot.pollingTimeMs; + + } + //sif::info << "Number of elements in slot list: " + // << slotList.size() << std::endl; + if (count > 0) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const { + std::set uniqueObjects; + uint32_t count = 0; + for(const auto& slot: slotList) { + // Ensure that each unique object is initialized once. + if(uniqueObjects.find(slot.executableObject) == uniqueObjects.end()) { + ReturnValue_t result = + slot.executableObject->initializeAfterTaskCreation(); + if(result != HasReturnvaluesIF::RETURN_OK) { + count++; + } + uniqueObjects.emplace(slot.executableObject); + } + } + if (count > 0) { + sif::error << "FixedSlotSequence::intializeSequenceAfterTaskCreation:" + "Counted " << count << " failed initializations!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/devicehandlers/FixedSlotSequence.h b/tasks/FixedSlotSequence.h similarity index 90% rename from devicehandlers/FixedSlotSequence.h rename to tasks/FixedSlotSequence.h index be6dc2d1..8aa04a27 100644 --- a/devicehandlers/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -1,152 +1,159 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_ -#define FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_ - -#include "FixedSequenceSlot.h" -#include "../objectmanager/SystemObject.h" -#include - -/** - * @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. - * - * The main idea is to create a list of device handlers, to announce all - * handlers to thepolling 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 - * which device handler shall be executed within a given polling period. - * The sequence is then executed by iterating through this slot list. - * Handlers are invoking by calling a certain function stored in the handler list. - */ -class FixedSlotSequence { -public: - using SlotList = std::multiset; - using SlotListIter = std::multiset::iterator; - - /** - * @brief The constructor of the FixedSlotSequence object. - * - * @details The constructor takes two arguments, the period length and the init function. - * - * @param setLength The period length, expressed in ms. - */ - FixedSlotSequence(uint32_t setLengthMs); - - /** - * @brief The destructor of the FixedSlotSequence object. - * - * @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. - * - * @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); - - /** - * Checks if the current slot shall be executed immediately after the one before. - * This allows to distinguish between grouped and not grouped handlers. - * @return - @c true if the slot has the same polling time as the previous - * - @c false else - */ - bool slotFollowsImmediately(); - - /** - * @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. - */ - uint32_t getIntervalToNextSlotMs(); - - /** - * @brief This method returns the time difference between the current - * slot and the previous slot - * - * @details - * This method is vitally important for the operation of the PST. - * By fetching the polling time of the current slot and that of the previous - * one (or the last one, if the slot is the first one) it calculates and - * returns the interval in milliseconds that the handler execution shall - * be delayed. - */ - uint32_t getIntervalToPreviousSlotMs(); - - /** - * @brief This method returns the length of this FixedSlotSequence instance. - */ - uint32_t getLengthMs() const; - - /** - * @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 talkToInterface or its listenToInterface - * method is invoked, depending on the isTalking flag of the polling slot. - * After execution the iterator current is increased or, by reaching the - * end of slotList, reset to the beginning. - */ - void executeAndAdvance(); - - /** - * @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. - */ - SlotListIter current; - - /** - * Iterate through slotList and check successful creation. - * Checks if timing is ok (must be ascending) and if all handlers were found. - * @return - */ - ReturnValue_t checkSequence() const; - -protected: - - /** - * @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 - * 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. - */ - SlotList slotList; - - uint32_t lengthMs; -}; - -#endif /* FIXEDSLOTSEQUENCE_H_ */ +#ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ +#define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ + +#include "FixedSequenceSlot.h" +#include "../objectmanager/SystemObject.h" + +#include + +/** + * @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. + * + * The main idea is to create a list of device handlers, to announce all + * handlers to thepolling 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 + * which device handler shall be executed within a given polling period. + * The sequence is then executed by iterating through this slot list. + * Handlers are invoking by calling a certain function stored in the handler list. + */ +class FixedSlotSequence { +public: + using SlotList = std::multiset; + using SlotListIter = std::multiset::iterator; + + /** + * @brief The constructor of the FixedSlotSequence object. + * + * @details The constructor takes two arguments, the period length and the init function. + * + * @param setLength The period length, expressed in ms. + */ + FixedSlotSequence(uint32_t setLengthMs); + + /** + * @brief The destructor of the FixedSlotSequence object. + * + * @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. + * + * @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, + ExecutableObjectIF* executableObject, PeriodicTaskIF* executingTask); + + /** + * Checks if the current slot shall be executed immediately after the one before. + * This allows to distinguish between grouped and not grouped handlers. + * @return - @c true if the slot has the same polling time as the previous + * - @c false else + */ + bool slotFollowsImmediately(); + + /** + * @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. + */ + uint32_t getIntervalToNextSlotMs(); + + /** + * @brief This method returns the time difference between the current + * slot and the previous slot + * + * @details + * This method is vitally important for the operation of the PST. + * By fetching the polling time of the current slot and that of the previous + * one (or the last one, if the slot is the first one) it calculates and + * returns the interval in milliseconds that the handler execution shall + * be delayed. + */ + uint32_t getIntervalToPreviousSlotMs(); + + /** + * @brief This method returns the length of this FixedSlotSequence instance. + */ + uint32_t getLengthMs() const; + + /** + * @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 talkToInterface or its listenToInterface + * method is invoked, depending on the isTalking flag of the polling slot. + * After execution the iterator current is increased or, by reaching the + * end of slotList, reset to the beginning. + */ + void executeAndAdvance(); + + /** + * @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. + */ + SlotListIter current; + + /** + * @brief Check and initialize slot list. + * @details + * Checks if timing is ok (must be ascending) and if all handlers were found. + * Also calls any initialization steps which are required after task + * creation. + * @return + */ + ReturnValue_t checkSequence() const; + + ReturnValue_t intializeSequenceAfterTaskCreation() const; + +protected: + + /** + * @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 + * 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. + */ + SlotList slotList; + + uint32_t lengthMs; + + bool isEmpty = false; +}; + +#endif /* FIXEDSLOTSEQUENCE_H_ */ From 64022212f97e6726feb6a5768f44897180081e20 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 27 Aug 2020 16:20:32 +0200 Subject: [PATCH 20/53] removed is empty flag --- tasks/FixedSlotSequence.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/tasks/FixedSlotSequence.h b/tasks/FixedSlotSequence.h index 8aa04a27..026d5a3d 100644 --- a/tasks/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -152,8 +152,6 @@ protected: SlotList slotList; uint32_t lengthMs; - - bool isEmpty = false; }; #endif /* FIXEDSLOTSEQUENCE_H_ */ From 5eaf6cfd1f3afa8a02f7ce30c0e84f6a648f7193 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 13:52:02 +0200 Subject: [PATCH 21/53] renormalizing pull request step1 --- osal/FreeRTOS/FixedTimeslotTask.cpp | 337 ++++++++++++++-------------- osal/FreeRTOS/FixedTimeslotTask.h | 202 ++++++++--------- 2 files changed, 272 insertions(+), 267 deletions(-) diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index 772c4bca..309574eb 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -1,166 +1,171 @@ -#include "FixedTimeslotTask.h" - -#include "../../serviceinterface/ServiceInterfaceStream.h" - -uint32_t FixedTimeslotTask::deadlineMissedCount = 0; -const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; - -FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod overallPeriod, - void (*setDeadlineMissedFunc)()) : - started(false), handle(nullptr), pst(overallPeriod * 1000) { - configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); - xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); - // All additional attributes are applied to the object. - this->deadlineMissedFunc = setDeadlineMissedFunc; -} - -FixedTimeslotTask::~FixedTimeslotTask() { -} - -void FixedTimeslotTask::taskEntryPoint(void* argument) { - - // The argument is re-interpreted as FixedTimeslotTask. The Task object is - // global, so it is found from any place. - FixedTimeslotTask *originalTask(reinterpret_cast(argument)); - /* Task should not start until explicitly requested, - * but in FreeRTOS, tasks start as soon as they are created if the scheduler - * is running but not if the scheduler is not running. - * To be able to accommodate both cases we check a member which is set in - * #startTask(). If it is not set and we get here, the scheduler was started - * before #startTask() was called and we need to suspend if it is set, - * the scheduler was not running before #startTask() was called and we - * can continue */ - - if (not originalTask->started) { - vTaskSuspend(NULL); - } - - originalTask->taskFunctionality(); - sif::debug << "Polling task " << originalTask->handle - << " returned from taskFunctionality." << std::endl; -} - -void FixedTimeslotTask::missedDeadlineCounter() { - FixedTimeslotTask::deadlineMissedCount++; - if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { - sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount - << " deadlines." << std::endl; - } -} - -ReturnValue_t FixedTimeslotTask::startTask() { - started = true; - - // We must not call resume if scheduler is not started yet - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - vTaskResume(handle); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, - uint32_t slotTimeMs, int8_t executionStep) { - ExecutableObjectIF* handler = - objectManager->get(componentId); - if (handler != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, handler, this); - return HasReturnvaluesIF::RETURN_OK; - } - - sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; -} - -uint32_t FixedTimeslotTask::getPeriodMs() const { - return pst.getLengthMs(); -} - -ReturnValue_t FixedTimeslotTask::checkSequence() const { - return pst.checkSequence(); -} - -void FixedTimeslotTask::taskFunctionality() { - // A local iterator for the Polling Sequence Table is created to find the - // start time for the first entry. - auto slotListIter = pst.current; - - pst.intializeSequenceAfterTaskCreation(); - - //The start time for the first entry is read. - uint32_t intervalMs = slotListIter->pollingTimeMs; - TickType_t interval = pdMS_TO_TICKS(intervalMs); - - TickType_t xLastWakeTime; - /* The xLastWakeTime variable needs to be initialized with the current tick - count. Note that this is the only time the variable is written to - explicitly. After this assignment, xLastWakeTime is updated automatically - internally within vTaskDelayUntil(). */ - xLastWakeTime = xTaskGetTickCount(); - - // wait for first entry's start time - if(interval > 0) { - vTaskDelayUntil(&xLastWakeTime, interval); - } - - /* Enter the loop that defines the task behavior. */ - for (;;) { - //The component for this slot is executed and the next one is chosen. - this->pst.executeAndAdvance(); - if (not pst.slotFollowsImmediately()) { - // Get the interval till execution of the next slot. - intervalMs = this->pst.getIntervalToPreviousSlotMs(); - interval = pdMS_TO_TICKS(intervalMs); - - checkMissedDeadline(xLastWakeTime, interval); - - // Wait for the interval. This exits immediately if a deadline was - // missed while also updating the last wake time. - vTaskDelayUntil(&xLastWakeTime, interval); - } - } -} - -void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval) { - /* Check whether deadline was missed while also taking overflows - * into account. Drawing this on paper with a timeline helps to understand - * it. */ - TickType_t currentTickCount = xTaskGetTickCount(); - TickType_t timeToWake = xLastWakeTime + interval; - // Time to wake has not overflown. - if(timeToWake > xLastWakeTime) { - /* If the current time has overflown exclusively or the current - * tick count is simply larger than the time to wake, a deadline was - * missed */ - if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } - } - /* Time to wake has overflown. A deadline was missed if the current time - * is larger than the time to wake */ - else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } -} - -void FixedTimeslotTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif - if(deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } -} - -ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { - vTaskDelay(pdMS_TO_TICKS(ms)); - return HasReturnvaluesIF::RETURN_OK; -} - -TaskHandle_t FixedTimeslotTask::getTaskHandle() { - return handle; -} +#include "FixedTimeslotTask.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" + +uint32_t FixedTimeslotTask::deadlineMissedCount = 0; +const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; + +FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod overallPeriod, + void (*setDeadlineMissedFunc)()) : + started(false), handle(nullptr), pst(overallPeriod * 1000) { + configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); + xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); + // All additional attributes are applied to the object. + this->deadlineMissedFunc = setDeadlineMissedFunc; +} + +FixedTimeslotTask::~FixedTimeslotTask() { +} + +void FixedTimeslotTask::taskEntryPoint(void* argument) { + + // The argument is re-interpreted as FixedTimeslotTask. The Task object is + // global, so it is found from any place. + FixedTimeslotTask *originalTask(reinterpret_cast(argument)); + /* Task should not start until explicitly requested, + * but in FreeRTOS, tasks start as soon as they are created if the scheduler + * is running but not if the scheduler is not running. + * To be able to accommodate both cases we check a member which is set in + * #startTask(). If it is not set and we get here, the scheduler was started + * before #startTask() was called and we need to suspend if it is set, + * the scheduler was not running before #startTask() was called and we + * can continue */ + + if (not originalTask->started) { + vTaskSuspend(NULL); + } + + originalTask->taskFunctionality(); + sif::debug << "Polling task " << originalTask->handle + << " returned from taskFunctionality." << std::endl; +} + +void FixedTimeslotTask::missedDeadlineCounter() { + FixedTimeslotTask::deadlineMissedCount++; + if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { + sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount + << " deadlines." << std::endl; + } +} + +ReturnValue_t FixedTimeslotTask::startTask() { + started = true; + + // We must not call resume if scheduler is not started yet + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + vTaskResume(handle); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) { + ExecutableObjectIF* handler = + objectManager->get(componentId); + if (handler != nullptr) { + pst.addSlot(componentId, slotTimeMs, executionStep, handler, this); + return HasReturnvaluesIF::RETURN_OK; + } + + sif::error << "Component " << std::hex << componentId << + " not found, not adding it to pst" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +} + +uint32_t FixedTimeslotTask::getPeriodMs() const { + return pst.getLengthMs(); +} + +ReturnValue_t FixedTimeslotTask::checkSequence() const { + return pst.checkSequence(); +} + +void FixedTimeslotTask::taskFunctionality() { + // A local iterator for the Polling Sequence Table is created to find the + // start time for the first entry. + auto slotListIter = pst.current; + + pst.intializeSequenceAfterTaskCreation(); + + //The start time for the first entry is read. + uint32_t intervalMs = slotListIter->pollingTimeMs; + TickType_t interval = pdMS_TO_TICKS(intervalMs); + + TickType_t xLastWakeTime; + /* The xLastWakeTime variable needs to be initialized with the current tick + count. Note that this is the only time the variable is written to + explicitly. After this assignment, xLastWakeTime is updated automatically + internally within vTaskDelayUntil(). */ + xLastWakeTime = xTaskGetTickCount(); + + // wait for first entry's start time + if(interval > 0) { + vTaskDelayUntil(&xLastWakeTime, interval); + } + + /* Enter the loop that defines the task behavior. */ + for (;;) { + //The component for this slot is executed and the next one is chosen. + this->pst.executeAndAdvance(); + if (not pst.slotFollowsImmediately()) { + // Get the interval till execution of the next slot. + intervalMs = this->pst.getIntervalToPreviousSlotMs(); + interval = pdMS_TO_TICKS(intervalMs); + + checkMissedDeadline(xLastWakeTime, interval); + + // Wait for the interval. This exits immediately if a deadline was + // missed while also updating the last wake time. + vTaskDelayUntil(&xLastWakeTime, interval); + } + } +} + +void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval) { + /* Check whether deadline was missed while also taking overflows + * into account. Drawing this on paper with a timeline helps to understand + * it. */ + TickType_t currentTickCount = xTaskGetTickCount(); + TickType_t timeToWake = xLastWakeTime + interval; + // Time to wake has not overflown. + if(timeToWake > xLastWakeTime) { + /* If the current time has overflown exclusively or the current + * tick count is simply larger than the time to wake, a deadline was + * missed */ + if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } + } + /* Time to wake has overflown. A deadline was missed if the current time + * is larger than the time to wake */ + else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } +} + +void FixedTimeslotTask::handleMissedDeadline() { + if(deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } + +#ifdef DEBUG + object_id_t handlerId = pst.current->handlerId; + sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << " with" + << " object ID 0x" << std::setfill('0') << std::setw(8) << std::hex + << handlerId << " missed deadline!" << std::setfill(' ') + << std::dec << std::endl; +#endif + +} + +ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +TaskHandle_t FixedTimeslotTask::getTaskHandle() { + return handle; +} diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/osal/FreeRTOS/FixedTimeslotTask.h index 42af14b8..c46de5b7 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -1,101 +1,101 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ - -#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" -#include "../../tasks/FixedSlotSequence.h" -#include "../../tasks/FixedTimeslotTaskIF.h" -#include "../../tasks/Typedef.h" - -#include -#include - -class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF { -public: - - /** - * Keep in mind that you need to call before vTaskStartScheduler()! - * A lot of task parameters are set in "FreeRTOSConfig.h". - * @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN - * @param setPriority Number of priorities specified by - * configMAX_PRIORITIES. High taskPriority_ number means high priority. - * @param setStack Stack size in words (not bytes!). - * Lower limit specified by configMINIMAL_STACK_SIZE - * @param overallPeriod Period in seconds. - * @param setDeadlineMissedFunc Callback if a deadline was missed. - * @return Pointer to the newly created task. - */ - FixedTimeslotTask(TaskName name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod overallPeriod, - void (*setDeadlineMissedFunc)()); - - /** - * @brief The destructor of the class. - * @details - * The destructor frees all heap memory that was allocated on thread - * initialization for the PST and the device handlers. This is done by - * calling the PST's destructor. - */ - virtual ~FixedTimeslotTask(void); - - ReturnValue_t startTask(void); - /** - * This static function can be used as #deadlineMissedFunc. - * It counts missedDeadlines and prints the number of missed deadlines - * every 10th time. - */ - static void missedDeadlineCounter(); - /** - * A helper variable to count missed deadlines. - */ - static uint32_t deadlineMissedCount; - - ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep) override; - - uint32_t getPeriodMs() const override; - - ReturnValue_t checkSequence() const override; - - ReturnValue_t sleepFor(uint32_t ms) override; - - TaskHandle_t getTaskHandle() override; - -protected: - bool started; - TaskHandle_t handle; - - FixedSlotSequence pst; - - /** - * @brief This attribute holds a function pointer that is executed when - * a deadline was missed. - * @details - * Another function may be announced to determine the actions to perform - * when a deadline was missed. Currently, only one function for missing - * any deadline is allowed. If not used, it shall be declared NULL. - */ - void (*deadlineMissedFunc)(void); - /** - * @brief This is the entry point for a new task. - * @details - * This method starts the task by calling taskFunctionality(), as soon as - * all requirements (task scheduler has started and startTask() - * has been called) are met. - */ - static void taskEntryPoint(void* argument); - - /** - * @brief This function holds the main functionality of the thread. - * @details - * Core function holding the main functionality of the task - * It links the functionalities provided by FixedSlotSequence with the - * OS's System Calls to keep the timing of the periods. - */ - void taskFunctionality(void); - - void checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval); - void handleMissedDeadline(); -}; - -#endif /* POLLINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ + +#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" +#include "../../tasks/FixedSlotSequence.h" +#include "../../tasks/FixedTimeslotTaskIF.h" +#include "../../tasks/Typedef.h" + +#include +#include + +class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF { +public: + + /** + * Keep in mind that you need to call before vTaskStartScheduler()! + * A lot of task parameters are set in "FreeRTOSConfig.h". + * @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN + * @param setPriority Number of priorities specified by + * configMAX_PRIORITIES. High taskPriority_ number means high priority. + * @param setStack Stack size in words (not bytes!). + * Lower limit specified by configMINIMAL_STACK_SIZE + * @param overallPeriod Period in seconds. + * @param setDeadlineMissedFunc Callback if a deadline was missed. + * @return Pointer to the newly created task. + */ + FixedTimeslotTask(TaskName name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod overallPeriod, + void (*setDeadlineMissedFunc)()); + + /** + * @brief The destructor of the class. + * @details + * The destructor frees all heap memory that was allocated on thread + * initialization for the PST and the device handlers. This is done by + * calling the PST's destructor. + */ + virtual ~FixedTimeslotTask(void); + + ReturnValue_t startTask(void); + /** + * This static function can be used as #deadlineMissedFunc. + * It counts missedDeadlines and prints the number of missed deadlines + * every 10th time. + */ + static void missedDeadlineCounter(); + /** + * A helper variable to count missed deadlines. + */ + static uint32_t deadlineMissedCount; + + ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep) override; + + uint32_t getPeriodMs() const override; + + ReturnValue_t checkSequence() const override; + + ReturnValue_t sleepFor(uint32_t ms) override; + + TaskHandle_t getTaskHandle() override; + +protected: + bool started; + TaskHandle_t handle; + + FixedSlotSequence pst; + + /** + * @brief This attribute holds a function pointer that is executed when + * a deadline was missed. + * @details + * Another function may be announced to determine the actions to perform + * when a deadline was missed. Currently, only one function for missing + * any deadline is allowed. If not used, it shall be declared NULL. + */ + void (*deadlineMissedFunc)(void); + /** + * @brief This is the entry point for a new task. + * @details + * This method starts the task by calling taskFunctionality(), as soon as + * all requirements (task scheduler has started and startTask() + * has been called) are met. + */ + static void taskEntryPoint(void* argument); + + /** + * @brief This function holds the main functionality of the thread. + * @details + * Core function holding the main functionality of the task + * It links the functionalities provided by FixedSlotSequence with the + * OS's System Calls to keep the timing of the periods. + */ + void taskFunctionality(void); + + void checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval); + void handleMissedDeadline(); +}; + +#endif /* POLLINGTASK_H_ */ From 04532b8f6b4bbd661e53ac4b19e37824c73bd2fa Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 13:52:54 +0200 Subject: [PATCH 22/53] renormalizing pull request step2 --- tasks/FixedSequenceSlot.cpp | 34 ++-- tasks/FixedSequenceSlot.h | 116 ++++++------- tasks/FixedSlotSequence.cpp | 294 ++++++++++++++++----------------- tasks/FixedSlotSequence.h | 316 ++++++++++++++++++------------------ 4 files changed, 382 insertions(+), 378 deletions(-) diff --git a/tasks/FixedSequenceSlot.cpp b/tasks/FixedSequenceSlot.cpp index 5fe49523..d7aeff0a 100644 --- a/tasks/FixedSequenceSlot.cpp +++ b/tasks/FixedSequenceSlot.cpp @@ -1,17 +1,17 @@ -#include "FixedSequenceSlot.h" -#include "../objectmanager/SystemObjectIF.h" -#include - -FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, - int8_t setSequenceId, ExecutableObjectIF* executableObject, - PeriodicTaskIF* executingTask) : - pollingTimeMs(setTime), opcode(setSequenceId) { - if(executableObject == nullptr) { - return; - } - this->executableObject = executableObject; - this->executableObject->setTaskIF(executingTask); -} - -FixedSequenceSlot::~FixedSequenceSlot() {} - +#include "../objectmanager/SystemObjectIF.h" +#include "../tasks/FixedSequenceSlot.h" +#include + +FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, + int8_t setSequenceId, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask) : handlerId(handlerId), + pollingTimeMs(setTime), opcode(setSequenceId) { + if(executableObject == nullptr) { + return; + } + this->executableObject = executableObject; + this->executableObject->setTaskIF(executingTask); +} + +FixedSequenceSlot::~FixedSequenceSlot() {} + diff --git a/tasks/FixedSequenceSlot.h b/tasks/FixedSequenceSlot.h index 9cf5894c..151173e9 100644 --- a/tasks/FixedSequenceSlot.h +++ b/tasks/FixedSequenceSlot.h @@ -1,57 +1,59 @@ -#ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ -#define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ - -#include "../objectmanager/ObjectManagerIF.h" -#include "../tasks/ExecutableObjectIF.h" -class PeriodicTaskIF; - -/** - * @brief This class is the representation of a single polling sequence - * table entry. - * @details - * The PollingSlot class is the representation of a single polling - * sequence table entry. - * @author baetz - */ -class FixedSequenceSlot { -public: - FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, - int8_t setSequenceId, ExecutableObjectIF* executableObject, - PeriodicTaskIF* executingTask); - virtual ~FixedSequenceSlot(); - - /** - * @brief Handler identifies which object is executed in this slot. - */ - ExecutableObjectIF* executableObject = nullptr; - - /** - * @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. - */ - 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. - */ - uint8_t opcode; - - /** - * @brief Operator overload for the comparison operator to - * allow sorting by polling time. - * @param fixedSequenceSlot - * @return - */ - bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { - return pollingTimeMs < fixedSequenceSlot.pollingTimeMs; - } -}; - - -#endif /* FIXEDSEQUENCESLOT_H_ */ +#ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ +#define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ + +#include "../objectmanager/ObjectManagerIF.h" +#include "../tasks/ExecutableObjectIF.h" +class PeriodicTaskIF; + +/** + * @brief This class is the representation of a single polling sequence + * table entry. + * @details + * The PollingSlot class is the representation of a single polling + * sequence table entry. + * @author baetz + */ +class FixedSequenceSlot { +public: + FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, + int8_t setSequenceId, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask); + virtual ~FixedSequenceSlot(); + + object_id_t handlerId; + + /** + * @brief Handler identifies which object is executed in this slot. + */ + ExecutableObjectIF* executableObject = nullptr; + + /** + * @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. + */ + 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. + */ + uint8_t opcode; + + /** + * @brief Operator overload for the comparison operator to + * allow sorting by polling time. + * @param fixedSequenceSlot + * @return + */ + bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { + return pollingTimeMs < fixedSequenceSlot.pollingTimeMs; + } +}; + + +#endif /* FIXEDSEQUENCESLOT_H_ */ diff --git a/tasks/FixedSlotSequence.cpp b/tasks/FixedSlotSequence.cpp index 78f512ca..59859ce5 100644 --- a/tasks/FixedSlotSequence.cpp +++ b/tasks/FixedSlotSequence.cpp @@ -1,147 +1,147 @@ -#include "FixedSlotSequence.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include - -FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : - lengthMs(setLengthMs) { - current = slotList.begin(); -} - -FixedSlotSequence::~FixedSlotSequence() { - // Call the destructor on each list entry. - slotList.clear(); -} - -void FixedSlotSequence::executeAndAdvance() { - current->executableObject->performOperation(current->opcode); -// if (returnValue != RETURN_OK) { -// this->sendErrorMessage( returnValue ); -// } - //Increment the polling Sequence iterator - this->current++; - //Set it to the beginning, if the list's end is reached. - if (this->current == this->slotList.end()) { - this->current = this->slotList.begin(); - } -} - -uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { - uint32_t oldTime; - SlotListIter slotListIter = current; - // Get the pollingTimeMs of the current slot object. - oldTime = slotListIter->pollingTimeMs; - // Advance to the next object. - slotListIter++; - // Find the next interval which is not 0. - while (slotListIter != slotList.end()) { - if (oldTime != slotListIter->pollingTimeMs) { - return slotListIter->pollingTimeMs - oldTime; - } else { - 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. - slotListIter = slotList.begin(); - return lengthMs - oldTime + slotListIter->pollingTimeMs; -} - -uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { - uint32_t currentTime; - SlotListIter slotListIter = current; - // Get the pollingTimeMs of the current slot object. - currentTime = slotListIter->pollingTimeMs; - - //if it is the first slot, calculate difference to last slot - if (slotListIter == slotList.begin()){ - return lengthMs - (--slotList.end())->pollingTimeMs + currentTime; - } - // get previous slot - slotListIter--; - - return currentTime - slotListIter->pollingTimeMs; -} - -bool FixedSlotSequence::slotFollowsImmediately() { - uint32_t currentTime = current->pollingTimeMs; - SlotListIter fixedSequenceIter = this->current; - // Get the pollingTimeMs of the current slot object. - if (fixedSequenceIter == slotList.begin()) - return false; - fixedSequenceIter--; - if (fixedSequenceIter->pollingTimeMs == currentTime) { - return true; - } else { - return false; - } -} - -uint32_t FixedSlotSequence::getLengthMs() const { - return this->lengthMs; -} - -void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep, ExecutableObjectIF* executableObject, - PeriodicTaskIF* executingTask) { - this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, - executionStep, executableObject, executingTask)); - this->current = slotList.begin(); -} - -ReturnValue_t FixedSlotSequence::checkSequence() const { - if(slotList.empty()) { - sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint32_t count = 0; - uint32_t time = 0; - for(const auto& slot: slotList) { - if (slot.executableObject == nullptr) { - count++; - } - else if (slot.pollingTimeMs < time) { - sif::error << "FixedSlotSequence::initialize: Time: " - << slot.pollingTimeMs << " is smaller than previous with " - << time << std::endl; - count++; - } - else { - // All ok, print slot. - //sif::info << "Current slot polling time: " << std::endl; - //sif::info << std::dec << slotIt->pollingTimeMs << std::endl; - } - time = slot.pollingTimeMs; - - } - //sif::info << "Number of elements in slot list: " - // << slotList.size() << std::endl; - if (count > 0) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const { - std::set uniqueObjects; - uint32_t count = 0; - for(const auto& slot: slotList) { - // Ensure that each unique object is initialized once. - if(uniqueObjects.find(slot.executableObject) == uniqueObjects.end()) { - ReturnValue_t result = - slot.executableObject->initializeAfterTaskCreation(); - if(result != HasReturnvaluesIF::RETURN_OK) { - count++; - } - uniqueObjects.emplace(slot.executableObject); - } - } - if (count > 0) { - sif::error << "FixedSlotSequence::intializeSequenceAfterTaskCreation:" - "Counted " << count << " failed initializations!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../tasks/FixedSlotSequence.h" +#include + +FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : + lengthMs(setLengthMs) { + current = slotList.begin(); +} + +FixedSlotSequence::~FixedSlotSequence() { + // Call the destructor on each list entry. + slotList.clear(); +} + +void FixedSlotSequence::executeAndAdvance() { + current->executableObject->performOperation(current->opcode); +// if (returnValue != RETURN_OK) { +// this->sendErrorMessage( returnValue ); +// } + //Increment the polling Sequence iterator + this->current++; + //Set it to the beginning, if the list's end is reached. + if (this->current == this->slotList.end()) { + this->current = this->slotList.begin(); + } +} + +uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { + uint32_t oldTime; + SlotListIter slotListIter = current; + // Get the pollingTimeMs of the current slot object. + oldTime = slotListIter->pollingTimeMs; + // Advance to the next object. + slotListIter++; + // Find the next interval which is not 0. + while (slotListIter != slotList.end()) { + if (oldTime != slotListIter->pollingTimeMs) { + return slotListIter->pollingTimeMs - oldTime; + } else { + 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. + slotListIter = slotList.begin(); + return lengthMs - oldTime + slotListIter->pollingTimeMs; +} + +uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { + uint32_t currentTime; + SlotListIter slotListIter = current; + // Get the pollingTimeMs of the current slot object. + currentTime = slotListIter->pollingTimeMs; + + //if it is the first slot, calculate difference to last slot + if (slotListIter == slotList.begin()){ + return lengthMs - (--slotList.end())->pollingTimeMs + currentTime; + } + // get previous slot + slotListIter--; + + return currentTime - slotListIter->pollingTimeMs; +} + +bool FixedSlotSequence::slotFollowsImmediately() { + uint32_t currentTime = current->pollingTimeMs; + SlotListIter fixedSequenceIter = this->current; + // Get the pollingTimeMs of the current slot object. + if (fixedSequenceIter == slotList.begin()) + return false; + fixedSequenceIter--; + if (fixedSequenceIter->pollingTimeMs == currentTime) { + return true; + } else { + return false; + } +} + +uint32_t FixedSlotSequence::getLengthMs() const { + return this->lengthMs; +} + +void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask) { + this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, + executionStep, executableObject, executingTask)); + this->current = slotList.begin(); +} + +ReturnValue_t FixedSlotSequence::checkSequence() const { + if(slotList.empty()) { + sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint32_t count = 0; + uint32_t time = 0; + for(const auto& slot: slotList) { + if (slot.executableObject == nullptr) { + count++; + } + else if (slot.pollingTimeMs < time) { + sif::error << "FixedSlotSequence::initialize: Time: " + << slot.pollingTimeMs << " is smaller than previous with " + << time << std::endl; + count++; + } + else { + // All ok, print slot. + //sif::info << "Current slot polling time: " << std::endl; + //sif::info << std::dec << slotIt->pollingTimeMs << std::endl; + } + time = slot.pollingTimeMs; + + } + //sif::info << "Number of elements in slot list: " + // << slotList.size() << std::endl; + if (count > 0) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const { + std::set uniqueObjects; + uint32_t count = 0; + for(const auto& slot: slotList) { + // Ensure that each unique object is initialized once. + if(uniqueObjects.find(slot.executableObject) == uniqueObjects.end()) { + ReturnValue_t result = + slot.executableObject->initializeAfterTaskCreation(); + if(result != HasReturnvaluesIF::RETURN_OK) { + count++; + } + uniqueObjects.emplace(slot.executableObject); + } + } + if (count > 0) { + sif::error << "FixedSlotSequence::intializeSequenceAfterTaskCreation:" + "Counted " << count << " failed initializations!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/tasks/FixedSlotSequence.h b/tasks/FixedSlotSequence.h index 026d5a3d..1140dd25 100644 --- a/tasks/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -1,157 +1,159 @@ -#ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ -#define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ - -#include "FixedSequenceSlot.h" -#include "../objectmanager/SystemObject.h" - -#include - -/** - * @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. - * - * The main idea is to create a list of device handlers, to announce all - * handlers to thepolling 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 - * which device handler shall be executed within a given polling period. - * The sequence is then executed by iterating through this slot list. - * Handlers are invoking by calling a certain function stored in the handler list. - */ -class FixedSlotSequence { -public: - using SlotList = std::multiset; - using SlotListIter = std::multiset::iterator; - - /** - * @brief The constructor of the FixedSlotSequence object. - * - * @details The constructor takes two arguments, the period length and the init function. - * - * @param setLength The period length, expressed in ms. - */ - FixedSlotSequence(uint32_t setLengthMs); - - /** - * @brief The destructor of the FixedSlotSequence object. - * - * @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. - * - * @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, - ExecutableObjectIF* executableObject, PeriodicTaskIF* executingTask); - - /** - * Checks if the current slot shall be executed immediately after the one before. - * This allows to distinguish between grouped and not grouped handlers. - * @return - @c true if the slot has the same polling time as the previous - * - @c false else - */ - bool slotFollowsImmediately(); - - /** - * @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. - */ - uint32_t getIntervalToNextSlotMs(); - - /** - * @brief This method returns the time difference between the current - * slot and the previous slot - * - * @details - * This method is vitally important for the operation of the PST. - * By fetching the polling time of the current slot and that of the previous - * one (or the last one, if the slot is the first one) it calculates and - * returns the interval in milliseconds that the handler execution shall - * be delayed. - */ - uint32_t getIntervalToPreviousSlotMs(); - - /** - * @brief This method returns the length of this FixedSlotSequence instance. - */ - uint32_t getLengthMs() const; - - /** - * @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 talkToInterface or its listenToInterface - * method is invoked, depending on the isTalking flag of the polling slot. - * After execution the iterator current is increased or, by reaching the - * end of slotList, reset to the beginning. - */ - void executeAndAdvance(); - - /** - * @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. - */ - SlotListIter current; - - /** - * @brief Check and initialize slot list. - * @details - * Checks if timing is ok (must be ascending) and if all handlers were found. - * Also calls any initialization steps which are required after task - * creation. - * @return - */ - ReturnValue_t checkSequence() const; - - ReturnValue_t intializeSequenceAfterTaskCreation() const; - -protected: - - /** - * @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 - * 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. - */ - SlotList slotList; - - uint32_t lengthMs; -}; - -#endif /* FIXEDSLOTSEQUENCE_H_ */ +#ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ +#define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ + +#include "../objectmanager/SystemObject.h" +#include "../tasks/FixedSequenceSlot.h" + +#include + +/** + * @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. + * + * The main idea is to create a list of device handlers, to announce all + * handlers to thepolling 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 + * which device handler shall be executed within a given polling period. + * The sequence is then executed by iterating through this slot list. + * Handlers are invoking by calling a certain function stored in the handler list. + */ +class FixedSlotSequence { +public: + using SlotList = std::multiset; + using SlotListIter = std::multiset::iterator; + + /** + * @brief The constructor of the FixedSlotSequence object. + * + * @details The constructor takes two arguments, the period length and the init function. + * + * @param setLength The period length, expressed in ms. + */ + FixedSlotSequence(uint32_t setLengthMs); + + /** + * @brief The destructor of the FixedSlotSequence object. + * + * @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. + * + * @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, + ExecutableObjectIF* executableObject, PeriodicTaskIF* executingTask); + + /** + * Checks if the current slot shall be executed immediately after the one before. + * This allows to distinguish between grouped and not grouped handlers. + * @return - @c true if the slot has the same polling time as the previous + * - @c false else + */ + bool slotFollowsImmediately(); + + /** + * @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. + */ + uint32_t getIntervalToNextSlotMs(); + + /** + * @brief This method returns the time difference between the current + * slot and the previous slot + * + * @details + * This method is vitally important for the operation of the PST. + * By fetching the polling time of the current slot and that of the previous + * one (or the last one, if the slot is the first one) it calculates and + * returns the interval in milliseconds that the handler execution shall + * be delayed. + */ + uint32_t getIntervalToPreviousSlotMs(); + + /** + * @brief This method returns the length of this FixedSlotSequence instance. + */ + uint32_t getLengthMs() const; + + /** + * @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 talkToInterface or its listenToInterface + * method is invoked, depending on the isTalking flag of the polling slot. + * After execution the iterator current is increased or, by reaching the + * end of slotList, reset to the beginning. + */ + void executeAndAdvance(); + + /** + * @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. + */ + SlotListIter current; + + /** + * @brief Check and initialize slot list. + * @details + * Checks if timing is ok (must be ascending) and if all handlers were found. + * Also calls any initialization steps which are required after task + * creation. + * @return + */ + ReturnValue_t checkSequence() const; + + ReturnValue_t intializeSequenceAfterTaskCreation() const; + +protected: + + /** + * @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 + * 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. + */ + SlotList slotList; + + uint32_t lengthMs; + + bool isEmpty = false; +}; + +#endif /* FIXEDSLOTSEQUENCE_H_ */ From 92c736927610847f18e1899f4e9fbf577d302bda Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 13:56:12 +0200 Subject: [PATCH 23/53] include guard fix --- osal/FreeRTOS/FixedTimeslotTask.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/osal/FreeRTOS/FixedTimeslotTask.h index c46de5b7..7d2cdb70 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -1,7 +1,7 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ +#ifndef FSFW_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ +#define FSFW_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ -#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" +#include "FreeRTOSTaskIF.h" #include "../../tasks/FixedSlotSequence.h" #include "../../tasks/FixedTimeslotTaskIF.h" #include "../../tasks/Typedef.h" @@ -98,4 +98,4 @@ protected: void handleMissedDeadline(); }; -#endif /* POLLINGTASK_H_ */ +#endif /* FSFW_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ */ From b8754fbc1609b05ea962133a7c5fbfbeb9e17535 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 14:11:59 +0200 Subject: [PATCH 24/53] made fixed sequence slot doc generic --- tasks/FixedSequenceSlot.cpp | 4 +- tasks/FixedSequenceSlot.h | 9 +++-- tasks/FixedSlotSequence.cpp | 2 +- tasks/FixedSlotSequence.h | 77 +++++++++++++++++++++---------------- 4 files changed, 51 insertions(+), 41 deletions(-) diff --git a/tasks/FixedSequenceSlot.cpp b/tasks/FixedSequenceSlot.cpp index d7aeff0a..f5d82178 100644 --- a/tasks/FixedSequenceSlot.cpp +++ b/tasks/FixedSequenceSlot.cpp @@ -1,5 +1,5 @@ -#include "../objectmanager/SystemObjectIF.h" -#include "../tasks/FixedSequenceSlot.h" +#include "FixedSequenceSlot.h" +#include "PeriodicTaskIF.h" #include FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, diff --git a/tasks/FixedSequenceSlot.h b/tasks/FixedSequenceSlot.h index 151173e9..1744ec19 100644 --- a/tasks/FixedSequenceSlot.h +++ b/tasks/FixedSequenceSlot.h @@ -1,8 +1,9 @@ -#ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ -#define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_ +#ifndef FSFW_TASKS_FIXEDSEQUENCESLOT_H_ +#define FSFW_TASKS_FIXEDSEQUENCESLOT_H_ +#include "ExecutableObjectIF.h" #include "../objectmanager/ObjectManagerIF.h" -#include "../tasks/ExecutableObjectIF.h" + class PeriodicTaskIF; /** @@ -56,4 +57,4 @@ public: }; -#endif /* FIXEDSEQUENCESLOT_H_ */ +#endif /* FSFW_TASKS_FIXEDSEQUENCESLOT_H_ */ diff --git a/tasks/FixedSlotSequence.cpp b/tasks/FixedSlotSequence.cpp index 59859ce5..2467671b 100644 --- a/tasks/FixedSlotSequence.cpp +++ b/tasks/FixedSlotSequence.cpp @@ -1,5 +1,5 @@ +#include "FixedSlotSequence.h" #include "../serviceinterface/ServiceInterfaceStream.h" -#include "../tasks/FixedSlotSequence.h" #include FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : diff --git a/tasks/FixedSlotSequence.h b/tasks/FixedSlotSequence.h index 1140dd25..056e0bb5 100644 --- a/tasks/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -1,26 +1,30 @@ -#ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ -#define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_ +#ifndef FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ +#define FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ +#include "FixedSequenceSlot.h" #include "../objectmanager/SystemObject.h" -#include "../tasks/FixedSequenceSlot.h" #include /** - * @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. + * objects with stricter timing requirements for the FixedTimeslotTask. * - * The main idea is to create a list of device handlers, to announce all - * handlers to thepolling sequence and to maintain a list of - * polling slot objects. This slot list represents the Polling Sequence Table - * in software. + * The main idea is to create a list of executable objects (for example + * 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 - * which device handler shall be executed within a given polling period. - * The sequence is then executed by iterating through this slot list. - * Handlers are invoking by calling a certain function stored in the handler list. + * which executable object shall be executed within a given polling period. + * When adding a slot, a pointer to the executing task, a pointer to the + * executable object and a step number can be passed. The step number will be + * passed to the periodic handler. + * The sequence is executed by iterating through the slot sequence and + * executing the executable object in the correct timeslot. */ class FixedSlotSequence { public: @@ -29,41 +33,44 @@ public: /** * @brief The constructor of the FixedSlotSequence object. - * - * @details The constructor takes two arguments, the period length and the init function. - * * @param setLength The period length, expressed in ms. */ FixedSlotSequence(uint32_t setLengthMs); /** * @brief The destructor of the FixedSlotSequence object. - * - * @details The destructor frees all allocated memory by iterating through the slotList - * and deleting all allocated resources. + * @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. * - * @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 + * @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 handlerId 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. This + * value will be passed to the executable function. * @param * @param */ void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId, - ExecutableObjectIF* executableObject, PeriodicTaskIF* executingTask); + ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask); /** - * Checks if the current slot shall be executed immediately after the one before. - * This allows to distinguish between grouped and not grouped handlers. + * @brief Checks if the current slot shall be executed immediately + * after the one before. + * @details + * This allows to distinguish between grouped and separated handlers. * @return - @c true if the slot has the same polling time as the previous * - @c false else */ @@ -128,12 +135,16 @@ public: * @brief Check and initialize slot list. * @details * Checks if timing is ok (must be ascending) and if all handlers were found. - * Also calls any initialization steps which are required after task - * creation. * @return */ ReturnValue_t checkSequence() const; + /** + * @brief Perform any initialization steps required after the executing + * task has been created. This function should be called from the + * executing task! + * @return + */ ReturnValue_t intializeSequenceAfterTaskCreation() const; protected: @@ -152,8 +163,6 @@ protected: SlotList slotList; uint32_t lengthMs; - - bool isEmpty = false; }; -#endif /* FIXEDSLOTSEQUENCE_H_ */ +#endif /* FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ */ From 4d7d48e8ca5206e384cf8bcd4241c0ac39f4104c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 14:24:34 +0200 Subject: [PATCH 25/53] added a generic way to add a custom check --- tasks/FixedSlotSequence.cpp | 27 +++++++++++++++++++++------ tasks/FixedSlotSequence.h | 4 ++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/tasks/FixedSlotSequence.cpp b/tasks/FixedSlotSequence.cpp index 2467671b..e5db4301 100644 --- a/tasks/FixedSlotSequence.cpp +++ b/tasks/FixedSlotSequence.cpp @@ -91,21 +91,31 @@ void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, ReturnValue_t FixedSlotSequence::checkSequence() const { if(slotList.empty()) { - sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; + sif::error << "FixedSlotSequence::checkSequence:" + << " Slot list is empty!" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } - uint32_t count = 0; + if(customCheckFunction != nullptr) { + ReturnValue_t result = customCheckFunction(slotList); + if(result != HasReturnvaluesIF::RETURN_OK) { + // Continue for now but print error output. + sif::error << "FixedSlotSequence::checkSequence:" + << " Custom check failed!" << std::endl; + } + } + + uint32_t errorCount = 0; uint32_t time = 0; for(const auto& slot: slotList) { if (slot.executableObject == nullptr) { - count++; + errorCount++; } else if (slot.pollingTimeMs < time) { - sif::error << "FixedSlotSequence::initialize: Time: " + sif::error << "FixedSlotSequence::checkSequence: Time: " << slot.pollingTimeMs << " is smaller than previous with " << time << std::endl; - count++; + errorCount++; } else { // All ok, print slot. @@ -117,7 +127,7 @@ ReturnValue_t FixedSlotSequence::checkSequence() const { } //sif::info << "Number of elements in slot list: " // << slotList.size() << std::endl; - if (count > 0) { + if (errorCount > 0) { return HasReturnvaluesIF::RETURN_FAILED; } return HasReturnvaluesIF::RETURN_OK; @@ -145,3 +155,8 @@ ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const { } return HasReturnvaluesIF::RETURN_OK; } + +void FixedSlotSequence::addCustomCheck(ReturnValue_t + (*customCheckFunction)(const SlotList&)) { + this->customCheckFunction = customCheckFunction; +} diff --git a/tasks/FixedSlotSequence.h b/tasks/FixedSlotSequence.h index 056e0bb5..19a05f21 100644 --- a/tasks/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -139,6 +139,8 @@ public: */ ReturnValue_t checkSequence() const; + void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList &)); + /** * @brief Perform any initialization steps required after the executing * task has been created. This function should be called from the @@ -162,6 +164,8 @@ protected: */ SlotList slotList; + ReturnValue_t (*customCheckFunction)(const SlotList&) = nullptr; + uint32_t lengthMs; }; From 0eb4c3817edb8abe0cfcf979d6fd5db9ff2a5c9d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 14:31:39 +0200 Subject: [PATCH 26/53] added initialize after taks creation for linux --- osal/linux/FixedTimeslotTask.cpp | 14 ++++++++++---- osal/linux/FixedTimeslotTask.h | 10 +++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/osal/linux/FixedTimeslotTask.cpp b/osal/linux/FixedTimeslotTask.cpp index 858a39a7..247a34ed 100644 --- a/osal/linux/FixedTimeslotTask.cpp +++ b/osal/linux/FixedTimeslotTask.cpp @@ -1,5 +1,5 @@ -#include "../../serviceinterface/ServiceInterfaceStream.h" #include "FixedTimeslotTask.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" #include @@ -39,13 +39,16 @@ uint32_t FixedTimeslotTask::getPeriodMs() const { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { - if (objectManager->get(componentId) != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); + ExecutableObjectIF* executableObject = + objectManager->get(componentId); + if (executableObject != nullptr) { + pst.addSlot(componentId, slotTimeMs, executionStep, + executableObject,this); return HasReturnvaluesIF::RETURN_OK; } sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::endl; + " not found, not adding it to pst" << std::dec << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } @@ -58,6 +61,9 @@ void FixedTimeslotTask::taskFunctionality() { if (!started) { suspend(); } + + pst.intializeSequenceAfterTaskCreation(); + //The start time for the first entry is read. uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); uint64_t interval = pst.getIntervalToNextSlotMs(); diff --git a/osal/linux/FixedTimeslotTask.h b/osal/linux/FixedTimeslotTask.h index 42802b1d..5c5c1814 100644 --- a/osal/linux/FixedTimeslotTask.h +++ b/osal/linux/FixedTimeslotTask.h @@ -1,9 +1,9 @@ -#ifndef FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ +#ifndef FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ +#define FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ -#include "../../tasks/FixedTimeslotTaskIF.h" -#include "../../devicehandlers/FixedSlotSequence.h" #include "PosixThread.h" +#include "../../tasks/FixedTimeslotTaskIF.h" +#include "../../tasks/FixedSlotSequence.h" #include class FixedTimeslotTask: public FixedTimeslotTaskIF, public PosixThread { @@ -74,4 +74,4 @@ private: bool started; }; -#endif /* FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ +#endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ From a6b2b4dd934f3268c6867b450d8218ca8dcc6aba Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 14:58:36 +0200 Subject: [PATCH 27/53] renormalization --- ipc/CommandMessage.cpp | 222 ++++++++++++++++++++--------------------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/ipc/CommandMessage.cpp b/ipc/CommandMessage.cpp index 16293608..513debd3 100644 --- a/ipc/CommandMessage.cpp +++ b/ipc/CommandMessage.cpp @@ -1,111 +1,111 @@ -#include "CommandMessage.h" -#include "CommandMessageCleaner.h" -#include - -CommandMessage::CommandMessage() { - MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); - setCommand(CMD_NONE); -} - -CommandMessage::CommandMessage(Command_t command, uint32_t parameter1, - uint32_t parameter2) { - MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); - setCommand(command); - setParameter(parameter1); - setParameter2(parameter2); -} - -Command_t CommandMessage::getCommand() const { - Command_t command; - std::memcpy(&command, MessageQueueMessage::getData(), sizeof(Command_t)); - return command; -} - -void CommandMessage::setCommand(Command_t command) { - std::memcpy(MessageQueueMessage::getData(), &command, sizeof(Command_t)); -} - -uint8_t CommandMessage::getMessageType() const { - // first byte of command ID. - return getCommand() >> 8 & 0xff; -} - -uint32_t CommandMessage::getParameter() const { - uint32_t parameter1; - std::memcpy(¶meter1, this->getData(), sizeof(parameter1)); - return parameter1; -} - -void CommandMessage::setParameter(uint32_t parameter1) { - std::memcpy(this->getData(), ¶meter1, sizeof(parameter1)); -} - -uint32_t CommandMessage::getParameter2() const { - uint32_t parameter2; - std::memcpy(¶meter2, this->getData() + sizeof(uint32_t), - sizeof(parameter2)); - return parameter2; -} - -void CommandMessage::setParameter2(uint32_t parameter2) { - std::memcpy(this->getData() + sizeof(uint32_t), ¶meter2, - sizeof(parameter2)); -} - -uint32_t CommandMessage::getParameter3() const { - uint32_t parameter3; - std::memcpy(¶meter3, this->getData() + 2 * sizeof(uint32_t), - sizeof(parameter3)); - return parameter3; -} - -void CommandMessage::setParameter3(uint32_t parameter3) { - std::memcpy(this->getData() + 2 * sizeof(uint32_t), ¶meter3, - sizeof(parameter3)); -} - -size_t CommandMessage::getMinimumMessageSize() const { - return MINIMUM_COMMAND_MESSAGE_SIZE; -} - -void CommandMessage::clearCommandMessage() { - clear(); -} - -void CommandMessage::clear() { - CommandMessageCleaner::clearCommandMessage(this); -} - -bool CommandMessage::isClearedCommandMessage() { - return getCommand() == CMD_NONE; -} - -void CommandMessage::setToUnknownCommand() { - Command_t initialCommand = getCommand(); - this->clear(); - setReplyRejected(UNKNOWN_COMMAND, initialCommand); -} - -void CommandMessage::setReplyRejected(ReturnValue_t reason, - Command_t initialCommand) { - setCommand(REPLY_REJECTED); - setParameter(reason); - setParameter2(initialCommand); -} - -ReturnValue_t CommandMessage::getReplyRejectedReason( - Command_t *initialCommand) const { - ReturnValue_t reason = getParameter(); - if(initialCommand != nullptr) { - *initialCommand = getParameter2(); - } - return reason; -} - -uint8_t* CommandMessage::getData() { - return MessageQueueMessage::getData() + sizeof(Command_t); -} - -const uint8_t* CommandMessage::getData() const { - return MessageQueueMessage::getData() + sizeof(Command_t); -} +#include "CommandMessage.h" +#include "CommandMessageCleaner.h" +#include + +CommandMessage::CommandMessage() { + MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); + setCommand(CMD_NONE); +} + +CommandMessage::CommandMessage(Command_t command, uint32_t parameter1, + uint32_t parameter2) { + MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); + setCommand(command); + setParameter(parameter1); + setParameter2(parameter2); +} + +Command_t CommandMessage::getCommand() const { + Command_t command; + std::memcpy(&command, MessageQueueMessage::getData(), sizeof(Command_t)); + return command; +} + +void CommandMessage::setCommand(Command_t command) { + std::memcpy(MessageQueueMessage::getData(), &command, sizeof(Command_t)); +} + +uint8_t CommandMessage::getMessageType() const { + // first byte of command ID. + return getCommand() >> 8 & 0xff; +} + +uint32_t CommandMessage::getParameter() const { + uint32_t parameter1; + std::memcpy(¶meter1, this->getData(), sizeof(parameter1)); + return parameter1; +} + +void CommandMessage::setParameter(uint32_t parameter1) { + std::memcpy(this->getData(), ¶meter1, sizeof(parameter1)); +} + +uint32_t CommandMessage::getParameter2() const { + uint32_t parameter2; + std::memcpy(¶meter2, this->getData() + sizeof(uint32_t), + sizeof(parameter2)); + return parameter2; +} + +void CommandMessage::setParameter2(uint32_t parameter2) { + std::memcpy(this->getData() + sizeof(uint32_t), ¶meter2, + sizeof(parameter2)); +} + +uint32_t CommandMessage::getParameter3() const { + uint32_t parameter3; + std::memcpy(¶meter3, this->getData() + 2 * sizeof(uint32_t), + sizeof(parameter3)); + return parameter3; +} + +void CommandMessage::setParameter3(uint32_t parameter3) { + std::memcpy(this->getData() + 2 * sizeof(uint32_t), ¶meter3, + sizeof(parameter3)); +} + +size_t CommandMessage::getMinimumMessageSize() const { + return MINIMUM_COMMAND_MESSAGE_SIZE; +} + +void CommandMessage::clearCommandMessage() { + clear(); +} + +void CommandMessage::clear() { + CommandMessageCleaner::clearCommandMessage(this); +} + +bool CommandMessage::isClearedCommandMessage() { + return getCommand() == CMD_NONE; +} + +void CommandMessage::setToUnknownCommand() { + Command_t initialCommand = getCommand(); + this->clear(); + setReplyRejected(UNKNOWN_COMMAND, initialCommand); +} + +void CommandMessage::setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) { + setCommand(REPLY_REJECTED); + setParameter(reason); + setParameter2(initialCommand); +} + +ReturnValue_t CommandMessage::getReplyRejectedReason( + Command_t *initialCommand) const { + ReturnValue_t reason = getParameter(); + if(initialCommand != nullptr) { + *initialCommand = getParameter2(); + } + return reason; +} + +uint8_t* CommandMessage::getData() { + return MessageQueueMessage::getData() + sizeof(Command_t); +} + +const uint8_t* CommandMessage::getData() const { + return MessageQueueMessage::getData() + sizeof(Command_t); +} From a53b9dc3dbfd5339c81c611123341cb3fcb63eea Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 14:59:59 +0200 Subject: [PATCH 28/53] renormalization --- ipc/CommandMessage.h | 258 ++++++++++++++--------------- ipc/CommandMessageCleaner.cpp | 90 +++++----- ipc/CommandMessageCleaner.h | 32 ++-- ipc/CommandMessageIF.h | 146 ++++++++--------- ipc/MessageQueueMessage.cpp | 168 +++++++++---------- ipc/MessageQueueMessage.h | 300 +++++++++++++++++----------------- 6 files changed, 497 insertions(+), 497 deletions(-) diff --git a/ipc/CommandMessage.h b/ipc/CommandMessage.h index 3be9a120..ca7b817f 100644 --- a/ipc/CommandMessage.h +++ b/ipc/CommandMessage.h @@ -1,129 +1,129 @@ -#ifndef FSFW_IPC_COMMANDMESSAGE_H_ -#define FSFW_IPC_COMMANDMESSAGE_H_ - -#include "CommandMessageIF.h" -#include "MessageQueueMessage.h" -#include "FwMessageTypes.h" - -/** - * @brief Default command message used to pass command messages between tasks. - * Primary message type for IPC. Contains sender, 2-byte command ID - * field, and 2 4-byte parameters. - * @details - * It operates on an external memory which is contained inside a - * class implementing MessageQueueMessageIF by taking its address. - * This allows for a more flexible designs of message implementations. - * The pointer can be passed to different message implementations without - * the need of unnecessary copying. - * - * The command message is based of the generic MessageQueueMessage which - * currently has an internal message size of 28 bytes. - * @author Bastian Baetz - */ -class CommandMessage: public MessageQueueMessage, public CommandMessageIF { -public: - /** - * Default size can accomodate 2 4-byte parameters. - */ - static constexpr size_t DEFAULT_COMMAND_MESSAGE_SIZE = - CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE + sizeof(uint32_t); - - /** - * @brief Default Constructor, does not initialize anything. - * @details - * This constructor should be used when receiving a Message, as the - * content is filled by the MessageQueue. - */ - CommandMessage(); - /** - * This constructor creates a new message with all message content - * initialized - * - * @param command The DeviceHandlerCommand_t that will be sent - * @param parameter1 The first parameter - * @param parameter2 The second parameter - */ - CommandMessage(Command_t command, uint32_t parameter1, uint32_t parameter2); - - /** - * @brief Default Destructor - */ - virtual ~CommandMessage() {} - - /** - * Read the DeviceHandlerCommand_t that is stored in the message, - * usually used after receiving. - * - * @return the Command stored in the Message - */ - virtual Command_t getCommand() const override; - /** - * Set the command type of the message. Default implementation also - * sets the message type, which will be the first byte of the command ID. - * @param the Command to be sent - */ - virtual void setCommand(Command_t command); - - virtual uint8_t* getData() override; - virtual const uint8_t* getData() const override; - - /** - * Get the first parameter of the message - * @return the first Parameter of the message - */ - uint32_t getParameter() const; - /** - * Set the first parameter of the message - * @param the first parameter of the message - */ - void setParameter(uint32_t parameter1); - uint32_t getParameter2() const; - void setParameter2(uint32_t parameter2); - uint32_t getParameter3() const; - void setParameter3(uint32_t parameter3); - - /** - * check if a message was cleared - * - * @return if the command is CMD_NONE - */ - bool isClearedCommandMessage(); - - /** - * Sets the command to REPLY_REJECTED with parameter UNKNOWN_COMMAND. - * Is needed quite often, so we better code it once only. - */ - void setToUnknownCommand() override; - - /** - * A command message can be rejected and needs to offer a function - * to set a rejected reply - * @param reason - * @param initialCommand - */ - void setReplyRejected(ReturnValue_t reason, - Command_t initialCommand) override; - /** - * Corrensonding getter function. - * @param initialCommand - * @return - */ - ReturnValue_t getReplyRejectedReason( - Command_t* initialCommand = nullptr) const override; - - - virtual void clear() override; - void clearCommandMessage(); - - /** - * Extract message ID, which is the first byte of the command ID for the - * default implementation. - * @return - */ - virtual uint8_t getMessageType() const override; - - /** MessageQueueMessageIF functions used for minimum size check. */ - size_t getMinimumMessageSize() const override; -}; - -#endif /* FSFW_IPC_COMMANDMESSAGE_H_ */ +#ifndef FSFW_IPC_COMMANDMESSAGE_H_ +#define FSFW_IPC_COMMANDMESSAGE_H_ + +#include "CommandMessageIF.h" +#include "MessageQueueMessage.h" +#include "FwMessageTypes.h" + +/** + * @brief Default command message used to pass command messages between tasks. + * Primary message type for IPC. Contains sender, 2-byte command ID + * field, and 2 4-byte parameters. + * @details + * It operates on an external memory which is contained inside a + * class implementing MessageQueueMessageIF by taking its address. + * This allows for a more flexible designs of message implementations. + * The pointer can be passed to different message implementations without + * the need of unnecessary copying. + * + * The command message is based of the generic MessageQueueMessage which + * currently has an internal message size of 28 bytes. + * @author Bastian Baetz + */ +class CommandMessage: public MessageQueueMessage, public CommandMessageIF { +public: + /** + * Default size can accomodate 2 4-byte parameters. + */ + static constexpr size_t DEFAULT_COMMAND_MESSAGE_SIZE = + CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE + sizeof(uint32_t); + + /** + * @brief Default Constructor, does not initialize anything. + * @details + * This constructor should be used when receiving a Message, as the + * content is filled by the MessageQueue. + */ + CommandMessage(); + /** + * This constructor creates a new message with all message content + * initialized + * + * @param command The DeviceHandlerCommand_t that will be sent + * @param parameter1 The first parameter + * @param parameter2 The second parameter + */ + CommandMessage(Command_t command, uint32_t parameter1, uint32_t parameter2); + + /** + * @brief Default Destructor + */ + virtual ~CommandMessage() {} + + /** + * Read the DeviceHandlerCommand_t that is stored in the message, + * usually used after receiving. + * + * @return the Command stored in the Message + */ + virtual Command_t getCommand() const override; + /** + * Set the command type of the message. Default implementation also + * sets the message type, which will be the first byte of the command ID. + * @param the Command to be sent + */ + virtual void setCommand(Command_t command); + + virtual uint8_t* getData() override; + virtual const uint8_t* getData() const override; + + /** + * Get the first parameter of the message + * @return the first Parameter of the message + */ + uint32_t getParameter() const; + /** + * Set the first parameter of the message + * @param the first parameter of the message + */ + void setParameter(uint32_t parameter1); + uint32_t getParameter2() const; + void setParameter2(uint32_t parameter2); + uint32_t getParameter3() const; + void setParameter3(uint32_t parameter3); + + /** + * check if a message was cleared + * + * @return if the command is CMD_NONE + */ + bool isClearedCommandMessage(); + + /** + * Sets the command to REPLY_REJECTED with parameter UNKNOWN_COMMAND. + * Is needed quite often, so we better code it once only. + */ + void setToUnknownCommand() override; + + /** + * A command message can be rejected and needs to offer a function + * to set a rejected reply + * @param reason + * @param initialCommand + */ + void setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) override; + /** + * Corrensonding getter function. + * @param initialCommand + * @return + */ + ReturnValue_t getReplyRejectedReason( + Command_t* initialCommand = nullptr) const override; + + + virtual void clear() override; + void clearCommandMessage(); + + /** + * Extract message ID, which is the first byte of the command ID for the + * default implementation. + * @return + */ + virtual uint8_t getMessageType() const override; + + /** MessageQueueMessageIF functions used for minimum size check. */ + size_t getMinimumMessageSize() const override; +}; + +#endif /* FSFW_IPC_COMMANDMESSAGE_H_ */ diff --git a/ipc/CommandMessageCleaner.cpp b/ipc/CommandMessageCleaner.cpp index a4dec78d..6a99b4d2 100644 --- a/ipc/CommandMessageCleaner.cpp +++ b/ipc/CommandMessageCleaner.cpp @@ -1,45 +1,45 @@ -#include "../ipc/CommandMessageCleaner.h" - -#include "../devicehandlers/DeviceHandlerMessage.h" -#include "../health/HealthMessage.h" -#include "../memory/MemoryMessage.h" -#include "../modes/ModeMessage.h" -#include "../monitoring/MonitoringMessage.h" -#include "../subsystem/modes/ModeSequenceMessage.h" -#include "../tmstorage/TmStoreMessage.h" -#include "../parameters/ParameterMessage.h" - -void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { - switch(message->getMessageType()){ - case messagetypes::MODE_COMMAND: - ModeMessage::clear(message); - break; - case messagetypes::HEALTH_COMMAND: - HealthMessage::clear(message); - break; - case messagetypes::MODE_SEQUENCE: - ModeSequenceMessage::clear(message); - break; - case messagetypes::ACTION: - ActionMessage::clear(message); - break; - case messagetypes::DEVICE_HANDLER_COMMAND: - DeviceHandlerMessage::clear(message); - break; - case messagetypes::MEMORY: - MemoryMessage::clear(message); - break; - case messagetypes::MONITORING: - MonitoringMessage::clear(message); - break; - case messagetypes::TM_STORE: - TmStoreMessage::clear(message); - break; - case messagetypes::PARAMETER: - ParameterMessage::clear(message); - break; - default: - messagetypes::clearMissionMessage(message); - break; - } -} +#include "../ipc/CommandMessageCleaner.h" + +#include "../devicehandlers/DeviceHandlerMessage.h" +#include "../health/HealthMessage.h" +#include "../memory/MemoryMessage.h" +#include "../modes/ModeMessage.h" +#include "../monitoring/MonitoringMessage.h" +#include "../subsystem/modes/ModeSequenceMessage.h" +#include "../tmstorage/TmStoreMessage.h" +#include "../parameters/ParameterMessage.h" + +void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { + switch(message->getMessageType()){ + case messagetypes::MODE_COMMAND: + ModeMessage::clear(message); + break; + case messagetypes::HEALTH_COMMAND: + HealthMessage::clear(message); + break; + case messagetypes::MODE_SEQUENCE: + ModeSequenceMessage::clear(message); + break; + case messagetypes::ACTION: + ActionMessage::clear(message); + break; + case messagetypes::DEVICE_HANDLER_COMMAND: + DeviceHandlerMessage::clear(message); + break; + case messagetypes::MEMORY: + MemoryMessage::clear(message); + break; + case messagetypes::MONITORING: + MonitoringMessage::clear(message); + break; + case messagetypes::TM_STORE: + TmStoreMessage::clear(message); + break; + case messagetypes::PARAMETER: + ParameterMessage::clear(message); + break; + default: + messagetypes::clearMissionMessage(message); + break; + } +} diff --git a/ipc/CommandMessageCleaner.h b/ipc/CommandMessageCleaner.h index f17bf282..2bf4a193 100644 --- a/ipc/CommandMessageCleaner.h +++ b/ipc/CommandMessageCleaner.h @@ -1,16 +1,16 @@ -#ifndef FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ -#define FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ -#include "../ipc/CommandMessage.h" - -namespace messagetypes { -// Implemented in config. -void clearMissionMessage(CommandMessage* message); -} - -class CommandMessageCleaner { -public: - static void clearCommandMessage(CommandMessage* message); -}; - - -#endif /* FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ */ +#ifndef FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ +#define FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ +#include "../ipc/CommandMessage.h" + +namespace messagetypes { +// Implemented in config. +void clearMissionMessage(CommandMessage* message); +} + +class CommandMessageCleaner { +public: + static void clearCommandMessage(CommandMessage* message); +}; + + +#endif /* FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ */ diff --git a/ipc/CommandMessageIF.h b/ipc/CommandMessageIF.h index 68a8d956..aafa40ef 100644 --- a/ipc/CommandMessageIF.h +++ b/ipc/CommandMessageIF.h @@ -1,73 +1,73 @@ -#ifndef FSFW_IPC_COMMANDMESSAGEIF_H_ -#define FSFW_IPC_COMMANDMESSAGEIF_H_ - -#include "MessageQueueMessageIF.h" -#include "FwMessageTypes.h" -#include "../returnvalues/HasReturnvaluesIF.h" - -#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) -typedef uint16_t Command_t; - -class CommandMessageIF { -public: - /** - * Header consists of sender ID and command ID. - */ - static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE + - sizeof(Command_t); - /** - * This minimum size is derived from the interface requirement to be able - * to set a rejected reply, which contains a returnvalue and the initial - * command. - */ - static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE = - CommandMessageIF::HEADER_SIZE + sizeof(ReturnValue_t) + - sizeof(Command_t); - - static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; - static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); - - static const uint8_t MESSAGE_ID = messagetypes::COMMAND; - //! Used internally, shall be ignored - static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 ); - static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 ); - //! Reply indicating that the current command was rejected, - //! par1 should contain the error code - static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 ); - - virtual ~CommandMessageIF() {}; - - /** - * A command message shall have a uint16_t command ID field. - * @return - */ - virtual Command_t getCommand() const = 0; - /** - * A command message shall have a uint8_t message type ID field. - * @return - */ - virtual uint8_t getMessageType() const = 0; - - /** - * A command message can be rejected and needs to offer a function - * to set a rejected reply - * @param reason - * @param initialCommand - */ - virtual void setReplyRejected(ReturnValue_t reason, - Command_t initialCommand) = 0; - /** - * Corrensonding getter function. - * @param initialCommand - * @return - */ - virtual ReturnValue_t getReplyRejectedReason( - Command_t* initialCommand = nullptr) const = 0; - - virtual void setToUnknownCommand() = 0; - - virtual void clear() = 0; - -}; - -#endif /* FSFW_IPC_COMMANDMESSAGEIF_H_ */ +#ifndef FSFW_IPC_COMMANDMESSAGEIF_H_ +#define FSFW_IPC_COMMANDMESSAGEIF_H_ + +#include "MessageQueueMessageIF.h" +#include "FwMessageTypes.h" +#include "../returnvalues/HasReturnvaluesIF.h" + +#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) +typedef uint16_t Command_t; + +class CommandMessageIF { +public: + /** + * Header consists of sender ID and command ID. + */ + static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE + + sizeof(Command_t); + /** + * This minimum size is derived from the interface requirement to be able + * to set a rejected reply, which contains a returnvalue and the initial + * command. + */ + static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE = + CommandMessageIF::HEADER_SIZE + sizeof(ReturnValue_t) + + sizeof(Command_t); + + static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; + static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); + + static const uint8_t MESSAGE_ID = messagetypes::COMMAND; + //! Used internally, shall be ignored + static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 ); + static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 ); + //! Reply indicating that the current command was rejected, + //! par1 should contain the error code + static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 ); + + virtual ~CommandMessageIF() {}; + + /** + * A command message shall have a uint16_t command ID field. + * @return + */ + virtual Command_t getCommand() const = 0; + /** + * A command message shall have a uint8_t message type ID field. + * @return + */ + virtual uint8_t getMessageType() const = 0; + + /** + * A command message can be rejected and needs to offer a function + * to set a rejected reply + * @param reason + * @param initialCommand + */ + virtual void setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) = 0; + /** + * Corrensonding getter function. + * @param initialCommand + * @return + */ + virtual ReturnValue_t getReplyRejectedReason( + Command_t* initialCommand = nullptr) const = 0; + + virtual void setToUnknownCommand() = 0; + + virtual void clear() = 0; + +}; + +#endif /* FSFW_IPC_COMMANDMESSAGEIF_H_ */ diff --git a/ipc/MessageQueueMessage.cpp b/ipc/MessageQueueMessage.cpp index 2f79cb3b..dcd4def3 100644 --- a/ipc/MessageQueueMessage.cpp +++ b/ipc/MessageQueueMessage.cpp @@ -1,84 +1,84 @@ -#include "MessageQueueMessage.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../globalfunctions/arrayprinter.h" -#include - -MessageQueueMessage::MessageQueueMessage() : - messageSize(getMinimumMessageSize()) { - memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); -} - -MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) : - messageSize(this->HEADER_SIZE + size) { - if (size <= this->MAX_DATA_SIZE) { - memcpy(this->getData(), data, size); - this->messageSize = this->HEADER_SIZE + size; - } - else { - sif::warning << "MessageQueueMessage: Passed size larger than maximum" - "allowed size! Setting content to 0" << std::endl; - memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); - this->messageSize = this->HEADER_SIZE; - } -} - -MessageQueueMessage::~MessageQueueMessage() { -} - -const uint8_t* MessageQueueMessage::getBuffer() const { - return this->internalBuffer; -} - -uint8_t* MessageQueueMessage::getBuffer() { - return this->internalBuffer; -} - -const uint8_t* MessageQueueMessage::getData() const { - return this->internalBuffer + this->HEADER_SIZE; -} - -uint8_t* MessageQueueMessage::getData() { - return this->internalBuffer + this->HEADER_SIZE; -} - -MessageQueueId_t MessageQueueMessage::getSender() const { - MessageQueueId_t temp_id; - memcpy(&temp_id, this->internalBuffer, sizeof(MessageQueueId_t)); - return temp_id; -} - -void MessageQueueMessage::setSender(MessageQueueId_t setId) { - memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t)); -} - -void MessageQueueMessage::print(bool printWholeMessage) { - sif::debug << "MessageQueueMessage content: " << std::endl; - if(printWholeMessage) { - arrayprinter::print(getData(), getMaximumMessageSize()); - } - else { - arrayprinter::print(getData(), getMessageSize()); - } - -} - -void MessageQueueMessage::clear() { - memset(this->getBuffer(), 0, this->MAX_MESSAGE_SIZE); -} - -size_t MessageQueueMessage::getMessageSize() const { - return this->messageSize; -} - -void MessageQueueMessage::setMessageSize(size_t messageSize) { - this->messageSize = messageSize; -} - -size_t MessageQueueMessage::getMinimumMessageSize() const { - return this->MIN_MESSAGE_SIZE; -} - -size_t MessageQueueMessage::getMaximumMessageSize() const { - return this->MAX_MESSAGE_SIZE; -} - +#include "MessageQueueMessage.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../globalfunctions/arrayprinter.h" +#include + +MessageQueueMessage::MessageQueueMessage() : + messageSize(getMinimumMessageSize()) { + memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); +} + +MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) : + messageSize(this->HEADER_SIZE + size) { + if (size <= this->MAX_DATA_SIZE) { + memcpy(this->getData(), data, size); + this->messageSize = this->HEADER_SIZE + size; + } + else { + sif::warning << "MessageQueueMessage: Passed size larger than maximum" + "allowed size! Setting content to 0" << std::endl; + memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); + this->messageSize = this->HEADER_SIZE; + } +} + +MessageQueueMessage::~MessageQueueMessage() { +} + +const uint8_t* MessageQueueMessage::getBuffer() const { + return this->internalBuffer; +} + +uint8_t* MessageQueueMessage::getBuffer() { + return this->internalBuffer; +} + +const uint8_t* MessageQueueMessage::getData() const { + return this->internalBuffer + this->HEADER_SIZE; +} + +uint8_t* MessageQueueMessage::getData() { + return this->internalBuffer + this->HEADER_SIZE; +} + +MessageQueueId_t MessageQueueMessage::getSender() const { + MessageQueueId_t temp_id; + memcpy(&temp_id, this->internalBuffer, sizeof(MessageQueueId_t)); + return temp_id; +} + +void MessageQueueMessage::setSender(MessageQueueId_t setId) { + memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t)); +} + +void MessageQueueMessage::print(bool printWholeMessage) { + sif::debug << "MessageQueueMessage content: " << std::endl; + if(printWholeMessage) { + arrayprinter::print(getData(), getMaximumMessageSize()); + } + else { + arrayprinter::print(getData(), getMessageSize()); + } + +} + +void MessageQueueMessage::clear() { + memset(this->getBuffer(), 0, this->MAX_MESSAGE_SIZE); +} + +size_t MessageQueueMessage::getMessageSize() const { + return this->messageSize; +} + +void MessageQueueMessage::setMessageSize(size_t messageSize) { + this->messageSize = messageSize; +} + +size_t MessageQueueMessage::getMinimumMessageSize() const { + return this->MIN_MESSAGE_SIZE; +} + +size_t MessageQueueMessage::getMaximumMessageSize() const { + return this->MAX_MESSAGE_SIZE; +} + diff --git a/ipc/MessageQueueMessage.h b/ipc/MessageQueueMessage.h index da5c78cb..f68e9b9f 100644 --- a/ipc/MessageQueueMessage.h +++ b/ipc/MessageQueueMessage.h @@ -1,150 +1,150 @@ -#ifndef FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ -#define FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ - -#include "../ipc/MessageQueueMessageIF.h" -#include "../ipc/MessageQueueSenderIF.h" -#include - -/** - * @brief This class is the representation and data organizer - * for interprocess messages. - * @details - * To facilitate and standardize interprocess communication, this class was - * created to handle a lightweight "interprocess message protocol". - * - * It adds a header with the sender's queue id to every sent message and - * defines the maximum total message size. Specialized messages, such as - * device commanding messages, can be created by inheriting from this class - * and filling the buffer provided by getData with additional content. - * - * If larger amounts of data must be sent between processes, the data shall - * be stored in the IPC Store object and only the storage id is passed in a - * queue message.The class is used both to generate and send messages and to - * receive messages from other tasks. - * @ingroup message_queue - */ -class MessageQueueMessage: public MessageQueueMessageIF { -public: - /** - * @brief The class is initialized empty with this constructor. - * @details - * The messageSize attribute is set to the header's size and the whole - * content is set to zero. - */ - MessageQueueMessage(); - /** - * @brief With this constructor the class is initialized with - * the given content. - * @details - * If the passed message size fits into the buffer, the passed data is - * copied to the internal buffer and the messageSize information is set. - * Otherwise, messageSize is set to the header's size and the whole - * content is set to zero. - * @param data The data to be put in the message. - * @param size Size of the data to be copied. Must be smaller than - * MAX_MESSAGE_SIZE and larger than MIN_MESSAGE_SIZE. - */ - MessageQueueMessage(uint8_t* data, size_t size); - - /** - * @brief As no memory is allocated in this class, - * the destructor is empty. - */ - virtual ~MessageQueueMessage(); - - /** - * @brief The size information of each message is stored in - * this attribute. - * @details - * It is public to simplify usage and to allow for passing the size - * address as a pointer. Care must be taken when inheriting from this class, - * as every child class is responsible for managing the size information by - * itself. When using the class to receive a message, the size information - * is updated automatically. - * - * Please note that the minimum size is limited by the size of the header - * while the maximum size is limited by the maximum allowed message size. - */ - size_t messageSize; - /** - * @brief This constant defines the maximum size of the data content, - * excluding the header. - * @details - * It may be changed if necessary, but in general should be kept - * as small as possible. - */ - static const size_t MAX_DATA_SIZE = 24; - - /** - * @brief This constant defines the maximum total size in bytes - * of a sent message. - * @details - * It is the sum of the maximum data and the header size. Be aware that - * this constant is used to define the buffer sizes for every message - * queue in the system. So, a change here may have significant impact on - * the required resources. - */ - static constexpr size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; - /** - * @brief Defines the minimum size of a message where only the - * header is included - */ - static constexpr size_t MIN_MESSAGE_SIZE = HEADER_SIZE; -private: - /** - * @brief This is the internal buffer that contains the - * actual message data. - */ - uint8_t internalBuffer[MAX_MESSAGE_SIZE]; -public: - /** - * @brief This method is used to get the complete data of the message. - */ - const uint8_t* getBuffer() const override; - /** - * @brief This method is used to get the complete data of the message. - */ - uint8_t* getBuffer() override; - /** - * @brief This method is used to fetch the data content of the message. - * @details - * It shall be used by child classes to add data at the right position. - */ - const uint8_t* getData() const override; - /** - * @brief This method is used to fetch the data content of the message. - * @details - * It shall be used by child classes to add data at the right position. - */ - uint8_t* getData() override; - /** - * @brief This method is used to extract the sender's message - * queue id information from a received message. - */ - MessageQueueId_t getSender() const override; - /** - * @brief With this method, the whole content - * and the message size is set to zero. - */ - void clear() override; - - /** - * @brief This method is used to set the sender's message queue id - * information prior to ing the message. - * @param setId - * The message queue id that identifies the sending message queue. - */ - void setSender(MessageQueueId_t setId) override; - - virtual size_t getMessageSize() const override; - virtual void setMessageSize(size_t messageSize) override; - virtual size_t getMinimumMessageSize() const override; - virtual size_t getMaximumMessageSize() const override; - - /** - * @brief This is a debug method that prints the content. - */ - void print(bool printWholeMessage); -}; - -#endif /* FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ */ +#ifndef FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ +#define FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ + +#include "../ipc/MessageQueueMessageIF.h" +#include "../ipc/MessageQueueSenderIF.h" +#include + +/** + * @brief This class is the representation and data organizer + * for interprocess messages. + * @details + * To facilitate and standardize interprocess communication, this class was + * created to handle a lightweight "interprocess message protocol". + * + * It adds a header with the sender's queue id to every sent message and + * defines the maximum total message size. Specialized messages, such as + * device commanding messages, can be created by inheriting from this class + * and filling the buffer provided by getData with additional content. + * + * If larger amounts of data must be sent between processes, the data shall + * be stored in the IPC Store object and only the storage id is passed in a + * queue message.The class is used both to generate and send messages and to + * receive messages from other tasks. + * @ingroup message_queue + */ +class MessageQueueMessage: public MessageQueueMessageIF { +public: + /** + * @brief The class is initialized empty with this constructor. + * @details + * The messageSize attribute is set to the header's size and the whole + * content is set to zero. + */ + MessageQueueMessage(); + /** + * @brief With this constructor the class is initialized with + * the given content. + * @details + * If the passed message size fits into the buffer, the passed data is + * copied to the internal buffer and the messageSize information is set. + * Otherwise, messageSize is set to the header's size and the whole + * content is set to zero. + * @param data The data to be put in the message. + * @param size Size of the data to be copied. Must be smaller than + * MAX_MESSAGE_SIZE and larger than MIN_MESSAGE_SIZE. + */ + MessageQueueMessage(uint8_t* data, size_t size); + + /** + * @brief As no memory is allocated in this class, + * the destructor is empty. + */ + virtual ~MessageQueueMessage(); + + /** + * @brief The size information of each message is stored in + * this attribute. + * @details + * It is public to simplify usage and to allow for passing the size + * address as a pointer. Care must be taken when inheriting from this class, + * as every child class is responsible for managing the size information by + * itself. When using the class to receive a message, the size information + * is updated automatically. + * + * Please note that the minimum size is limited by the size of the header + * while the maximum size is limited by the maximum allowed message size. + */ + size_t messageSize; + /** + * @brief This constant defines the maximum size of the data content, + * excluding the header. + * @details + * It may be changed if necessary, but in general should be kept + * as small as possible. + */ + static const size_t MAX_DATA_SIZE = 24; + + /** + * @brief This constant defines the maximum total size in bytes + * of a sent message. + * @details + * It is the sum of the maximum data and the header size. Be aware that + * this constant is used to define the buffer sizes for every message + * queue in the system. So, a change here may have significant impact on + * the required resources. + */ + static constexpr size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; + /** + * @brief Defines the minimum size of a message where only the + * header is included + */ + static constexpr size_t MIN_MESSAGE_SIZE = HEADER_SIZE; +private: + /** + * @brief This is the internal buffer that contains the + * actual message data. + */ + uint8_t internalBuffer[MAX_MESSAGE_SIZE]; +public: + /** + * @brief This method is used to get the complete data of the message. + */ + const uint8_t* getBuffer() const override; + /** + * @brief This method is used to get the complete data of the message. + */ + uint8_t* getBuffer() override; + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + const uint8_t* getData() const override; + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + uint8_t* getData() override; + /** + * @brief This method is used to extract the sender's message + * queue id information from a received message. + */ + MessageQueueId_t getSender() const override; + /** + * @brief With this method, the whole content + * and the message size is set to zero. + */ + void clear() override; + + /** + * @brief This method is used to set the sender's message queue id + * information prior to ing the message. + * @param setId + * The message queue id that identifies the sending message queue. + */ + void setSender(MessageQueueId_t setId) override; + + virtual size_t getMessageSize() const override; + virtual void setMessageSize(size_t messageSize) override; + virtual size_t getMinimumMessageSize() const override; + virtual size_t getMaximumMessageSize() const override; + + /** + * @brief This is a debug method that prints the content. + */ + void print(bool printWholeMessage); +}; + +#endif /* FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ */ From d885dddee8c8f053207c5c652f5acc81d66efff8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 15:04:53 +0200 Subject: [PATCH 29/53] renormalize files --- container/SimpleRingBuffer.cpp | 270 ++++++++++++++++----------------- container/SimpleRingBuffer.h | 256 +++++++++++++++---------------- 2 files changed, 263 insertions(+), 263 deletions(-) diff --git a/container/SimpleRingBuffer.cpp b/container/SimpleRingBuffer.cpp index 2a19d619..d6b6f5af 100644 --- a/container/SimpleRingBuffer.cpp +++ b/container/SimpleRingBuffer.cpp @@ -1,135 +1,135 @@ -#include "../container/SimpleRingBuffer.h" -#include - -SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, - size_t maxExcessBytes) : - RingBufferBase<>(0, size, overwriteOld), - maxExcessBytes(maxExcessBytes) { - if(maxExcessBytes > size) { - this->maxExcessBytes = size; - } - else { - this->maxExcessBytes = maxExcessBytes; - } - buffer = new uint8_t[size + maxExcessBytes]; -} - -SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size, - bool overwriteOld, size_t maxExcessBytes): - RingBufferBase<>(0, size, overwriteOld), buffer(buffer) { - if(maxExcessBytes > size) { - this->maxExcessBytes = size; - } - else { - this->maxExcessBytes = maxExcessBytes; - } -} - - -SimpleRingBuffer::~SimpleRingBuffer() { - delete[] buffer; -} - - -ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer, - size_t amount) { - if ((availableWriteSpace() >= amount) or overwriteOld) { - size_t amountTillWrap = writeTillWrap(); - if (amountTillWrap < amount) { - if((amount - amountTillWrap + excessBytes) > maxExcessBytes) { - return HasReturnvaluesIF::RETURN_FAILED; - } - excessBytes = amount - amountTillWrap; - } - *writePointer = &buffer[write]; - return HasReturnvaluesIF::RETURN_OK; - } - else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -void SimpleRingBuffer::confirmBytesWritten(size_t amount) { - if(getExcessBytes() > 0) { - moveExcessBytesToStart(); - } - incrementWrite(amount); - -} - -ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, - size_t amount) { - if ((availableWriteSpace() >= amount) or overwriteOld) { - size_t amountTillWrap = writeTillWrap(); - if (amountTillWrap >= amount) { - // remaining size in buffer is sufficient to fit full amount. - memcpy(&buffer[write], data, amount); - } - else { - memcpy(&buffer[write], data, amountTillWrap); - memcpy(buffer, data + amountTillWrap, amount - amountTillWrap); - } - incrementWrite(amount); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount, - bool incrementReadPtr, bool readRemaining, size_t* trueAmount) { - size_t availableData = getAvailableReadData(READ_PTR); - size_t amountTillWrap = readTillWrap(READ_PTR); - if (availableData < amount) { - if (readRemaining) { - // more data available than amount specified. - amount = availableData; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - if (trueAmount != nullptr) { - *trueAmount = amount; - } - if (amountTillWrap >= amount) { - memcpy(data, &buffer[read[READ_PTR]], amount); - } else { - memcpy(data, &buffer[read[READ_PTR]], amountTillWrap); - memcpy(data + amountTillWrap, buffer, amount - amountTillWrap); - } - - if(incrementReadPtr) { - deleteData(amount, readRemaining); - } - return HasReturnvaluesIF::RETURN_OK; -} - -size_t SimpleRingBuffer::getExcessBytes() const { - return excessBytes; -} - -void SimpleRingBuffer::moveExcessBytesToStart() { - if(excessBytes > 0) { - std::memcpy(buffer, &buffer[size], excessBytes); - excessBytes = 0; - } -} - -ReturnValue_t SimpleRingBuffer::deleteData(size_t amount, - bool deleteRemaining, size_t* trueAmount) { - size_t availableData = getAvailableReadData(READ_PTR); - if (availableData < amount) { - if (deleteRemaining) { - amount = availableData; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - if (trueAmount != nullptr) { - *trueAmount = amount; - } - incrementRead(amount, READ_PTR); - return HasReturnvaluesIF::RETURN_OK; -} - - +#include "../container/SimpleRingBuffer.h" +#include + +SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, + size_t maxExcessBytes) : + RingBufferBase<>(0, size, overwriteOld), + maxExcessBytes(maxExcessBytes) { + if(maxExcessBytes > size) { + this->maxExcessBytes = size; + } + else { + this->maxExcessBytes = maxExcessBytes; + } + buffer = new uint8_t[size + maxExcessBytes]; +} + +SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size, + bool overwriteOld, size_t maxExcessBytes): + RingBufferBase<>(0, size, overwriteOld), buffer(buffer) { + if(maxExcessBytes > size) { + this->maxExcessBytes = size; + } + else { + this->maxExcessBytes = maxExcessBytes; + } +} + + +SimpleRingBuffer::~SimpleRingBuffer() { + delete[] buffer; +} + + +ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer, + size_t amount) { + if (availableWriteSpace() >= amount or overwriteOld) { + size_t amountTillWrap = writeTillWrap(); + if (amountTillWrap < amount) { + if((amount - amountTillWrap + excessBytes) > maxExcessBytes) { + return HasReturnvaluesIF::RETURN_FAILED; + } + excessBytes = amount - amountTillWrap; + } + *writePointer = &buffer[write]; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +void SimpleRingBuffer::confirmBytesWritten(size_t amount) { + if(getExcessBytes() > 0) { + moveExcessBytesToStart(); + } + incrementWrite(amount); + +} + +ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, + size_t amount) { + if (availableWriteSpace() >= amount or overwriteOld) { + size_t amountTillWrap = writeTillWrap(); + if (amountTillWrap >= amount) { + // remaining size in buffer is sufficient to fit full amount. + memcpy(&buffer[write], data, amount); + } + else { + memcpy(&buffer[write], data, amountTillWrap); + memcpy(buffer, data + amountTillWrap, amount - amountTillWrap); + } + incrementWrite(amount); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount, + bool incrementReadPtr, bool readRemaining, size_t* trueAmount) { + size_t availableData = getAvailableReadData(READ_PTR); + size_t amountTillWrap = readTillWrap(READ_PTR); + if (availableData < amount) { + if (readRemaining) { + // more data available than amount specified. + amount = availableData; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + if (trueAmount != nullptr) { + *trueAmount = amount; + } + if (amountTillWrap >= amount) { + memcpy(data, &buffer[read[READ_PTR]], amount); + } else { + memcpy(data, &buffer[read[READ_PTR]], amountTillWrap); + memcpy(data + amountTillWrap, buffer, amount - amountTillWrap); + } + + if(incrementReadPtr) { + deleteData(amount, readRemaining); + } + return HasReturnvaluesIF::RETURN_OK; +} + +size_t SimpleRingBuffer::getExcessBytes() const { + return excessBytes; +} + +void SimpleRingBuffer::moveExcessBytesToStart() { + if(excessBytes > 0) { + std::memcpy(buffer, &buffer[size], excessBytes); + excessBytes = 0; + } +} + +ReturnValue_t SimpleRingBuffer::deleteData(size_t amount, + bool deleteRemaining, size_t* trueAmount) { + size_t availableData = getAvailableReadData(READ_PTR); + if (availableData < amount) { + if (deleteRemaining) { + amount = availableData; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + if (trueAmount != nullptr) { + *trueAmount = amount; + } + incrementRead(amount, READ_PTR); + return HasReturnvaluesIF::RETURN_OK; +} + + diff --git a/container/SimpleRingBuffer.h b/container/SimpleRingBuffer.h index b13e9f2a..dcf2684b 100644 --- a/container/SimpleRingBuffer.h +++ b/container/SimpleRingBuffer.h @@ -1,128 +1,128 @@ -#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ -#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ - -#include "../container/RingBufferBase.h" -#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. - * This class allocated dynamically, so - * @ingroup containers - */ -class SimpleRingBuffer: public RingBufferBase<> { -public: - /** - * This constructor allocates a new internal buffer with the supplied size. - * - * @param size - * @param overwriteOld If the ring buffer is overflowing at a write - * operation, the oldest data will be overwritten. - * @param maxExcessBytes These additional bytes will be allocated in addtion - * to the specified size to accomodate contiguous write operations - * with getFreeElement. - * - */ - SimpleRingBuffer(const size_t size, bool overwriteOld, - size_t maxExcessBytes = 0); - /** - * This constructor takes an external buffer with the specified size. - * @param buffer - * @param size - * @param overwriteOld - * If the ring buffer is overflowing at a write operartion, the oldest data - * will be overwritten. - * @param maxExcessBytes - * If the buffer can accomodate additional bytes for contigous write - * operations with getFreeElement, this is the maximum allowed additional - * size - */ - SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld, - size_t maxExcessBytes = 0); - - virtual ~SimpleRingBuffer(); - - /** - * Write to circular buffer and increment write pointer by amount. - * @param data - * @param amount - * @return -@c RETURN_OK if write operation was successfull - * -@c RETURN_FAILED if - */ - ReturnValue_t writeData(const uint8_t* data, size_t amount); - - /** - * Returns a pointer to a free element. If the remaining buffer is - * not large enough, the data will be written past the actual size - * and the amount of excess bytes will be cached. This function - * does not increment the write pointer! - * @param writePointer Pointer to a pointer which can be used to write - * contiguous blocks into the ring buffer - * @param amount - * @return - */ - ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount); - - /** - * This increments the write pointer and also copies the excess bytes - * to the beginning. It should be called if the write operation - * conducted after calling getFreeElement() was performed. - * @return - */ - void confirmBytesWritten(size_t amount); - - virtual size_t getExcessBytes() const; - /** - * Helper functions which moves any excess bytes to the start - * of the ring buffer. - * @return - */ - virtual void moveExcessBytesToStart(); - - /** - * Read from circular buffer at read pointer. - * @param data - * @param amount - * @param incrementReadPtr - * If this is set to true, the read pointer will be incremented. - * If readRemaining is set to true, the read pointer will be incremented - * accordingly. - * @param readRemaining - * If this is set to true, the data will be read even if the amount - * specified exceeds the read data available. - * @param trueAmount [out] - * If readRemaining was set to true, the true amount read will be assigned - * to the passed value. - * @return - * - @c RETURN_OK if data was read successfully - * - @c RETURN_FAILED if not enough data was available and readRemaining - * was set to false. - */ - ReturnValue_t readData(uint8_t* data, size_t amount, - bool incrementReadPtr = false, bool readRemaining = false, - size_t* trueAmount = nullptr); - - /** - * Delete data by incrementing read pointer. - * @param amount - * @param deleteRemaining - * If the amount specified is larger than the remaing size to read and this - * is set to true, the remaining amount will be deleted as well - * @param trueAmount [out] - * If deleteRemaining was set to true, the amount deleted will be assigned - * to the passed value. - * @return - */ - ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false, - size_t* trueAmount = nullptr); -private: - static const uint8_t READ_PTR = 0; - uint8_t* buffer = nullptr; - size_t maxExcessBytes; - size_t excessBytes = 0; -}; - -#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ - +#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ +#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ + +#include "../container/RingBufferBase.h" +#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. + * This class allocated dynamically, so + * @ingroup containers + */ +class SimpleRingBuffer: public RingBufferBase<> { +public: + /** + * This constructor allocates a new internal buffer with the supplied size. + * + * @param size + * @param overwriteOld If the ring buffer is overflowing at a write + * operation, the oldest data will be overwritten. + * @param maxExcessBytes These additional bytes will be allocated in addtion + * to the specified size to accomodate contiguous write operations + * with getFreeElement. + * + */ + SimpleRingBuffer(const size_t size, bool overwriteOld, + size_t maxExcessBytes = 0); + /** + * This constructor takes an external buffer with the specified size. + * @param buffer + * @param size + * @param overwriteOld + * If the ring buffer is overflowing at a write operartion, the oldest data + * will be overwritten. + * @param maxExcessBytes + * If the buffer can accomodate additional bytes for contigous write + * operations with getFreeElement, this is the maximum allowed additional + * size + */ + SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld, + size_t maxExcessBytes = 0); + + virtual ~SimpleRingBuffer(); + + /** + * Write to circular buffer and increment write pointer by amount. + * @param data + * @param amount + * @return -@c RETURN_OK if write operation was successfull + * -@c RETURN_FAILED if + */ + ReturnValue_t writeData(const uint8_t* data, size_t amount); + + /** + * Returns a pointer to a free element. If the remaining buffer is + * not large enough, the data will be written past the actual size + * and the amount of excess bytes will be cached. This function + * does not increment the write pointer! + * @param writePointer Pointer to a pointer which can be used to write + * contiguous blocks into the ring buffer + * @param amount + * @return + */ + ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount); + + /** + * This increments the write pointer and also copies the excess bytes + * to the beginning. It should be called if the write operation + * conducted after calling getFreeElement() was performed. + * @return + */ + void confirmBytesWritten(size_t amount); + + virtual size_t getExcessBytes() const; + /** + * Helper functions which moves any excess bytes to the start + * of the ring buffer. + * @return + */ + virtual void moveExcessBytesToStart(); + + /** + * Read from circular buffer at read pointer. + * @param data + * @param amount + * @param incrementReadPtr + * If this is set to true, the read pointer will be incremented. + * If readRemaining is set to true, the read pointer will be incremented + * accordingly. + * @param readRemaining + * If this is set to true, the data will be read even if the amount + * specified exceeds the read data available. + * @param trueAmount [out] + * If readRemaining was set to true, the true amount read will be assigned + * to the passed value. + * @return + * - @c RETURN_OK if data was read successfully + * - @c RETURN_FAILED if not enough data was available and readRemaining + * was set to false. + */ + ReturnValue_t readData(uint8_t* data, size_t amount, + bool incrementReadPtr = false, bool readRemaining = false, + size_t* trueAmount = nullptr); + + /** + * Delete data by incrementing read pointer. + * @param amount + * @param deleteRemaining + * If the amount specified is larger than the remaing size to read and this + * is set to true, the remaining amount will be deleted as well + * @param trueAmount [out] + * If deleteRemaining was set to true, the amount deleted will be assigned + * to the passed value. + * @return + */ + ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false, + size_t* trueAmount = nullptr); +private: + static const uint8_t READ_PTR = 0; + uint8_t* buffer = nullptr; + size_t maxExcessBytes; + size_t excessBytes = 0; +}; + +#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ + From e105be229a075bb83e867cf00baa9f392d9d5468 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 15:06:48 +0200 Subject: [PATCH 30/53] include guards fand include improvements --- container/SimpleRingBuffer.cpp | 2 +- container/SimpleRingBuffer.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/container/SimpleRingBuffer.cpp b/container/SimpleRingBuffer.cpp index d6b6f5af..01c22463 100644 --- a/container/SimpleRingBuffer.cpp +++ b/container/SimpleRingBuffer.cpp @@ -1,4 +1,4 @@ -#include "../container/SimpleRingBuffer.h" +#include "SimpleRingBuffer.h" #include SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, diff --git a/container/SimpleRingBuffer.h b/container/SimpleRingBuffer.h index dcf2684b..a790712f 100644 --- a/container/SimpleRingBuffer.h +++ b/container/SimpleRingBuffer.h @@ -1,7 +1,7 @@ -#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ -#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ +#ifndef FSFW_CONTAINER_SIMPLERINGBUFFER_H_ +#define FSFW_CONTAINER_SIMPLERINGBUFFER_H_ -#include "../container/RingBufferBase.h" +#include "RingBufferBase.h" #include /** @@ -124,5 +124,5 @@ private: size_t excessBytes = 0; }; -#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ +#endif /* FSFW_CONTAINER_SIMPLERINGBUFFER_H_ */ From 3e67701933e6e64ac998691cd4e2e043e7786427 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 15:09:24 +0200 Subject: [PATCH 31/53] taken over ring buffer base changes --- container/RingBufferBase.h | 125 +++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/container/RingBufferBase.h b/container/RingBufferBase.h index e3a87d9d..886b9fab 100644 --- a/container/RingBufferBase.h +++ b/container/RingBufferBase.h @@ -1,96 +1,113 @@ -#ifndef FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ -#define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ +#ifndef FSFW_CONTAINER_RINGBUFFERBASE_H_ +#define FSFW_CONTAINER_RINGBUFFERBASE_H_ #include "../returnvalues/HasReturnvaluesIF.h" +#include template class RingBufferBase { public: - RingBufferBase(uint32_t startAddress, uint32_t size, bool overwriteOld) : - start(startAddress), write(startAddress), size(size), overwriteOld(overwriteOld) { + RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) : + start(startAddress), write(startAddress), size(size), + overwriteOld(overwriteOld) { for (uint8_t count = 0; count < N_READ_PTRS; count++) { read[count] = startAddress; } } - ReturnValue_t readData(uint32_t amount, uint8_t n = 0) { - if (availableReadData(n) >= amount) { - incrementRead(amount, n); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - ReturnValue_t writeData(uint32_t amount) { - if (availableWriteSpace() >= amount || overwriteOld) { - incrementWrite(amount); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - uint32_t availableReadData(uint8_t n = 0) const { - return ((write + size) - read[n]) % size; - } - uint32_t availableWriteSpace(uint8_t n = 0) const { - //One less to avoid ambiguous full/empty problem. - return (((read[n] + size) - write - 1) % size); - } + + virtual ~RingBufferBase() {} + bool isFull(uint8_t n = 0) { return (availableWriteSpace(n) == 0); } bool isEmpty(uint8_t n = 0) { - return (availableReadData(n) == 0); + return (getAvailableReadData(n) == 0); } - virtual ~RingBufferBase() { + size_t getAvailableReadData(uint8_t n = 0) const { + return ((write + size) - read[n]) % size; } - uint32_t getRead(uint8_t n = 0) const { - return read[n]; + size_t availableWriteSpace(uint8_t n = 0) const { + //One less to avoid ambiguous full/empty problem. + return (((read[n] + size) - write - 1) % size); } - void setRead(uint32_t read, uint8_t n = 0) { - if (read >= start && read < (start+size)) { - this->read[n] = read; - } + + bool overwritesOld() const { + return overwriteOld; } - uint32_t getWrite() const { - return write; - } - void setWrite(uint32_t write) { - this->write = write; + + size_t getMaxSize() const { + return size - 1; } + void clear() { write = start; for (uint8_t count = 0; count < N_READ_PTRS; count++) { read[count] = start; } } - uint32_t writeTillWrap() { + + size_t writeTillWrap() { return (start + size) - write; } - uint32_t readTillWrap(uint8_t n = 0) { + + size_t readTillWrap(uint8_t n = 0) { return (start + size) - read[n]; } - uint32_t getStart() const { + + size_t getStart() const { return start; } - bool overwritesOld() const { - return overwriteOld; - } - uint32_t maxSize() const { - return size - 1; - } + protected: - const uint32_t start; - uint32_t write; - uint32_t read[N_READ_PTRS]; - const uint32_t size; + const size_t start; + size_t write; + size_t read[N_READ_PTRS]; + const size_t size; const bool overwriteOld; + void incrementWrite(uint32_t amount) { write = ((write + amount - start) % size) + start; } void incrementRead(uint32_t amount, uint8_t n = 0) { read[n] = ((read[n] + amount - start) % size) + start; } + + ReturnValue_t readData(uint32_t amount, uint8_t n = 0) { + if (getAvailableReadData(n) >= amount) { + incrementRead(amount, n); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + ReturnValue_t writeData(uint32_t amount) { + if (availableWriteSpace() >= amount or overwriteOld) { + incrementWrite(amount); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + size_t getRead(uint8_t n = 0) const { + return read[n]; + } + + void setRead(uint32_t read, uint8_t n = 0) { + if (read >= start && read < (start+size)) { + this->read[n] = read; + } + } + + uint32_t getWrite() const { + return write; + } + + void setWrite(uint32_t write) { + this->write = write; + } }; -#endif /* FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ */ +#endif /* FSFW_CONTAINER_RINGBUFFERBASE_H_ */ From 06400fa7bbd89792bc1e508aa6ecf424981ab453 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 15:10:44 +0200 Subject: [PATCH 32/53] share dring buffer update --- container/SharedRingBuffer.cpp | 6 +++--- container/SharedRingBuffer.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/container/SharedRingBuffer.cpp b/container/SharedRingBuffer.cpp index 001a21ed..490988e5 100644 --- a/container/SharedRingBuffer.cpp +++ b/container/SharedRingBuffer.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include "../container/SharedRingBuffer.h" +#include "../ipc/MutexFactory.h" +#include "../ipc/MutexHelper.h" SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, bool overwriteOld, size_t maxExcessBytes): diff --git a/container/SharedRingBuffer.h b/container/SharedRingBuffer.h index 0b5be052..394dcaaa 100644 --- a/container/SharedRingBuffer.h +++ b/container/SharedRingBuffer.h @@ -1,10 +1,10 @@ #ifndef FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ #define FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ -#include -#include -#include -#include +#include "../container/SimpleRingBuffer.h" +#include "../ipc/MutexIF.h" +#include "../objectmanager/SystemObject.h" +#include "../timemanager/Clock.h" /** * @brief Ring buffer which can be shared among multiple objects From dbac6e139b6e7991d5f0997d7b2a9f7daebbbe44 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 15:11:53 +0200 Subject: [PATCH 33/53] shared ring buffer update --- container/SharedRingBuffer.cpp | 2 +- container/SharedRingBuffer.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/container/SharedRingBuffer.cpp b/container/SharedRingBuffer.cpp index 490988e5..800e75d3 100644 --- a/container/SharedRingBuffer.cpp +++ b/container/SharedRingBuffer.cpp @@ -1,4 +1,4 @@ -#include "../container/SharedRingBuffer.h" +#include "SharedRingBuffer.h" #include "../ipc/MutexFactory.h" #include "../ipc/MutexHelper.h" diff --git a/container/SharedRingBuffer.h b/container/SharedRingBuffer.h index 394dcaaa..80c068b3 100644 --- a/container/SharedRingBuffer.h +++ b/container/SharedRingBuffer.h @@ -1,7 +1,7 @@ -#ifndef FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ -#define FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ +#ifndef FSFW_CONTAINER_SHAREDRINGBUFFER_H_ +#define FSFW_CONTAINER_SHAREDRINGBUFFER_H_ -#include "../container/SimpleRingBuffer.h" +#include "SimpleRingBuffer.h" #include "../ipc/MutexIF.h" #include "../objectmanager/SystemObject.h" #include "../timemanager/Clock.h" @@ -65,4 +65,4 @@ private: -#endif /* FRAMEWORK_CONTAINER_SHAREDRINGBUFFER_H_ */ +#endif /* FSFW_CONTAINER_SHAREDRINGBUFFER_H_ */ From e96ab123121d5d0039e60f3069b4a8b226fa7751 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 15 Sep 2020 15:55:35 +0200 Subject: [PATCH 34/53] comment and calculation fix --- ipc/CommandMessage.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ipc/CommandMessage.h b/ipc/CommandMessage.h index ca7b817f..8f5daa04 100644 --- a/ipc/CommandMessage.h +++ b/ipc/CommandMessage.h @@ -8,7 +8,7 @@ /** * @brief Default command message used to pass command messages between tasks. * Primary message type for IPC. Contains sender, 2-byte command ID - * field, and 2 4-byte parameters. + * field, and 3 4-byte parameter * @details * It operates on an external memory which is contained inside a * class implementing MessageQueueMessageIF by taking its address. @@ -23,10 +23,11 @@ class CommandMessage: public MessageQueueMessage, public CommandMessageIF { public: /** - * Default size can accomodate 2 4-byte parameters. + * Default size can accomodate 3 4-byte parameters. */ static constexpr size_t DEFAULT_COMMAND_MESSAGE_SIZE = - CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE + sizeof(uint32_t); + CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE + + 3 * sizeof(uint32_t); /** * @brief Default Constructor, does not initialize anything. From 3fcbb988ae0c299b48ed632761d690467426ca23 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 15 Sep 2020 16:47:01 +0200 Subject: [PATCH 35/53] new file for typedef to avoid circular include --- ipc/MessageQueueMessageIF.h | 17 +++-------------- ipc/MessageQueueSenderIF.h | 23 ++++++----------------- ipc/messageQueueDefinitions.h | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 31 deletions(-) create mode 100644 ipc/messageQueueDefinitions.h diff --git a/ipc/MessageQueueMessageIF.h b/ipc/MessageQueueMessageIF.h index 91753ced..b5a30c08 100644 --- a/ipc/MessageQueueMessageIF.h +++ b/ipc/MessageQueueMessageIF.h @@ -1,24 +1,13 @@ #ifndef FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ #define FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ + +#include #include #include -/* - * TODO: Actually, the definition of this ID to be a uint32_t is not ideal and - * breaks layering. However, it is difficult to keep layering, as the ID is - * stored in many places and sent around in MessageQueueMessage. - * Ideally, one would use the (current) object_id_t only, however, doing a - * lookup of queueIDs for every call does not sound ideal. - * In a first step, I'll circumvent the issue by not touching it, - * maybe in a second step. This also influences Interface design - * (getCommandQueue) and some other issues.. - */ - -typedef uint32_t MessageQueueId_t; - class MessageQueueMessageIF { public: - static const MessageQueueId_t NO_QUEUE = -1; + /** * @brief This constants defines the size of the header, * which is added to every message. diff --git a/ipc/MessageQueueSenderIF.h b/ipc/MessageQueueSenderIF.h index d9692f54..beb27f50 100644 --- a/ipc/MessageQueueSenderIF.h +++ b/ipc/MessageQueueSenderIF.h @@ -1,37 +1,26 @@ #ifndef FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ #define FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ +#include "../ipc/MessageQueueIF.h" +#include "../ipc/MessageQueueMessageIF.h" #include "../objectmanager/ObjectManagerIF.h" -class MessageQueueMessage; - - -//TODO: Actually, the definition of this ID to be a uint32_t is not ideal and breaks layering. -//However, it is difficult to keep layering, as the ID is stored in many places and sent around in -//MessageQueueMessage. -//Ideally, one would use the (current) object_id_t only, however, doing a lookup of queueIDs for every -//call does not sound ideal. -//In a first step, I'll circumvent the issue by not touching it, maybe in a second step. -//This also influences Interface design (getCommandQueue) and some other issues.. -typedef uint32_t MessageQueueId_t; class MessageQueueSenderIF { public: - static const MessageQueueId_t NO_QUEUE = 0; virtual ~MessageQueueSenderIF() {} /** - * Allows sending messages without actually "owing" a message queue. + * Allows sending messages without actually "owning" a message queue. * Not sure whether this is actually a good idea. - * Must be implemented by a subclass. */ static ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom = - MessageQueueSenderIF::NO_QUEUE, bool ignoreFault=false); + MessageQueueMessageIF* message, + MessageQueueId_t sentFrom = MessageQueueIF::NO_QUEUE, + bool ignoreFault = false); private: MessageQueueSenderIF() {} }; - #endif /* FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ */ diff --git a/ipc/messageQueueDefinitions.h b/ipc/messageQueueDefinitions.h new file mode 100644 index 00000000..d30e6984 --- /dev/null +++ b/ipc/messageQueueDefinitions.h @@ -0,0 +1,18 @@ +#ifndef FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ +#define FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ + +#include + +/* + * TODO: Actually, the definition of this ID to be a uint32_t is not ideal and + * breaks layering. However, it is difficult to keep layering, as the ID is + * stored in many places and sent around in MessageQueueMessage. + * Ideally, one would use the (current) object_id_t only, however, doing a + * lookup of queueIDs for every call does not sound ideal. + * In a first step, I'll circumvent the issue by not touching it, + * maybe in a second step. This also influences Interface design + * (getCommandQueue) and some other issues.. + */ +using MessageQueueId_t = uint32_t; + +#endif /* FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ */ From 21346e40a54e93a3753042fd4259ddc4154d9622 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 15 Sep 2020 16:58:38 +0200 Subject: [PATCH 36/53] some improvements --- action/ActionHelper.cpp | 1 + datalinklayer/MapPacketExtraction.cpp | 2 +- ipc/MessageQueueIF.h | 10 +++++----- ipc/MessageQueueMessage.h | 1 - ipc/MessageQueueSenderIF.h | 8 ++++---- ipc/messageQueueDefinitions.h | 1 + modes/ModeHelper.cpp | 8 ++++---- osal/FreeRTOS/MessageQueue.cpp | 4 +++- osal/FreeRTOS/QueueFactory.cpp | 7 +++++-- 9 files changed, 24 insertions(+), 18 deletions(-) diff --git a/action/ActionHelper.cpp b/action/ActionHelper.cpp index b43c676d..361f7dc3 100644 --- a/action/ActionHelper.cpp +++ b/action/ActionHelper.cpp @@ -1,5 +1,6 @@ #include "ActionHelper.h" #include "HasActionsIF.h" +#include "../ipc/MessageQueueSenderIF.h" #include "../objectmanager/ObjectManagerIF.h" ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : diff --git a/datalinklayer/MapPacketExtraction.cpp b/datalinklayer/MapPacketExtraction.cpp index cb12b321..d64348e1 100644 --- a/datalinklayer/MapPacketExtraction.cpp +++ b/datalinklayer/MapPacketExtraction.cpp @@ -18,7 +18,7 @@ MapPacketExtraction::MapPacketExtraction(uint8_t setMapId, object_id_t setPacketDestination) : lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), bufferPosition( packetBuffer), packetDestination(setPacketDestination), packetStore( - NULL), tcQueueId(MessageQueueSenderIF::NO_QUEUE) { + NULL), tcQueueId(MessageQueueIF::NO_QUEUE) { memset(packetBuffer, 0, sizeof(packetBuffer)); } diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index 9fff5287..b0347db9 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -1,15 +1,15 @@ -#ifndef FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ -#define FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ +#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_ +#define FSFW_IPC_MESSAGEQUEUEIF_H_ // COULDDO: We could support blocking calls +#include "messageQueueDefinitions.h" #include "MessageQueueMessage.h" -#include "MessageQueueSenderIF.h" #include "../returnvalues/HasReturnvaluesIF.h" + class MessageQueueIF { public: - - static const MessageQueueId_t NO_QUEUE = MessageQueueSenderIF::NO_QUEUE; //!< Ugly hack. + static const MessageQueueId_t NO_QUEUE = 0; static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; /** diff --git a/ipc/MessageQueueMessage.h b/ipc/MessageQueueMessage.h index f68e9b9f..5234f64f 100644 --- a/ipc/MessageQueueMessage.h +++ b/ipc/MessageQueueMessage.h @@ -2,7 +2,6 @@ #define FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ #include "../ipc/MessageQueueMessageIF.h" -#include "../ipc/MessageQueueSenderIF.h" #include /** diff --git a/ipc/MessageQueueSenderIF.h b/ipc/MessageQueueSenderIF.h index beb27f50..7eea5146 100644 --- a/ipc/MessageQueueSenderIF.h +++ b/ipc/MessageQueueSenderIF.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ -#define FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ +#ifndef FSFW_IPC_MESSAGEQUEUESENDERIF_H_ +#define FSFW_IPC_MESSAGEQUEUESENDERIF_H_ #include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueMessageIF.h" @@ -15,7 +15,7 @@ public: * Not sure whether this is actually a good idea. */ static ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, + MessageQueueMessage* message, MessageQueueId_t sentFrom = MessageQueueIF::NO_QUEUE, bool ignoreFault = false); private: @@ -23,4 +23,4 @@ private: }; -#endif /* FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ */ +#endif /* FSFW_IPC_MESSAGEQUEUESENDERIF_H_ */ diff --git a/ipc/messageQueueDefinitions.h b/ipc/messageQueueDefinitions.h index d30e6984..60c09b05 100644 --- a/ipc/messageQueueDefinitions.h +++ b/ipc/messageQueueDefinitions.h @@ -15,4 +15,5 @@ */ using MessageQueueId_t = uint32_t; + #endif /* FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ */ diff --git a/modes/ModeHelper.cpp b/modes/ModeHelper.cpp index cb62c468..f464a743 100644 --- a/modes/ModeHelper.cpp +++ b/modes/ModeHelper.cpp @@ -36,7 +36,7 @@ ReturnValue_t ModeHelper::handleModeCommand(CommandMessage* message) { commandedMode = mode; commandedSubmode = submode; - if ((parentQueueId != MessageQueueSenderIF::NO_QUEUE) + if ((parentQueueId != MessageQueueIF::NO_QUEUE) && (theOneWhoCommandedAMode != parentQueueId)) { owner->setToExternalControl(); } @@ -74,7 +74,7 @@ ReturnValue_t ModeHelper::initialize(MessageQueueId_t parentQueueId) { void ModeHelper::modeChanged(Mode_t mode, Submode_t submode) { forced = false; CommandMessage reply; - if (theOneWhoCommandedAMode != MessageQueueSenderIF::NO_QUEUE) { + if (theOneWhoCommandedAMode != MessageQueueIF::NO_QUEUE) { if ((mode != commandedMode) || (submode != commandedSubmode)) { ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_WRONG_MODE_REPLY, mode, submode); @@ -86,12 +86,12 @@ void ModeHelper::modeChanged(Mode_t mode, Submode_t submode) { owner->getCommandQueue()); } if (theOneWhoCommandedAMode != parentQueueId - && parentQueueId != MessageQueueSenderIF::NO_QUEUE) { + && parentQueueId != MessageQueueIF::NO_QUEUE) { ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_MODE_INFO, mode, submode); MessageQueueSenderIF::sendMessage(parentQueueId, &reply, owner->getCommandQueue()); } - theOneWhoCommandedAMode = MessageQueueSenderIF::NO_QUEUE; + theOneWhoCommandedAMode = MessageQueueIF::NO_QUEUE; } void ModeHelper::startTimer(uint32_t timeoutMs) { diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 3bbd4d9d..6c8e1de9 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -1,5 +1,6 @@ #include "MessageQueue.h" +#include "../../objectmanager/ObjectManagerIF.h" #include "../../serviceinterface/ServiceInterfaceStream.h" // 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 @@ -101,7 +102,8 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, reinterpret_cast(message->getBuffer()), 0); if (result != pdPASS) { if (!ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = objectManager->get( + InternalErrorReporterIF* internalErrorReporter = + objectManager->get( objects::INTERNAL_ERROR_REPORTER); if (internalErrorReporter != NULL) { internalErrorReporter->queueMessageNotSent(); diff --git a/osal/FreeRTOS/QueueFactory.cpp b/osal/FreeRTOS/QueueFactory.cpp index e639179a..0de6ad4f 100644 --- a/osal/FreeRTOS/QueueFactory.cpp +++ b/osal/FreeRTOS/QueueFactory.cpp @@ -1,3 +1,4 @@ +#include "../../ipc/MessageQueueSenderIF.h" #include "../../ipc/QueueFactory.h" #include "MessageQueue.h" @@ -7,8 +8,10 @@ QueueFactory* QueueFactory::factoryInstance = NULL; ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) { - return MessageQueue::sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault); + MessageQueueMessage* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return MessageQueue::sendMessageFromMessageQueue(sendTo, message, + sentFrom, ignoreFault); } QueueFactory* QueueFactory::instance() { From 386f3475741bd07af46a313b78dd77882a697f76 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 18 Sep 2020 13:15:14 +0200 Subject: [PATCH 37/53] renormalized files --- contrib/sgp4/sgp4unit.cpp | 4180 ++++++++++----------- contrib/sgp4/sgp4unit.h | 234 +- globalfunctions/timevalOperations.cpp | 198 +- osal/FreeRTOS/BinSemaphUsingTask.cpp | 190 +- osal/FreeRTOS/BinSemaphUsingTask.h | 152 +- osal/FreeRTOS/BinarySemaphore.cpp | 216 +- osal/FreeRTOS/BinarySemaphore.h | 214 +- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 228 +- osal/FreeRTOS/CountingSemaphUsingTask.h | 204 +- osal/FreeRTOS/CountingSemaphore.cpp | 86 +- osal/FreeRTOS/CountingSemaphore.h | 68 +- osal/FreeRTOS/SemaphoreFactory.cpp | 118 +- osal/FreeRTOS/TaskManagement.cpp | 48 +- osal/FreeRTOS/TaskManagement.h | 128 +- osal/linux/BinarySemaphore.cpp | 298 +- osal/linux/BinarySemaphore.h | 162 +- osal/linux/CountingSemaphore.cpp | 108 +- osal/linux/CountingSemaphore.h | 74 +- osal/linux/SemaphoreFactory.cpp | 66 +- serialize/SerialBufferAdapter.cpp | 258 +- serialize/SerialBufferAdapter.h | 156 +- tasks/SemaphoreFactory.h | 100 +- tasks/SemaphoreIF.h | 136 +- 23 files changed, 3811 insertions(+), 3811 deletions(-) diff --git a/contrib/sgp4/sgp4unit.cpp b/contrib/sgp4/sgp4unit.cpp index 24d63aa9..b707a7a2 100644 --- a/contrib/sgp4/sgp4unit.cpp +++ b/contrib/sgp4/sgp4unit.cpp @@ -1,2090 +1,2090 @@ -/* ---------------------------------------------------------------- -* -* sgp4unit.cpp -* -* this file contains the sgp4 procedures for analytical propagation -* of a satellite. the code was originally released in the 1980 and 1986 -* spacetrack papers. a detailed discussion of the theory and history -* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, -* and kelso. -* -* companion code for -* fundamentals of astrodynamics and applications -* 2007 -* by david vallado -* -* (w) 719-573-2600, email dvallado@agi.com -* -* current : -* 16 nov 07 david vallado -* misc fixes for better compliance -* changes : -* 20 apr 07 david vallado -* misc fixes for constants -* 11 aug 06 david vallado -* chg lyddane choice back to strn3, constants, misc doc -* 15 dec 05 david vallado -* misc fixes -* 26 jul 05 david vallado -* fixes for paper -* note that each fix is preceded by a -* comment with "sgp4fix" and an explanation of -* what was changed -* 10 aug 04 david vallado -* 2nd printing baseline working -* 14 may 01 david vallado -* 2nd edition baseline -* 80 norad -* original baseline -* ---------------------------------------------------------------- */ - -#include "sgp4unit.h" - -const char help = 'n'; -FILE *dbgfile; - -#define pi 3.14159265358979323846 - - -/* ----------- local functions - only ever used internally by sgp4 ---------- */ -static void dpper - ( - double e3, double ee2, double peo, double pgho, double pho, - double pinco, double plo, double se2, double se3, double sgh2, - double sgh3, double sgh4, double sh2, double sh3, double si2, - double si3, double sl2, double sl3, double sl4, double t, - double xgh2, double xgh3, double xgh4, double xh2, double xh3, - double xi2, double xi3, double xl2, double xl3, double xl4, - double zmol, double zmos, double inclo, - char init, - double& ep, double& inclp, double& nodep, double& argpp, double& mp - ); - -static void dscom - ( - double epoch, double ep, double argpp, double tc, double inclp, - double nodep, double np, - double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, - double& cosomm,double& day, double& e3, double& ee2, double& em, - double& emsq, double& gam, double& peo, double& pgho, double& pho, - double& pinco, double& plo, double& rtemsq, double& se2, double& se3, - double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, - double& si2, double& si3, double& sl2, double& sl3, double& sl4, - double& s1, double& s2, double& s3, double& s4, double& s5, - double& s6, double& s7, double& ss1, double& ss2, double& ss3, - double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, - double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, - double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, - double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, - double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, - double& xl4, double& nm, double& z1, double& z2, double& z3, - double& z11, double& z12, double& z13, double& z21, double& z22, - double& z23, double& z31, double& z32, double& z33, double& zmol, - double& zmos - ); - -static void dsinit - ( - gravconsttype whichconst, - double cosim, double emsq, double argpo, double s1, double s2, - double s3, double s4, double s5, double sinim, double ss1, - double ss2, double ss3, double ss4, double ss5, double sz1, - double sz3, double sz11, double sz13, double sz21, double sz23, - double sz31, double sz33, double t, double tc, double gsto, - double mo, double mdot, double no, double nodeo, double nodedot, - double xpidot, double z1, double z3, double z11, double z13, - double z21, double z23, double z31, double z33, double ecco, - double eccsq, double& em, double& argpm, double& inclm, double& mm, - double& nm, double& nodem, - int& irez, - double& atime, double& d2201, double& d2211, double& d3210, double& d3222, - double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, - double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, - double& dnodt, double& domdt, double& del1, double& del2, double& del3, - double& xfact, double& xlamo, double& xli, double& xni - ); - -static void dspace - ( - int irez, - double d2201, double d2211, double d3210, double d3222, double d4410, - double d4422, double d5220, double d5232, double d5421, double d5433, - double dedt, double del1, double del2, double del3, double didt, - double dmdt, double dnodt, double domdt, double argpo, double argpdot, - double t, double tc, double gsto, double xfact, double xlamo, - double no, - double& atime, double& em, double& argpm, double& inclm, double& xli, - double& mm, double& xni, double& nodem, double& dndt, double& nm - ); - -static void initl - ( - int satn, gravconsttype whichconst, - double ecco, double epoch, double inclo, double& no, - char& method, - double& ainv, double& ao, double& con41, double& con42, double& cosio, - double& cosio2,double& eccsq, double& omeosq, double& posq, - double& rp, double& rteosq,double& sinio , double& gsto - ); - -/* ----------------------------------------------------------------------------- -* -* procedure dpper -* -* this procedure provides deep space long period periodic contributions -* to the mean elements. by design, these periodics are zero at epoch. -* this used to be dscom which included initialization, but it's really a -* recurring function. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* e3 - -* ee2 - -* peo - -* pgho - -* pho - -* pinco - -* plo - -* se2 , se3 , sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4 - -* t - -* xh2, xh3, xi2, xi3, xl2, xl3, xl4 - -* zmol - -* zmos - -* ep - eccentricity 0.0 - 1.0 -* inclo - inclination - needed for lyddane modification -* nodep - right ascension of ascending node -* argpp - argument of perigee -* mp - mean anomaly -* -* outputs : -* ep - eccentricity 0.0 - 1.0 -* inclp - inclination -* nodep - right ascension of ascending node -* argpp - argument of perigee -* mp - mean anomaly -* -* locals : -* alfdp - -* betdp - -* cosip , sinip , cosop , sinop , -* dalf - -* dbet - -* dls - -* f2, f3 - -* pe - -* pgh - -* ph - -* pinc - -* pl - -* sel , ses , sghl , sghs , shl , shs , sil , sinzf , sis , -* sll , sls -* xls - -* xnoh - -* zf - -* zm - -* -* coupling : -* none. -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void dpper - ( - double e3, double ee2, double peo, double pgho, double pho, - double pinco, double plo, double se2, double se3, double sgh2, - double sgh3, double sgh4, double sh2, double sh3, double si2, - double si3, double sl2, double sl3, double sl4, double t, - double xgh2, double xgh3, double xgh4, double xh2, double xh3, - double xi2, double xi3, double xl2, double xl3, double xl4, - double zmol, double zmos, double inclo, - char init, - double& ep, double& inclp, double& nodep, double& argpp, double& mp - ) -{ - /* --------------------- local variables ------------------------ */ - const double twopi = 2.0 * pi; - double alfdp, betdp, cosip, cosop, dalf, dbet, dls, - f2, f3, pe, pgh, ph, pinc, pl , - sel, ses, sghl, sghs, shll, shs, sil, - sinip, sinop, sinzf, sis, sll, sls, xls, - xnoh, zf, zm, zel, zes, znl, zns; - - /* ---------------------- constants ----------------------------- */ - zns = 1.19459e-5; - zes = 0.01675; - znl = 1.5835218e-4; - zel = 0.05490; - - /* --------------- calculate time varying periodics ----------- */ - zm = zmos + zns * t; - // be sure that the initial call has time set to zero - if (init == 'y') - zm = zmos; - zf = zm + 2.0 * zes * sin(zm); - sinzf = sin(zf); - f2 = 0.5 * sinzf * sinzf - 0.25; - f3 = -0.5 * sinzf * cos(zf); - ses = se2* f2 + se3 * f3; - sis = si2 * f2 + si3 * f3; - sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf; - sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf; - shs = sh2 * f2 + sh3 * f3; - zm = zmol + znl * t; - if (init == 'y') - zm = zmol; - zf = zm + 2.0 * zel * sin(zm); - sinzf = sin(zf); - f2 = 0.5 * sinzf * sinzf - 0.25; - f3 = -0.5 * sinzf * cos(zf); - sel = ee2 * f2 + e3 * f3; - sil = xi2 * f2 + xi3 * f3; - sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf; - sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf; - shll = xh2 * f2 + xh3 * f3; - pe = ses + sel; - pinc = sis + sil; - pl = sls + sll; - pgh = sghs + sghl; - ph = shs + shll; - - if (init == 'n') - { - pe = pe - peo; - pinc = pinc - pinco; - pl = pl - plo; - pgh = pgh - pgho; - ph = ph - pho; - inclp = inclp + pinc; - ep = ep + pe; - sinip = sin(inclp); - cosip = cos(inclp); - - /* ----------------- apply periodics directly ------------ */ - // sgp4fix for lyddane choice - // strn3 used original inclination - this is technically feasible - // gsfc used perturbed inclination - also technically feasible - // probably best to readjust the 0.2 limit value and limit discontinuity - // 0.2 rad = 11.45916 deg - // use next line for original strn3 approach and original inclination - // if (inclo >= 0.2) - // use next line for gsfc version and perturbed inclination - if (inclp >= 0.2) - { - ph = ph / sinip; - pgh = pgh - cosip * ph; - argpp = argpp + pgh; - nodep = nodep + ph; - mp = mp + pl; - } - else - { - /* ---- apply periodics with lyddane modification ---- */ - sinop = sin(nodep); - cosop = cos(nodep); - alfdp = sinip * sinop; - betdp = sinip * cosop; - dalf = ph * cosop + pinc * cosip * sinop; - dbet = -ph * sinop + pinc * cosip * cosop; - alfdp = alfdp + dalf; - betdp = betdp + dbet; - nodep = fmod(nodep, twopi); - // sgp4fix for afspc written intrinsic functions - // nodep used without a trigonometric function ahead - if (nodep < 0.0) - nodep = nodep + twopi; - xls = mp + argpp + cosip * nodep; - dls = pl + pgh - pinc * nodep * sinip; - xls = xls + dls; - xnoh = nodep; - nodep = atan2(alfdp, betdp); - // sgp4fix for afspc written intrinsic functions - // nodep used without a trigonometric function ahead - if (nodep < 0.0) - nodep = nodep + twopi; - if (fabs(xnoh - nodep) > pi){ - if (nodep < xnoh) - nodep = nodep + twopi; - else - nodep = nodep - twopi; - } - mp = mp + pl; - argpp = xls - mp - cosip * nodep; - } - } // if init == 'n' - -//#include "debug1.cpp" -} // end dpper - -/*----------------------------------------------------------------------------- -* -* procedure dscom -* -* this procedure provides deep space common items used by both the secular -* and periodics subroutines. input is provided as shown. this routine -* used to be called dpper, but the functions inside weren't well organized. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* epoch - -* ep - eccentricity -* argpp - argument of perigee -* tc - -* inclp - inclination -* nodep - right ascension of ascending node -* np - mean motion -* -* outputs : -* sinim , cosim , sinomm , cosomm , snodm , cnodm -* day - -* e3 - -* ee2 - -* em - eccentricity -* emsq - eccentricity squared -* gam - -* peo - -* pgho - -* pho - -* pinco - -* plo - -* rtemsq - -* se2, se3 - -* sgh2, sgh3, sgh4 - -* sh2, sh3, si2, si3, sl2, sl3, sl4 - -* s1, s2, s3, s4, s5, s6, s7 - -* ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3 - -* sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - -* xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4 - -* nm - mean motion -* z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33 - -* zmol - -* zmos - -* -* locals : -* a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 - -* betasq - -* cc - -* ctem, stem - -* x1, x2, x3, x4, x5, x6, x7, x8 - -* xnodce - -* xnoi - -* zcosg , zsing , zcosgl , zsingl , zcosh , zsinh , zcoshl , zsinhl , -* zcosi , zsini , zcosil , zsinil , -* zx - -* zy - -* -* coupling : -* none. -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void dscom - ( - double epoch, double ep, double argpp, double tc, double inclp, - double nodep, double np, - double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, - double& cosomm,double& day, double& e3, double& ee2, double& em, - double& emsq, double& gam, double& peo, double& pgho, double& pho, - double& pinco, double& plo, double& rtemsq, double& se2, double& se3, - double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, - double& si2, double& si3, double& sl2, double& sl3, double& sl4, - double& s1, double& s2, double& s3, double& s4, double& s5, - double& s6, double& s7, double& ss1, double& ss2, double& ss3, - double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, - double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, - double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, - double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, - double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, - double& xl4, double& nm, double& z1, double& z2, double& z3, - double& z11, double& z12, double& z13, double& z21, double& z22, - double& z23, double& z31, double& z32, double& z33, double& zmol, - double& zmos - ) -{ - /* -------------------------- constants ------------------------- */ - const double zes = 0.01675; - const double zel = 0.05490; - const double c1ss = 2.9864797e-6; - const double c1l = 4.7968065e-7; - const double zsinis = 0.39785416; - const double zcosis = 0.91744867; - const double zcosgs = 0.1945905; - const double zsings = -0.98088458; - const double twopi = 2.0 * pi; - - /* --------------------- local variables ------------------------ */ - int lsflg; - double a1 , a2 , a3 , a4 , a5 , a6 , a7 , - a8 , a9 , a10 , betasq, cc , ctem , stem , - x1 , x2 , x3 , x4 , x5 , x6 , x7 , - x8 , xnodce, xnoi , zcosg , zcosgl, zcosh , zcoshl, - zcosi , zcosil, zsing , zsingl, zsinh , zsinhl, zsini , - zsinil, zx , zy; - - nm = np; - em = ep; - snodm = sin(nodep); - cnodm = cos(nodep); - sinomm = sin(argpp); - cosomm = cos(argpp); - sinim = sin(inclp); - cosim = cos(inclp); - emsq = em * em; - betasq = 1.0 - emsq; - rtemsq = sqrt(betasq); - - /* ----------------- initialize lunar solar terms --------------- */ - peo = 0.0; - pinco = 0.0; - plo = 0.0; - pgho = 0.0; - pho = 0.0; - day = epoch + 18261.5 + tc / 1440.0; - xnodce = fmod(4.5236020 - 9.2422029e-4 * day, twopi); - stem = sin(xnodce); - ctem = cos(xnodce); - zcosil = 0.91375164 - 0.03568096 * ctem; - zsinil = sqrt(1.0 - zcosil * zcosil); - zsinhl = 0.089683511 * stem / zsinil; - zcoshl = sqrt(1.0 - zsinhl * zsinhl); - gam = 5.8351514 + 0.0019443680 * day; - zx = 0.39785416 * stem / zsinil; - zy = zcoshl * ctem + 0.91744867 * zsinhl * stem; - zx = atan2(zx, zy); - zx = gam + zx - xnodce; - zcosgl = cos(zx); - zsingl = sin(zx); - - /* ------------------------- do solar terms --------------------- */ - zcosg = zcosgs; - zsing = zsings; - zcosi = zcosis; - zsini = zsinis; - zcosh = cnodm; - zsinh = snodm; - cc = c1ss; - xnoi = 1.0 / nm; - - for (lsflg = 1; lsflg <= 2; lsflg++) - { - a1 = zcosg * zcosh + zsing * zcosi * zsinh; - a3 = -zsing * zcosh + zcosg * zcosi * zsinh; - a7 = -zcosg * zsinh + zsing * zcosi * zcosh; - a8 = zsing * zsini; - a9 = zsing * zsinh + zcosg * zcosi * zcosh; - a10 = zcosg * zsini; - a2 = cosim * a7 + sinim * a8; - a4 = cosim * a9 + sinim * a10; - a5 = -sinim * a7 + cosim * a8; - a6 = -sinim * a9 + cosim * a10; - - x1 = a1 * cosomm + a2 * sinomm; - x2 = a3 * cosomm + a4 * sinomm; - x3 = -a1 * sinomm + a2 * cosomm; - x4 = -a3 * sinomm + a4 * cosomm; - x5 = a5 * sinomm; - x6 = a6 * sinomm; - x7 = a5 * cosomm; - x8 = a6 * cosomm; - - z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3; - z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4; - z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4; - z1 = 3.0 * (a1 * a1 + a2 * a2) + z31 * emsq; - z2 = 6.0 * (a1 * a3 + a2 * a4) + z32 * emsq; - z3 = 3.0 * (a3 * a3 + a4 * a4) + z33 * emsq; - z11 = -6.0 * a1 * a5 + emsq * (-24.0 * x1 * x7-6.0 * x3 * x5); - z12 = -6.0 * (a1 * a6 + a3 * a5) + emsq * - (-24.0 * (x2 * x7 + x1 * x8) - 6.0 * (x3 * x6 + x4 * x5)); - z13 = -6.0 * a3 * a6 + emsq * (-24.0 * x2 * x8 - 6.0 * x4 * x6); - z21 = 6.0 * a2 * a5 + emsq * (24.0 * x1 * x5 - 6.0 * x3 * x7); - z22 = 6.0 * (a4 * a5 + a2 * a6) + emsq * - (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8)); - z23 = 6.0 * a4 * a6 + emsq * (24.0 * x2 * x6 - 6.0 * x4 * x8); - z1 = z1 + z1 + betasq * z31; - z2 = z2 + z2 + betasq * z32; - z3 = z3 + z3 + betasq * z33; - s3 = cc * xnoi; - s2 = -0.5 * s3 / rtemsq; - s4 = s3 * rtemsq; - s1 = -15.0 * em * s4; - s5 = x1 * x3 + x2 * x4; - s6 = x2 * x3 + x1 * x4; - s7 = x2 * x4 - x1 * x3; - - /* ----------------------- do lunar terms ------------------- */ - if (lsflg == 1) - { - ss1 = s1; - ss2 = s2; - ss3 = s3; - ss4 = s4; - ss5 = s5; - ss6 = s6; - ss7 = s7; - sz1 = z1; - sz2 = z2; - sz3 = z3; - sz11 = z11; - sz12 = z12; - sz13 = z13; - sz21 = z21; - sz22 = z22; - sz23 = z23; - sz31 = z31; - sz32 = z32; - sz33 = z33; - zcosg = zcosgl; - zsing = zsingl; - zcosi = zcosil; - zsini = zsinil; - zcosh = zcoshl * cnodm + zsinhl * snodm; - zsinh = snodm * zcoshl - cnodm * zsinhl; - cc = c1l; - } - } - - zmol = fmod(4.7199672 + 0.22997150 * day - gam, twopi); - zmos = fmod(6.2565837 + 0.017201977 * day, twopi); - - /* ------------------------ do solar terms ---------------------- */ - se2 = 2.0 * ss1 * ss6; - se3 = 2.0 * ss1 * ss7; - si2 = 2.0 * ss2 * sz12; - si3 = 2.0 * ss2 * (sz13 - sz11); - sl2 = -2.0 * ss3 * sz2; - sl3 = -2.0 * ss3 * (sz3 - sz1); - sl4 = -2.0 * ss3 * (-21.0 - 9.0 * emsq) * zes; - sgh2 = 2.0 * ss4 * sz32; - sgh3 = 2.0 * ss4 * (sz33 - sz31); - sgh4 = -18.0 * ss4 * zes; - sh2 = -2.0 * ss2 * sz22; - sh3 = -2.0 * ss2 * (sz23 - sz21); - - /* ------------------------ do lunar terms ---------------------- */ - ee2 = 2.0 * s1 * s6; - e3 = 2.0 * s1 * s7; - xi2 = 2.0 * s2 * z12; - xi3 = 2.0 * s2 * (z13 - z11); - xl2 = -2.0 * s3 * z2; - xl3 = -2.0 * s3 * (z3 - z1); - xl4 = -2.0 * s3 * (-21.0 - 9.0 * emsq) * zel; - xgh2 = 2.0 * s4 * z32; - xgh3 = 2.0 * s4 * (z33 - z31); - xgh4 = -18.0 * s4 * zel; - xh2 = -2.0 * s2 * z22; - xh3 = -2.0 * s2 * (z23 - z21); - -//#include "debug2.cpp" -} // end dscom - -/*----------------------------------------------------------------------------- -* -* procedure dsinit -* -* this procedure provides deep space contributions to mean motion dot due -* to geopotential resonance with half day and one day orbits. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* cosim, sinim- -* emsq - eccentricity squared -* argpo - argument of perigee -* s1, s2, s3, s4, s5 - -* ss1, ss2, ss3, ss4, ss5 - -* sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33 - -* t - time -* tc - -* gsto - greenwich sidereal time rad -* mo - mean anomaly -* mdot - mean anomaly dot (rate) -* no - mean motion -* nodeo - right ascension of ascending node -* nodedot - right ascension of ascending node dot (rate) -* xpidot - -* z1, z3, z11, z13, z21, z23, z31, z33 - -* eccm - eccentricity -* argpm - argument of perigee -* inclm - inclination -* mm - mean anomaly -* xn - mean motion -* nodem - right ascension of ascending node -* -* outputs : -* em - eccentricity -* argpm - argument of perigee -* inclm - inclination -* mm - mean anomaly -* nm - mean motion -* nodem - right ascension of ascending node -* irez - flag for resonance 0-none, 1-one day, 2-half day -* atime - -* d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - -* dedt - -* didt - -* dmdt - -* dndt - -* dnodt - -* domdt - -* del1, del2, del3 - -* ses , sghl , sghs , sgs , shl , shs , sis , sls -* theta - -* xfact - -* xlamo - -* xli - -* xni -* -* locals : -* ainv2 - -* aonv - -* cosisq - -* eoc - -* f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543 - -* g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533 - -* sini2 - -* temp - -* temp1 - -* theta - -* xno2 - -* -* coupling : -* getgravconst -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void dsinit - ( - gravconsttype whichconst, - double cosim, double emsq, double argpo, double s1, double s2, - double s3, double s4, double s5, double sinim, double ss1, - double ss2, double ss3, double ss4, double ss5, double sz1, - double sz3, double sz11, double sz13, double sz21, double sz23, - double sz31, double sz33, double t, double tc, double gsto, - double mo, double mdot, double no, double nodeo, double nodedot, - double xpidot, double z1, double z3, double z11, double z13, - double z21, double z23, double z31, double z33, double ecco, - double eccsq, double& em, double& argpm, double& inclm, double& mm, - double& nm, double& nodem, - int& irez, - double& atime, double& d2201, double& d2211, double& d3210, double& d3222, - double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, - double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, - double& dnodt, double& domdt, double& del1, double& del2, double& del3, - double& xfact, double& xlamo, double& xli, double& xni - ) -{ - /* --------------------- local variables ------------------------ */ - const double twopi = 2.0 * pi; - - double ainv2 , aonv=0.0, cosisq, eoc, f220 , f221 , f311 , - f321 , f322 , f330 , f441 , f442 , f522 , f523 , - f542 , f543 , g200 , g201 , g211 , g300 , g310 , - g322 , g410 , g422 , g520 , g521 , g532 , g533 , - ses , sgs , sghl , sghs , shs , shll , sis , - sini2 , sls , temp , temp1 , theta , xno2 , q22 , - q31 , q33 , root22, root44, root54, rptim , root32, - root52, x2o3 , xke , znl , emo , zns , emsqo, - tumin, mu, radiusearthkm, j2, j3, j4, j3oj2; - - q22 = 1.7891679e-6; - q31 = 2.1460748e-6; - q33 = 2.2123015e-7; - root22 = 1.7891679e-6; - root44 = 7.3636953e-9; - root54 = 2.1765803e-9; - rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec - root32 = 3.7393792e-7; - root52 = 1.1428639e-7; - x2o3 = 2.0 / 3.0; - znl = 1.5835218e-4; - zns = 1.19459e-5; - - // sgp4fix identify constants and allow alternate values - getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); - - /* -------------------- deep space initialization ------------ */ - irez = 0; - if ((nm < 0.0052359877) && (nm > 0.0034906585)) - irez = 1; - if ((nm >= 8.26e-3) && (nm <= 9.24e-3) && (em >= 0.5)) - irez = 2; - - /* ------------------------ do solar terms ------------------- */ - ses = ss1 * zns * ss5; - sis = ss2 * zns * (sz11 + sz13); - sls = -zns * ss3 * (sz1 + sz3 - 14.0 - 6.0 * emsq); - sghs = ss4 * zns * (sz31 + sz33 - 6.0); - shs = -zns * ss2 * (sz21 + sz23); - // sgp4fix for 180 deg incl - if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) - shs = 0.0; - if (sinim != 0.0) - shs = shs / sinim; - sgs = sghs - cosim * shs; - - /* ------------------------- do lunar terms ------------------ */ - dedt = ses + s1 * znl * s5; - didt = sis + s2 * znl * (z11 + z13); - dmdt = sls - znl * s3 * (z1 + z3 - 14.0 - 6.0 * emsq); - sghl = s4 * znl * (z31 + z33 - 6.0); - shll = -znl * s2 * (z21 + z23); - // sgp4fix for 180 deg incl - if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) - shll = 0.0; - domdt = sgs + sghl; - dnodt = shs; - if (sinim != 0.0) - { - domdt = domdt - cosim / sinim * shll; - dnodt = dnodt + shll / sinim; - } - - /* ----------- calculate deep space resonance effects -------- */ - dndt = 0.0; - theta = fmod(gsto + tc * rptim, twopi); - em = em + dedt * t; - inclm = inclm + didt * t; - argpm = argpm + domdt * t; - nodem = nodem + dnodt * t; - mm = mm + dmdt * t; - // sgp4fix for negative inclinations - // the following if statement should be commented out - //if (inclm < 0.0) - // { - // inclm = -inclm; - // argpm = argpm - pi; - // nodem = nodem + pi; - // } - - /* -------------- initialize the resonance terms ------------- */ - if (irez != 0) - { - aonv = pow(nm / xke, x2o3); - - /* ---------- geopotential resonance for 12 hour orbits ------ */ - if (irez == 2) - { - cosisq = cosim * cosim; - emo = em; - em = ecco; - emsqo = emsq; - emsq = eccsq; - eoc = em * emsq; - g201 = -0.306 - (em - 0.64) * 0.440; - - if (em <= 0.65) - { - g211 = 3.616 - 13.2470 * em + 16.2900 * emsq; - g310 = -19.302 + 117.3900 * em - 228.4190 * emsq + 156.5910 * eoc; - g322 = -18.9068 + 109.7927 * em - 214.6334 * emsq + 146.5816 * eoc; - g410 = -41.122 + 242.6940 * em - 471.0940 * emsq + 313.9530 * eoc; - g422 = -146.407 + 841.8800 * em - 1629.014 * emsq + 1083.4350 * eoc; - g520 = -532.114 + 3017.977 * em - 5740.032 * emsq + 3708.2760 * eoc; - } - else - { - g211 = -72.099 + 331.819 * em - 508.738 * emsq + 266.724 * eoc; - g310 = -346.844 + 1582.851 * em - 2415.925 * emsq + 1246.113 * eoc; - g322 = -342.585 + 1554.908 * em - 2366.899 * emsq + 1215.972 * eoc; - g410 = -1052.797 + 4758.686 * em - 7193.992 * emsq + 3651.957 * eoc; - g422 = -3581.690 + 16178.110 * em - 24462.770 * emsq + 12422.520 * eoc; - if (em > 0.715) - g520 =-5149.66 + 29936.92 * em - 54087.36 * emsq + 31324.56 * eoc; - else - g520 = 1464.74 - 4664.75 * em + 3763.64 * emsq; - } - if (em < 0.7) - { - g533 = -919.22770 + 4988.6100 * em - 9064.7700 * emsq + 5542.21 * eoc; - g521 = -822.71072 + 4568.6173 * em - 8491.4146 * emsq + 5337.524 * eoc; - g532 = -853.66600 + 4690.2500 * em - 8624.7700 * emsq + 5341.4 * eoc; - } - else - { - g533 =-37995.780 + 161616.52 * em - 229838.20 * emsq + 109377.94 * eoc; - g521 =-51752.104 + 218913.95 * em - 309468.16 * emsq + 146349.42 * eoc; - g532 =-40023.880 + 170470.89 * em - 242699.48 * emsq + 115605.82 * eoc; - } - - sini2= sinim * sinim; - f220 = 0.75 * (1.0 + 2.0 * cosim+cosisq); - f221 = 1.5 * sini2; - f321 = 1.875 * sinim * (1.0 - 2.0 * cosim - 3.0 * cosisq); - f322 = -1.875 * sinim * (1.0 + 2.0 * cosim - 3.0 * cosisq); - f441 = 35.0 * sini2 * f220; - f442 = 39.3750 * sini2 * sini2; - f522 = 9.84375 * sinim * (sini2 * (1.0 - 2.0 * cosim- 5.0 * cosisq) + - 0.33333333 * (-2.0 + 4.0 * cosim + 6.0 * cosisq) ); - f523 = sinim * (4.92187512 * sini2 * (-2.0 - 4.0 * cosim + - 10.0 * cosisq) + 6.56250012 * (1.0+2.0 * cosim - 3.0 * cosisq)); - f542 = 29.53125 * sinim * (2.0 - 8.0 * cosim+cosisq * - (-12.0 + 8.0 * cosim + 10.0 * cosisq)); - f543 = 29.53125 * sinim * (-2.0 - 8.0 * cosim+cosisq * - (12.0 + 8.0 * cosim - 10.0 * cosisq)); - xno2 = nm * nm; - ainv2 = aonv * aonv; - temp1 = 3.0 * xno2 * ainv2; - temp = temp1 * root22; - d2201 = temp * f220 * g201; - d2211 = temp * f221 * g211; - temp1 = temp1 * aonv; - temp = temp1 * root32; - d3210 = temp * f321 * g310; - d3222 = temp * f322 * g322; - temp1 = temp1 * aonv; - temp = 2.0 * temp1 * root44; - d4410 = temp * f441 * g410; - d4422 = temp * f442 * g422; - temp1 = temp1 * aonv; - temp = temp1 * root52; - d5220 = temp * f522 * g520; - d5232 = temp * f523 * g532; - temp = 2.0 * temp1 * root54; - d5421 = temp * f542 * g521; - d5433 = temp * f543 * g533; - xlamo = fmod(mo + nodeo + nodeo-theta - theta, twopi); - xfact = mdot + dmdt + 2.0 * (nodedot + dnodt - rptim) - no; - em = emo; - emsq = emsqo; - } - - /* ---------------- synchronous resonance terms -------------- */ - if (irez == 1) - { - g200 = 1.0 + emsq * (-2.5 + 0.8125 * emsq); - g310 = 1.0 + 2.0 * emsq; - g300 = 1.0 + emsq * (-6.0 + 6.60937 * emsq); - f220 = 0.75 * (1.0 + cosim) * (1.0 + cosim); - f311 = 0.9375 * sinim * sinim * (1.0 + 3.0 * cosim) - 0.75 * (1.0 + cosim); - f330 = 1.0 + cosim; - f330 = 1.875 * f330 * f330 * f330; - del1 = 3.0 * nm * nm * aonv * aonv; - del2 = 2.0 * del1 * f220 * g200 * q22; - del3 = 3.0 * del1 * f330 * g300 * q33 * aonv; - del1 = del1 * f311 * g310 * q31 * aonv; - xlamo = fmod(mo + nodeo + argpo - theta, twopi); - xfact = mdot + xpidot - rptim + dmdt + domdt + dnodt - no; - } - - /* ------------ for sgp4, initialize the integrator ---------- */ - xli = xlamo; - xni = no; - atime = 0.0; - nm = no + dndt; - } - -//#include "debug3.cpp" -} // end dsinit - -/*----------------------------------------------------------------------------- -* -* procedure dspace -* -* this procedure provides deep space contributions to mean elements for -* perturbing third body. these effects have been averaged over one -* revolution of the sun and moon. for earth resonance effects, the -* effects have been averaged over no revolutions of the satellite. -* (mean motion) -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - -* dedt - -* del1, del2, del3 - -* didt - -* dmdt - -* dnodt - -* domdt - -* irez - flag for resonance 0-none, 1-one day, 2-half day -* argpo - argument of perigee -* argpdot - argument of perigee dot (rate) -* t - time -* tc - -* gsto - gst -* xfact - -* xlamo - -* no - mean motion -* atime - -* em - eccentricity -* ft - -* argpm - argument of perigee -* inclm - inclination -* xli - -* mm - mean anomaly -* xni - mean motion -* nodem - right ascension of ascending node -* -* outputs : -* atime - -* em - eccentricity -* argpm - argument of perigee -* inclm - inclination -* xli - -* mm - mean anomaly -* xni - -* nodem - right ascension of ascending node -* dndt - -* nm - mean motion -* -* locals : -* delt - -* ft - -* theta - -* x2li - -* x2omi - -* xl - -* xldot - -* xnddt - -* xndt - -* xomi - -* -* coupling : -* none - -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void dspace - ( - int irez, - double d2201, double d2211, double d3210, double d3222, double d4410, - double d4422, double d5220, double d5232, double d5421, double d5433, - double dedt, double del1, double del2, double del3, double didt, - double dmdt, double dnodt, double domdt, double argpo, double argpdot, - double t, double tc, double gsto, double xfact, double xlamo, - double no, - double& atime, double& em, double& argpm, double& inclm, double& xli, - double& mm, double& xni, double& nodem, double& dndt, double& nm - ) -{ - const double twopi = 2.0 * pi; - int iretn , iret; - double delt, ft, theta, x2li, x2omi, xl, xldot , xnddt, xndt, xomi, g22, g32, - g44, g52, g54, fasx2, fasx4, fasx6, rptim , step2, stepn , stepp; - - ft = 0.0; - fasx2 = 0.13130908; - fasx4 = 2.8843198; - fasx6 = 0.37448087; - g22 = 5.7686396; - g32 = 0.95240898; - g44 = 1.8014998; - g52 = 1.0508330; - g54 = 4.4108898; - rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec - stepp = 720.0; - stepn = -720.0; - step2 = 259200.0; - - /* ----------- calculate deep space resonance effects ----------- */ - dndt = 0.0; - theta = fmod(gsto + tc * rptim, twopi); - em = em + dedt * t; - - inclm = inclm + didt * t; - argpm = argpm + domdt * t; - nodem = nodem + dnodt * t; - mm = mm + dmdt * t; - - // sgp4fix for negative inclinations - // the following if statement should be commented out - // if (inclm < 0.0) - // { - // inclm = -inclm; - // argpm = argpm - pi; - // nodem = nodem + pi; - // } - - /* - update resonances : numerical (euler-maclaurin) integration - */ - /* ------------------------- epoch restart ---------------------- */ - // sgp4fix for propagator problems - // the following integration works for negative time steps and periods - // the specific changes are unknown because the original code was so convoluted - - ft = 0.0; - atime = 0.0; - if (irez != 0) - { - if ((atime == 0.0) || ((t >= 0.0) && (atime < 0.0)) || - ((t < 0.0) && (atime >= 0.0))) - { - if (t >= 0.0) - delt = stepp; - else - delt = stepn; - atime = 0.0; - xni = no; - xli = xlamo; - } - iretn = 381; // added for do loop - iret = 0; // added for loop - while (iretn == 381) - { - if ((fabs(t) < fabs(atime)) || (iret == 351)) - { - if (t >= 0.0) - delt = stepn; - else - delt = stepp; - iret = 351; - iretn = 381; - } - else - { - if (t > 0.0) // error if prev if has atime:=0.0 and t:=0.0 (ge) - delt = stepp; - else - delt = stepn; - if (fabs(t - atime) >= stepp) - { - iret = 0; - iretn = 381; - } - else - { - ft = t - atime; - iretn = 0; - } - } - - /* ------------------- dot terms calculated ------------- */ - /* ----------- near - synchronous resonance terms ------- */ - if (irez != 2) - { - xndt = del1 * sin(xli - fasx2) + del2 * sin(2.0 * (xli - fasx4)) + - del3 * sin(3.0 * (xli - fasx6)); - xldot = xni + xfact; - xnddt = del1 * cos(xli - fasx2) + - 2.0 * del2 * cos(2.0 * (xli - fasx4)) + - 3.0 * del3 * cos(3.0 * (xli - fasx6)); - xnddt = xnddt * xldot; - } - else - { - /* --------- near - half-day resonance terms -------- */ - xomi = argpo + argpdot * atime; - x2omi = xomi + xomi; - x2li = xli + xli; - xndt = d2201 * sin(x2omi + xli - g22) + d2211 * sin(xli - g22) + - d3210 * sin(xomi + xli - g32) + d3222 * sin(-xomi + xli - g32)+ - d4410 * sin(x2omi + x2li - g44)+ d4422 * sin(x2li - g44) + - d5220 * sin(xomi + xli - g52) + d5232 * sin(-xomi + xli - g52)+ - d5421 * sin(xomi + x2li - g54) + d5433 * sin(-xomi + x2li - g54); - xldot = xni + xfact; - xnddt = d2201 * cos(x2omi + xli - g22) + d2211 * cos(xli - g22) + - d3210 * cos(xomi + xli - g32) + d3222 * cos(-xomi + xli - g32) + - d5220 * cos(xomi + xli - g52) + d5232 * cos(-xomi + xli - g52) + - 2.0 * (d4410 * cos(x2omi + x2li - g44) + - d4422 * cos(x2li - g44) + d5421 * cos(xomi + x2li - g54) + - d5433 * cos(-xomi + x2li - g54)); - xnddt = xnddt * xldot; - } - - /* ----------------------- integrator ------------------- */ - if (iretn == 381) - { - xli = xli + xldot * delt + xndt * step2; - xni = xni + xndt * delt + xnddt * step2; - atime = atime + delt; - } - } // while iretn = 381 - - nm = xni + xndt * ft + xnddt * ft * ft * 0.5; - xl = xli + xldot * ft + xndt * ft * ft * 0.5; - if (irez != 1) - { - mm = xl - 2.0 * nodem + 2.0 * theta; - dndt = nm - no; - } - else - { - mm = xl - nodem - argpm + theta; - dndt = nm - no; - } - nm = no + dndt; - } - -//#include "debug4.cpp" -} // end dsspace - -/*----------------------------------------------------------------------------- -* -* procedure initl -* -* this procedure initializes the spg4 propagator. all the initialization is -* consolidated here instead of having multiple loops inside other routines. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* ecco - eccentricity 0.0 - 1.0 -* epoch - epoch time in days from jan 0, 1950. 0 hr -* inclo - inclination of satellite -* no - mean motion of satellite -* satn - satellite number -* -* outputs : -* ainv - 1.0 / a -* ao - semi major axis -* con41 - -* con42 - 1.0 - 5.0 cos(i) -* cosio - cosine of inclination -* cosio2 - cosio squared -* eccsq - eccentricity squared -* method - flag for deep space 'd', 'n' -* omeosq - 1.0 - ecco * ecco -* posq - semi-parameter squared -* rp - radius of perigee -* rteosq - square root of (1.0 - ecco*ecco) -* sinio - sine of inclination -* gsto - gst at time of observation rad -* no - mean motion of satellite -* -* locals : -* ak - -* d1 - -* del - -* adel - -* po - -* -* coupling : -* getgravconst -* gstime - find greenwich sidereal time from the julian date -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void initl - ( - int satn, gravconsttype whichconst, - double ecco, double epoch, double inclo, double& no, - char& method, - double& ainv, double& ao, double& con41, double& con42, double& cosio, - double& cosio2,double& eccsq, double& omeosq, double& posq, - double& rp, double& rteosq,double& sinio , double& gsto - ) -{ - /* --------------------- local variables ------------------------ */ - double ak, d1, del, adel, po, x2o3, j2, xke, - tumin, mu, radiusearthkm, j3, j4, j3oj2; - - // sgp4fix use old way of finding gst - int ids70; - double ts70, ds70, tfrac, c1, thgr70, fk5r, c1p2p; - const double twopi = 2.0 * pi; - - /* ----------------------- earth constants ---------------------- */ - // sgp4fix identify constants and allow alternate values - getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); - x2o3 = 2.0 / 3.0; - - /* ------------- calculate auxillary epoch quantities ---------- */ - eccsq = ecco * ecco; - omeosq = 1.0 - eccsq; - rteosq = sqrt(omeosq); - cosio = cos(inclo); - cosio2 = cosio * cosio; - - /* ------------------ un-kozai the mean motion ----------------- */ - ak = pow(xke / no, x2o3); - d1 = 0.75 * j2 * (3.0 * cosio2 - 1.0) / (rteosq * omeosq); - del = d1 / (ak * ak); - adel = ak * (1.0 - del * del - del * - (1.0 / 3.0 + 134.0 * del * del / 81.0)); - del = d1/(adel * adel); - no = no / (1.0 + del); - - ao = pow(xke / no, x2o3); - sinio = sin(inclo); - po = ao * omeosq; - con42 = 1.0 - 5.0 * cosio2; - con41 = -con42-cosio2-cosio2; - ainv = 1.0 / ao; - posq = po * po; - rp = ao * (1.0 - ecco); - method = 'n'; - - // sgp4fix modern approach to finding sidereal timew - // gsto = gstime(epoch + 2433281.5); - - // sgp4fix use old way of finding gst - // count integer number of days from 0 jan 1970 - ts70 = epoch - 7305.0; - ids70 = floor(ts70 + 1.0e-8); - ds70 = ids70; - tfrac = ts70 - ds70; - // find greenwich location at epoch - c1 = 1.72027916940703639e-2; - thgr70= 1.7321343856509374; - fk5r = 5.07551419432269442e-15; - c1p2p = c1 + twopi; - gsto = fmod( thgr70 + c1*ds70 + c1p2p*tfrac + ts70*ts70*fk5r, twopi); - if ( gsto < 0.0 ) - gsto = gsto + twopi; - -//#include "debug5.cpp" -} // end initl - -/*----------------------------------------------------------------------------- -* -* procedure sgp4init -* -* this procedure initializes variables for sgp4. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* satn - satellite number -* bstar - sgp4 type drag coefficient kg/m2er -* ecco - eccentricity -* epoch - epoch time in days from jan 0, 1950. 0 hr -* argpo - argument of perigee (output if ds) -* inclo - inclination -* mo - mean anomaly (output if ds) -* no - mean motion -* nodeo - right ascension of ascending node -* -* outputs : -* satrec - common values for subsequent calls -* return code - non-zero on error. -* 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er -* 2 - mean motion less than 0.0 -* 3 - pert elements, ecc < 0.0 or ecc > 1.0 -* 4 - semi-latus rectum < 0.0 -* 5 - epoch elements are sub-orbital -* 6 - satellite has decayed -* -* locals : -* cnodm , snodm , cosim , sinim , cosomm , sinomm -* cc1sq , cc2 , cc3 -* coef , coef1 -* cosio4 - -* day - -* dndt - -* em - eccentricity -* emsq - eccentricity squared -* eeta - -* etasq - -* gam - -* argpm - argument of perigee -* nodem - -* inclm - inclination -* mm - mean anomaly -* nm - mean motion -* perige - perigee -* pinvsq - -* psisq - -* qzms24 - -* rtemsq - -* s1, s2, s3, s4, s5, s6, s7 - -* sfour - -* ss1, ss2, ss3, ss4, ss5, ss6, ss7 - -* sz1, sz2, sz3 -* sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - -* tc - -* temp - -* temp1, temp2, temp3 - -* tsi - -* xpidot - -* xhdot1 - -* z1, z2, z3 - -* z11, z12, z13, z21, z22, z23, z31, z32, z33 - -* -* coupling : -* getgravconst- -* initl - -* dscom - -* dpper - -* dsinit - -* sgp4 - -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -int sgp4init - ( - gravconsttype whichconst, const int satn, const double epoch, - const double xbstar, const double xecco, const double xargpo, - const double xinclo, const double xmo, const double xno, - const double xnodeo, elsetrec& satrec - ) -{ - /* --------------------- local variables ------------------------ */ - double ao, ainv, con42, cosio, sinio, cosio2, eccsq, - omeosq, posq, rp, rteosq, - cnodm , snodm , cosim , sinim , cosomm, sinomm, cc1sq , - cc2 , cc3 , coef , coef1 , cosio4, day , dndt , - em , emsq , eeta , etasq , gam , argpm , nodem , - inclm , mm , nm , perige, pinvsq, psisq , qzms24, - rtemsq, s1 , s2 , s3 , s4 , s5 , s6 , - s7 , sfour , ss1 = 0 , ss2 = 0 , ss3 = 0 , ss4 = 0 , ss5 = 0 , - ss6 = 0 , ss7 = 0 , sz1 = 0 , sz2 = 0 , sz3 = 0 , sz11 = 0 , sz12 = 0 , - sz13 = 0 , sz21 = 0 , sz22 = 0 , sz23 = 0 , sz31 = 0 , sz32 = 0 , sz33 = 0 , - tc , temp , temp1 , temp2 , temp3 , tsi , xpidot, - xhdot1, z1 , z2 , z3 , z11 , z12 , z13 , - z21 , z22 , z23 , z31 , z32 , z33, - qzms2t, ss, j2, j3oj2, j4, x2o3, r[3], v[3], - tumin, mu, radiusearthkm, xke, j3; - - /* ------------------------ initialization --------------------- */ - // sgp4fix divisor for divide by zero check on inclination - const double temp4 = 1.0 + cos(pi-1.0e-9); - - /* ----------- set all near earth variables to zero ------------ */ - satrec.isimp = 0; satrec.method = 'n'; satrec.aycof = 0.0; - satrec.con41 = 0.0; satrec.cc1 = 0.0; satrec.cc4 = 0.0; - satrec.cc5 = 0.0; satrec.d2 = 0.0; satrec.d3 = 0.0; - satrec.d4 = 0.0; satrec.delmo = 0.0; satrec.eta = 0.0; - satrec.argpdot = 0.0; satrec.omgcof = 0.0; satrec.sinmao = 0.0; - satrec.t = 0.0; satrec.t2cof = 0.0; satrec.t3cof = 0.0; - satrec.t4cof = 0.0; satrec.t5cof = 0.0; satrec.x1mth2 = 0.0; - satrec.x7thm1 = 0.0; satrec.mdot = 0.0; satrec.nodedot = 0.0; - satrec.xlcof = 0.0; satrec.xmcof = 0.0; satrec.nodecf = 0.0; - - /* ----------- set all deep space variables to zero ------------ */ - satrec.irez = 0; satrec.d2201 = 0.0; satrec.d2211 = 0.0; - satrec.d3210 = 0.0; satrec.d3222 = 0.0; satrec.d4410 = 0.0; - satrec.d4422 = 0.0; satrec.d5220 = 0.0; satrec.d5232 = 0.0; - satrec.d5421 = 0.0; satrec.d5433 = 0.0; satrec.dedt = 0.0; - satrec.del1 = 0.0; satrec.del2 = 0.0; satrec.del3 = 0.0; - satrec.didt = 0.0; satrec.dmdt = 0.0; satrec.dnodt = 0.0; - satrec.domdt = 0.0; satrec.e3 = 0.0; satrec.ee2 = 0.0; - satrec.peo = 0.0; satrec.pgho = 0.0; satrec.pho = 0.0; - satrec.pinco = 0.0; satrec.plo = 0.0; satrec.se2 = 0.0; - satrec.se3 = 0.0; satrec.sgh2 = 0.0; satrec.sgh3 = 0.0; - satrec.sgh4 = 0.0; satrec.sh2 = 0.0; satrec.sh3 = 0.0; - satrec.si2 = 0.0; satrec.si3 = 0.0; satrec.sl2 = 0.0; - satrec.sl3 = 0.0; satrec.sl4 = 0.0; satrec.gsto = 0.0; - satrec.xfact = 0.0; satrec.xgh2 = 0.0; satrec.xgh3 = 0.0; - satrec.xgh4 = 0.0; satrec.xh2 = 0.0; satrec.xh3 = 0.0; - satrec.xi2 = 0.0; satrec.xi3 = 0.0; satrec.xl2 = 0.0; - satrec.xl3 = 0.0; satrec.xl4 = 0.0; satrec.xlamo = 0.0; - satrec.zmol = 0.0; satrec.zmos = 0.0; satrec.atime = 0.0; - satrec.xli = 0.0; satrec.xni = 0.0; - - // sgp4fix - note the following variables are also passed directly via satrec. - // it is possible to streamline the sgp4init call by deleting the "x" - // variables, but the user would need to set the satrec.* values first. we - // include the additional assignments in case twoline2rv is not used. - satrec.bstar = xbstar; - satrec.ecco = xecco; - satrec.argpo = xargpo; - satrec.inclo = xinclo; - satrec.mo = xmo; - satrec.no = xno; - satrec.nodeo = xnodeo; - - /* ------------------------ earth constants ----------------------- */ - // sgp4fix identify constants and allow alternate values - getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); - ss = 78.0 / radiusearthkm + 1.0; - qzms2t = pow(((120.0 - 78.0) / radiusearthkm), 4); - x2o3 = 2.0 / 3.0; - - satrec.init = 'y'; - satrec.t = 0.0; - - initl - ( - satn, whichconst, satrec.ecco, epoch, satrec.inclo, satrec.no, satrec.method, - ainv, ao, satrec.con41, con42, cosio, cosio2, eccsq, omeosq, - posq, rp, rteosq, sinio, satrec.gsto - ); - satrec.error = 0; - - if (rp < 1.0) - { -// printf("# *** satn%d epoch elts sub-orbital ***\n", satn); - satrec.error = 5; - } - - if ((omeosq >= 0.0 ) || ( satrec.no >= 0.0)) - { - satrec.isimp = 0; - if (rp < (220.0 / radiusearthkm + 1.0)) - satrec.isimp = 1; - sfour = ss; - qzms24 = qzms2t; - perige = (rp - 1.0) * radiusearthkm; - - /* - for perigees below 156 km, s and qoms2t are altered - */ - if (perige < 156.0) - { - sfour = perige - 78.0; - if (perige < 98.0) - sfour = 20.0; - qzms24 = pow(((120.0 - sfour) / radiusearthkm), 4.0); - sfour = sfour / radiusearthkm + 1.0; - } - pinvsq = 1.0 / posq; - - tsi = 1.0 / (ao - sfour); - satrec.eta = ao * satrec.ecco * tsi; - etasq = satrec.eta * satrec.eta; - eeta = satrec.ecco * satrec.eta; - psisq = fabs(1.0 - etasq); - coef = qzms24 * pow(tsi, 4.0); - coef1 = coef / pow(psisq, 3.5); - cc2 = coef1 * satrec.no * (ao * (1.0 + 1.5 * etasq + eeta * - (4.0 + etasq)) + 0.375 * j2 * tsi / psisq * satrec.con41 * - (8.0 + 3.0 * etasq * (8.0 + etasq))); - satrec.cc1 = satrec.bstar * cc2; - cc3 = 0.0; - if (satrec.ecco > 1.0e-4) - cc3 = -2.0 * coef * tsi * j3oj2 * satrec.no * sinio / satrec.ecco; - satrec.x1mth2 = 1.0 - cosio2; - satrec.cc4 = 2.0* satrec.no * coef1 * ao * omeosq * - (satrec.eta * (2.0 + 0.5 * etasq) + satrec.ecco * - (0.5 + 2.0 * etasq) - j2 * tsi / (ao * psisq) * - (-3.0 * satrec.con41 * (1.0 - 2.0 * eeta + etasq * - (1.5 - 0.5 * eeta)) + 0.75 * satrec.x1mth2 * - (2.0 * etasq - eeta * (1.0 + etasq)) * cos(2.0 * satrec.argpo))); - satrec.cc5 = 2.0 * coef1 * ao * omeosq * (1.0 + 2.75 * - (etasq + eeta) + eeta * etasq); - cosio4 = cosio2 * cosio2; - temp1 = 1.5 * j2 * pinvsq * satrec.no; - temp2 = 0.5 * temp1 * j2 * pinvsq; - temp3 = -0.46875 * j4 * pinvsq * pinvsq * satrec.no; - satrec.mdot = satrec.no + 0.5 * temp1 * rteosq * satrec.con41 + 0.0625 * - temp2 * rteosq * (13.0 - 78.0 * cosio2 + 137.0 * cosio4); - satrec.argpdot = -0.5 * temp1 * con42 + 0.0625 * temp2 * - (7.0 - 114.0 * cosio2 + 395.0 * cosio4) + - temp3 * (3.0 - 36.0 * cosio2 + 49.0 * cosio4); - xhdot1 = -temp1 * cosio; - satrec.nodedot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * cosio2) + - 2.0 * temp3 * (3.0 - 7.0 * cosio2)) * cosio; - xpidot = satrec.argpdot+ satrec.nodedot; - satrec.omgcof = satrec.bstar * cc3 * cos(satrec.argpo); - satrec.xmcof = 0.0; - if (satrec.ecco > 1.0e-4) - satrec.xmcof = -x2o3 * coef * satrec.bstar / eeta; - satrec.nodecf = 3.5 * omeosq * xhdot1 * satrec.cc1; - satrec.t2cof = 1.5 * satrec.cc1; - // sgp4fix for divide by zero with xinco = 180 deg - if (fabs(cosio+1.0) > 1.5e-12) - satrec.xlcof = -0.25 * j3oj2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio); - else - satrec.xlcof = -0.25 * j3oj2 * sinio * (3.0 + 5.0 * cosio) / temp4; - satrec.aycof = -0.5 * j3oj2 * sinio; - satrec.delmo = pow((1.0 + satrec.eta * cos(satrec.mo)), 3); - satrec.sinmao = sin(satrec.mo); - satrec.x7thm1 = 7.0 * cosio2 - 1.0; - - /* --------------- deep space initialization ------------- */ - if ((2*pi / satrec.no) >= 225.0) - { - satrec.method = 'd'; - satrec.isimp = 1; - tc = 0.0; - inclm = satrec.inclo; - - dscom - ( - epoch, satrec.ecco, satrec.argpo, tc, satrec.inclo, satrec.nodeo, - satrec.no, snodm, cnodm, sinim, cosim,sinomm, cosomm, - day, satrec.e3, satrec.ee2, em, emsq, gam, - satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, - satrec.plo, rtemsq, satrec.se2, satrec.se3, - satrec.sgh2, satrec.sgh3, satrec.sgh4, - satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, - satrec.sl2, satrec.sl3, satrec.sl4, s1, s2, s3, s4, s5, - s6, s7, ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3, - sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33, - satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, - satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, - satrec.xl3, satrec.xl4, nm, z1, z2, z3, z11, - z12, z13, z21, z22, z23, z31, z32, z33, - satrec.zmol, satrec.zmos - ); - dpper - ( - satrec.e3, satrec.ee2, satrec.peo, satrec.pgho, - satrec.pho, satrec.pinco, satrec.plo, satrec.se2, - satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, - satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, - satrec.sl2, satrec.sl3, satrec.sl4, satrec.t, - satrec.xgh2,satrec.xgh3,satrec.xgh4, satrec.xh2, - satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, - satrec.xl3, satrec.xl4, satrec.zmol, satrec.zmos, inclm, satrec.init, - satrec.ecco, satrec.inclo, satrec.nodeo, satrec.argpo, satrec.mo - ); - - argpm = 0.0; - nodem = 0.0; - mm = 0.0; - - dsinit - ( - whichconst, - cosim, emsq, satrec.argpo, s1, s2, s3, s4, s5, sinim, ss1, ss2, ss3, ss4, - ss5, sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33, satrec.t, tc, - satrec.gsto, satrec.mo, satrec.mdot, satrec.no, satrec.nodeo, - satrec.nodedot, xpidot, z1, z3, z11, z13, z21, z23, z31, z33, - satrec.ecco, eccsq, em, argpm, inclm, mm, nm, nodem, - satrec.irez, satrec.atime, - satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222 , - satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, - satrec.d5421, satrec.d5433, satrec.dedt, satrec.didt, - satrec.dmdt, dndt, satrec.dnodt, satrec.domdt , - satrec.del1, satrec.del2, satrec.del3, satrec.xfact, - satrec.xlamo, satrec.xli, satrec.xni - ); - } - - /* ----------- set variables if not deep space ----------- */ - if (satrec.isimp != 1) - { - cc1sq = satrec.cc1 * satrec.cc1; - satrec.d2 = 4.0 * ao * tsi * cc1sq; - temp = satrec.d2 * tsi * satrec.cc1 / 3.0; - satrec.d3 = (17.0 * ao + sfour) * temp; - satrec.d4 = 0.5 * temp * ao * tsi * (221.0 * ao + 31.0 * sfour) * - satrec.cc1; - satrec.t3cof = satrec.d2 + 2.0 * cc1sq; - satrec.t4cof = 0.25 * (3.0 * satrec.d3 + satrec.cc1 * - (12.0 * satrec.d2 + 10.0 * cc1sq)); - satrec.t5cof = 0.2 * (3.0 * satrec.d4 + - 12.0 * satrec.cc1 * satrec.d3 + - 6.0 * satrec.d2 * satrec.d2 + - 15.0 * cc1sq * (2.0 * satrec.d2 + cc1sq)); - } - } // if omeosq = 0 ... - - /* finally propogate to zero epoch to initialise all others. */ - if(satrec.error == 0) - sgp4(whichconst, satrec, 0.0, r, v); - - satrec.init = 'n'; - -//#include "debug6.cpp" - return satrec.error; -} // end sgp4init - -/*----------------------------------------------------------------------------- -* -* procedure sgp4 -* -* this procedure is the sgp4 prediction model from space command. this is an -* updated and combined version of sgp4 and sdp4, which were originally -* published separately in spacetrack report #3. this version follows the -* methodology from the aiaa paper (2006) describing the history and -* development of the code. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* satrec - initialised structure from sgp4init() call. -* tsince - time eince epoch (minutes) -* -* outputs : -* r - position vector km -* v - velocity km/sec -* return code - non-zero on error. -* 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er -* 2 - mean motion less than 0.0 -* 3 - pert elements, ecc < 0.0 or ecc > 1.0 -* 4 - semi-latus rectum < 0.0 -* 5 - epoch elements are sub-orbital -* 6 - satellite has decayed -* -* locals : -* am - -* axnl, aynl - -* betal - -* cosim , sinim , cosomm , sinomm , cnod , snod , cos2u , -* sin2u , coseo1 , sineo1 , cosi , sini , cosip , sinip , -* cosisq , cossu , sinsu , cosu , sinu -* delm - -* delomg - -* dndt - -* eccm - -* emsq - -* ecose - -* el2 - -* eo1 - -* eccp - -* esine - -* argpm - -* argpp - -* omgadf - -* pl - -* r - -* rtemsq - -* rdotl - -* rl - -* rvdot - -* rvdotl - -* su - -* t2 , t3 , t4 , tc -* tem5, temp , temp1 , temp2 , tempa , tempe , templ -* u , ux , uy , uz , vx , vy , vz -* inclm - inclination -* mm - mean anomaly -* nm - mean motion -* nodem - right asc of ascending node -* xinc - -* xincp - -* xl - -* xlm - -* mp - -* xmdf - -* xmx - -* xmy - -* nodedf - -* xnode - -* nodep - -* np - -* -* coupling : -* getgravconst- -* dpper -* dpspace -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -int sgp4 - ( - gravconsttype whichconst, elsetrec& satrec, double tsince, - double r[3], double v[3] - ) -{ - double am , axnl , aynl , betal , cosim , cnod , - cos2u, coseo1, cosi , cosip , cosisq, cossu , cosu, - delm , delomg, em , emsq , ecose , el2 , eo1 , - ep , esine , argpm, argpp , argpdf, pl, mrt = 0.0, - mvt , rdotl , rl , rvdot , rvdotl, sinim , - sin2u, sineo1, sini , sinip , sinsu , sinu , - snod , su , t2 , t3 , t4 , tem5 , temp, - temp1, temp2 , tempa, tempe , templ , u , ux , - uy , uz , vx , vy , vz , inclm , mm , - nm , nodem, xinc , xincp , xl , xlm , mp , - xmdf , xmx , xmy , nodedf, xnode , nodep, tc , dndt, - twopi, x2o3 , j2 , j3 , tumin, j4 , xke , j3oj2, radiusearthkm, - mu, vkmpersec; - int ktr; - - /* ------------------ set mathematical constants --------------- */ - // sgp4fix divisor for divide by zero check on inclination - const double temp4 = 1.0 + cos(pi-1.0e-9); - twopi = 2.0 * pi; - x2o3 = 2.0 / 3.0; - // sgp4fix identify constants and allow alternate values - getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); - vkmpersec = radiusearthkm * xke/60.0; - - /* --------------------- clear sgp4 error flag ----------------- */ - satrec.t = tsince; - satrec.error = 0; - - /* ------- update for secular gravity and atmospheric drag ----- */ - xmdf = satrec.mo + satrec.mdot * satrec.t; - argpdf = satrec.argpo + satrec.argpdot * satrec.t; - nodedf = satrec.nodeo + satrec.nodedot * satrec.t; - argpm = argpdf; - mm = xmdf; - t2 = satrec.t * satrec.t; - nodem = nodedf + satrec.nodecf * t2; - tempa = 1.0 - satrec.cc1 * satrec.t; - tempe = satrec.bstar * satrec.cc4 * satrec.t; - templ = satrec.t2cof * t2; - - if (satrec.isimp != 1) - { - delomg = satrec.omgcof * satrec.t; - delm = satrec.xmcof * - (pow((1.0 + satrec.eta * cos(xmdf)), 3) - - satrec.delmo); - temp = delomg + delm; - mm = xmdf + temp; - argpm = argpdf - temp; - t3 = t2 * satrec.t; - t4 = t3 * satrec.t; - tempa = tempa - satrec.d2 * t2 - satrec.d3 * t3 - - satrec.d4 * t4; - tempe = tempe + satrec.bstar * satrec.cc5 * (sin(mm) - - satrec.sinmao); - templ = templ + satrec.t3cof * t3 + t4 * (satrec.t4cof + - satrec.t * satrec.t5cof); - } - - nm = satrec.no; - em = satrec.ecco; - inclm = satrec.inclo; - if (satrec.method == 'd') - { - tc = satrec.t; - dspace - ( - satrec.irez, - satrec.d2201, satrec.d2211, satrec.d3210, - satrec.d3222, satrec.d4410, satrec.d4422, - satrec.d5220, satrec.d5232, satrec.d5421, - satrec.d5433, satrec.dedt, satrec.del1, - satrec.del2, satrec.del3, satrec.didt, - satrec.dmdt, satrec.dnodt, satrec.domdt, - satrec.argpo, satrec.argpdot, satrec.t, tc, - satrec.gsto, satrec.xfact, satrec.xlamo, - satrec.no, satrec.atime, - em, argpm, inclm, satrec.xli, mm, satrec.xni, - nodem, dndt, nm - ); - } // if method = d - - if (nm <= 0.0) - { -// printf("# error nm %f\n", nm); - satrec.error = 2; - } - am = pow((xke / nm),x2o3) * tempa * tempa; - nm = xke / pow(am, 1.5); - em = em - tempe; - - // fix tolerance for error recognition - if ((em >= 1.0) || (em < -0.001) || (am < 0.95)) - { -// printf("# error em %f\n", em); - satrec.error = 1; - } - if (em < 0.0) - em = 1.0e-6; - mm = mm + satrec.no * templ; - xlm = mm + argpm + nodem; - emsq = em * em; - temp = 1.0 - emsq; - - nodem = fmod(nodem, twopi); - argpm = fmod(argpm, twopi); - xlm = fmod(xlm, twopi); - mm = fmod(xlm - argpm - nodem, twopi); - - /* ----------------- compute extra mean quantities ------------- */ - sinim = sin(inclm); - cosim = cos(inclm); - - /* -------------------- add lunar-solar periodics -------------- */ - ep = em; - xincp = inclm; - argpp = argpm; - nodep = nodem; - mp = mm; - sinip = sinim; - cosip = cosim; - if (satrec.method == 'd') - { - dpper - ( - satrec.e3, satrec.ee2, satrec.peo, - satrec.pgho, satrec.pho, satrec.pinco, - satrec.plo, satrec.se2, satrec.se3, - satrec.sgh2, satrec.sgh3, satrec.sgh4, - satrec.sh2, satrec.sh3, satrec.si2, - satrec.si3, satrec.sl2, satrec.sl3, - satrec.sl4, satrec.t, satrec.xgh2, - satrec.xgh3, satrec.xgh4, satrec.xh2, - satrec.xh3, satrec.xi2, satrec.xi3, - satrec.xl2, satrec.xl3, satrec.xl4, - satrec.zmol, satrec.zmos, satrec.inclo, - 'n', ep, xincp, nodep, argpp, mp - ); - if (xincp < 0.0) - { - xincp = -xincp; - nodep = nodep + pi; - argpp = argpp - pi; - } - if ((ep < 0.0 ) || ( ep > 1.0)) - { - // printf("# error ep %f\n", ep); - satrec.error = 3; - } - } // if method = d - - /* -------------------- long period periodics ------------------ */ - if (satrec.method == 'd') - { - sinip = sin(xincp); - cosip = cos(xincp); - satrec.aycof = -0.5*j3oj2*sinip; - // sgp4fix for divide by zero for xincp = 180 deg - if (fabs(cosip+1.0) > 1.5e-12) - satrec.xlcof = -0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip) / (1.0 + cosip); - else - satrec.xlcof = -0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip) / temp4; - } - axnl = ep * cos(argpp); - temp = 1.0 / (am * (1.0 - ep * ep)); - aynl = ep* sin(argpp) + temp * satrec.aycof; - xl = mp + argpp + nodep + temp * satrec.xlcof * axnl; - - /* --------------------- solve kepler's equation --------------- */ - u = fmod(xl - nodep, twopi); - eo1 = u; - tem5 = 9999.9; - ktr = 1; - // sgp4fix for kepler iteration - // the following iteration needs better limits on corrections - while (( fabs(tem5) >= 1.0e-12) && (ktr <= 10) ) - { - sineo1 = sin(eo1); - coseo1 = cos(eo1); - tem5 = 1.0 - coseo1 * axnl - sineo1 * aynl; - tem5 = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5; - if(fabs(tem5) >= 0.95) - tem5 = tem5 > 0.0 ? 0.95 : -0.95; - eo1 = eo1 + tem5; - ktr = ktr + 1; - } - - /* ------------- short period preliminary quantities ----------- */ - ecose = axnl*coseo1 + aynl*sineo1; - esine = axnl*sineo1 - aynl*coseo1; - el2 = axnl*axnl + aynl*aynl; - pl = am*(1.0-el2); - if (pl < 0.0) - { -// printf("# error pl %f\n", pl); - satrec.error = 4; - } - else - { - rl = am * (1.0 - ecose); - rdotl = sqrt(am) * esine/rl; - rvdotl = sqrt(pl) / rl; - betal = sqrt(1.0 - el2); - temp = esine / (1.0 + betal); - sinu = am / rl * (sineo1 - aynl - axnl * temp); - cosu = am / rl * (coseo1 - axnl + aynl * temp); - su = atan2(sinu, cosu); - sin2u = (cosu + cosu) * sinu; - cos2u = 1.0 - 2.0 * sinu * sinu; - temp = 1.0 / pl; - temp1 = 0.5 * j2 * temp; - temp2 = temp1 * temp; - - /* -------------- update for short period periodics ------------ */ - if (satrec.method == 'd') - { - cosisq = cosip * cosip; - satrec.con41 = 3.0*cosisq - 1.0; - satrec.x1mth2 = 1.0 - cosisq; - satrec.x7thm1 = 7.0*cosisq - 1.0; - } - mrt = rl * (1.0 - 1.5 * temp2 * betal * satrec.con41) + - 0.5 * temp1 * satrec.x1mth2 * cos2u; - su = su - 0.25 * temp2 * satrec.x7thm1 * sin2u; - xnode = nodep + 1.5 * temp2 * cosip * sin2u; - xinc = xincp + 1.5 * temp2 * cosip * sinip * cos2u; - mvt = rdotl - nm * temp1 * satrec.x1mth2 * sin2u / xke; - rvdot = rvdotl + nm * temp1 * (satrec.x1mth2 * cos2u + - 1.5 * satrec.con41) / xke; - - /* --------------------- orientation vectors ------------------- */ - sinsu = sin(su); - cossu = cos(su); - snod = sin(xnode); - cnod = cos(xnode); - sini = sin(xinc); - cosi = cos(xinc); - xmx = -snod * cosi; - xmy = cnod * cosi; - ux = xmx * sinsu + cnod * cossu; - uy = xmy * sinsu + snod * cossu; - uz = sini * sinsu; - vx = xmx * cossu - cnod * sinsu; - vy = xmy * cossu - snod * sinsu; - vz = sini * cossu; - - /* --------- position and velocity (in km and km/sec) ---------- */ - r[0] = (mrt * ux)* radiusearthkm; - r[1] = (mrt * uy)* radiusearthkm; - r[2] = (mrt * uz)* radiusearthkm; - v[0] = (mvt * ux + rvdot * vx) * vkmpersec; - v[1] = (mvt * uy + rvdot * vy) * vkmpersec; - v[2] = (mvt * uz + rvdot * vz) * vkmpersec; - } // if pl > 0 - - // sgp4fix for decaying satellites - if (mrt < 1.0) - { -// printf("# decay condition %11.6f \n",mrt); - satrec.error = 6; - } - - -//#include "debug7.cpp" - return satrec.error; -} // end sgp4 - - -/* ----------------------------------------------------------------------------- -* -* function gstime -* -* this function finds the greenwich sidereal time. -* -* author : david vallado 719-573-2600 1 mar 2001 -* -* inputs description range / units -* jdut1 - julian date in ut1 days from 4713 bc -* -* outputs : -* gstime - greenwich sidereal time 0 to 2pi rad -* -* locals : -* temp - temporary variable for doubles rad -* tut1 - julian centuries from the -* jan 1, 2000 12 h epoch (ut1) -* -* coupling : -* none -* -* references : -* vallado 2004, 191, eq 3-45 -* --------------------------------------------------------------------------- */ - -double gstime - ( - double jdut1 - ) - { - const double twopi = 2.0 * pi; - const double deg2rad = pi / 180.0; - double temp, tut1; - - tut1 = (jdut1 - 2451545.0) / 36525.0; - temp = -6.2e-6* tut1 * tut1 * tut1 + 0.093104 * tut1 * tut1 + - (876600.0*3600 + 8640184.812866) * tut1 + 67310.54841; // sec - temp = fmod(temp * deg2rad / 240.0, twopi); //360/86400 = 1/240, to deg, to rad - - // ------------------------ check quadrants --------------------- - if (temp < 0.0) - temp += twopi; - - return temp; - } // end gstime - -/* ----------------------------------------------------------------------------- -* -* function getgravconst -* -* this function gets constants for the propagator. note that mu is identified to -* facilitiate comparisons with newer models. the common useage is wgs72. -* -* author : david vallado 719-573-2600 21 jul 2006 -* -* inputs : -* whichconst - which set of constants to use wgs72old, wgs72, wgs84 -* -* outputs : -* tumin - minutes in one time unit -* mu - earth gravitational parameter -* radiusearthkm - radius of the earth in km -* xke - reciprocal of tumin -* j2, j3, j4 - un-normalized zonal harmonic values -* j3oj2 - j3 divided by j2 -* -* locals : -* -* coupling : -* none -* -* references : -* norad spacetrack report #3 -* vallado, crawford, hujsak, kelso 2006 - --------------------------------------------------------------------------- */ - -void getgravconst - ( - gravconsttype whichconst, - double& tumin, - double& mu, - double& radiusearthkm, - double& xke, - double& j2, - double& j3, - double& j4, - double& j3oj2 - ) - { - - switch (whichconst) - { - // -- wgs-72 low precision str#3 constants -- - case wgs72old: - mu = 398600.79964; // in km3 / s2 - radiusearthkm = 6378.135; // km - xke = 0.0743669161; - tumin = 1.0 / xke; - j2 = 0.001082616; - j3 = -0.00000253881; - j4 = -0.00000165597; - j3oj2 = j3 / j2; - break; - // ------------ wgs-72 constants ------------ - case wgs72: - mu = 398600.8; // in km3 / s2 - radiusearthkm = 6378.135; // km - xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); - tumin = 1.0 / xke; - j2 = 0.001082616; - j3 = -0.00000253881; - j4 = -0.00000165597; - j3oj2 = j3 / j2; - break; - case wgs84: - // ------------ wgs-84 constants ------------ - mu = 398600.5; // in km3 / s2 - radiusearthkm = 6378.137; // km - xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); - tumin = 1.0 / xke; - j2 = 0.00108262998905; - j3 = -0.00000253215306; - j4 = -0.00000161098761; - j3oj2 = j3 / j2; - break; - default: - fprintf(stderr,"unknown gravity option (%d)\n",whichconst); - break; - } - - } // end getgravconst - - - - - +/* ---------------------------------------------------------------- +* +* sgp4unit.cpp +* +* this file contains the sgp4 procedures for analytical propagation +* of a satellite. the code was originally released in the 1980 and 1986 +* spacetrack papers. a detailed discussion of the theory and history +* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, +* and kelso. +* +* companion code for +* fundamentals of astrodynamics and applications +* 2007 +* by david vallado +* +* (w) 719-573-2600, email dvallado@agi.com +* +* current : +* 16 nov 07 david vallado +* misc fixes for better compliance +* changes : +* 20 apr 07 david vallado +* misc fixes for constants +* 11 aug 06 david vallado +* chg lyddane choice back to strn3, constants, misc doc +* 15 dec 05 david vallado +* misc fixes +* 26 jul 05 david vallado +* fixes for paper +* note that each fix is preceded by a +* comment with "sgp4fix" and an explanation of +* what was changed +* 10 aug 04 david vallado +* 2nd printing baseline working +* 14 may 01 david vallado +* 2nd edition baseline +* 80 norad +* original baseline +* ---------------------------------------------------------------- */ + +#include "sgp4unit.h" + +const char help = 'n'; +FILE *dbgfile; + +#define pi 3.14159265358979323846 + + +/* ----------- local functions - only ever used internally by sgp4 ---------- */ +static void dpper + ( + double e3, double ee2, double peo, double pgho, double pho, + double pinco, double plo, double se2, double se3, double sgh2, + double sgh3, double sgh4, double sh2, double sh3, double si2, + double si3, double sl2, double sl3, double sl4, double t, + double xgh2, double xgh3, double xgh4, double xh2, double xh3, + double xi2, double xi3, double xl2, double xl3, double xl4, + double zmol, double zmos, double inclo, + char init, + double& ep, double& inclp, double& nodep, double& argpp, double& mp + ); + +static void dscom + ( + double epoch, double ep, double argpp, double tc, double inclp, + double nodep, double np, + double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, + double& cosomm,double& day, double& e3, double& ee2, double& em, + double& emsq, double& gam, double& peo, double& pgho, double& pho, + double& pinco, double& plo, double& rtemsq, double& se2, double& se3, + double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, + double& si2, double& si3, double& sl2, double& sl3, double& sl4, + double& s1, double& s2, double& s3, double& s4, double& s5, + double& s6, double& s7, double& ss1, double& ss2, double& ss3, + double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, + double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, + double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, + double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, + double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, + double& xl4, double& nm, double& z1, double& z2, double& z3, + double& z11, double& z12, double& z13, double& z21, double& z22, + double& z23, double& z31, double& z32, double& z33, double& zmol, + double& zmos + ); + +static void dsinit + ( + gravconsttype whichconst, + double cosim, double emsq, double argpo, double s1, double s2, + double s3, double s4, double s5, double sinim, double ss1, + double ss2, double ss3, double ss4, double ss5, double sz1, + double sz3, double sz11, double sz13, double sz21, double sz23, + double sz31, double sz33, double t, double tc, double gsto, + double mo, double mdot, double no, double nodeo, double nodedot, + double xpidot, double z1, double z3, double z11, double z13, + double z21, double z23, double z31, double z33, double ecco, + double eccsq, double& em, double& argpm, double& inclm, double& mm, + double& nm, double& nodem, + int& irez, + double& atime, double& d2201, double& d2211, double& d3210, double& d3222, + double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, + double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, + double& dnodt, double& domdt, double& del1, double& del2, double& del3, + double& xfact, double& xlamo, double& xli, double& xni + ); + +static void dspace + ( + int irez, + double d2201, double d2211, double d3210, double d3222, double d4410, + double d4422, double d5220, double d5232, double d5421, double d5433, + double dedt, double del1, double del2, double del3, double didt, + double dmdt, double dnodt, double domdt, double argpo, double argpdot, + double t, double tc, double gsto, double xfact, double xlamo, + double no, + double& atime, double& em, double& argpm, double& inclm, double& xli, + double& mm, double& xni, double& nodem, double& dndt, double& nm + ); + +static void initl + ( + int satn, gravconsttype whichconst, + double ecco, double epoch, double inclo, double& no, + char& method, + double& ainv, double& ao, double& con41, double& con42, double& cosio, + double& cosio2,double& eccsq, double& omeosq, double& posq, + double& rp, double& rteosq,double& sinio , double& gsto + ); + +/* ----------------------------------------------------------------------------- +* +* procedure dpper +* +* this procedure provides deep space long period periodic contributions +* to the mean elements. by design, these periodics are zero at epoch. +* this used to be dscom which included initialization, but it's really a +* recurring function. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* e3 - +* ee2 - +* peo - +* pgho - +* pho - +* pinco - +* plo - +* se2 , se3 , sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4 - +* t - +* xh2, xh3, xi2, xi3, xl2, xl3, xl4 - +* zmol - +* zmos - +* ep - eccentricity 0.0 - 1.0 +* inclo - inclination - needed for lyddane modification +* nodep - right ascension of ascending node +* argpp - argument of perigee +* mp - mean anomaly +* +* outputs : +* ep - eccentricity 0.0 - 1.0 +* inclp - inclination +* nodep - right ascension of ascending node +* argpp - argument of perigee +* mp - mean anomaly +* +* locals : +* alfdp - +* betdp - +* cosip , sinip , cosop , sinop , +* dalf - +* dbet - +* dls - +* f2, f3 - +* pe - +* pgh - +* ph - +* pinc - +* pl - +* sel , ses , sghl , sghs , shl , shs , sil , sinzf , sis , +* sll , sls +* xls - +* xnoh - +* zf - +* zm - +* +* coupling : +* none. +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void dpper + ( + double e3, double ee2, double peo, double pgho, double pho, + double pinco, double plo, double se2, double se3, double sgh2, + double sgh3, double sgh4, double sh2, double sh3, double si2, + double si3, double sl2, double sl3, double sl4, double t, + double xgh2, double xgh3, double xgh4, double xh2, double xh3, + double xi2, double xi3, double xl2, double xl3, double xl4, + double zmol, double zmos, double inclo, + char init, + double& ep, double& inclp, double& nodep, double& argpp, double& mp + ) +{ + /* --------------------- local variables ------------------------ */ + const double twopi = 2.0 * pi; + double alfdp, betdp, cosip, cosop, dalf, dbet, dls, + f2, f3, pe, pgh, ph, pinc, pl , + sel, ses, sghl, sghs, shll, shs, sil, + sinip, sinop, sinzf, sis, sll, sls, xls, + xnoh, zf, zm, zel, zes, znl, zns; + + /* ---------------------- constants ----------------------------- */ + zns = 1.19459e-5; + zes = 0.01675; + znl = 1.5835218e-4; + zel = 0.05490; + + /* --------------- calculate time varying periodics ----------- */ + zm = zmos + zns * t; + // be sure that the initial call has time set to zero + if (init == 'y') + zm = zmos; + zf = zm + 2.0 * zes * sin(zm); + sinzf = sin(zf); + f2 = 0.5 * sinzf * sinzf - 0.25; + f3 = -0.5 * sinzf * cos(zf); + ses = se2* f2 + se3 * f3; + sis = si2 * f2 + si3 * f3; + sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf; + sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf; + shs = sh2 * f2 + sh3 * f3; + zm = zmol + znl * t; + if (init == 'y') + zm = zmol; + zf = zm + 2.0 * zel * sin(zm); + sinzf = sin(zf); + f2 = 0.5 * sinzf * sinzf - 0.25; + f3 = -0.5 * sinzf * cos(zf); + sel = ee2 * f2 + e3 * f3; + sil = xi2 * f2 + xi3 * f3; + sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf; + sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf; + shll = xh2 * f2 + xh3 * f3; + pe = ses + sel; + pinc = sis + sil; + pl = sls + sll; + pgh = sghs + sghl; + ph = shs + shll; + + if (init == 'n') + { + pe = pe - peo; + pinc = pinc - pinco; + pl = pl - plo; + pgh = pgh - pgho; + ph = ph - pho; + inclp = inclp + pinc; + ep = ep + pe; + sinip = sin(inclp); + cosip = cos(inclp); + + /* ----------------- apply periodics directly ------------ */ + // sgp4fix for lyddane choice + // strn3 used original inclination - this is technically feasible + // gsfc used perturbed inclination - also technically feasible + // probably best to readjust the 0.2 limit value and limit discontinuity + // 0.2 rad = 11.45916 deg + // use next line for original strn3 approach and original inclination + // if (inclo >= 0.2) + // use next line for gsfc version and perturbed inclination + if (inclp >= 0.2) + { + ph = ph / sinip; + pgh = pgh - cosip * ph; + argpp = argpp + pgh; + nodep = nodep + ph; + mp = mp + pl; + } + else + { + /* ---- apply periodics with lyddane modification ---- */ + sinop = sin(nodep); + cosop = cos(nodep); + alfdp = sinip * sinop; + betdp = sinip * cosop; + dalf = ph * cosop + pinc * cosip * sinop; + dbet = -ph * sinop + pinc * cosip * cosop; + alfdp = alfdp + dalf; + betdp = betdp + dbet; + nodep = fmod(nodep, twopi); + // sgp4fix for afspc written intrinsic functions + // nodep used without a trigonometric function ahead + if (nodep < 0.0) + nodep = nodep + twopi; + xls = mp + argpp + cosip * nodep; + dls = pl + pgh - pinc * nodep * sinip; + xls = xls + dls; + xnoh = nodep; + nodep = atan2(alfdp, betdp); + // sgp4fix for afspc written intrinsic functions + // nodep used without a trigonometric function ahead + if (nodep < 0.0) + nodep = nodep + twopi; + if (fabs(xnoh - nodep) > pi){ + if (nodep < xnoh) + nodep = nodep + twopi; + else + nodep = nodep - twopi; + } + mp = mp + pl; + argpp = xls - mp - cosip * nodep; + } + } // if init == 'n' + +//#include "debug1.cpp" +} // end dpper + +/*----------------------------------------------------------------------------- +* +* procedure dscom +* +* this procedure provides deep space common items used by both the secular +* and periodics subroutines. input is provided as shown. this routine +* used to be called dpper, but the functions inside weren't well organized. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* epoch - +* ep - eccentricity +* argpp - argument of perigee +* tc - +* inclp - inclination +* nodep - right ascension of ascending node +* np - mean motion +* +* outputs : +* sinim , cosim , sinomm , cosomm , snodm , cnodm +* day - +* e3 - +* ee2 - +* em - eccentricity +* emsq - eccentricity squared +* gam - +* peo - +* pgho - +* pho - +* pinco - +* plo - +* rtemsq - +* se2, se3 - +* sgh2, sgh3, sgh4 - +* sh2, sh3, si2, si3, sl2, sl3, sl4 - +* s1, s2, s3, s4, s5, s6, s7 - +* ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3 - +* sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - +* xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4 - +* nm - mean motion +* z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33 - +* zmol - +* zmos - +* +* locals : +* a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 - +* betasq - +* cc - +* ctem, stem - +* x1, x2, x3, x4, x5, x6, x7, x8 - +* xnodce - +* xnoi - +* zcosg , zsing , zcosgl , zsingl , zcosh , zsinh , zcoshl , zsinhl , +* zcosi , zsini , zcosil , zsinil , +* zx - +* zy - +* +* coupling : +* none. +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void dscom + ( + double epoch, double ep, double argpp, double tc, double inclp, + double nodep, double np, + double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, + double& cosomm,double& day, double& e3, double& ee2, double& em, + double& emsq, double& gam, double& peo, double& pgho, double& pho, + double& pinco, double& plo, double& rtemsq, double& se2, double& se3, + double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, + double& si2, double& si3, double& sl2, double& sl3, double& sl4, + double& s1, double& s2, double& s3, double& s4, double& s5, + double& s6, double& s7, double& ss1, double& ss2, double& ss3, + double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, + double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, + double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, + double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, + double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, + double& xl4, double& nm, double& z1, double& z2, double& z3, + double& z11, double& z12, double& z13, double& z21, double& z22, + double& z23, double& z31, double& z32, double& z33, double& zmol, + double& zmos + ) +{ + /* -------------------------- constants ------------------------- */ + const double zes = 0.01675; + const double zel = 0.05490; + const double c1ss = 2.9864797e-6; + const double c1l = 4.7968065e-7; + const double zsinis = 0.39785416; + const double zcosis = 0.91744867; + const double zcosgs = 0.1945905; + const double zsings = -0.98088458; + const double twopi = 2.0 * pi; + + /* --------------------- local variables ------------------------ */ + int lsflg; + double a1 , a2 , a3 , a4 , a5 , a6 , a7 , + a8 , a9 , a10 , betasq, cc , ctem , stem , + x1 , x2 , x3 , x4 , x5 , x6 , x7 , + x8 , xnodce, xnoi , zcosg , zcosgl, zcosh , zcoshl, + zcosi , zcosil, zsing , zsingl, zsinh , zsinhl, zsini , + zsinil, zx , zy; + + nm = np; + em = ep; + snodm = sin(nodep); + cnodm = cos(nodep); + sinomm = sin(argpp); + cosomm = cos(argpp); + sinim = sin(inclp); + cosim = cos(inclp); + emsq = em * em; + betasq = 1.0 - emsq; + rtemsq = sqrt(betasq); + + /* ----------------- initialize lunar solar terms --------------- */ + peo = 0.0; + pinco = 0.0; + plo = 0.0; + pgho = 0.0; + pho = 0.0; + day = epoch + 18261.5 + tc / 1440.0; + xnodce = fmod(4.5236020 - 9.2422029e-4 * day, twopi); + stem = sin(xnodce); + ctem = cos(xnodce); + zcosil = 0.91375164 - 0.03568096 * ctem; + zsinil = sqrt(1.0 - zcosil * zcosil); + zsinhl = 0.089683511 * stem / zsinil; + zcoshl = sqrt(1.0 - zsinhl * zsinhl); + gam = 5.8351514 + 0.0019443680 * day; + zx = 0.39785416 * stem / zsinil; + zy = zcoshl * ctem + 0.91744867 * zsinhl * stem; + zx = atan2(zx, zy); + zx = gam + zx - xnodce; + zcosgl = cos(zx); + zsingl = sin(zx); + + /* ------------------------- do solar terms --------------------- */ + zcosg = zcosgs; + zsing = zsings; + zcosi = zcosis; + zsini = zsinis; + zcosh = cnodm; + zsinh = snodm; + cc = c1ss; + xnoi = 1.0 / nm; + + for (lsflg = 1; lsflg <= 2; lsflg++) + { + a1 = zcosg * zcosh + zsing * zcosi * zsinh; + a3 = -zsing * zcosh + zcosg * zcosi * zsinh; + a7 = -zcosg * zsinh + zsing * zcosi * zcosh; + a8 = zsing * zsini; + a9 = zsing * zsinh + zcosg * zcosi * zcosh; + a10 = zcosg * zsini; + a2 = cosim * a7 + sinim * a8; + a4 = cosim * a9 + sinim * a10; + a5 = -sinim * a7 + cosim * a8; + a6 = -sinim * a9 + cosim * a10; + + x1 = a1 * cosomm + a2 * sinomm; + x2 = a3 * cosomm + a4 * sinomm; + x3 = -a1 * sinomm + a2 * cosomm; + x4 = -a3 * sinomm + a4 * cosomm; + x5 = a5 * sinomm; + x6 = a6 * sinomm; + x7 = a5 * cosomm; + x8 = a6 * cosomm; + + z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3; + z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4; + z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4; + z1 = 3.0 * (a1 * a1 + a2 * a2) + z31 * emsq; + z2 = 6.0 * (a1 * a3 + a2 * a4) + z32 * emsq; + z3 = 3.0 * (a3 * a3 + a4 * a4) + z33 * emsq; + z11 = -6.0 * a1 * a5 + emsq * (-24.0 * x1 * x7-6.0 * x3 * x5); + z12 = -6.0 * (a1 * a6 + a3 * a5) + emsq * + (-24.0 * (x2 * x7 + x1 * x8) - 6.0 * (x3 * x6 + x4 * x5)); + z13 = -6.0 * a3 * a6 + emsq * (-24.0 * x2 * x8 - 6.0 * x4 * x6); + z21 = 6.0 * a2 * a5 + emsq * (24.0 * x1 * x5 - 6.0 * x3 * x7); + z22 = 6.0 * (a4 * a5 + a2 * a6) + emsq * + (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8)); + z23 = 6.0 * a4 * a6 + emsq * (24.0 * x2 * x6 - 6.0 * x4 * x8); + z1 = z1 + z1 + betasq * z31; + z2 = z2 + z2 + betasq * z32; + z3 = z3 + z3 + betasq * z33; + s3 = cc * xnoi; + s2 = -0.5 * s3 / rtemsq; + s4 = s3 * rtemsq; + s1 = -15.0 * em * s4; + s5 = x1 * x3 + x2 * x4; + s6 = x2 * x3 + x1 * x4; + s7 = x2 * x4 - x1 * x3; + + /* ----------------------- do lunar terms ------------------- */ + if (lsflg == 1) + { + ss1 = s1; + ss2 = s2; + ss3 = s3; + ss4 = s4; + ss5 = s5; + ss6 = s6; + ss7 = s7; + sz1 = z1; + sz2 = z2; + sz3 = z3; + sz11 = z11; + sz12 = z12; + sz13 = z13; + sz21 = z21; + sz22 = z22; + sz23 = z23; + sz31 = z31; + sz32 = z32; + sz33 = z33; + zcosg = zcosgl; + zsing = zsingl; + zcosi = zcosil; + zsini = zsinil; + zcosh = zcoshl * cnodm + zsinhl * snodm; + zsinh = snodm * zcoshl - cnodm * zsinhl; + cc = c1l; + } + } + + zmol = fmod(4.7199672 + 0.22997150 * day - gam, twopi); + zmos = fmod(6.2565837 + 0.017201977 * day, twopi); + + /* ------------------------ do solar terms ---------------------- */ + se2 = 2.0 * ss1 * ss6; + se3 = 2.0 * ss1 * ss7; + si2 = 2.0 * ss2 * sz12; + si3 = 2.0 * ss2 * (sz13 - sz11); + sl2 = -2.0 * ss3 * sz2; + sl3 = -2.0 * ss3 * (sz3 - sz1); + sl4 = -2.0 * ss3 * (-21.0 - 9.0 * emsq) * zes; + sgh2 = 2.0 * ss4 * sz32; + sgh3 = 2.0 * ss4 * (sz33 - sz31); + sgh4 = -18.0 * ss4 * zes; + sh2 = -2.0 * ss2 * sz22; + sh3 = -2.0 * ss2 * (sz23 - sz21); + + /* ------------------------ do lunar terms ---------------------- */ + ee2 = 2.0 * s1 * s6; + e3 = 2.0 * s1 * s7; + xi2 = 2.0 * s2 * z12; + xi3 = 2.0 * s2 * (z13 - z11); + xl2 = -2.0 * s3 * z2; + xl3 = -2.0 * s3 * (z3 - z1); + xl4 = -2.0 * s3 * (-21.0 - 9.0 * emsq) * zel; + xgh2 = 2.0 * s4 * z32; + xgh3 = 2.0 * s4 * (z33 - z31); + xgh4 = -18.0 * s4 * zel; + xh2 = -2.0 * s2 * z22; + xh3 = -2.0 * s2 * (z23 - z21); + +//#include "debug2.cpp" +} // end dscom + +/*----------------------------------------------------------------------------- +* +* procedure dsinit +* +* this procedure provides deep space contributions to mean motion dot due +* to geopotential resonance with half day and one day orbits. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* cosim, sinim- +* emsq - eccentricity squared +* argpo - argument of perigee +* s1, s2, s3, s4, s5 - +* ss1, ss2, ss3, ss4, ss5 - +* sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33 - +* t - time +* tc - +* gsto - greenwich sidereal time rad +* mo - mean anomaly +* mdot - mean anomaly dot (rate) +* no - mean motion +* nodeo - right ascension of ascending node +* nodedot - right ascension of ascending node dot (rate) +* xpidot - +* z1, z3, z11, z13, z21, z23, z31, z33 - +* eccm - eccentricity +* argpm - argument of perigee +* inclm - inclination +* mm - mean anomaly +* xn - mean motion +* nodem - right ascension of ascending node +* +* outputs : +* em - eccentricity +* argpm - argument of perigee +* inclm - inclination +* mm - mean anomaly +* nm - mean motion +* nodem - right ascension of ascending node +* irez - flag for resonance 0-none, 1-one day, 2-half day +* atime - +* d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - +* dedt - +* didt - +* dmdt - +* dndt - +* dnodt - +* domdt - +* del1, del2, del3 - +* ses , sghl , sghs , sgs , shl , shs , sis , sls +* theta - +* xfact - +* xlamo - +* xli - +* xni +* +* locals : +* ainv2 - +* aonv - +* cosisq - +* eoc - +* f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543 - +* g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533 - +* sini2 - +* temp - +* temp1 - +* theta - +* xno2 - +* +* coupling : +* getgravconst +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void dsinit + ( + gravconsttype whichconst, + double cosim, double emsq, double argpo, double s1, double s2, + double s3, double s4, double s5, double sinim, double ss1, + double ss2, double ss3, double ss4, double ss5, double sz1, + double sz3, double sz11, double sz13, double sz21, double sz23, + double sz31, double sz33, double t, double tc, double gsto, + double mo, double mdot, double no, double nodeo, double nodedot, + double xpidot, double z1, double z3, double z11, double z13, + double z21, double z23, double z31, double z33, double ecco, + double eccsq, double& em, double& argpm, double& inclm, double& mm, + double& nm, double& nodem, + int& irez, + double& atime, double& d2201, double& d2211, double& d3210, double& d3222, + double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, + double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, + double& dnodt, double& domdt, double& del1, double& del2, double& del3, + double& xfact, double& xlamo, double& xli, double& xni + ) +{ + /* --------------------- local variables ------------------------ */ + const double twopi = 2.0 * pi; + + double ainv2 , aonv=0.0, cosisq, eoc, f220 , f221 , f311 , + f321 , f322 , f330 , f441 , f442 , f522 , f523 , + f542 , f543 , g200 , g201 , g211 , g300 , g310 , + g322 , g410 , g422 , g520 , g521 , g532 , g533 , + ses , sgs , sghl , sghs , shs , shll , sis , + sini2 , sls , temp , temp1 , theta , xno2 , q22 , + q31 , q33 , root22, root44, root54, rptim , root32, + root52, x2o3 , xke , znl , emo , zns , emsqo, + tumin, mu, radiusearthkm, j2, j3, j4, j3oj2; + + q22 = 1.7891679e-6; + q31 = 2.1460748e-6; + q33 = 2.2123015e-7; + root22 = 1.7891679e-6; + root44 = 7.3636953e-9; + root54 = 2.1765803e-9; + rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec + root32 = 3.7393792e-7; + root52 = 1.1428639e-7; + x2o3 = 2.0 / 3.0; + znl = 1.5835218e-4; + zns = 1.19459e-5; + + // sgp4fix identify constants and allow alternate values + getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); + + /* -------------------- deep space initialization ------------ */ + irez = 0; + if ((nm < 0.0052359877) && (nm > 0.0034906585)) + irez = 1; + if ((nm >= 8.26e-3) && (nm <= 9.24e-3) && (em >= 0.5)) + irez = 2; + + /* ------------------------ do solar terms ------------------- */ + ses = ss1 * zns * ss5; + sis = ss2 * zns * (sz11 + sz13); + sls = -zns * ss3 * (sz1 + sz3 - 14.0 - 6.0 * emsq); + sghs = ss4 * zns * (sz31 + sz33 - 6.0); + shs = -zns * ss2 * (sz21 + sz23); + // sgp4fix for 180 deg incl + if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) + shs = 0.0; + if (sinim != 0.0) + shs = shs / sinim; + sgs = sghs - cosim * shs; + + /* ------------------------- do lunar terms ------------------ */ + dedt = ses + s1 * znl * s5; + didt = sis + s2 * znl * (z11 + z13); + dmdt = sls - znl * s3 * (z1 + z3 - 14.0 - 6.0 * emsq); + sghl = s4 * znl * (z31 + z33 - 6.0); + shll = -znl * s2 * (z21 + z23); + // sgp4fix for 180 deg incl + if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) + shll = 0.0; + domdt = sgs + sghl; + dnodt = shs; + if (sinim != 0.0) + { + domdt = domdt - cosim / sinim * shll; + dnodt = dnodt + shll / sinim; + } + + /* ----------- calculate deep space resonance effects -------- */ + dndt = 0.0; + theta = fmod(gsto + tc * rptim, twopi); + em = em + dedt * t; + inclm = inclm + didt * t; + argpm = argpm + domdt * t; + nodem = nodem + dnodt * t; + mm = mm + dmdt * t; + // sgp4fix for negative inclinations + // the following if statement should be commented out + //if (inclm < 0.0) + // { + // inclm = -inclm; + // argpm = argpm - pi; + // nodem = nodem + pi; + // } + + /* -------------- initialize the resonance terms ------------- */ + if (irez != 0) + { + aonv = pow(nm / xke, x2o3); + + /* ---------- geopotential resonance for 12 hour orbits ------ */ + if (irez == 2) + { + cosisq = cosim * cosim; + emo = em; + em = ecco; + emsqo = emsq; + emsq = eccsq; + eoc = em * emsq; + g201 = -0.306 - (em - 0.64) * 0.440; + + if (em <= 0.65) + { + g211 = 3.616 - 13.2470 * em + 16.2900 * emsq; + g310 = -19.302 + 117.3900 * em - 228.4190 * emsq + 156.5910 * eoc; + g322 = -18.9068 + 109.7927 * em - 214.6334 * emsq + 146.5816 * eoc; + g410 = -41.122 + 242.6940 * em - 471.0940 * emsq + 313.9530 * eoc; + g422 = -146.407 + 841.8800 * em - 1629.014 * emsq + 1083.4350 * eoc; + g520 = -532.114 + 3017.977 * em - 5740.032 * emsq + 3708.2760 * eoc; + } + else + { + g211 = -72.099 + 331.819 * em - 508.738 * emsq + 266.724 * eoc; + g310 = -346.844 + 1582.851 * em - 2415.925 * emsq + 1246.113 * eoc; + g322 = -342.585 + 1554.908 * em - 2366.899 * emsq + 1215.972 * eoc; + g410 = -1052.797 + 4758.686 * em - 7193.992 * emsq + 3651.957 * eoc; + g422 = -3581.690 + 16178.110 * em - 24462.770 * emsq + 12422.520 * eoc; + if (em > 0.715) + g520 =-5149.66 + 29936.92 * em - 54087.36 * emsq + 31324.56 * eoc; + else + g520 = 1464.74 - 4664.75 * em + 3763.64 * emsq; + } + if (em < 0.7) + { + g533 = -919.22770 + 4988.6100 * em - 9064.7700 * emsq + 5542.21 * eoc; + g521 = -822.71072 + 4568.6173 * em - 8491.4146 * emsq + 5337.524 * eoc; + g532 = -853.66600 + 4690.2500 * em - 8624.7700 * emsq + 5341.4 * eoc; + } + else + { + g533 =-37995.780 + 161616.52 * em - 229838.20 * emsq + 109377.94 * eoc; + g521 =-51752.104 + 218913.95 * em - 309468.16 * emsq + 146349.42 * eoc; + g532 =-40023.880 + 170470.89 * em - 242699.48 * emsq + 115605.82 * eoc; + } + + sini2= sinim * sinim; + f220 = 0.75 * (1.0 + 2.0 * cosim+cosisq); + f221 = 1.5 * sini2; + f321 = 1.875 * sinim * (1.0 - 2.0 * cosim - 3.0 * cosisq); + f322 = -1.875 * sinim * (1.0 + 2.0 * cosim - 3.0 * cosisq); + f441 = 35.0 * sini2 * f220; + f442 = 39.3750 * sini2 * sini2; + f522 = 9.84375 * sinim * (sini2 * (1.0 - 2.0 * cosim- 5.0 * cosisq) + + 0.33333333 * (-2.0 + 4.0 * cosim + 6.0 * cosisq) ); + f523 = sinim * (4.92187512 * sini2 * (-2.0 - 4.0 * cosim + + 10.0 * cosisq) + 6.56250012 * (1.0+2.0 * cosim - 3.0 * cosisq)); + f542 = 29.53125 * sinim * (2.0 - 8.0 * cosim+cosisq * + (-12.0 + 8.0 * cosim + 10.0 * cosisq)); + f543 = 29.53125 * sinim * (-2.0 - 8.0 * cosim+cosisq * + (12.0 + 8.0 * cosim - 10.0 * cosisq)); + xno2 = nm * nm; + ainv2 = aonv * aonv; + temp1 = 3.0 * xno2 * ainv2; + temp = temp1 * root22; + d2201 = temp * f220 * g201; + d2211 = temp * f221 * g211; + temp1 = temp1 * aonv; + temp = temp1 * root32; + d3210 = temp * f321 * g310; + d3222 = temp * f322 * g322; + temp1 = temp1 * aonv; + temp = 2.0 * temp1 * root44; + d4410 = temp * f441 * g410; + d4422 = temp * f442 * g422; + temp1 = temp1 * aonv; + temp = temp1 * root52; + d5220 = temp * f522 * g520; + d5232 = temp * f523 * g532; + temp = 2.0 * temp1 * root54; + d5421 = temp * f542 * g521; + d5433 = temp * f543 * g533; + xlamo = fmod(mo + nodeo + nodeo-theta - theta, twopi); + xfact = mdot + dmdt + 2.0 * (nodedot + dnodt - rptim) - no; + em = emo; + emsq = emsqo; + } + + /* ---------------- synchronous resonance terms -------------- */ + if (irez == 1) + { + g200 = 1.0 + emsq * (-2.5 + 0.8125 * emsq); + g310 = 1.0 + 2.0 * emsq; + g300 = 1.0 + emsq * (-6.0 + 6.60937 * emsq); + f220 = 0.75 * (1.0 + cosim) * (1.0 + cosim); + f311 = 0.9375 * sinim * sinim * (1.0 + 3.0 * cosim) - 0.75 * (1.0 + cosim); + f330 = 1.0 + cosim; + f330 = 1.875 * f330 * f330 * f330; + del1 = 3.0 * nm * nm * aonv * aonv; + del2 = 2.0 * del1 * f220 * g200 * q22; + del3 = 3.0 * del1 * f330 * g300 * q33 * aonv; + del1 = del1 * f311 * g310 * q31 * aonv; + xlamo = fmod(mo + nodeo + argpo - theta, twopi); + xfact = mdot + xpidot - rptim + dmdt + domdt + dnodt - no; + } + + /* ------------ for sgp4, initialize the integrator ---------- */ + xli = xlamo; + xni = no; + atime = 0.0; + nm = no + dndt; + } + +//#include "debug3.cpp" +} // end dsinit + +/*----------------------------------------------------------------------------- +* +* procedure dspace +* +* this procedure provides deep space contributions to mean elements for +* perturbing third body. these effects have been averaged over one +* revolution of the sun and moon. for earth resonance effects, the +* effects have been averaged over no revolutions of the satellite. +* (mean motion) +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - +* dedt - +* del1, del2, del3 - +* didt - +* dmdt - +* dnodt - +* domdt - +* irez - flag for resonance 0-none, 1-one day, 2-half day +* argpo - argument of perigee +* argpdot - argument of perigee dot (rate) +* t - time +* tc - +* gsto - gst +* xfact - +* xlamo - +* no - mean motion +* atime - +* em - eccentricity +* ft - +* argpm - argument of perigee +* inclm - inclination +* xli - +* mm - mean anomaly +* xni - mean motion +* nodem - right ascension of ascending node +* +* outputs : +* atime - +* em - eccentricity +* argpm - argument of perigee +* inclm - inclination +* xli - +* mm - mean anomaly +* xni - +* nodem - right ascension of ascending node +* dndt - +* nm - mean motion +* +* locals : +* delt - +* ft - +* theta - +* x2li - +* x2omi - +* xl - +* xldot - +* xnddt - +* xndt - +* xomi - +* +* coupling : +* none - +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void dspace + ( + int irez, + double d2201, double d2211, double d3210, double d3222, double d4410, + double d4422, double d5220, double d5232, double d5421, double d5433, + double dedt, double del1, double del2, double del3, double didt, + double dmdt, double dnodt, double domdt, double argpo, double argpdot, + double t, double tc, double gsto, double xfact, double xlamo, + double no, + double& atime, double& em, double& argpm, double& inclm, double& xli, + double& mm, double& xni, double& nodem, double& dndt, double& nm + ) +{ + const double twopi = 2.0 * pi; + int iretn , iret; + double delt, ft, theta, x2li, x2omi, xl, xldot , xnddt, xndt, xomi, g22, g32, + g44, g52, g54, fasx2, fasx4, fasx6, rptim , step2, stepn , stepp; + + ft = 0.0; + fasx2 = 0.13130908; + fasx4 = 2.8843198; + fasx6 = 0.37448087; + g22 = 5.7686396; + g32 = 0.95240898; + g44 = 1.8014998; + g52 = 1.0508330; + g54 = 4.4108898; + rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec + stepp = 720.0; + stepn = -720.0; + step2 = 259200.0; + + /* ----------- calculate deep space resonance effects ----------- */ + dndt = 0.0; + theta = fmod(gsto + tc * rptim, twopi); + em = em + dedt * t; + + inclm = inclm + didt * t; + argpm = argpm + domdt * t; + nodem = nodem + dnodt * t; + mm = mm + dmdt * t; + + // sgp4fix for negative inclinations + // the following if statement should be commented out + // if (inclm < 0.0) + // { + // inclm = -inclm; + // argpm = argpm - pi; + // nodem = nodem + pi; + // } + + /* - update resonances : numerical (euler-maclaurin) integration - */ + /* ------------------------- epoch restart ---------------------- */ + // sgp4fix for propagator problems + // the following integration works for negative time steps and periods + // the specific changes are unknown because the original code was so convoluted + + ft = 0.0; + atime = 0.0; + if (irez != 0) + { + if ((atime == 0.0) || ((t >= 0.0) && (atime < 0.0)) || + ((t < 0.0) && (atime >= 0.0))) + { + if (t >= 0.0) + delt = stepp; + else + delt = stepn; + atime = 0.0; + xni = no; + xli = xlamo; + } + iretn = 381; // added for do loop + iret = 0; // added for loop + while (iretn == 381) + { + if ((fabs(t) < fabs(atime)) || (iret == 351)) + { + if (t >= 0.0) + delt = stepn; + else + delt = stepp; + iret = 351; + iretn = 381; + } + else + { + if (t > 0.0) // error if prev if has atime:=0.0 and t:=0.0 (ge) + delt = stepp; + else + delt = stepn; + if (fabs(t - atime) >= stepp) + { + iret = 0; + iretn = 381; + } + else + { + ft = t - atime; + iretn = 0; + } + } + + /* ------------------- dot terms calculated ------------- */ + /* ----------- near - synchronous resonance terms ------- */ + if (irez != 2) + { + xndt = del1 * sin(xli - fasx2) + del2 * sin(2.0 * (xli - fasx4)) + + del3 * sin(3.0 * (xli - fasx6)); + xldot = xni + xfact; + xnddt = del1 * cos(xli - fasx2) + + 2.0 * del2 * cos(2.0 * (xli - fasx4)) + + 3.0 * del3 * cos(3.0 * (xli - fasx6)); + xnddt = xnddt * xldot; + } + else + { + /* --------- near - half-day resonance terms -------- */ + xomi = argpo + argpdot * atime; + x2omi = xomi + xomi; + x2li = xli + xli; + xndt = d2201 * sin(x2omi + xli - g22) + d2211 * sin(xli - g22) + + d3210 * sin(xomi + xli - g32) + d3222 * sin(-xomi + xli - g32)+ + d4410 * sin(x2omi + x2li - g44)+ d4422 * sin(x2li - g44) + + d5220 * sin(xomi + xli - g52) + d5232 * sin(-xomi + xli - g52)+ + d5421 * sin(xomi + x2li - g54) + d5433 * sin(-xomi + x2li - g54); + xldot = xni + xfact; + xnddt = d2201 * cos(x2omi + xli - g22) + d2211 * cos(xli - g22) + + d3210 * cos(xomi + xli - g32) + d3222 * cos(-xomi + xli - g32) + + d5220 * cos(xomi + xli - g52) + d5232 * cos(-xomi + xli - g52) + + 2.0 * (d4410 * cos(x2omi + x2li - g44) + + d4422 * cos(x2li - g44) + d5421 * cos(xomi + x2li - g54) + + d5433 * cos(-xomi + x2li - g54)); + xnddt = xnddt * xldot; + } + + /* ----------------------- integrator ------------------- */ + if (iretn == 381) + { + xli = xli + xldot * delt + xndt * step2; + xni = xni + xndt * delt + xnddt * step2; + atime = atime + delt; + } + } // while iretn = 381 + + nm = xni + xndt * ft + xnddt * ft * ft * 0.5; + xl = xli + xldot * ft + xndt * ft * ft * 0.5; + if (irez != 1) + { + mm = xl - 2.0 * nodem + 2.0 * theta; + dndt = nm - no; + } + else + { + mm = xl - nodem - argpm + theta; + dndt = nm - no; + } + nm = no + dndt; + } + +//#include "debug4.cpp" +} // end dsspace + +/*----------------------------------------------------------------------------- +* +* procedure initl +* +* this procedure initializes the spg4 propagator. all the initialization is +* consolidated here instead of having multiple loops inside other routines. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* ecco - eccentricity 0.0 - 1.0 +* epoch - epoch time in days from jan 0, 1950. 0 hr +* inclo - inclination of satellite +* no - mean motion of satellite +* satn - satellite number +* +* outputs : +* ainv - 1.0 / a +* ao - semi major axis +* con41 - +* con42 - 1.0 - 5.0 cos(i) +* cosio - cosine of inclination +* cosio2 - cosio squared +* eccsq - eccentricity squared +* method - flag for deep space 'd', 'n' +* omeosq - 1.0 - ecco * ecco +* posq - semi-parameter squared +* rp - radius of perigee +* rteosq - square root of (1.0 - ecco*ecco) +* sinio - sine of inclination +* gsto - gst at time of observation rad +* no - mean motion of satellite +* +* locals : +* ak - +* d1 - +* del - +* adel - +* po - +* +* coupling : +* getgravconst +* gstime - find greenwich sidereal time from the julian date +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void initl + ( + int satn, gravconsttype whichconst, + double ecco, double epoch, double inclo, double& no, + char& method, + double& ainv, double& ao, double& con41, double& con42, double& cosio, + double& cosio2,double& eccsq, double& omeosq, double& posq, + double& rp, double& rteosq,double& sinio , double& gsto + ) +{ + /* --------------------- local variables ------------------------ */ + double ak, d1, del, adel, po, x2o3, j2, xke, + tumin, mu, radiusearthkm, j3, j4, j3oj2; + + // sgp4fix use old way of finding gst + int ids70; + double ts70, ds70, tfrac, c1, thgr70, fk5r, c1p2p; + const double twopi = 2.0 * pi; + + /* ----------------------- earth constants ---------------------- */ + // sgp4fix identify constants and allow alternate values + getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); + x2o3 = 2.0 / 3.0; + + /* ------------- calculate auxillary epoch quantities ---------- */ + eccsq = ecco * ecco; + omeosq = 1.0 - eccsq; + rteosq = sqrt(omeosq); + cosio = cos(inclo); + cosio2 = cosio * cosio; + + /* ------------------ un-kozai the mean motion ----------------- */ + ak = pow(xke / no, x2o3); + d1 = 0.75 * j2 * (3.0 * cosio2 - 1.0) / (rteosq * omeosq); + del = d1 / (ak * ak); + adel = ak * (1.0 - del * del - del * + (1.0 / 3.0 + 134.0 * del * del / 81.0)); + del = d1/(adel * adel); + no = no / (1.0 + del); + + ao = pow(xke / no, x2o3); + sinio = sin(inclo); + po = ao * omeosq; + con42 = 1.0 - 5.0 * cosio2; + con41 = -con42-cosio2-cosio2; + ainv = 1.0 / ao; + posq = po * po; + rp = ao * (1.0 - ecco); + method = 'n'; + + // sgp4fix modern approach to finding sidereal timew + // gsto = gstime(epoch + 2433281.5); + + // sgp4fix use old way of finding gst + // count integer number of days from 0 jan 1970 + ts70 = epoch - 7305.0; + ids70 = floor(ts70 + 1.0e-8); + ds70 = ids70; + tfrac = ts70 - ds70; + // find greenwich location at epoch + c1 = 1.72027916940703639e-2; + thgr70= 1.7321343856509374; + fk5r = 5.07551419432269442e-15; + c1p2p = c1 + twopi; + gsto = fmod( thgr70 + c1*ds70 + c1p2p*tfrac + ts70*ts70*fk5r, twopi); + if ( gsto < 0.0 ) + gsto = gsto + twopi; + +//#include "debug5.cpp" +} // end initl + +/*----------------------------------------------------------------------------- +* +* procedure sgp4init +* +* this procedure initializes variables for sgp4. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* satn - satellite number +* bstar - sgp4 type drag coefficient kg/m2er +* ecco - eccentricity +* epoch - epoch time in days from jan 0, 1950. 0 hr +* argpo - argument of perigee (output if ds) +* inclo - inclination +* mo - mean anomaly (output if ds) +* no - mean motion +* nodeo - right ascension of ascending node +* +* outputs : +* satrec - common values for subsequent calls +* return code - non-zero on error. +* 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er +* 2 - mean motion less than 0.0 +* 3 - pert elements, ecc < 0.0 or ecc > 1.0 +* 4 - semi-latus rectum < 0.0 +* 5 - epoch elements are sub-orbital +* 6 - satellite has decayed +* +* locals : +* cnodm , snodm , cosim , sinim , cosomm , sinomm +* cc1sq , cc2 , cc3 +* coef , coef1 +* cosio4 - +* day - +* dndt - +* em - eccentricity +* emsq - eccentricity squared +* eeta - +* etasq - +* gam - +* argpm - argument of perigee +* nodem - +* inclm - inclination +* mm - mean anomaly +* nm - mean motion +* perige - perigee +* pinvsq - +* psisq - +* qzms24 - +* rtemsq - +* s1, s2, s3, s4, s5, s6, s7 - +* sfour - +* ss1, ss2, ss3, ss4, ss5, ss6, ss7 - +* sz1, sz2, sz3 +* sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - +* tc - +* temp - +* temp1, temp2, temp3 - +* tsi - +* xpidot - +* xhdot1 - +* z1, z2, z3 - +* z11, z12, z13, z21, z22, z23, z31, z32, z33 - +* +* coupling : +* getgravconst- +* initl - +* dscom - +* dpper - +* dsinit - +* sgp4 - +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +int sgp4init + ( + gravconsttype whichconst, const int satn, const double epoch, + const double xbstar, const double xecco, const double xargpo, + const double xinclo, const double xmo, const double xno, + const double xnodeo, elsetrec& satrec + ) +{ + /* --------------------- local variables ------------------------ */ + double ao, ainv, con42, cosio, sinio, cosio2, eccsq, + omeosq, posq, rp, rteosq, + cnodm , snodm , cosim , sinim , cosomm, sinomm, cc1sq , + cc2 , cc3 , coef , coef1 , cosio4, day , dndt , + em , emsq , eeta , etasq , gam , argpm , nodem , + inclm , mm , nm , perige, pinvsq, psisq , qzms24, + rtemsq, s1 , s2 , s3 , s4 , s5 , s6 , + s7 , sfour , ss1 = 0 , ss2 = 0 , ss3 = 0 , ss4 = 0 , ss5 = 0 , + ss6 = 0 , ss7 = 0 , sz1 = 0 , sz2 = 0 , sz3 = 0 , sz11 = 0 , sz12 = 0 , + sz13 = 0 , sz21 = 0 , sz22 = 0 , sz23 = 0 , sz31 = 0 , sz32 = 0 , sz33 = 0 , + tc , temp , temp1 , temp2 , temp3 , tsi , xpidot, + xhdot1, z1 , z2 , z3 , z11 , z12 , z13 , + z21 , z22 , z23 , z31 , z32 , z33, + qzms2t, ss, j2, j3oj2, j4, x2o3, r[3], v[3], + tumin, mu, radiusearthkm, xke, j3; + + /* ------------------------ initialization --------------------- */ + // sgp4fix divisor for divide by zero check on inclination + const double temp4 = 1.0 + cos(pi-1.0e-9); + + /* ----------- set all near earth variables to zero ------------ */ + satrec.isimp = 0; satrec.method = 'n'; satrec.aycof = 0.0; + satrec.con41 = 0.0; satrec.cc1 = 0.0; satrec.cc4 = 0.0; + satrec.cc5 = 0.0; satrec.d2 = 0.0; satrec.d3 = 0.0; + satrec.d4 = 0.0; satrec.delmo = 0.0; satrec.eta = 0.0; + satrec.argpdot = 0.0; satrec.omgcof = 0.0; satrec.sinmao = 0.0; + satrec.t = 0.0; satrec.t2cof = 0.0; satrec.t3cof = 0.0; + satrec.t4cof = 0.0; satrec.t5cof = 0.0; satrec.x1mth2 = 0.0; + satrec.x7thm1 = 0.0; satrec.mdot = 0.0; satrec.nodedot = 0.0; + satrec.xlcof = 0.0; satrec.xmcof = 0.0; satrec.nodecf = 0.0; + + /* ----------- set all deep space variables to zero ------------ */ + satrec.irez = 0; satrec.d2201 = 0.0; satrec.d2211 = 0.0; + satrec.d3210 = 0.0; satrec.d3222 = 0.0; satrec.d4410 = 0.0; + satrec.d4422 = 0.0; satrec.d5220 = 0.0; satrec.d5232 = 0.0; + satrec.d5421 = 0.0; satrec.d5433 = 0.0; satrec.dedt = 0.0; + satrec.del1 = 0.0; satrec.del2 = 0.0; satrec.del3 = 0.0; + satrec.didt = 0.0; satrec.dmdt = 0.0; satrec.dnodt = 0.0; + satrec.domdt = 0.0; satrec.e3 = 0.0; satrec.ee2 = 0.0; + satrec.peo = 0.0; satrec.pgho = 0.0; satrec.pho = 0.0; + satrec.pinco = 0.0; satrec.plo = 0.0; satrec.se2 = 0.0; + satrec.se3 = 0.0; satrec.sgh2 = 0.0; satrec.sgh3 = 0.0; + satrec.sgh4 = 0.0; satrec.sh2 = 0.0; satrec.sh3 = 0.0; + satrec.si2 = 0.0; satrec.si3 = 0.0; satrec.sl2 = 0.0; + satrec.sl3 = 0.0; satrec.sl4 = 0.0; satrec.gsto = 0.0; + satrec.xfact = 0.0; satrec.xgh2 = 0.0; satrec.xgh3 = 0.0; + satrec.xgh4 = 0.0; satrec.xh2 = 0.0; satrec.xh3 = 0.0; + satrec.xi2 = 0.0; satrec.xi3 = 0.0; satrec.xl2 = 0.0; + satrec.xl3 = 0.0; satrec.xl4 = 0.0; satrec.xlamo = 0.0; + satrec.zmol = 0.0; satrec.zmos = 0.0; satrec.atime = 0.0; + satrec.xli = 0.0; satrec.xni = 0.0; + + // sgp4fix - note the following variables are also passed directly via satrec. + // it is possible to streamline the sgp4init call by deleting the "x" + // variables, but the user would need to set the satrec.* values first. we + // include the additional assignments in case twoline2rv is not used. + satrec.bstar = xbstar; + satrec.ecco = xecco; + satrec.argpo = xargpo; + satrec.inclo = xinclo; + satrec.mo = xmo; + satrec.no = xno; + satrec.nodeo = xnodeo; + + /* ------------------------ earth constants ----------------------- */ + // sgp4fix identify constants and allow alternate values + getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); + ss = 78.0 / radiusearthkm + 1.0; + qzms2t = pow(((120.0 - 78.0) / radiusearthkm), 4); + x2o3 = 2.0 / 3.0; + + satrec.init = 'y'; + satrec.t = 0.0; + + initl + ( + satn, whichconst, satrec.ecco, epoch, satrec.inclo, satrec.no, satrec.method, + ainv, ao, satrec.con41, con42, cosio, cosio2, eccsq, omeosq, + posq, rp, rteosq, sinio, satrec.gsto + ); + satrec.error = 0; + + if (rp < 1.0) + { +// printf("# *** satn%d epoch elts sub-orbital ***\n", satn); + satrec.error = 5; + } + + if ((omeosq >= 0.0 ) || ( satrec.no >= 0.0)) + { + satrec.isimp = 0; + if (rp < (220.0 / radiusearthkm + 1.0)) + satrec.isimp = 1; + sfour = ss; + qzms24 = qzms2t; + perige = (rp - 1.0) * radiusearthkm; + + /* - for perigees below 156 km, s and qoms2t are altered - */ + if (perige < 156.0) + { + sfour = perige - 78.0; + if (perige < 98.0) + sfour = 20.0; + qzms24 = pow(((120.0 - sfour) / radiusearthkm), 4.0); + sfour = sfour / radiusearthkm + 1.0; + } + pinvsq = 1.0 / posq; + + tsi = 1.0 / (ao - sfour); + satrec.eta = ao * satrec.ecco * tsi; + etasq = satrec.eta * satrec.eta; + eeta = satrec.ecco * satrec.eta; + psisq = fabs(1.0 - etasq); + coef = qzms24 * pow(tsi, 4.0); + coef1 = coef / pow(psisq, 3.5); + cc2 = coef1 * satrec.no * (ao * (1.0 + 1.5 * etasq + eeta * + (4.0 + etasq)) + 0.375 * j2 * tsi / psisq * satrec.con41 * + (8.0 + 3.0 * etasq * (8.0 + etasq))); + satrec.cc1 = satrec.bstar * cc2; + cc3 = 0.0; + if (satrec.ecco > 1.0e-4) + cc3 = -2.0 * coef * tsi * j3oj2 * satrec.no * sinio / satrec.ecco; + satrec.x1mth2 = 1.0 - cosio2; + satrec.cc4 = 2.0* satrec.no * coef1 * ao * omeosq * + (satrec.eta * (2.0 + 0.5 * etasq) + satrec.ecco * + (0.5 + 2.0 * etasq) - j2 * tsi / (ao * psisq) * + (-3.0 * satrec.con41 * (1.0 - 2.0 * eeta + etasq * + (1.5 - 0.5 * eeta)) + 0.75 * satrec.x1mth2 * + (2.0 * etasq - eeta * (1.0 + etasq)) * cos(2.0 * satrec.argpo))); + satrec.cc5 = 2.0 * coef1 * ao * omeosq * (1.0 + 2.75 * + (etasq + eeta) + eeta * etasq); + cosio4 = cosio2 * cosio2; + temp1 = 1.5 * j2 * pinvsq * satrec.no; + temp2 = 0.5 * temp1 * j2 * pinvsq; + temp3 = -0.46875 * j4 * pinvsq * pinvsq * satrec.no; + satrec.mdot = satrec.no + 0.5 * temp1 * rteosq * satrec.con41 + 0.0625 * + temp2 * rteosq * (13.0 - 78.0 * cosio2 + 137.0 * cosio4); + satrec.argpdot = -0.5 * temp1 * con42 + 0.0625 * temp2 * + (7.0 - 114.0 * cosio2 + 395.0 * cosio4) + + temp3 * (3.0 - 36.0 * cosio2 + 49.0 * cosio4); + xhdot1 = -temp1 * cosio; + satrec.nodedot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * cosio2) + + 2.0 * temp3 * (3.0 - 7.0 * cosio2)) * cosio; + xpidot = satrec.argpdot+ satrec.nodedot; + satrec.omgcof = satrec.bstar * cc3 * cos(satrec.argpo); + satrec.xmcof = 0.0; + if (satrec.ecco > 1.0e-4) + satrec.xmcof = -x2o3 * coef * satrec.bstar / eeta; + satrec.nodecf = 3.5 * omeosq * xhdot1 * satrec.cc1; + satrec.t2cof = 1.5 * satrec.cc1; + // sgp4fix for divide by zero with xinco = 180 deg + if (fabs(cosio+1.0) > 1.5e-12) + satrec.xlcof = -0.25 * j3oj2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio); + else + satrec.xlcof = -0.25 * j3oj2 * sinio * (3.0 + 5.0 * cosio) / temp4; + satrec.aycof = -0.5 * j3oj2 * sinio; + satrec.delmo = pow((1.0 + satrec.eta * cos(satrec.mo)), 3); + satrec.sinmao = sin(satrec.mo); + satrec.x7thm1 = 7.0 * cosio2 - 1.0; + + /* --------------- deep space initialization ------------- */ + if ((2*pi / satrec.no) >= 225.0) + { + satrec.method = 'd'; + satrec.isimp = 1; + tc = 0.0; + inclm = satrec.inclo; + + dscom + ( + epoch, satrec.ecco, satrec.argpo, tc, satrec.inclo, satrec.nodeo, + satrec.no, snodm, cnodm, sinim, cosim,sinomm, cosomm, + day, satrec.e3, satrec.ee2, em, emsq, gam, + satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, + satrec.plo, rtemsq, satrec.se2, satrec.se3, + satrec.sgh2, satrec.sgh3, satrec.sgh4, + satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, + satrec.sl2, satrec.sl3, satrec.sl4, s1, s2, s3, s4, s5, + s6, s7, ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3, + sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33, + satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, + satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, + satrec.xl3, satrec.xl4, nm, z1, z2, z3, z11, + z12, z13, z21, z22, z23, z31, z32, z33, + satrec.zmol, satrec.zmos + ); + dpper + ( + satrec.e3, satrec.ee2, satrec.peo, satrec.pgho, + satrec.pho, satrec.pinco, satrec.plo, satrec.se2, + satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, + satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, + satrec.sl2, satrec.sl3, satrec.sl4, satrec.t, + satrec.xgh2,satrec.xgh3,satrec.xgh4, satrec.xh2, + satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, + satrec.xl3, satrec.xl4, satrec.zmol, satrec.zmos, inclm, satrec.init, + satrec.ecco, satrec.inclo, satrec.nodeo, satrec.argpo, satrec.mo + ); + + argpm = 0.0; + nodem = 0.0; + mm = 0.0; + + dsinit + ( + whichconst, + cosim, emsq, satrec.argpo, s1, s2, s3, s4, s5, sinim, ss1, ss2, ss3, ss4, + ss5, sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33, satrec.t, tc, + satrec.gsto, satrec.mo, satrec.mdot, satrec.no, satrec.nodeo, + satrec.nodedot, xpidot, z1, z3, z11, z13, z21, z23, z31, z33, + satrec.ecco, eccsq, em, argpm, inclm, mm, nm, nodem, + satrec.irez, satrec.atime, + satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222 , + satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, + satrec.d5421, satrec.d5433, satrec.dedt, satrec.didt, + satrec.dmdt, dndt, satrec.dnodt, satrec.domdt , + satrec.del1, satrec.del2, satrec.del3, satrec.xfact, + satrec.xlamo, satrec.xli, satrec.xni + ); + } + + /* ----------- set variables if not deep space ----------- */ + if (satrec.isimp != 1) + { + cc1sq = satrec.cc1 * satrec.cc1; + satrec.d2 = 4.0 * ao * tsi * cc1sq; + temp = satrec.d2 * tsi * satrec.cc1 / 3.0; + satrec.d3 = (17.0 * ao + sfour) * temp; + satrec.d4 = 0.5 * temp * ao * tsi * (221.0 * ao + 31.0 * sfour) * + satrec.cc1; + satrec.t3cof = satrec.d2 + 2.0 * cc1sq; + satrec.t4cof = 0.25 * (3.0 * satrec.d3 + satrec.cc1 * + (12.0 * satrec.d2 + 10.0 * cc1sq)); + satrec.t5cof = 0.2 * (3.0 * satrec.d4 + + 12.0 * satrec.cc1 * satrec.d3 + + 6.0 * satrec.d2 * satrec.d2 + + 15.0 * cc1sq * (2.0 * satrec.d2 + cc1sq)); + } + } // if omeosq = 0 ... + + /* finally propogate to zero epoch to initialise all others. */ + if(satrec.error == 0) + sgp4(whichconst, satrec, 0.0, r, v); + + satrec.init = 'n'; + +//#include "debug6.cpp" + return satrec.error; +} // end sgp4init + +/*----------------------------------------------------------------------------- +* +* procedure sgp4 +* +* this procedure is the sgp4 prediction model from space command. this is an +* updated and combined version of sgp4 and sdp4, which were originally +* published separately in spacetrack report #3. this version follows the +* methodology from the aiaa paper (2006) describing the history and +* development of the code. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* satrec - initialised structure from sgp4init() call. +* tsince - time eince epoch (minutes) +* +* outputs : +* r - position vector km +* v - velocity km/sec +* return code - non-zero on error. +* 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er +* 2 - mean motion less than 0.0 +* 3 - pert elements, ecc < 0.0 or ecc > 1.0 +* 4 - semi-latus rectum < 0.0 +* 5 - epoch elements are sub-orbital +* 6 - satellite has decayed +* +* locals : +* am - +* axnl, aynl - +* betal - +* cosim , sinim , cosomm , sinomm , cnod , snod , cos2u , +* sin2u , coseo1 , sineo1 , cosi , sini , cosip , sinip , +* cosisq , cossu , sinsu , cosu , sinu +* delm - +* delomg - +* dndt - +* eccm - +* emsq - +* ecose - +* el2 - +* eo1 - +* eccp - +* esine - +* argpm - +* argpp - +* omgadf - +* pl - +* r - +* rtemsq - +* rdotl - +* rl - +* rvdot - +* rvdotl - +* su - +* t2 , t3 , t4 , tc +* tem5, temp , temp1 , temp2 , tempa , tempe , templ +* u , ux , uy , uz , vx , vy , vz +* inclm - inclination +* mm - mean anomaly +* nm - mean motion +* nodem - right asc of ascending node +* xinc - +* xincp - +* xl - +* xlm - +* mp - +* xmdf - +* xmx - +* xmy - +* nodedf - +* xnode - +* nodep - +* np - +* +* coupling : +* getgravconst- +* dpper +* dpspace +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +int sgp4 + ( + gravconsttype whichconst, elsetrec& satrec, double tsince, + double r[3], double v[3] + ) +{ + double am , axnl , aynl , betal , cosim , cnod , + cos2u, coseo1, cosi , cosip , cosisq, cossu , cosu, + delm , delomg, em , emsq , ecose , el2 , eo1 , + ep , esine , argpm, argpp , argpdf, pl, mrt = 0.0, + mvt , rdotl , rl , rvdot , rvdotl, sinim , + sin2u, sineo1, sini , sinip , sinsu , sinu , + snod , su , t2 , t3 , t4 , tem5 , temp, + temp1, temp2 , tempa, tempe , templ , u , ux , + uy , uz , vx , vy , vz , inclm , mm , + nm , nodem, xinc , xincp , xl , xlm , mp , + xmdf , xmx , xmy , nodedf, xnode , nodep, tc , dndt, + twopi, x2o3 , j2 , j3 , tumin, j4 , xke , j3oj2, radiusearthkm, + mu, vkmpersec; + int ktr; + + /* ------------------ set mathematical constants --------------- */ + // sgp4fix divisor for divide by zero check on inclination + const double temp4 = 1.0 + cos(pi-1.0e-9); + twopi = 2.0 * pi; + x2o3 = 2.0 / 3.0; + // sgp4fix identify constants and allow alternate values + getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); + vkmpersec = radiusearthkm * xke/60.0; + + /* --------------------- clear sgp4 error flag ----------------- */ + satrec.t = tsince; + satrec.error = 0; + + /* ------- update for secular gravity and atmospheric drag ----- */ + xmdf = satrec.mo + satrec.mdot * satrec.t; + argpdf = satrec.argpo + satrec.argpdot * satrec.t; + nodedf = satrec.nodeo + satrec.nodedot * satrec.t; + argpm = argpdf; + mm = xmdf; + t2 = satrec.t * satrec.t; + nodem = nodedf + satrec.nodecf * t2; + tempa = 1.0 - satrec.cc1 * satrec.t; + tempe = satrec.bstar * satrec.cc4 * satrec.t; + templ = satrec.t2cof * t2; + + if (satrec.isimp != 1) + { + delomg = satrec.omgcof * satrec.t; + delm = satrec.xmcof * + (pow((1.0 + satrec.eta * cos(xmdf)), 3) - + satrec.delmo); + temp = delomg + delm; + mm = xmdf + temp; + argpm = argpdf - temp; + t3 = t2 * satrec.t; + t4 = t3 * satrec.t; + tempa = tempa - satrec.d2 * t2 - satrec.d3 * t3 - + satrec.d4 * t4; + tempe = tempe + satrec.bstar * satrec.cc5 * (sin(mm) - + satrec.sinmao); + templ = templ + satrec.t3cof * t3 + t4 * (satrec.t4cof + + satrec.t * satrec.t5cof); + } + + nm = satrec.no; + em = satrec.ecco; + inclm = satrec.inclo; + if (satrec.method == 'd') + { + tc = satrec.t; + dspace + ( + satrec.irez, + satrec.d2201, satrec.d2211, satrec.d3210, + satrec.d3222, satrec.d4410, satrec.d4422, + satrec.d5220, satrec.d5232, satrec.d5421, + satrec.d5433, satrec.dedt, satrec.del1, + satrec.del2, satrec.del3, satrec.didt, + satrec.dmdt, satrec.dnodt, satrec.domdt, + satrec.argpo, satrec.argpdot, satrec.t, tc, + satrec.gsto, satrec.xfact, satrec.xlamo, + satrec.no, satrec.atime, + em, argpm, inclm, satrec.xli, mm, satrec.xni, + nodem, dndt, nm + ); + } // if method = d + + if (nm <= 0.0) + { +// printf("# error nm %f\n", nm); + satrec.error = 2; + } + am = pow((xke / nm),x2o3) * tempa * tempa; + nm = xke / pow(am, 1.5); + em = em - tempe; + + // fix tolerance for error recognition + if ((em >= 1.0) || (em < -0.001) || (am < 0.95)) + { +// printf("# error em %f\n", em); + satrec.error = 1; + } + if (em < 0.0) + em = 1.0e-6; + mm = mm + satrec.no * templ; + xlm = mm + argpm + nodem; + emsq = em * em; + temp = 1.0 - emsq; + + nodem = fmod(nodem, twopi); + argpm = fmod(argpm, twopi); + xlm = fmod(xlm, twopi); + mm = fmod(xlm - argpm - nodem, twopi); + + /* ----------------- compute extra mean quantities ------------- */ + sinim = sin(inclm); + cosim = cos(inclm); + + /* -------------------- add lunar-solar periodics -------------- */ + ep = em; + xincp = inclm; + argpp = argpm; + nodep = nodem; + mp = mm; + sinip = sinim; + cosip = cosim; + if (satrec.method == 'd') + { + dpper + ( + satrec.e3, satrec.ee2, satrec.peo, + satrec.pgho, satrec.pho, satrec.pinco, + satrec.plo, satrec.se2, satrec.se3, + satrec.sgh2, satrec.sgh3, satrec.sgh4, + satrec.sh2, satrec.sh3, satrec.si2, + satrec.si3, satrec.sl2, satrec.sl3, + satrec.sl4, satrec.t, satrec.xgh2, + satrec.xgh3, satrec.xgh4, satrec.xh2, + satrec.xh3, satrec.xi2, satrec.xi3, + satrec.xl2, satrec.xl3, satrec.xl4, + satrec.zmol, satrec.zmos, satrec.inclo, + 'n', ep, xincp, nodep, argpp, mp + ); + if (xincp < 0.0) + { + xincp = -xincp; + nodep = nodep + pi; + argpp = argpp - pi; + } + if ((ep < 0.0 ) || ( ep > 1.0)) + { + // printf("# error ep %f\n", ep); + satrec.error = 3; + } + } // if method = d + + /* -------------------- long period periodics ------------------ */ + if (satrec.method == 'd') + { + sinip = sin(xincp); + cosip = cos(xincp); + satrec.aycof = -0.5*j3oj2*sinip; + // sgp4fix for divide by zero for xincp = 180 deg + if (fabs(cosip+1.0) > 1.5e-12) + satrec.xlcof = -0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip) / (1.0 + cosip); + else + satrec.xlcof = -0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip) / temp4; + } + axnl = ep * cos(argpp); + temp = 1.0 / (am * (1.0 - ep * ep)); + aynl = ep* sin(argpp) + temp * satrec.aycof; + xl = mp + argpp + nodep + temp * satrec.xlcof * axnl; + + /* --------------------- solve kepler's equation --------------- */ + u = fmod(xl - nodep, twopi); + eo1 = u; + tem5 = 9999.9; + ktr = 1; + // sgp4fix for kepler iteration + // the following iteration needs better limits on corrections + while (( fabs(tem5) >= 1.0e-12) && (ktr <= 10) ) + { + sineo1 = sin(eo1); + coseo1 = cos(eo1); + tem5 = 1.0 - coseo1 * axnl - sineo1 * aynl; + tem5 = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5; + if(fabs(tem5) >= 0.95) + tem5 = tem5 > 0.0 ? 0.95 : -0.95; + eo1 = eo1 + tem5; + ktr = ktr + 1; + } + + /* ------------- short period preliminary quantities ----------- */ + ecose = axnl*coseo1 + aynl*sineo1; + esine = axnl*sineo1 - aynl*coseo1; + el2 = axnl*axnl + aynl*aynl; + pl = am*(1.0-el2); + if (pl < 0.0) + { +// printf("# error pl %f\n", pl); + satrec.error = 4; + } + else + { + rl = am * (1.0 - ecose); + rdotl = sqrt(am) * esine/rl; + rvdotl = sqrt(pl) / rl; + betal = sqrt(1.0 - el2); + temp = esine / (1.0 + betal); + sinu = am / rl * (sineo1 - aynl - axnl * temp); + cosu = am / rl * (coseo1 - axnl + aynl * temp); + su = atan2(sinu, cosu); + sin2u = (cosu + cosu) * sinu; + cos2u = 1.0 - 2.0 * sinu * sinu; + temp = 1.0 / pl; + temp1 = 0.5 * j2 * temp; + temp2 = temp1 * temp; + + /* -------------- update for short period periodics ------------ */ + if (satrec.method == 'd') + { + cosisq = cosip * cosip; + satrec.con41 = 3.0*cosisq - 1.0; + satrec.x1mth2 = 1.0 - cosisq; + satrec.x7thm1 = 7.0*cosisq - 1.0; + } + mrt = rl * (1.0 - 1.5 * temp2 * betal * satrec.con41) + + 0.5 * temp1 * satrec.x1mth2 * cos2u; + su = su - 0.25 * temp2 * satrec.x7thm1 * sin2u; + xnode = nodep + 1.5 * temp2 * cosip * sin2u; + xinc = xincp + 1.5 * temp2 * cosip * sinip * cos2u; + mvt = rdotl - nm * temp1 * satrec.x1mth2 * sin2u / xke; + rvdot = rvdotl + nm * temp1 * (satrec.x1mth2 * cos2u + + 1.5 * satrec.con41) / xke; + + /* --------------------- orientation vectors ------------------- */ + sinsu = sin(su); + cossu = cos(su); + snod = sin(xnode); + cnod = cos(xnode); + sini = sin(xinc); + cosi = cos(xinc); + xmx = -snod * cosi; + xmy = cnod * cosi; + ux = xmx * sinsu + cnod * cossu; + uy = xmy * sinsu + snod * cossu; + uz = sini * sinsu; + vx = xmx * cossu - cnod * sinsu; + vy = xmy * cossu - snod * sinsu; + vz = sini * cossu; + + /* --------- position and velocity (in km and km/sec) ---------- */ + r[0] = (mrt * ux)* radiusearthkm; + r[1] = (mrt * uy)* radiusearthkm; + r[2] = (mrt * uz)* radiusearthkm; + v[0] = (mvt * ux + rvdot * vx) * vkmpersec; + v[1] = (mvt * uy + rvdot * vy) * vkmpersec; + v[2] = (mvt * uz + rvdot * vz) * vkmpersec; + } // if pl > 0 + + // sgp4fix for decaying satellites + if (mrt < 1.0) + { +// printf("# decay condition %11.6f \n",mrt); + satrec.error = 6; + } + + +//#include "debug7.cpp" + return satrec.error; +} // end sgp4 + + +/* ----------------------------------------------------------------------------- +* +* function gstime +* +* this function finds the greenwich sidereal time. +* +* author : david vallado 719-573-2600 1 mar 2001 +* +* inputs description range / units +* jdut1 - julian date in ut1 days from 4713 bc +* +* outputs : +* gstime - greenwich sidereal time 0 to 2pi rad +* +* locals : +* temp - temporary variable for doubles rad +* tut1 - julian centuries from the +* jan 1, 2000 12 h epoch (ut1) +* +* coupling : +* none +* +* references : +* vallado 2004, 191, eq 3-45 +* --------------------------------------------------------------------------- */ + +double gstime + ( + double jdut1 + ) + { + const double twopi = 2.0 * pi; + const double deg2rad = pi / 180.0; + double temp, tut1; + + tut1 = (jdut1 - 2451545.0) / 36525.0; + temp = -6.2e-6* tut1 * tut1 * tut1 + 0.093104 * tut1 * tut1 + + (876600.0*3600 + 8640184.812866) * tut1 + 67310.54841; // sec + temp = fmod(temp * deg2rad / 240.0, twopi); //360/86400 = 1/240, to deg, to rad + + // ------------------------ check quadrants --------------------- + if (temp < 0.0) + temp += twopi; + + return temp; + } // end gstime + +/* ----------------------------------------------------------------------------- +* +* function getgravconst +* +* this function gets constants for the propagator. note that mu is identified to +* facilitiate comparisons with newer models. the common useage is wgs72. +* +* author : david vallado 719-573-2600 21 jul 2006 +* +* inputs : +* whichconst - which set of constants to use wgs72old, wgs72, wgs84 +* +* outputs : +* tumin - minutes in one time unit +* mu - earth gravitational parameter +* radiusearthkm - radius of the earth in km +* xke - reciprocal of tumin +* j2, j3, j4 - un-normalized zonal harmonic values +* j3oj2 - j3 divided by j2 +* +* locals : +* +* coupling : +* none +* +* references : +* norad spacetrack report #3 +* vallado, crawford, hujsak, kelso 2006 + --------------------------------------------------------------------------- */ + +void getgravconst + ( + gravconsttype whichconst, + double& tumin, + double& mu, + double& radiusearthkm, + double& xke, + double& j2, + double& j3, + double& j4, + double& j3oj2 + ) + { + + switch (whichconst) + { + // -- wgs-72 low precision str#3 constants -- + case wgs72old: + mu = 398600.79964; // in km3 / s2 + radiusearthkm = 6378.135; // km + xke = 0.0743669161; + tumin = 1.0 / xke; + j2 = 0.001082616; + j3 = -0.00000253881; + j4 = -0.00000165597; + j3oj2 = j3 / j2; + break; + // ------------ wgs-72 constants ------------ + case wgs72: + mu = 398600.8; // in km3 / s2 + radiusearthkm = 6378.135; // km + xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); + tumin = 1.0 / xke; + j2 = 0.001082616; + j3 = -0.00000253881; + j4 = -0.00000165597; + j3oj2 = j3 / j2; + break; + case wgs84: + // ------------ wgs-84 constants ------------ + mu = 398600.5; // in km3 / s2 + radiusearthkm = 6378.137; // km + xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); + tumin = 1.0 / xke; + j2 = 0.00108262998905; + j3 = -0.00000253215306; + j4 = -0.00000161098761; + j3oj2 = j3 / j2; + break; + default: + fprintf(stderr,"unknown gravity option (%d)\n",whichconst); + break; + } + + } // end getgravconst + + + + + diff --git a/contrib/sgp4/sgp4unit.h b/contrib/sgp4/sgp4unit.h index 48c113d7..f16acbd9 100644 --- a/contrib/sgp4/sgp4unit.h +++ b/contrib/sgp4/sgp4unit.h @@ -1,117 +1,117 @@ -#ifndef _sgp4unit_ -#define _sgp4unit_ -/* ---------------------------------------------------------------- -* -* sgp4unit.h -* -* this file contains the sgp4 procedures for analytical propagation -* of a satellite. the code was originally released in the 1980 and 1986 -* spacetrack papers. a detailed discussion of the theory and history -* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, -* and kelso. -* -* companion code for -* fundamentals of astrodynamics and applications -* 2007 -* by david vallado -* -* (w) 719-573-2600, email dvallado@agi.com -* -* current : -* 20 apr 07 david vallado -* misc fixes for constants -* changes : -* 11 aug 06 david vallado -* chg lyddane choice back to strn3, constants, misc doc -* 15 dec 05 david vallado -* misc fixes -* 26 jul 05 david vallado -* fixes for paper -* note that each fix is preceded by a -* comment with "sgp4fix" and an explanation of -* what was changed -* 10 aug 04 david vallado -* 2nd printing baseline working -* 14 may 01 david vallado -* 2nd edition baseline -* 80 norad -* original baseline -* ---------------------------------------------------------------- */ - -#include -#include - -// -------------------------- structure declarations ---------------------------- -typedef enum -{ - wgs72old, - wgs72, - wgs84 -} gravconsttype; - -typedef struct elsetrec -{ - long int satnum; - int epochyr, epochtynumrev; - int error; - char init, method; - - /* Near Earth */ - int isimp; - double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 , - delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof , - t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof , - nodecf; - - /* Deep Space */ - int irez; - double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 , - d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt , - dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco , - plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 , - si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 , - xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 , - xl4 , xlamo , zmol , zmos , atime , xli , xni; - - double a , altp , alta , epochdays, jdsatepoch , nddot , ndot , - bstar , rcse , inclo , nodeo , ecco , argpo , mo , - no; -} elsetrec; - -// --------------------------- function declarations ---------------------------- -int sgp4init - ( - gravconsttype whichconst, const int satn, const double epoch, - const double xbstar, const double xecco, const double xargpo, - const double xinclo, const double xmo, const double xno, - const double xnodeo, - elsetrec& satrec - ); - -int sgp4 - ( - gravconsttype whichconst, - elsetrec& satrec, double tsince, - double r[], double v[] - ); - -double gstime - ( - double - ); - -void getgravconst - ( - gravconsttype, - double&, - double&, - double&, - double&, - double&, - double&, - double&, - double& - ); - -#endif - +#ifndef _sgp4unit_ +#define _sgp4unit_ +/* ---------------------------------------------------------------- +* +* sgp4unit.h +* +* this file contains the sgp4 procedures for analytical propagation +* of a satellite. the code was originally released in the 1980 and 1986 +* spacetrack papers. a detailed discussion of the theory and history +* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, +* and kelso. +* +* companion code for +* fundamentals of astrodynamics and applications +* 2007 +* by david vallado +* +* (w) 719-573-2600, email dvallado@agi.com +* +* current : +* 20 apr 07 david vallado +* misc fixes for constants +* changes : +* 11 aug 06 david vallado +* chg lyddane choice back to strn3, constants, misc doc +* 15 dec 05 david vallado +* misc fixes +* 26 jul 05 david vallado +* fixes for paper +* note that each fix is preceded by a +* comment with "sgp4fix" and an explanation of +* what was changed +* 10 aug 04 david vallado +* 2nd printing baseline working +* 14 may 01 david vallado +* 2nd edition baseline +* 80 norad +* original baseline +* ---------------------------------------------------------------- */ + +#include +#include + +// -------------------------- structure declarations ---------------------------- +typedef enum +{ + wgs72old, + wgs72, + wgs84 +} gravconsttype; + +typedef struct elsetrec +{ + long int satnum; + int epochyr, epochtynumrev; + int error; + char init, method; + + /* Near Earth */ + int isimp; + double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 , + delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof , + t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof , + nodecf; + + /* Deep Space */ + int irez; + double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 , + d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt , + dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco , + plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 , + si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 , + xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 , + xl4 , xlamo , zmol , zmos , atime , xli , xni; + + double a , altp , alta , epochdays, jdsatepoch , nddot , ndot , + bstar , rcse , inclo , nodeo , ecco , argpo , mo , + no; +} elsetrec; + +// --------------------------- function declarations ---------------------------- +int sgp4init + ( + gravconsttype whichconst, const int satn, const double epoch, + const double xbstar, const double xecco, const double xargpo, + const double xinclo, const double xmo, const double xno, + const double xnodeo, + elsetrec& satrec + ); + +int sgp4 + ( + gravconsttype whichconst, + elsetrec& satrec, double tsince, + double r[], double v[] + ); + +double gstime + ( + double + ); + +void getgravconst + ( + gravconsttype, + double&, + double&, + double&, + double&, + double&, + double&, + double&, + double& + ); + +#endif + diff --git a/globalfunctions/timevalOperations.cpp b/globalfunctions/timevalOperations.cpp index ae49ef21..1228da04 100644 --- a/globalfunctions/timevalOperations.cpp +++ b/globalfunctions/timevalOperations.cpp @@ -1,99 +1,99 @@ -#include "timevalOperations.h" - -timeval& operator+=(timeval& lhs, const timeval& rhs) { - int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; - sum += rhs.tv_sec * 1000000. + rhs.tv_usec; - lhs.tv_sec = sum / 1000000; - lhs.tv_usec = sum - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator+(timeval lhs, const timeval& rhs) { - lhs += rhs; - return lhs; -} - -timeval& operator-=(timeval& lhs, const timeval& rhs) { - int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; - sum -= rhs.tv_sec * 1000000. + rhs.tv_usec; - lhs.tv_sec = sum / 1000000; - lhs.tv_usec = sum - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator-(timeval lhs, const timeval& rhs) { - lhs -= rhs; - return lhs; -} - -double operator/(const timeval& lhs, const timeval& rhs) { - double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 / rhs64; -} - -timeval& operator/=(timeval& lhs, double scalar) { - int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; - product /= scalar; - lhs.tv_sec = product / 1000000; - lhs.tv_usec = product - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator/(timeval lhs, double scalar) { - lhs /= scalar; - return lhs; -} - -timeval& operator*=(timeval& lhs, double scalar) { - int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; - product *= scalar; - lhs.tv_sec = product / 1000000; - lhs.tv_usec = product - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator*(timeval lhs, double scalar) { - lhs *= scalar; - return lhs; -} - -timeval operator*(double scalar, timeval rhs) { - rhs *= scalar; - return rhs; -} - -bool operator==(const timeval& lhs, const timeval& rhs) { - int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 == rhs64; -} -bool operator!=(const timeval& lhs, const timeval& rhs) { - return !operator==(lhs, rhs); -} -bool operator<(const timeval& lhs, const timeval& rhs) { - int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 < rhs64; -} -bool operator>(const timeval& lhs, const timeval& rhs) { - return operator<(rhs, lhs); -} -bool operator<=(const timeval& lhs, const timeval& rhs) { - return !operator>(lhs, rhs); -} -bool operator>=(const timeval& lhs, const timeval& rhs) { - return !operator<(lhs, rhs); -} - -double timevalOperations::toDouble(const timeval timeval) { - double result = timeval.tv_sec * 1000000. + timeval.tv_usec; - return result / 1000000.; -} - -timeval timevalOperations::toTimeval(const double seconds) { - timeval tval; - tval.tv_sec = seconds; - tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6); - return tval; -} +#include "timevalOperations.h" + +timeval& operator+=(timeval& lhs, const timeval& rhs) { + int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; + sum += rhs.tv_sec * 1000000. + rhs.tv_usec; + lhs.tv_sec = sum / 1000000; + lhs.tv_usec = sum - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator+(timeval lhs, const timeval& rhs) { + lhs += rhs; + return lhs; +} + +timeval& operator-=(timeval& lhs, const timeval& rhs) { + int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; + sum -= rhs.tv_sec * 1000000. + rhs.tv_usec; + lhs.tv_sec = sum / 1000000; + lhs.tv_usec = sum - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator-(timeval lhs, const timeval& rhs) { + lhs -= rhs; + return lhs; +} + +double operator/(const timeval& lhs, const timeval& rhs) { + double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 / rhs64; +} + +timeval& operator/=(timeval& lhs, double scalar) { + int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; + product /= scalar; + lhs.tv_sec = product / 1000000; + lhs.tv_usec = product - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator/(timeval lhs, double scalar) { + lhs /= scalar; + return lhs; +} + +timeval& operator*=(timeval& lhs, double scalar) { + int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; + product *= scalar; + lhs.tv_sec = product / 1000000; + lhs.tv_usec = product - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator*(timeval lhs, double scalar) { + lhs *= scalar; + return lhs; +} + +timeval operator*(double scalar, timeval rhs) { + rhs *= scalar; + return rhs; +} + +bool operator==(const timeval& lhs, const timeval& rhs) { + int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 == rhs64; +} +bool operator!=(const timeval& lhs, const timeval& rhs) { + return !operator==(lhs, rhs); +} +bool operator<(const timeval& lhs, const timeval& rhs) { + int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 < rhs64; +} +bool operator>(const timeval& lhs, const timeval& rhs) { + return operator<(rhs, lhs); +} +bool operator<=(const timeval& lhs, const timeval& rhs) { + return !operator>(lhs, rhs); +} +bool operator>=(const timeval& lhs, const timeval& rhs) { + return !operator<(lhs, rhs); +} + +double timevalOperations::toDouble(const timeval timeval) { + double result = timeval.tv_sec * 1000000. + timeval.tv_usec; + return result / 1000000.; +} + +timeval timevalOperations::toTimeval(const double seconds) { + timeval tval; + tval.tv_sec = seconds; + tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6); + return tval; +} diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index 8c831bbe..dd1e48ca 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -1,95 +1,95 @@ -#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" -#include "../../osal/FreeRTOS/TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { - handle = TaskManagement::getCurrentTaskHandle(); - if(handle == nullptr) { - sif::error << "Could not retrieve task handle. Please ensure the" - "constructor was called inside a task." << std::endl; - } - xTaskNotifyGive(handle); -} - -BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { - // Clear notification value on destruction. - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); -} - -ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - TickType_t timeout = 0; - if(timeoutType == TimeoutType::POLLING) { - timeout = 0; - } - else if(timeoutType == TimeoutType::WAITING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - else { - timeout = portMAX_DELAY; - } - return acquireWithTickTimeout(timeoutType, timeout); -} - -ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( - TimeoutType timeoutType, TickType_t timeoutTicks) { - BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t BinarySemaphoreUsingTask::release() { - return release(this->handle); -} - -ReturnValue_t BinarySemaphoreUsingTask::release( - TaskHandle_t taskHandle) { - if(getSemaphoreCounter(taskHandle) == 1) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - BaseType_t returncode = xTaskNotifyGive(taskHandle); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { - return handle; -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { - return getSemaphoreCounter(this->handle); -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( - TaskHandle_t taskHandle) { - uint32_t notificationValue; - xTaskNotifyAndQuery(taskHandle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - -// Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( - TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { - if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { - uint32_t notificationValue = 0; - xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, - higherPriorityTaskWoken); - return notificationValue; -} +#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "Could not retrieve task handle. Please ensure the" + "constructor was called inside a task." << std::endl; + } + xTaskNotifyGive(handle); +} + +BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { + // Clear notification value on destruction. + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + TickType_t timeout = 0; + if(timeoutType == TimeoutType::POLLING) { + timeout = 0; + } + else if(timeoutType == TimeoutType::WAITING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + else { + timeout = portMAX_DELAY; + } + return acquireWithTickTimeout(timeoutType, timeout); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( + TimeoutType timeoutType, TickType_t timeoutTicks) { + BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphoreUsingTask::release() { + return release(this->handle); +} + +ReturnValue_t BinarySemaphoreUsingTask::release( + TaskHandle_t taskHandle) { + if(getSemaphoreCounter(taskHandle) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + BaseType_t returncode = xTaskNotifyGive(taskHandle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { + return handle; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { + return getSemaphoreCounter(this->handle); +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( + TaskHandle_t taskHandle) { + uint32_t notificationValue; + xTaskNotifyAndQuery(taskHandle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { + if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue = 0; + xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index 2d2cf159..f3c0b0ea 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -1,76 +1,76 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/SemaphoreIF.h" - -#include -#include - -/** - * @brief Binary Semaphore implementation using the task notification value. - * The notification value should therefore not be used - * for other purposes. - * @details - * Additional information: https://www.freertos.org/RTOS-task-notifications.html - * and general semaphore documentation. - */ -class BinarySemaphoreUsingTask: public SemaphoreIF, - public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! @brief Default ctor - BinarySemaphoreUsingTask(); - //! @brief Default dtor - virtual~ BinarySemaphoreUsingTask(); - - ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = portMAX_DELAY) override; - ReturnValue_t release() override; - uint8_t getSemaphoreCounter() const override; - static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, - BaseType_t* higherPriorityTaskWoken); - - /** - * Same as acquire() with timeout in FreeRTOS ticks. - * @param timeoutTicks - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - ReturnValue_t acquireWithTickTimeout( - TimeoutType timeoutType = TimeoutType::BLOCKING, - TickType_t timeoutTicks = portMAX_DELAY); - - /** - * Get handle to the task related to the semaphore. - * @return - */ - TaskHandle_t getTaskHandle(); - - /** - * Wrapper function to give back semaphore from handle - * @param semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - static ReturnValue_t release(TaskHandle_t taskToNotify); - - /** - * 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. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, - BaseType_t * higherPriorityTaskWoken); - -protected: - TaskHandle_t handle; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" + +#include +#include + +/** + * @brief Binary Semaphore implementation using the task notification value. + * The notification value should therefore not be used + * for other purposes. + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ +class BinarySemaphoreUsingTask: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphoreUsingTask(); + //! @brief Default dtor + virtual~ BinarySemaphoreUsingTask(); + + ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, + uint32_t timeoutMs = portMAX_DELAY) override; + ReturnValue_t release() override; + uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, + BaseType_t* higherPriorityTaskWoken); + + /** + * Same as acquire() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t acquireWithTickTimeout( + TimeoutType timeoutType = TimeoutType::BLOCKING, + TickType_t timeoutTicks = portMAX_DELAY); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + + /** + * 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. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t * higherPriorityTaskWoken); + +protected: + TaskHandle_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index f1c78473..8cc3c495 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -1,108 +1,108 @@ -#include "../../osal/FreeRTOS/BinarySemaphore.h" -#include "../../osal/FreeRTOS/TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -BinarySemaphore::BinarySemaphore() { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Semaphore: Binary semaph creation failure" << std::endl; - } - // Initiated semaphore must be given before it can be taken. - xSemaphoreGive(handle); -} - -BinarySemaphore::~BinarySemaphore() { - vSemaphoreDelete(handle); -} - -BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; - } - xSemaphoreGive(handle); -} - -BinarySemaphore& BinarySemaphore::operator =( - BinarySemaphore&& s) { - if(&s != this) { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; - } - xSemaphoreGive(handle); - } - return *this; -} - -ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - TickType_t timeout = 0; - if(timeoutType == TimeoutType::POLLING) { - timeout = 0; - } - else if(timeoutType == TimeoutType::WAITING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - else { - timeout = portMAX_DELAY; - } - return acquireWithTickTimeout(timeoutType, timeout); -} - -ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType, - TickType_t timeoutTicks) { - if(handle == nullptr) { - return SemaphoreIF::SEMAPHORE_INVALID; - } - - BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t BinarySemaphore::release() { - return release(handle); -} - -ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { - if (semaphore == nullptr) { - return SemaphoreIF::SEMAPHORE_INVALID; - } - BaseType_t returncode = xSemaphoreGive(semaphore); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } -} - -uint8_t BinarySemaphore::getSemaphoreCounter() const { - return uxSemaphoreGetCount(handle); -} - -SemaphoreHandle_t BinarySemaphore::getSemaphore() { - return handle; -} - - -// Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphore::releaseFromISR( - SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { - if (semaphore == nullptr) { - return SemaphoreIF::SEMAPHORE_INVALID; - } - BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, - higherPriorityTaskWoken); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } -} +#include "../../osal/FreeRTOS/BinarySemaphore.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +BinarySemaphore::BinarySemaphore() { + handle = xSemaphoreCreateBinary(); + if(handle == nullptr) { + sif::error << "Semaphore: Binary semaph creation failure" << std::endl; + } + // Initiated semaphore must be given before it can be taken. + xSemaphoreGive(handle); +} + +BinarySemaphore::~BinarySemaphore() { + vSemaphoreDelete(handle); +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + handle = xSemaphoreCreateBinary(); + if(handle == nullptr) { + sif::error << "Binary semaphore creation failure" << std::endl; + } + xSemaphoreGive(handle); +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + if(&s != this) { + handle = xSemaphoreCreateBinary(); + if(handle == nullptr) { + sif::error << "Binary semaphore creation failure" << std::endl; + } + xSemaphoreGive(handle); + } + return *this; +} + +ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + TickType_t timeout = 0; + if(timeoutType == TimeoutType::POLLING) { + timeout = 0; + } + else if(timeoutType == TimeoutType::WAITING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + else { + timeout = portMAX_DELAY; + } + return acquireWithTickTimeout(timeoutType, timeout); +} + +ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType, + TickType_t timeoutTicks) { + if(handle == nullptr) { + return SemaphoreIF::SEMAPHORE_INVALID; + } + + BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::release() { + return release(handle); +} + +ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { + if (semaphore == nullptr) { + return SemaphoreIF::SEMAPHORE_INVALID; + } + BaseType_t returncode = xSemaphoreGive(semaphore); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + return uxSemaphoreGetCount(handle); +} + +SemaphoreHandle_t BinarySemaphore::getSemaphore() { + return handle; +} + + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphore::releaseFromISR( + SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { + if (semaphore == nullptr) { + return SemaphoreIF::SEMAPHORE_INVALID; + } + BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, + higherPriorityTaskWoken); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } +} diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 5a32088a..c6cedc53 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -1,107 +1,107 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/SemaphoreIF.h" - -#include -#include - -/** - * @brief OS Tool to achieve synchronization of between tasks or between - * task and ISR. The default semaphore implementation creates a - * binary semaphore, which can only be taken once. - * @details - * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html - * - * Please note that if the semaphore implementation is only related to - * the synchronization of one task, the new task notifications can be used, - * also see the BinSemaphUsingTask and CountingSemaphUsingTask classes. - * These use the task notification value instead of a queue and are - * faster and more efficient. - * - * @author R. Mueller - * @ingroup osal - */ -class BinarySemaphore: public SemaphoreIF, - public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! @brief Default ctor - BinarySemaphore(); - //! @brief Copy ctor, deleted explicitely. - BinarySemaphore(const BinarySemaphore&) = delete; - //! @brief Copy assignment, deleted explicitely. - BinarySemaphore& operator=(const BinarySemaphore&) = delete; - //! @brief Move ctor - BinarySemaphore (BinarySemaphore &&); - //! @brief Move assignment - BinarySemaphore & operator=(BinarySemaphore &&); - //! @brief Destructor - virtual ~BinarySemaphore(); - - uint8_t getSemaphoreCounter() const override; - - /** - * 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 SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquire(TimeoutType timeoutType = - TimeoutType::BLOCKING, uint32_t timeoutMs = portMAX_DELAY) override; - - /** - * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. - * @param timeoutTicks - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType = - TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY); - - /** - * Release the binary semaphore. - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is - * already available. - */ - ReturnValue_t release() override; - - /** - * Get Handle to the semaphore. - * @return - */ - SemaphoreHandle_t getSemaphore(); - - /** - * Wrapper function to give back semaphore from handle - * @param semaphore - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is - * already available. - */ - static ReturnValue_t release(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. A context switch from an ISR should - * then be requested (see TaskManagement functions) - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is - * already available. - */ - static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore, - BaseType_t * higherPriorityTaskWoken); - -protected: - SemaphoreHandle_t handle; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" + +#include +#include + +/** + * @brief OS Tool to achieve synchronization of between tasks or between + * task and ISR. The default semaphore implementation creates a + * binary semaphore, which can only be taken once. + * @details + * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html + * + * Please note that if the semaphore implementation is only related to + * the synchronization of one task, the new task notifications can be used, + * also see the BinSemaphUsingTask and CountingSemaphUsingTask classes. + * These use the task notification value instead of a queue and are + * faster and more efficient. + * + * @author R. Mueller + * @ingroup osal + */ +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphore(); + //! @brief Copy ctor, deleted explicitely. + BinarySemaphore(const BinarySemaphore&) = delete; + //! @brief Copy assignment, deleted explicitely. + BinarySemaphore& operator=(const BinarySemaphore&) = delete; + //! @brief Move ctor + BinarySemaphore (BinarySemaphore &&); + //! @brief Move assignment + BinarySemaphore & operator=(BinarySemaphore &&); + //! @brief Destructor + virtual ~BinarySemaphore(); + + uint8_t getSemaphoreCounter() const override; + + /** + * 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 SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(TimeoutType timeoutType = + TimeoutType::BLOCKING, uint32_t timeoutMs = portMAX_DELAY) override; + + /** + * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType = + TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY); + + /** + * Release the binary semaphore. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + ReturnValue_t release() override; + + /** + * Get Handle to the semaphore. + * @return + */ + SemaphoreHandle_t getSemaphore(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + static ReturnValue_t release(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. A context switch from an ISR should + * then be requested (see TaskManagement functions) + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore, + BaseType_t * higherPriorityTaskWoken); + +protected: + SemaphoreHandle_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index e66671ac..a47341bc 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -1,114 +1,114 @@ -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" -#include "../../osal/FreeRTOS/TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, - uint8_t initCount): maxCount(maxCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - handle = TaskManagement::getCurrentTaskHandle(); - if(handle == nullptr) { - sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " - "handle. Please ensure the constructor was called inside a " - "task." << std::endl; - } - - uint32_t oldNotificationValue; - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, - &oldNotificationValue); - if(oldNotificationValue != 0) { - sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " - "current notification value is not 0. Please ensure the " - "notification value is not used for other purposes!" << std::endl; - } - for(int i = 0; i < initCount; i++) { - xTaskNotifyGive(handle); - } -} - -CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { - // Clear notification value on destruction. - // If this is not desired, don't call the destructor - // (or implement a boolean which disables the reset) - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); -} - -ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - TickType_t timeout = 0; - if(timeoutType == TimeoutType::POLLING) { - timeout = 0; - } - else if(timeoutType == TimeoutType::WAITING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - else { - timeout = portMAX_DELAY; - } - return acquireWithTickTimeout(timeoutType, timeout); - -} - -ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( - TimeoutType timeoutType, TickType_t timeoutTicks) { - // Decrement notfication value without resetting it. - BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); - if (getSemaphoreCounter() == oldCount - 1) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t CountingSemaphoreUsingTask::release() { - if(getSemaphoreCounter() == maxCount) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - return release(handle); -} - -ReturnValue_t CountingSemaphoreUsingTask::release( - TaskHandle_t taskToNotify) { - BaseType_t returncode = xTaskNotifyGive(taskToNotify); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } -} - - -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { - uint32_t notificationValue = 0; - xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - -TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { - return handle; -} - -ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( - TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { - vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { - uint32_t notificationValue; - xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, - higherPriorityTaskWoken); - return notificationValue; -} - -uint8_t CountingSemaphoreUsingTask::getMaxCount() const { - return maxCount; -} +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, + uint8_t initCount): maxCount(maxCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " + "handle. Please ensure the constructor was called inside a " + "task." << std::endl; + } + + uint32_t oldNotificationValue; + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, + &oldNotificationValue); + if(oldNotificationValue != 0) { + sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " + "current notification value is not 0. Please ensure the " + "notification value is not used for other purposes!" << std::endl; + } + for(int i = 0; i < initCount; i++) { + xTaskNotifyGive(handle); + } +} + +CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { + // Clear notification value on destruction. + // If this is not desired, don't call the destructor + // (or implement a boolean which disables the reset) + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + +ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + TickType_t timeout = 0; + if(timeoutType == TimeoutType::POLLING) { + timeout = 0; + } + else if(timeoutType == TimeoutType::WAITING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + else { + timeout = portMAX_DELAY; + } + return acquireWithTickTimeout(timeoutType, timeout); + +} + +ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( + TimeoutType timeoutType, TickType_t timeoutTicks) { + // Decrement notfication value without resetting it. + BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); + if (getSemaphoreCounter() == oldCount - 1) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t CountingSemaphoreUsingTask::release() { + if(getSemaphoreCounter() == maxCount) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return release(handle); +} + +ReturnValue_t CountingSemaphoreUsingTask::release( + TaskHandle_t taskToNotify) { + BaseType_t returncode = xTaskNotifyGive(taskToNotify); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { + uint32_t notificationValue = 0; + xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { + return handle; +} + +ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { + vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue; + xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} + +uint8_t CountingSemaphoreUsingTask::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index e3733382..8977258c 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -1,102 +1,102 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ - -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" -#include "../../tasks/SemaphoreIF.h" - -extern "C" { -#include -#include -} - -/** - * @brief Couting Semaphore implementation which uses the notification value - * of the task. The notification value should therefore not be used - * for other purposes. - * @details - * Additional information: https://www.freertos.org/RTOS-task-notifications.html - * and general semaphore documentation. - */ -class CountingSemaphoreUsingTask: public SemaphoreIF { -public: - CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); - virtual ~CountingSemaphoreUsingTask(); - - /** - * Acquire the counting semaphore. - * If no semaphores are available, the task will be blocked - * for a maximum of #timeoutMs or until one is given back, - * for example by an ISR or another task. - * @param timeoutMs - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = portMAX_DELAY) override; - - /** - * Release a semaphore, increasing the number of available counting - * semaphores up to the #maxCount value. - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - ReturnValue_t release() override; - - uint8_t getSemaphoreCounter() const override; - /** - * Get the semaphore counter from an ISR. - * @param task - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return - */ - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, - BaseType_t* higherPriorityTaskWoken); - - /** - * Acquire with a timeout value in ticks - * @param timeoutTicks - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquireWithTickTimeout( - TimeoutType timeoutType = TimeoutType::BLOCKING, - TickType_t timeoutTicks = portMAX_DELAY); - - /** - * Get handle to the task related to the semaphore. - * @return - */ - TaskHandle_t getTaskHandle(); - - /** - * Release semaphore of task by supplying task handle - * @param taskToNotify - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - static ReturnValue_t release(TaskHandle_t taskToNotify); - /** - * Release seamphore of a task from an ISR. - * @param taskToNotify - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, - BaseType_t* higherPriorityTaskWoken); - - uint8_t getMaxCount() const; - -private: - TaskHandle_t handle; - const uint8_t maxCount; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ + +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../tasks/SemaphoreIF.h" + +extern "C" { +#include +#include +} + +/** + * @brief Couting Semaphore implementation which uses the notification value + * of the task. The notification value should therefore not be used + * for other purposes. + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ +class CountingSemaphoreUsingTask: public SemaphoreIF { +public: + CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); + virtual ~CountingSemaphoreUsingTask(); + + /** + * Acquire the counting semaphore. + * If no semaphores are available, the task will be blocked + * for a maximum of #timeoutMs or until one is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, + uint32_t timeoutMs = portMAX_DELAY) override; + + /** + * Release a semaphore, increasing the number of available counting + * semaphores up to the #maxCount value. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + ReturnValue_t release() override; + + uint8_t getSemaphoreCounter() const override; + /** + * Get the semaphore counter from an ISR. + * @param task + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return + */ + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, + BaseType_t* higherPriorityTaskWoken); + + /** + * Acquire with a timeout value in ticks + * @param timeoutTicks + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquireWithTickTimeout( + TimeoutType timeoutType = TimeoutType::BLOCKING, + TickType_t timeoutTicks = portMAX_DELAY); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Release semaphore of task by supplying task handle + * @param taskToNotify + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + /** + * Release seamphore of a task from an ISR. + * @param taskToNotify + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t* higherPriorityTaskWoken); + + uint8_t getMaxCount() const; + +private: + TaskHandle_t handle; + const uint8_t maxCount; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index 0b218e54..d1310a6a 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,43 +1,43 @@ -#include "../../osal/FreeRTOS/CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../osal/FreeRTOS/TaskManagement.h" - -#include - -// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in -// free FreeRTOSConfig.h file. -CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): - maxCount(maxCount), initCount(initCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - handle = xSemaphoreCreateCounting(maxCount, initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } -} - -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): - maxCount(other.maxCount), initCount(other.initCount) { - handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } -} - -CountingSemaphore& CountingSemaphore::operator =( - CountingSemaphore&& other) { - handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } - return * this; -} - - -uint8_t CountingSemaphore::getMaxCount() const { - return maxCount; -} +#include "../../osal/FreeRTOS/CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../osal/FreeRTOS/TaskManagement.h" + +#include + +// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in +// free FreeRTOSConfig.h file. +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + handle = xSemaphoreCreateCounting(maxCount, initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } + return * this; +} + + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index 9432ed81..ae2f62ae 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -1,34 +1,34 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ -#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ -#include "../../osal/FreeRTOS/BinarySemaphore.h" - -/** - * @brief Counting semaphores, which can be acquire more than once. - * @details - * See: https://www.freertos.org/CreateCounting.html - * API of counting semaphores is almost identical to binary semaphores, - * so we just inherit from binary semaphore and provide the respective - * constructors. - */ -class CountingSemaphore: public BinarySemaphore { -public: - CountingSemaphore(const uint8_t maxCount, uint8_t initCount); - //! @brief Copy ctor, disabled - CountingSemaphore(const CountingSemaphore&) = delete; - //! @brief Copy assignment, disabled - CountingSemaphore& operator=(const CountingSemaphore&) = delete; - //! @brief Move ctor - CountingSemaphore (CountingSemaphore &&); - //! @brief Move assignment - CountingSemaphore & operator=(CountingSemaphore &&); - - /* Same API as binary semaphore otherwise. acquire() can be called - * until there are not semaphores left and release() can be called - * until maxCount is reached. */ - uint8_t getMaxCount() const; -private: - const uint8_t maxCount; - uint8_t initCount = 0; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#include "../../osal/FreeRTOS/BinarySemaphore.h" + +/** + * @brief Counting semaphores, which can be acquire more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { +public: + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); + + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + uint8_t getMaxCount() const; +private: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 8575cf4a..beb0d096 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -1,59 +1,59 @@ -#include "../../osal/FreeRTOS/BinarySemaphore.h" -#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" -#include "../../osal/FreeRTOS/CountingSemaphore.h" -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" -#include "../../tasks/SemaphoreFactory.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; - -static const uint32_t USE_REGULAR_SEMAPHORES = 0; -static const uint32_t USE_TASK_NOTIFICATIONS = 1; - -SemaphoreFactory::SemaphoreFactory() { -} - -SemaphoreFactory::~SemaphoreFactory() { - delete factoryInstance; -} - -SemaphoreFactory* SemaphoreFactory::instance() { - if (factoryInstance == nullptr){ - factoryInstance = new SemaphoreFactory(); - } - return SemaphoreFactory::factoryInstance; -} - -SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { - if(argument == USE_REGULAR_SEMAPHORES) { - return new BinarySemaphore(); - } - else if(argument == USE_TASK_NOTIFICATIONS) { - return new BinarySemaphoreUsingTask(); - } - else { - sif::warning << "SemaphoreFactory: Invalid argument, return regular" - "binary semaphore" << std::endl; - return new BinarySemaphore(); - } -} - -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, - uint8_t initCount, uint32_t argument) { - if(argument == USE_REGULAR_SEMAPHORES) { - return new CountingSemaphore(maxCount, initCount); - } - else if(argument == USE_TASK_NOTIFICATIONS) { - return new CountingSemaphoreUsingTask(maxCount, initCount); - } - else { - sif::warning << "SemaphoreFactory: Invalid argument, return regular" - "binary semaphore" << std::endl; - return new CountingSemaphore(maxCount, initCount); - } - -} - -void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { - delete semaphore; -} +#include "../../osal/FreeRTOS/BinarySemaphore.h" +#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" +#include "../../osal/FreeRTOS/CountingSemaphore.h" +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../tasks/SemaphoreFactory.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +static const uint32_t USE_REGULAR_SEMAPHORES = 0; +static const uint32_t USE_TASK_NOTIFICATIONS = 1; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { + if(argument == USE_REGULAR_SEMAPHORES) { + return new BinarySemaphore(); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new BinarySemaphoreUsingTask(); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new BinarySemaphore(); + } +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, + uint8_t initCount, uint32_t argument) { + if(argument == USE_REGULAR_SEMAPHORES) { + return new CountingSemaphore(maxCount, initCount); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new CountingSemaphoreUsingTask(maxCount, initCount); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new CountingSemaphore(maxCount, initCount); + } + +} + +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index 16682d36..b77f12a9 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -1,24 +1,24 @@ -#include "../../osal/FreeRTOS/TaskManagement.h" - -void TaskManagement::vRequestContextSwitchFromTask() { - 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 - vRequestContextSwitchFromISR(); - } else { - vRequestContextSwitchFromTask(); - } -} - -TaskHandle_t TaskManagement::getCurrentTaskHandle() { - return xTaskGetCurrentTaskHandle(); -} - -size_t TaskManagement::getTaskStackHighWatermark( - TaskHandle_t task) { - return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); -} +#include "../../osal/FreeRTOS/TaskManagement.h" + +void TaskManagement::vRequestContextSwitchFromTask() { + 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 + vRequestContextSwitchFromISR(); + } else { + vRequestContextSwitchFromTask(); + } +} + +TaskHandle_t TaskManagement::getCurrentTaskHandle() { + return xTaskGetCurrentTaskHandle(); +} + +size_t TaskManagement::getTaskStackHighWatermark( + TaskHandle_t task) { + return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); +} diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index 43003d76..4b7fe3eb 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -1,64 +1,64 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ -#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" - -extern "C" { -#include -#include -} -#include - -/** - * Architecture dependant portmacro.h function call. - * Should be implemented in bsp. - */ -extern void vRequestContextSwitchFromISR(); - -/*! - * 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 class CallContext { - TASK = 0x00,//!< task_context - ISR = 0xFF //!< isr_context -}; - - -class TaskManagement { -public: - /** - * @brief 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 vRequestContextSwitchFromTask(void); - - /** - * @return The current task handle - */ - static TaskHandle_t getCurrentTaskHandle(); - - /** - * Get returns the minimum amount of remaining stack space in words - * that was a available to the task since the task started executing. - * Please note that the actual value in bytes depends - * on the stack depth type. - * E.g. on a 32 bit machine, a value of 200 means 800 bytes. - * @return Smallest value of stack remaining since the task was started in - * words. - */ - static size_t getTaskStackHighWatermark( - TaskHandle_t task = nullptr); -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" + +extern "C" { +#include +#include +} +#include + +/** + * Architecture dependant portmacro.h function call. + * Should be implemented in bsp. + */ +extern void vRequestContextSwitchFromISR(); + +/*! + * 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 class CallContext { + TASK = 0x00,//!< task_context + ISR = 0xFF //!< isr_context +}; + + +class TaskManagement { +public: + /** + * @brief 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 vRequestContextSwitchFromTask(void); + + /** + * @return The current task handle + */ + static TaskHandle_t getCurrentTaskHandle(); + + /** + * Get returns the minimum amount of remaining stack space in words + * that was a available to the task since the task started executing. + * Please note that the actual value in bytes depends + * on the stack depth type. + * E.g. on a 32 bit machine, a value of 200 means 800 bytes. + * @return Smallest value of stack remaining since the task was started in + * words. + */ + static size_t getTaskStackHighWatermark( + TaskHandle_t task = nullptr); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp index 5216ff37..8c0eeae7 100644 --- a/osal/linux/BinarySemaphore.cpp +++ b/osal/linux/BinarySemaphore.cpp @@ -1,149 +1,149 @@ -#include "../../osal/linux/BinarySemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -extern "C" { -#include -#include -} - -BinarySemaphore::BinarySemaphore() { - // Using unnamed semaphores for now - initSemaphore(); -} - -BinarySemaphore::~BinarySemaphore() { - sem_destroy(&handle); -} - -BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { - initSemaphore(); -} - -BinarySemaphore& BinarySemaphore::operator =( - BinarySemaphore&& s) { - initSemaphore(); - return * this; -} - -ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - int result = 0; - if(timeoutType == TimeoutType::POLLING) { - result = sem_trywait(&handle); - } - else if(timeoutType == TimeoutType::BLOCKING) { - result = sem_wait(&handle); - } - else if(timeoutType == TimeoutType::WAITING){ - timespec timeOut; - clock_gettime(CLOCK_REALTIME, &timeOut); - uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; - nseconds += timeoutMs * 1000000; - timeOut.tv_sec = nseconds / 1000000000; - timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; - result = sem_timedwait(&handle, &timeOut); - if(result != 0 and errno == EINVAL) { - sif::debug << "BinarySemaphore::acquire: Invalid time value possible" - << std::endl; - } - } - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EAGAIN): - // Operation could not be performed without blocking (for sem_trywait) - case(ETIMEDOUT): - // Semaphore is 0 - return SemaphoreIF::SEMAPHORE_TIMEOUT; - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EINTR): - // Call was interrupted by signal handler - sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." - "Code " << strerror(errno) << std::endl; - /* No break */ - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t BinarySemaphore::release() { - return BinarySemaphore::release(&this->handle); -} - -ReturnValue_t BinarySemaphore::release(sem_t *handle) { - ReturnValue_t countResult = checkCount(handle, 1); - if(countResult != HasReturnvaluesIF::RETURN_OK) { - return countResult; - } - - int result = sem_post(handle); - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EOVERFLOW): - // SEM_MAX_VALUE overflow. This should never happen - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t BinarySemaphore::getSemaphoreCounter() const { - // And another ugly cast :-D - return getSemaphoreCounter(const_cast(&this->handle)); -} - -uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { - int value = 0; - int result = sem_getvalue(handle, &value); - if (result == 0) { - return value; - } - else if(result != 0 and errno == EINVAL) { - // Could be called from interrupt, use lightweight printf - printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); - return 0; - } - else { - // This should never happen. - return 0; - } -} - -void BinarySemaphore::initSemaphore(uint8_t initCount) { - auto result = sem_init(&handle, true, initCount); - if(result == -1) { - switch(errno) { - case(EINVAL): - // Value exceeds SEM_VALUE_MAX - case(ENOSYS): - // System does not support process-shared semaphores - sif::error << "BinarySemaphore: Init failed with" << strerror(errno) - << std::endl; - } - } -} - -ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { - int value = getSemaphoreCounter(handle); - if(value >= maxCount) { - if(maxCount == 1 and value > 1) { - // Binary Semaphore special case. - // This is a config error use lightweight printf is this is called - // from an interrupt - printf("BinarySemaphore::release: Value of binary semaphore greater" - " than 1!\n"); - return HasReturnvaluesIF::RETURN_FAILED; - } - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "../../osal/linux/BinarySemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +extern "C" { +#include +#include +} + +BinarySemaphore::BinarySemaphore() { + // Using unnamed semaphores for now + initSemaphore(); +} + +BinarySemaphore::~BinarySemaphore() { + sem_destroy(&handle); +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + initSemaphore(); +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + initSemaphore(); + return * this; +} + +ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + int result = 0; + if(timeoutType == TimeoutType::POLLING) { + result = sem_trywait(&handle); + } + else if(timeoutType == TimeoutType::BLOCKING) { + result = sem_wait(&handle); + } + else if(timeoutType == TimeoutType::WAITING){ + timespec timeOut; + clock_gettime(CLOCK_REALTIME, &timeOut); + uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; + nseconds += timeoutMs * 1000000; + timeOut.tv_sec = nseconds / 1000000000; + timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; + result = sem_timedwait(&handle, &timeOut); + if(result != 0 and errno == EINVAL) { + sif::debug << "BinarySemaphore::acquire: Invalid time value possible" + << std::endl; + } + } + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EAGAIN): + // Operation could not be performed without blocking (for sem_trywait) + case(ETIMEDOUT): + // Semaphore is 0 + return SemaphoreIF::SEMAPHORE_TIMEOUT; + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EINTR): + // Call was interrupted by signal handler + sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." + "Code " << strerror(errno) << std::endl; + /* No break */ + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t BinarySemaphore::release() { + return BinarySemaphore::release(&this->handle); +} + +ReturnValue_t BinarySemaphore::release(sem_t *handle) { + ReturnValue_t countResult = checkCount(handle, 1); + if(countResult != HasReturnvaluesIF::RETURN_OK) { + return countResult; + } + + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + // And another ugly cast :-D + return getSemaphoreCounter(const_cast(&this->handle)); +} + +uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { + int value = 0; + int result = sem_getvalue(handle, &value); + if (result == 0) { + return value; + } + else if(result != 0 and errno == EINVAL) { + // Could be called from interrupt, use lightweight printf + printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); + return 0; + } + else { + // This should never happen. + return 0; + } +} + +void BinarySemaphore::initSemaphore(uint8_t initCount) { + auto result = sem_init(&handle, true, initCount); + if(result == -1) { + switch(errno) { + case(EINVAL): + // Value exceeds SEM_VALUE_MAX + case(ENOSYS): + // System does not support process-shared semaphores + sif::error << "BinarySemaphore: Init failed with" << strerror(errno) + << std::endl; + } + } +} + +ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { + int value = getSemaphoreCounter(handle); + if(value >= maxCount) { + if(maxCount == 1 and value > 1) { + // Binary Semaphore special case. + // This is a config error use lightweight printf is this is called + // from an interrupt + printf("BinarySemaphore::release: Value of binary semaphore greater" + " than 1!\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/linux/BinarySemaphore.h b/osal/linux/BinarySemaphore.h index 4181de85..e9bb8bb6 100644 --- a/osal/linux/BinarySemaphore.h +++ b/osal/linux/BinarySemaphore.h @@ -1,81 +1,81 @@ -#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ -#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/SemaphoreIF.h" - -extern "C" { -#include -} - -/** - * @brief OS Tool to achieve synchronization of between tasks or between - * task and ISR. The default semaphore implementation creates a - * binary semaphore, which can only be taken once. - * @details - * See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html - * @author R. Mueller - * @ingroup osal - */ -class BinarySemaphore: public SemaphoreIF, - public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! @brief Default ctor - BinarySemaphore(); - //! @brief Copy ctor, deleted explicitely. - BinarySemaphore(const BinarySemaphore&) = delete; - //! @brief Copy assignment, deleted explicitely. - BinarySemaphore& operator=(const BinarySemaphore&) = delete; - //! @brief Move ctor - BinarySemaphore (BinarySemaphore &&); - //! @brief Move assignment - BinarySemaphore & operator=(BinarySemaphore &&); - //! @brief Destructor - virtual ~BinarySemaphore(); - - void initSemaphore(uint8_t initCount = 1); - - uint8_t getSemaphoreCounter() const override; - static uint8_t getSemaphoreCounter(sem_t* handle); - - /** - * 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 SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = 0) override; - - /** - * Release the binary semaphore. - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is - * already available. - */ - virtual ReturnValue_t release() override; - /** - * This static function can be used to release a semaphore by providing - * its handle. - * @param handle - * @return - */ - static ReturnValue_t release(sem_t* handle); - - /** Checks the validity of the semaphore count against a specified - * known maxCount - * @param handle - * @param maxCount - * @return - */ - static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); -protected: - sem_t handle; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" + +extern "C" { +#include +} + +/** + * @brief OS Tool to achieve synchronization of between tasks or between + * task and ISR. The default semaphore implementation creates a + * binary semaphore, which can only be taken once. + * @details + * See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html + * @author R. Mueller + * @ingroup osal + */ +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphore(); + //! @brief Copy ctor, deleted explicitely. + BinarySemaphore(const BinarySemaphore&) = delete; + //! @brief Copy assignment, deleted explicitely. + BinarySemaphore& operator=(const BinarySemaphore&) = delete; + //! @brief Move ctor + BinarySemaphore (BinarySemaphore &&); + //! @brief Move assignment + BinarySemaphore & operator=(BinarySemaphore &&); + //! @brief Destructor + virtual ~BinarySemaphore(); + + void initSemaphore(uint8_t initCount = 1); + + uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(sem_t* handle); + + /** + * 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 SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, + uint32_t timeoutMs = 0) override; + + /** + * Release the binary semaphore. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + virtual ReturnValue_t release() override; + /** + * This static function can be used to release a semaphore by providing + * its handle. + * @param handle + * @return + */ + static ReturnValue_t release(sem_t* handle); + + /** Checks the validity of the semaphore count against a specified + * known maxCount + * @param handle + * @param maxCount + * @return + */ + static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); +protected: + sem_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp index ef32539b..18339399 100644 --- a/osal/linux/CountingSemaphore.cpp +++ b/osal/linux/CountingSemaphore.cpp @@ -1,54 +1,54 @@ -#include "../../osal/linux/CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): - maxCount(maxCount), initCount(initCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - initSemaphore(initCount); -} - -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): - maxCount(other.maxCount), initCount(other.initCount) { - initSemaphore(initCount); -} - -CountingSemaphore& CountingSemaphore::operator =( - CountingSemaphore&& other) { - initSemaphore(other.initCount); - return * this; -} - -ReturnValue_t CountingSemaphore::release() { - ReturnValue_t result = checkCount(&handle, maxCount); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return CountingSemaphore::release(&this->handle); -} - -ReturnValue_t CountingSemaphore::release(sem_t* handle) { - int result = sem_post(handle); - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EOVERFLOW): - // SEM_MAX_VALUE overflow. This should never happen - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t CountingSemaphore::getMaxCount() const { - return maxCount; -} - +#include "../../osal/linux/CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + initSemaphore(initCount); +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + initSemaphore(initCount); +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + initSemaphore(other.initCount); + return * this; +} + +ReturnValue_t CountingSemaphore::release() { + ReturnValue_t result = checkCount(&handle, maxCount); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CountingSemaphore::release(&this->handle); +} + +ReturnValue_t CountingSemaphore::release(sem_t* handle) { + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} + diff --git a/osal/linux/CountingSemaphore.h b/osal/linux/CountingSemaphore.h index afe21a61..e0fbb992 100644 --- a/osal/linux/CountingSemaphore.h +++ b/osal/linux/CountingSemaphore.h @@ -1,37 +1,37 @@ -#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ -#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ -#include "../../osal/linux/BinarySemaphore.h" - -/** - * @brief Counting semaphores, which can be acquired more than once. - * @details - * See: https://www.freertos.org/CreateCounting.html - * API of counting semaphores is almost identical to binary semaphores, - * so we just inherit from binary semaphore and provide the respective - * constructors. - */ -class CountingSemaphore: public BinarySemaphore { -public: - CountingSemaphore(const uint8_t maxCount, uint8_t initCount); - //! @brief Copy ctor, disabled - CountingSemaphore(const CountingSemaphore&) = delete; - //! @brief Copy assignment, disabled - CountingSemaphore& operator=(const CountingSemaphore&) = delete; - //! @brief Move ctor - CountingSemaphore (CountingSemaphore &&); - //! @brief Move assignment - CountingSemaphore & operator=(CountingSemaphore &&); - - ReturnValue_t release() override; - static ReturnValue_t release(sem_t* sem); - /* Same API as binary semaphore otherwise. acquire() can be called - * until there are not semaphores left and release() can be called - * until maxCount is reached. */ - - uint8_t getMaxCount() const; -private: - const uint8_t maxCount; - uint8_t initCount = 0; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#include "../../osal/linux/BinarySemaphore.h" + +/** + * @brief Counting semaphores, which can be acquired more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { +public: + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); + + ReturnValue_t release() override; + static ReturnValue_t release(sem_t* sem); + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + + uint8_t getMaxCount() const; +private: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index bcb5d16f..e4710933 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -1,33 +1,33 @@ -#include "../../tasks/SemaphoreFactory.h" -#include "BinarySemaphore.h" -#include "CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; - -SemaphoreFactory::SemaphoreFactory() { -} - -SemaphoreFactory::~SemaphoreFactory() { - delete factoryInstance; -} - -SemaphoreFactory* SemaphoreFactory::instance() { - if (factoryInstance == nullptr){ - factoryInstance = new SemaphoreFactory(); - } - return SemaphoreFactory::factoryInstance; -} - -SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { - return new BinarySemaphore(); -} - -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, - uint8_t initCount, uint32_t arguments) { - return new CountingSemaphore(maxCount, initCount); -} - -void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { - delete semaphore; -} +#include "../../tasks/SemaphoreFactory.h" +#include "BinarySemaphore.h" +#include "CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { + return new BinarySemaphore(); +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments) { + return new CountingSemaphore(maxCount, initCount); +} + +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/serialize/SerialBufferAdapter.cpp b/serialize/SerialBufferAdapter.cpp index 812cd34b..1c11afd4 100644 --- a/serialize/SerialBufferAdapter.cpp +++ b/serialize/SerialBufferAdapter.cpp @@ -1,129 +1,129 @@ -#include "../serialize/SerialBufferAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include - -template -SerialBufferAdapter::SerialBufferAdapter(const uint8_t* buffer, - count_t bufferLength, bool serializeLength) : - serializeLength(serializeLength), - constBuffer(buffer), buffer(nullptr), - bufferLength(bufferLength) {} - -template -SerialBufferAdapter::SerialBufferAdapter(uint8_t* buffer, - count_t bufferLength, bool serializeLength) : - serializeLength(serializeLength), constBuffer(buffer), buffer(buffer), - bufferLength(bufferLength) {} - - -template -SerialBufferAdapter::~SerialBufferAdapter() { -} - -template -ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, - size_t* size, size_t maxSize, Endianness streamEndianness) const { - if (serializeLength) { - ReturnValue_t result = SerializeAdapter::serialize(&bufferLength, - buffer, size, maxSize, streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - - if (*size + bufferLength > maxSize) { - return BUFFER_TOO_SHORT; - } - - if (this->constBuffer != nullptr) { - std::memcpy(*buffer, this->constBuffer, bufferLength); - } - else if (this->buffer != nullptr) { - // This will propably be never reached, constBuffer should always be - // set if non-const buffer is set. - std::memcpy(*buffer, this->buffer, bufferLength); - } - else { - return HasReturnvaluesIF::RETURN_FAILED; - } - *size += bufferLength; - (*buffer) += bufferLength; - return HasReturnvaluesIF::RETURN_OK; - -} - -template -size_t SerialBufferAdapter::getSerializedSize() const { - if (serializeLength) { - return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength); - } else { - return bufferLength; - } -} - -template -ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, - size_t* size, Endianness streamEndianness) { - if (this->buffer == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - if(serializeLength){ - count_t lengthField = 0; - ReturnValue_t result = SerializeAdapter::deSerialize(&lengthField, - buffer, size, streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if(lengthField > bufferLength) { - return TOO_MANY_ELEMENTS; - } - bufferLength = lengthField; - } - - if (bufferLength <= *size) { - *size -= bufferLength; - std::memcpy(this->buffer, *buffer, bufferLength); - (*buffer) += bufferLength; - return HasReturnvaluesIF::RETURN_OK; - } - else { - return STREAM_TOO_SHORT; - } -} - -template -uint8_t * SerialBufferAdapter::getBuffer() { - if(buffer == nullptr) { - sif::error << "Wrong access function for stored type !" - " Use getConstBuffer()." << std::endl; - return nullptr; - } - return buffer; -} - -template -const uint8_t * SerialBufferAdapter::getConstBuffer() { - if(constBuffer == nullptr) { - sif::error << "SerialBufferAdapter::getConstBuffer:" - " Buffers are unitialized!" << std::endl; - return nullptr; - } - return constBuffer; -} - -template -void SerialBufferAdapter::setBuffer(uint8_t* buffer, - count_t bufferLength) { - this->buffer = buffer; - this->constBuffer = buffer; - this->bufferLength = bufferLength; -} - - -//forward Template declaration for linker -template class SerialBufferAdapter; -template class SerialBufferAdapter; -template class SerialBufferAdapter; -template class SerialBufferAdapter; - +#include "../serialize/SerialBufferAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include + +template +SerialBufferAdapter::SerialBufferAdapter(const uint8_t* buffer, + count_t bufferLength, bool serializeLength) : + serializeLength(serializeLength), + constBuffer(buffer), buffer(nullptr), + bufferLength(bufferLength) {} + +template +SerialBufferAdapter::SerialBufferAdapter(uint8_t* buffer, + count_t bufferLength, bool serializeLength) : + serializeLength(serializeLength), constBuffer(buffer), buffer(buffer), + bufferLength(bufferLength) {} + + +template +SerialBufferAdapter::~SerialBufferAdapter() { +} + +template +ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, + size_t* size, size_t maxSize, Endianness streamEndianness) const { + if (serializeLength) { + ReturnValue_t result = SerializeAdapter::serialize(&bufferLength, + buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + if (*size + bufferLength > maxSize) { + return BUFFER_TOO_SHORT; + } + + if (this->constBuffer != nullptr) { + std::memcpy(*buffer, this->constBuffer, bufferLength); + } + else if (this->buffer != nullptr) { + // This will propably be never reached, constBuffer should always be + // set if non-const buffer is set. + std::memcpy(*buffer, this->buffer, bufferLength); + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } + *size += bufferLength; + (*buffer) += bufferLength; + return HasReturnvaluesIF::RETURN_OK; + +} + +template +size_t SerialBufferAdapter::getSerializedSize() const { + if (serializeLength) { + return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength); + } else { + return bufferLength; + } +} + +template +ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, + size_t* size, Endianness streamEndianness) { + if (this->buffer == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(serializeLength){ + count_t lengthField = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(&lengthField, + buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(lengthField > bufferLength) { + return TOO_MANY_ELEMENTS; + } + bufferLength = lengthField; + } + + if (bufferLength <= *size) { + *size -= bufferLength; + std::memcpy(this->buffer, *buffer, bufferLength); + (*buffer) += bufferLength; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return STREAM_TOO_SHORT; + } +} + +template +uint8_t * SerialBufferAdapter::getBuffer() { + if(buffer == nullptr) { + sif::error << "Wrong access function for stored type !" + " Use getConstBuffer()." << std::endl; + return nullptr; + } + return buffer; +} + +template +const uint8_t * SerialBufferAdapter::getConstBuffer() { + if(constBuffer == nullptr) { + sif::error << "SerialBufferAdapter::getConstBuffer:" + " Buffers are unitialized!" << std::endl; + return nullptr; + } + return constBuffer; +} + +template +void SerialBufferAdapter::setBuffer(uint8_t* buffer, + count_t bufferLength) { + this->buffer = buffer; + this->constBuffer = buffer; + this->bufferLength = bufferLength; +} + + +//forward Template declaration for linker +template class SerialBufferAdapter; +template class SerialBufferAdapter; +template class SerialBufferAdapter; +template class SerialBufferAdapter; + diff --git a/serialize/SerialBufferAdapter.h b/serialize/SerialBufferAdapter.h index c3dfcd8f..9a89e18b 100644 --- a/serialize/SerialBufferAdapter.h +++ b/serialize/SerialBufferAdapter.h @@ -1,78 +1,78 @@ -#ifndef SERIALBUFFERADAPTER_H_ -#define SERIALBUFFERADAPTER_H_ - -#include "../serialize/SerializeIF.h" -#include "../serialize/SerializeAdapter.h" - -/** - * 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>. - * Right now, the SerialBufferAdapter must always - * be initialized with the buffer and size ! - * - * \ingroup serialize - */ -template -class SerialBufferAdapter: public SerializeIF { -public: - - /** - * 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 uint8_t* 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 Length field will be serialized with size count_t - */ - SerialBufferAdapter(uint8_t* buffer, count_t bufferLength, - bool serializeLength = false); - - virtual ~SerialBufferAdapter(); - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - /** - * @brief This function deserializes a buffer into the member buffer. - * @details - * If a length field is present, it is ignored, as the size should have - * been set in the constructor. If the size is not known beforehand, - * consider using SerialFixedArrayListAdapter instead. - * @param buffer [out] Resulting buffer - * @param size remaining size to deserialize, should be larger than buffer - * + size field size - * @param bigEndian - * @return - */ - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - - uint8_t * getBuffer(); - const uint8_t * getConstBuffer(); - void setBuffer(uint8_t* buffer, count_t bufferLength); -private: - bool serializeLength = false; - const uint8_t *constBuffer = nullptr; - uint8_t *buffer = nullptr; - count_t bufferLength = 0; -}; - -#endif /* SERIALBUFFERADAPTER_H_ */ +#ifndef SERIALBUFFERADAPTER_H_ +#define SERIALBUFFERADAPTER_H_ + +#include "../serialize/SerializeIF.h" +#include "../serialize/SerializeAdapter.h" + +/** + * 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>. + * Right now, the SerialBufferAdapter must always + * be initialized with the buffer and size ! + * + * \ingroup serialize + */ +template +class SerialBufferAdapter: public SerializeIF { +public: + + /** + * 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 uint8_t* 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 Length field will be serialized with size count_t + */ + SerialBufferAdapter(uint8_t* buffer, count_t bufferLength, + bool serializeLength = false); + + virtual ~SerialBufferAdapter(); + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + /** + * @brief This function deserializes a buffer into the member buffer. + * @details + * If a length field is present, it is ignored, as the size should have + * been set in the constructor. If the size is not known beforehand, + * consider using SerialFixedArrayListAdapter instead. + * @param buffer [out] Resulting buffer + * @param size remaining size to deserialize, should be larger than buffer + * + size field size + * @param bigEndian + * @return + */ + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + + uint8_t * getBuffer(); + const uint8_t * getConstBuffer(); + void setBuffer(uint8_t* buffer, count_t bufferLength); +private: + bool serializeLength = false; + const uint8_t *constBuffer = nullptr; + uint8_t *buffer = nullptr; + count_t bufferLength = 0; +}; + +#endif /* SERIALBUFFERADAPTER_H_ */ diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h index 2c41a135..01c09d1b 100644 --- a/tasks/SemaphoreFactory.h +++ b/tasks/SemaphoreFactory.h @@ -1,50 +1,50 @@ -#ifndef FSFW_TASKS_SEMAPHOREFACTORY_H_ -#define FSFW_TASKS_SEMAPHOREFACTORY_H_ - -#include "../tasks/SemaphoreIF.h" - -/** - * Creates Semaphore. - * This class is a "singleton" interface, i.e. it provides an - * interface, but also is the base class for a singleton. - */ -class SemaphoreFactory { -public: - virtual ~SemaphoreFactory(); - /** - * Returns the single instance of SemaphoreFactory. - * The implementation of #instance is found in its subclasses. - * Thus, we choose link-time variability of the instance. - */ - static SemaphoreFactory* instance(); - - /** - * Create a binary semaphore. - * Creator function for a binary semaphore which may only be acquired once - * @param argument Can be used to pass implementation specific information. - * @return Pointer to newly created semaphore class instance. - */ - SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); - /** - * Create a counting semaphore. - * Creator functons for a counting semaphore which may be acquired multiple - * times. - * @param count Semaphore can be taken count times. - * @param initCount Initial count value. - * @param argument Can be used to pass implementation specific information. - * @return - */ - SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, - uint8_t initCount, uint32_t arguments = 0); - - void deleteSemaphore(SemaphoreIF* semaphore); - -private: - /** - * External instantiation is not allowed. - */ - SemaphoreFactory(); - static SemaphoreFactory* factoryInstance; -}; - -#endif /* FSFW_TASKS_SEMAPHOREFACTORY_H_ */ +#ifndef FSFW_TASKS_SEMAPHOREFACTORY_H_ +#define FSFW_TASKS_SEMAPHOREFACTORY_H_ + +#include "../tasks/SemaphoreIF.h" + +/** + * Creates Semaphore. + * This class is a "singleton" interface, i.e. it provides an + * interface, but also is the base class for a singleton. + */ +class SemaphoreFactory { +public: + virtual ~SemaphoreFactory(); + /** + * Returns the single instance of SemaphoreFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static SemaphoreFactory* instance(); + + /** + * Create a binary semaphore. + * Creator function for a binary semaphore which may only be acquired once + * @param argument Can be used to pass implementation specific information. + * @return Pointer to newly created semaphore class instance. + */ + SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); + /** + * Create a counting semaphore. + * Creator functons for a counting semaphore which may be acquired multiple + * times. + * @param count Semaphore can be taken count times. + * @param initCount Initial count value. + * @param argument Can be used to pass implementation specific information. + * @return + */ + SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments = 0); + + void deleteSemaphore(SemaphoreIF* semaphore); + +private: + /** + * External instantiation is not allowed. + */ + SemaphoreFactory(); + static SemaphoreFactory* factoryInstance; +}; + +#endif /* FSFW_TASKS_SEMAPHOREFACTORY_H_ */ diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 30d4ed88..dd327e23 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -1,68 +1,68 @@ -#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ -#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ -#include "../returnvalues/FwClassIds.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include - -/** - * @brief Generic interface for semaphores, which can be used to achieve - * task synchronization. This is a generic interface which can be - * used for both binary semaphores and counting semaphores. - * @details - * A semaphore is a synchronization primitive. - * See: https://en.wikipedia.org/wiki/Semaphore_(programming) - * A semaphore can be used to achieve task synchonization and track the - * availability of resources by using either the binary or the counting - * semaphore types. - * - * If mutual exlcusion of a resource is desired, a mutex should be used, - * which is a special form of a semaphore and has an own interface. - */ -class SemaphoreIF { -public: - /** - * Different types of timeout for the mutex lock. - */ - enum TimeoutType { - POLLING, //!< If mutex is not available, return immediately - WAITING, //!< Wait a specified time for the mutex to become available - BLOCKING //!< Block indefinitely until the mutex becomes available. - }; - - virtual~ SemaphoreIF() {}; - - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - //! Semaphore timeout - static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); - //! The current semaphore can not be given, because it is not owned - static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); - static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3); - - /** - * Generic call to acquire a semaphore. - * If there are no more semaphores to be taken (for a counting semaphore, - * a semaphore may be taken more than once), the taks will block - * for a maximum of timeoutMs while trying to acquire the semaphore. - * This can be used to achieve task synchrnization. - * @param timeoutMs - * @return - c RETURN_OK for successfull acquisition - */ - virtual ReturnValue_t acquire(TimeoutType timeoutType = - TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0; - - /** - * Corrensponding call to release a semaphore. - * @return -@c RETURN_OK for successfull release - */ - virtual ReturnValue_t release() = 0; - - /** - * If the semaphore is a counting semaphore then the semaphores current - * count value is returned. If the semaphore is a binary semaphore then 1 - * is returned if the semaphore is available, and 0 is returned if the - * semaphore is not available. - */ - virtual uint8_t getSemaphoreCounter() const = 0; -}; - -#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ +#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#include "../returnvalues/FwClassIds.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @brief Generic interface for semaphores, which can be used to achieve + * task synchronization. This is a generic interface which can be + * used for both binary semaphores and counting semaphores. + * @details + * A semaphore is a synchronization primitive. + * See: https://en.wikipedia.org/wiki/Semaphore_(programming) + * A semaphore can be used to achieve task synchonization and track the + * availability of resources by using either the binary or the counting + * semaphore types. + * + * If mutual exlcusion of a resource is desired, a mutex should be used, + * which is a special form of a semaphore and has an own interface. + */ +class SemaphoreIF { +public: + /** + * Different types of timeout for the mutex lock. + */ + enum TimeoutType { + POLLING, //!< If mutex is not available, return immediately + WAITING, //!< Wait a specified time for the mutex to become available + BLOCKING //!< Block indefinitely until the mutex becomes available. + }; + + virtual~ SemaphoreIF() {}; + + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + //! Semaphore timeout + static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); + //! The current semaphore can not be given, because it is not owned + static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); + static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3); + + /** + * Generic call to acquire a semaphore. + * If there are no more semaphores to be taken (for a counting semaphore, + * a semaphore may be taken more than once), the taks will block + * for a maximum of timeoutMs while trying to acquire the semaphore. + * This can be used to achieve task synchrnization. + * @param timeoutMs + * @return - c RETURN_OK for successfull acquisition + */ + virtual ReturnValue_t acquire(TimeoutType timeoutType = + TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0; + + /** + * Corrensponding call to release a semaphore. + * @return -@c RETURN_OK for successfull release + */ + virtual ReturnValue_t release() = 0; + + /** + * If the semaphore is a counting semaphore then the semaphores current + * count value is returned. If the semaphore is a binary semaphore then 1 + * is returned if the semaphore is available, and 0 is returned if the + * semaphore is not available. + */ + virtual uint8_t getSemaphoreCounter() const = 0; +}; + +#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ From b2777faf66885ee6dc440cf1633e7e34c39c4e1a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 22 Sep 2020 15:29:28 +0200 Subject: [PATCH 38/53] queueue factory update --- osal/linux/QueueFactory.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osal/linux/QueueFactory.cpp b/osal/linux/QueueFactory.cpp index afeca547..44def48a 100644 --- a/osal/linux/QueueFactory.cpp +++ b/osal/linux/QueueFactory.cpp @@ -1,15 +1,21 @@ #include "../../ipc/QueueFactory.h" +#include "MessageQueue.h" + +#include "../../ipc/messageQueueDefinitions.h" +#include "../../ipc/MessageQueueSenderIF.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + #include #include -#include "MessageQueue.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" + + #include QueueFactory* QueueFactory::factoryInstance = nullptr; ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { return MessageQueue::sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault); From 7dc3a7ecbd79440c69cf28cec16950bdc8f44419 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 22 Sep 2020 15:31:15 +0200 Subject: [PATCH 39/53] fix so it compiles --- osal/linux/QueueFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osal/linux/QueueFactory.cpp b/osal/linux/QueueFactory.cpp index 44def48a..0860950c 100644 --- a/osal/linux/QueueFactory.cpp +++ b/osal/linux/QueueFactory.cpp @@ -15,7 +15,7 @@ QueueFactory* QueueFactory::factoryInstance = nullptr; ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault) { return MessageQueue::sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault); From 74b9aef36b2dd920565ed119172cade85bcfd421 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 22 Sep 2020 15:33:28 +0200 Subject: [PATCH 40/53] freeRTOS update --- osal/FreeRTOS/QueueFactory.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osal/FreeRTOS/QueueFactory.cpp b/osal/FreeRTOS/QueueFactory.cpp index 0de6ad4f..153d9b51 100644 --- a/osal/FreeRTOS/QueueFactory.cpp +++ b/osal/FreeRTOS/QueueFactory.cpp @@ -4,18 +4,18 @@ #include "MessageQueue.h" -QueueFactory* QueueFactory::factoryInstance = NULL; +QueueFactory* QueueFactory::factoryInstance = nullptr; ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault) { - return MessageQueue::sendMessageFromMessageQueue(sendTo, message, - sentFrom, ignoreFault); + return MessageQueue::sendMessageFromMessageQueue(sendTo,message, + sentFrom,ignoreFault); } QueueFactory* QueueFactory::instance() { - if (factoryInstance == NULL) { + if (factoryInstance == nullptr) { factoryInstance = new QueueFactory; } return factoryInstance; @@ -27,9 +27,9 @@ QueueFactory::QueueFactory() { QueueFactory::~QueueFactory() { } -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t message_depth, +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { - return new MessageQueue(message_depth, maxMessageSize); + return new MessageQueue(messageDepth, maxMessageSize); } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { From 98333b92eff9389783a2b70c4979eed4b96d5e88 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 22 Sep 2020 15:57:26 +0200 Subject: [PATCH 41/53] srv17 id added, include fix for linux --- objectmanager/frameworkObjects.h | 1 + osal/linux/Clock.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/objectmanager/frameworkObjects.h b/objectmanager/frameworkObjects.h index 4a30e70a..a7103018 100644 --- a/objectmanager/frameworkObjects.h +++ b/objectmanager/frameworkObjects.h @@ -8,6 +8,7 @@ enum framework_objects { PUS_SERVICE_2 = 0x53000002, PUS_SERVICE_5 = 0x53000005, PUS_SERVICE_8 = 0x53000008, + PUS_SERVICE_17 = 0x53000017, PUS_SERVICE_200 = 0x53000200, //Generic IDs for IPC, modes, health, events diff --git a/osal/linux/Clock.cpp b/osal/linux/Clock.cpp index b14f2a97..4de18f83 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -6,8 +6,8 @@ #include #include #include +#include -//#include uint16_t Clock::leapSeconds = 0; MutexIF* Clock::timeMutex = NULL; From ab0f4d8c87aedf5013debc6012da3aebb4389f8a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 22 Sep 2020 16:01:34 +0200 Subject: [PATCH 42/53] service 9 ID added --- objectmanager/frameworkObjects.h | 1 + 1 file changed, 1 insertion(+) diff --git a/objectmanager/frameworkObjects.h b/objectmanager/frameworkObjects.h index a7103018..87439c88 100644 --- a/objectmanager/frameworkObjects.h +++ b/objectmanager/frameworkObjects.h @@ -8,6 +8,7 @@ enum framework_objects { PUS_SERVICE_2 = 0x53000002, PUS_SERVICE_5 = 0x53000005, PUS_SERVICE_8 = 0x53000008, + PUS_SERVICE_9 = 0x53000009, PUS_SERVICE_17 = 0x53000017, PUS_SERVICE_200 = 0x53000200, From 59f72d1031a20e403cd52d2e3922e28c293b6537 Mon Sep 17 00:00:00 2001 From: Steffen Gaisser Date: Tue, 22 Sep 2020 16:59:13 +0200 Subject: [PATCH 43/53] Small fix with new pus services --- events/fwSubsystemIdRanges.h | 1 + returnvalues/FwClassIds.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/events/fwSubsystemIdRanges.h b/events/fwSubsystemIdRanges.h index 5e086f0e..1b0b238e 100644 --- a/events/fwSubsystemIdRanges.h +++ b/events/fwSubsystemIdRanges.h @@ -19,6 +19,7 @@ enum { SYSTEM_MANAGER_1 = 75, SYSTEM_1 = 79, PUS_SERVICE_1 = 80, + PUS_SERVICE_9 = 89, PUS_SERVICE_17 = 97, FW_SUBSYSTEM_ID_RANGE }; diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index e547025b..53add6a0 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -56,7 +56,6 @@ enum { DEVICE_COMMUNICATION_IF, //DC BSP, //BSP TIME_STAMPER_IF, //TSI 53 - //TODO This will shift all IDs for FLP SGP4PROPAGATOR_CLASS, //SGP4 54 MUTEX_IF, //MUX 55 MESSAGE_QUEUE_IF,//MQI 56 From 22d9b771654aba5698c6e4f94d8eb7a925d159e2 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sat, 26 Sep 2020 14:19:51 +0200 Subject: [PATCH 44/53] added documentation --- tasks/FixedSlotSequence.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tasks/FixedSlotSequence.h b/tasks/FixedSlotSequence.h index 19a05f21..077dd10b 100644 --- a/tasks/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -139,6 +139,15 @@ public: */ ReturnValue_t checkSequence() const; + /** + * @brief A custom check can be injected for the respective slot list. + * @details + * This can be used by the developer to check the validity of a certain + * sequence. The function will be run in the #checkSequence function. + * The general check will be continued for now if the custom check function + * fails but a diagnostic debug output will be given. + * @param customCheckFunction + */ void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList &)); /** From 183b6a419338dbc2680526ab02314b62b1f3fa1d Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 13:34:27 +0200 Subject: [PATCH 45/53] small bugfix --- objectmanager/frameworkObjects.h | 14 ++--- tmtcservices/VerificationReporter.cpp | 77 +++++++++++++++------------ tmtcservices/VerificationReporter.h | 41 ++++++++++---- 3 files changed, 81 insertions(+), 51 deletions(-) diff --git a/objectmanager/frameworkObjects.h b/objectmanager/frameworkObjects.h index 87439c88..4d08f084 100644 --- a/objectmanager/frameworkObjects.h +++ b/objectmanager/frameworkObjects.h @@ -4,13 +4,13 @@ namespace objects { enum framework_objects { // Default verification reporter. - PUS_SERVICE_1 = 0x53000001, - PUS_SERVICE_2 = 0x53000002, - PUS_SERVICE_5 = 0x53000005, - PUS_SERVICE_8 = 0x53000008, - PUS_SERVICE_9 = 0x53000009, - PUS_SERVICE_17 = 0x53000017, - PUS_SERVICE_200 = 0x53000200, + PUS_SERVICE_1_VERIFICATION = 0x53000001, + PUS_SERVICE_2_DEVICE_ACCESS = 0x53000002, + PUS_SERVICE_5_EVENT_REPORTING = 0x53000005, + PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008, + PUS_SERVICE_9_TIME_MGMT = 0x53000009, + PUS_SERVICE_17_TEST = 0x53000017, + PUS_SERVICE_200_MODE_MGMT = 0x53000200, //Generic IDs for IPC, modes, health, events HEALTH_TABLE = 0x53010000, diff --git a/tmtcservices/VerificationReporter.cpp b/tmtcservices/VerificationReporter.cpp index 43e712a2..7e40bd27 100644 --- a/tmtcservices/VerificationReporter.cpp +++ b/tmtcservices/VerificationReporter.cpp @@ -1,55 +1,59 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "VerificationReporter.h" #include "AcceptsVerifyMessageIF.h" #include "PusVerificationReport.h" -#include "VerificationReporter.h" -object_id_t VerificationReporter::messageReceiver = 0; +#include "../ipc/MessageQueueIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../objectmanager/frameworkObjects.h" + +object_id_t VerificationReporter::messageReceiver = + objects::PUS_SERVICE_1_VERIFICATION; VerificationReporter::VerificationReporter() : - acknowledgeQueue() { + acknowledgeQueue(MessageQueueIF::NO_QUEUE) { } -VerificationReporter::~VerificationReporter() { - //Default, empty -} +VerificationReporter::~VerificationReporter() {} void VerificationReporter::sendSuccessReport(uint8_t set_report_id, TcPacketBase* current_packet, uint8_t set_step) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(set_report_id, current_packet->getAcknowledgeFlags(), current_packet->getPacketId(), current_packet->getPacketSequenceControl(), 0, set_step); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendSuccessReport: Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendSuccessReport: Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; } } void VerificationReporter::sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, uint8_t set_step) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(set_report_id, ackFlags, tcPacketId, tcSequenceControl, 0, set_step); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendSuccessReport: Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendSuccessReport: Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; } } void VerificationReporter::sendFailureReport(uint8_t report_id, TcPacketBase* current_packet, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(report_id, @@ -57,11 +61,12 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, current_packet->getPacketId(), current_packet->getPacketSequenceControl(), error_code, step, parameter1, parameter2); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendFailureReport Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendFailureReport: Error writing " + << "to queue. Code: " << std::hex << "0x" << status << std::dec + << std::endl; } } @@ -69,27 +74,33 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(report_id, ackFlags, tcPacketId, tcSequenceControl, error_code, step, parameter1, parameter2); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendFailureReport Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendFailureReport: Error writing " + << "to queue. Code: " << std::hex << "0x" << status << std::dec + << std::endl; } } void VerificationReporter::initialize() { + if(messageReceiver == objects::NO_OBJECT) { + sif::warning << "VerificationReporter::initialize: Verification message" + " receiver object ID not set yet in Factory!" << std::endl; + return; + } AcceptsVerifyMessageIF* temp = objectManager->get( messageReceiver); - if (temp != NULL) { - this->acknowledgeQueue = temp->getVerificationQueue(); - } else { - sif::error - << "VerificationReporter::VerificationReporter: Configuration error." - << std::endl; + if (temp == nullptr) { + sif::error << "VerificationReporter::initialize: Message " + << "receiver invalid. Make sure it is set up properly and " + << "implementsAcceptsVerifyMessageIF" << std::endl; + return; } + this->acknowledgeQueue = temp->getVerificationQueue(); } diff --git a/tmtcservices/VerificationReporter.h b/tmtcservices/VerificationReporter.h index 29a273c5..f26fa54f 100644 --- a/tmtcservices/VerificationReporter.h +++ b/tmtcservices/VerificationReporter.h @@ -1,31 +1,50 @@ -#ifndef VERIFICATIONREPORTER_H_ -#define VERIFICATIONREPORTER_H_ +#ifndef FSFW_TMTCSERVICES_VERIFICATIONREPORTER_H_ +#define FSFW_TMTCSERVICES_VERIFICATIONREPORTER_H_ -#include "../objectmanager/ObjectManagerIF.h" #include "PusVerificationReport.h" +#include "../objectmanager/ObjectManagerIF.h" namespace Factory{ void setStaticFrameworkObjectIds(); } +/** + * @brief This helper object is used to forward verification messages + * which are generated by the Flight Software Framework. + * @details + * The messages can be relayed to an arbitrary object, for example a dedicated + * Verification Reporter. The destination is set by setting the static framework + * Id VerificationReporter::messageReceiver. The default verification reporter + * will be the PUS service 1, which sends verification messages according + * to the PUS standard. + * + */ class VerificationReporter { friend void (Factory::setStaticFrameworkObjectIds)(); public: VerificationReporter(); virtual ~VerificationReporter(); - void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, uint8_t set_step = 0 ); - void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, uint8_t set_step = 0); - void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, ReturnValue_t error_code = 0, - uint8_t step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0 ); + + void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, + uint8_t set_step = 0 ); + void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, + uint16_t tcPacketId, uint16_t tcSequenceControl, + uint8_t set_step = 0); + + void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, + ReturnValue_t error_code = 0, + uint8_t step = 0, uint32_t parameter1 = 0, + uint32_t parameter2 = 0 ); void sendFailureReport(uint8_t report_id, - uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, ReturnValue_t error_code = 0, uint8_t step = 0, + uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, + ReturnValue_t error_code = 0, uint8_t step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0); + void initialize(); + private: static object_id_t messageReceiver; MessageQueueId_t acknowledgeQueue; - - }; -#endif /* VERIFICATIONREPORTER_H_ */ +#endif /* FSFW_TMTCSERVICES_VERIFICATIONREPORTER_H_ */ From 7dbb73b7d8e7cb9e655327e7341aeb5a23c1b046 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 14:29:57 +0200 Subject: [PATCH 46/53] removed dbeug printout --- osal/FreeRTOS/FixedTimeslotTask.cpp | 9 --------- osal/FreeRTOS/PeriodicTask.cpp | 4 ---- 2 files changed, 13 deletions(-) diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index 309574eb..062686e2 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -150,15 +150,6 @@ void FixedTimeslotTask::handleMissedDeadline() { if(deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } - -#ifdef DEBUG - object_id_t handlerId = pst.current->handlerId; - sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << " with" - << " object ID 0x" << std::setfill('0') << std::setw(8) << std::hex - << handlerId << " missed deadline!" << std::setfill(' ') - << std::dec << std::endl; -#endif - } ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index 990d38d6..5c0a840d 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -133,10 +133,6 @@ TaskHandle_t PeriodicTask::getTaskHandle() { } void PeriodicTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif if(deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } From cef84b13d923524e10e497602b6b6c27a62a34d0 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 14:35:05 +0200 Subject: [PATCH 47/53] renormalization --- ipc/messageQueueDefinitions.h | 38 +-- storagemanager/ConstStorageAccessor.cpp | 174 ++++++------ storagemanager/ConstStorageAccessor.h | 232 ++++++++-------- storagemanager/StorageAccessor.cpp | 134 +++++----- storagemanager/StorageAccessor.h | 90 +++---- storagemanager/StorageManagerIF.h | 334 ++++++++++++------------ 6 files changed, 501 insertions(+), 501 deletions(-) diff --git a/ipc/messageQueueDefinitions.h b/ipc/messageQueueDefinitions.h index 60c09b05..b4f861b8 100644 --- a/ipc/messageQueueDefinitions.h +++ b/ipc/messageQueueDefinitions.h @@ -1,19 +1,19 @@ -#ifndef FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ -#define FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ - -#include - -/* - * TODO: Actually, the definition of this ID to be a uint32_t is not ideal and - * breaks layering. However, it is difficult to keep layering, as the ID is - * stored in many places and sent around in MessageQueueMessage. - * Ideally, one would use the (current) object_id_t only, however, doing a - * lookup of queueIDs for every call does not sound ideal. - * In a first step, I'll circumvent the issue by not touching it, - * maybe in a second step. This also influences Interface design - * (getCommandQueue) and some other issues.. - */ -using MessageQueueId_t = uint32_t; - - -#endif /* FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ */ +#ifndef FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ +#define FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ + +#include + +/* + * TODO: Actually, the definition of this ID to be a uint32_t is not ideal and + * breaks layering. However, it is difficult to keep layering, as the ID is + * stored in many places and sent around in MessageQueueMessage. + * Ideally, one would use the (current) object_id_t only, however, doing a + * lookup of queueIDs for every call does not sound ideal. + * In a first step, I'll circumvent the issue by not touching it, + * maybe in a second step. This also influences Interface design + * (getCommandQueue) and some other issues.. + */ +using MessageQueueId_t = uint32_t; + + +#endif /* FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ */ diff --git a/storagemanager/ConstStorageAccessor.cpp b/storagemanager/ConstStorageAccessor.cpp index ea9f2e44..4ada7f80 100644 --- a/storagemanager/ConstStorageAccessor.cpp +++ b/storagemanager/ConstStorageAccessor.cpp @@ -1,87 +1,87 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../storagemanager/ConstStorageAccessor.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../globalfunctions/arrayprinter.h" - -ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): - storeId(storeId) {} - -ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, - StorageManagerIF* store): - storeId(storeId), store(store) { - internalState = AccessState::ASSIGNED; -} - -ConstStorageAccessor::~ConstStorageAccessor() { - if(deleteData and store != nullptr) { - sif::debug << "deleting store data" << std::endl; - store->deleteData(storeId); - } -} - -ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): - constDataPointer(other.constDataPointer), storeId(other.storeId), - size_(other.size_), store(other.store), deleteData(other.deleteData), - internalState(other.internalState) { - // This prevent premature deletion - other.store = nullptr; -} - -ConstStorageAccessor& ConstStorageAccessor::operator=( - ConstStorageAccessor&& other) { - constDataPointer = other.constDataPointer; - storeId = other.storeId; - store = other.store; - size_ = other.size_; - deleteData = other.deleteData; - this->store = other.store; - // This prevents premature deletion - other.store = nullptr; - return *this; -} - -const uint8_t* ConstStorageAccessor::data() const { - return constDataPointer; -} - -size_t ConstStorageAccessor::size() const { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - } - return size_; -} - -ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, - size_t maxSize) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(constDataPointer, constDataPointer + size_, pointer); - return HasReturnvaluesIF::RETURN_OK; -} - -void ConstStorageAccessor::release() { - deleteData = false; -} - -store_address_t ConstStorageAccessor::getId() const { - return storeId; -} - -void ConstStorageAccessor::print() const { - if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return; - } - arrayprinter::print(constDataPointer, size_); -} - -void ConstStorageAccessor::assignStore(StorageManagerIF* store) { - internalState = AccessState::ASSIGNED; - this->store = store; -} +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../storagemanager/ConstStorageAccessor.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../globalfunctions/arrayprinter.h" + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): + storeId(storeId) {} + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, + StorageManagerIF* store): + storeId(storeId), store(store) { + internalState = AccessState::ASSIGNED; +} + +ConstStorageAccessor::~ConstStorageAccessor() { + if(deleteData and store != nullptr) { + sif::debug << "deleting store data" << std::endl; + store->deleteData(storeId); + } +} + +ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): + constDataPointer(other.constDataPointer), storeId(other.storeId), + size_(other.size_), store(other.store), deleteData(other.deleteData), + internalState(other.internalState) { + // This prevent premature deletion + other.store = nullptr; +} + +ConstStorageAccessor& ConstStorageAccessor::operator=( + ConstStorageAccessor&& other) { + constDataPointer = other.constDataPointer; + storeId = other.storeId; + store = other.store; + size_ = other.size_; + deleteData = other.deleteData; + this->store = other.store; + // This prevents premature deletion + other.store = nullptr; + return *this; +} + +const uint8_t* ConstStorageAccessor::data() const { + return constDataPointer; +} + +size_t ConstStorageAccessor::size() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return size_; +} + +ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, + size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(constDataPointer, constDataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +void ConstStorageAccessor::release() { + deleteData = false; +} + +store_address_t ConstStorageAccessor::getId() const { + return storeId; +} + +void ConstStorageAccessor::print() const { + if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return; + } + arrayprinter::print(constDataPointer, size_); +} + +void ConstStorageAccessor::assignStore(StorageManagerIF* store) { + internalState = AccessState::ASSIGNED; + this->store = store; +} diff --git a/storagemanager/ConstStorageAccessor.h b/storagemanager/ConstStorageAccessor.h index ec2da8ce..573892da 100644 --- a/storagemanager/ConstStorageAccessor.h +++ b/storagemanager/ConstStorageAccessor.h @@ -1,116 +1,116 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ - -#include "../storagemanager/storeAddress.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include - -class StorageManagerIF; - -/** - * @brief Helper classes to facilitate safe access to storages which is also - * conforming to RAII principles - * @details - * Accessor class which can be returned by pool manager or passed and set by - * pool managers to have safe access to the pool resources. - * - * These helper can be used together with the StorageManager classes to manage - * access to a storage. It can take care of thread-safety while also providing - * mechanisms to automatically clear storage data. - */ -class ConstStorageAccessor { - //! StorageManager classes have exclusive access to private variables. - template - friend class PoolManager; - template - friend class LocalPool; -public: - /** - * @brief Simple constructor which takes the store ID of the storage - * entry to access. - * @param storeId - */ - ConstStorageAccessor(store_address_t storeId); - ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); - - /** - * @brief The destructor in default configuration takes care of - * deleting the accessed pool entry and unlocking the mutex - */ - virtual ~ConstStorageAccessor(); - - /** - * @brief Returns a pointer to the read-only data - * @return - */ - const uint8_t* data() const; - - /** - * @brief Copies the read-only data to the supplied pointer - * @param pointer - */ - virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); - - /** - * @brief Calling this will prevent the Accessor from deleting the data - * when the destructor is called. - */ - void release(); - - /** - * Get the size of the data - * @return - */ - size_t size() const; - - /** - * Get the storage ID. - * @return - */ - store_address_t getId() const; - - void print() const; - - /** - * @brief Move ctor and move assignment allow returning accessors as - * a returnvalue. They prevent resource being free prematurely. - * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ - * move-constructors-and-move-assignment-operators-cpp.md - * @param - * @return - */ - ConstStorageAccessor& operator= (ConstStorageAccessor&&); - ConstStorageAccessor(ConstStorageAccessor&&); - - //! The copy ctor and copy assignemnt should be deleted implicitely - //! according to https://foonathan.net/2019/02/special-member-functions/ - //! but I still deleted them to make it more explicit. (remember rule of 5). - ConstStorageAccessor& operator=(const ConstStorageAccessor&) = delete; - ConstStorageAccessor(const ConstStorageAccessor&) = delete; -protected: - const uint8_t* constDataPointer = nullptr; - store_address_t storeId; - size_t size_ = 0; - //! Managing pool, has to assign itself. - StorageManagerIF* store = nullptr; - bool deleteData = true; - - enum class AccessState { - UNINIT, - ASSIGNED - }; - //! Internal state for safety reasons. - AccessState internalState = AccessState::UNINIT; - /** - * Used by the pool manager instances to assign themselves to the - * accessor. This is necessary to delete the data when the acessor - * exits the scope ! The internal state will be considered read - * when this function is called, so take care all data is set properly as - * well. - * @param - */ - void assignStore(StorageManagerIF*); -}; - - -#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ +#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ + +#include "../storagemanager/storeAddress.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +class StorageManagerIF; + +/** + * @brief Helper classes to facilitate safe access to storages which is also + * conforming to RAII principles + * @details + * Accessor class which can be returned by pool manager or passed and set by + * pool managers to have safe access to the pool resources. + * + * These helper can be used together with the StorageManager classes to manage + * access to a storage. It can take care of thread-safety while also providing + * mechanisms to automatically clear storage data. + */ +class ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + /** + * @brief Simple constructor which takes the store ID of the storage + * entry to access. + * @param storeId + */ + ConstStorageAccessor(store_address_t storeId); + ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief The destructor in default configuration takes care of + * deleting the accessed pool entry and unlocking the mutex + */ + virtual ~ConstStorageAccessor(); + + /** + * @brief Returns a pointer to the read-only data + * @return + */ + const uint8_t* data() const; + + /** + * @brief Copies the read-only data to the supplied pointer + * @param pointer + */ + virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); + + /** + * @brief Calling this will prevent the Accessor from deleting the data + * when the destructor is called. + */ + void release(); + + /** + * Get the size of the data + * @return + */ + size_t size() const; + + /** + * Get the storage ID. + * @return + */ + store_address_t getId() const; + + void print() const; + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + ConstStorageAccessor& operator= (ConstStorageAccessor&&); + ConstStorageAccessor(ConstStorageAccessor&&); + + //! The copy ctor and copy assignemnt should be deleted implicitely + //! according to https://foonathan.net/2019/02/special-member-functions/ + //! but I still deleted them to make it more explicit. (remember rule of 5). + ConstStorageAccessor& operator=(const ConstStorageAccessor&) = delete; + ConstStorageAccessor(const ConstStorageAccessor&) = delete; +protected: + const uint8_t* constDataPointer = nullptr; + store_address_t storeId; + size_t size_ = 0; + //! Managing pool, has to assign itself. + StorageManagerIF* store = nullptr; + bool deleteData = true; + + enum class AccessState { + UNINIT, + ASSIGNED + }; + //! Internal state for safety reasons. + AccessState internalState = AccessState::UNINIT; + /** + * Used by the pool manager instances to assign themselves to the + * accessor. This is necessary to delete the data when the acessor + * exits the scope ! The internal state will be considered read + * when this function is called, so take care all data is set properly as + * well. + * @param + */ + void assignStore(StorageManagerIF*); +}; + + +#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp index d4d2a54d..60bd4130 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/storagemanager/StorageAccessor.cpp @@ -1,67 +1,67 @@ -#include "../storagemanager/StorageAccessor.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -StorageAccessor::StorageAccessor(store_address_t storeId): - ConstStorageAccessor(storeId) { -} - -StorageAccessor::StorageAccessor(store_address_t storeId, - StorageManagerIF* store): - ConstStorageAccessor(storeId, store) { -} - -StorageAccessor& StorageAccessor::operator =( - StorageAccessor&& other) { - // Call the parent move assignment and also assign own member. - dataPointer = other.dataPointer; - StorageAccessor::operator=(std::move(other)); - return * this; -} - -// Call the parent move ctor and also transfer own member. -StorageAccessor::StorageAccessor(StorageAccessor&& other): - ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { -} - -ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large " - "enough" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(dataPointer, dataPointer + size_, pointer); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t* StorageAccessor::data() { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - } - return dataPointer; -} - -ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, - uint16_t offset) { - if(internalState == AccessState::UNINIT) { - sif::warning << "StorageAccessor: Not initialized!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - if(offset + size > size_) { - sif::error << "StorageAccessor: Data too large for pool " - "entry!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - std::copy(data, data + size, dataPointer + offset); - return HasReturnvaluesIF::RETURN_OK; -} - -void StorageAccessor::assignConstPointer() { - constDataPointer = dataPointer; -} - - +#include "../storagemanager/StorageAccessor.h" +#include "../storagemanager/StorageManagerIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +StorageAccessor::StorageAccessor(store_address_t storeId): + ConstStorageAccessor(storeId) { +} + +StorageAccessor::StorageAccessor(store_address_t storeId, + StorageManagerIF* store): + ConstStorageAccessor(storeId, store) { +} + +StorageAccessor& StorageAccessor::operator =( + StorageAccessor&& other) { + // Call the parent move assignment and also assign own member. + dataPointer = other.dataPointer; + StorageAccessor::operator=(std::move(other)); + return * this; +} + +// Call the parent move ctor and also transfer own member. +StorageAccessor::StorageAccessor(StorageAccessor&& other): + ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { +} + +ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large " + "enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(dataPointer, dataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t* StorageAccessor::data() { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return dataPointer; +} + +ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, + uint16_t offset) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(offset + size > size_) { + sif::error << "StorageAccessor: Data too large for pool " + "entry!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(data, data + size, dataPointer + offset); + return HasReturnvaluesIF::RETURN_OK; +} + +void StorageAccessor::assignConstPointer() { + constDataPointer = dataPointer; +} + + diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index 1ca5f7dd..a65427b8 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -1,45 +1,45 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ - -#include "../storagemanager/ConstStorageAccessor.h" - -class StorageManagerIF; - -/** - * @brief Child class for modifyable data. Also has a normal pointer member. - */ -class StorageAccessor: public ConstStorageAccessor { - //! StorageManager classes have exclusive access to private variables. - template - friend class PoolManager; - template - friend class LocalPool; -public: - StorageAccessor(store_address_t storeId); - StorageAccessor(store_address_t storeId, StorageManagerIF* store); - - /** - * @brief Move ctor and move assignment allow returning accessors as - * a returnvalue. They prevent resource being freed prematurely. - * See: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ - * move-constructors-and-move-assignment-operators-cpp.md - * @param - * @return - */ - StorageAccessor& operator=(StorageAccessor&&); - StorageAccessor(StorageAccessor&&); - - ReturnValue_t write(uint8_t *data, size_t size, - uint16_t offset = 0); - uint8_t* data(); - ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize) override; - -private: - //! Non-const pointer for modifyable data. - uint8_t* dataPointer = nullptr; - //! For modifyable data, the const pointer is assigned to the normal - //! pointer by the pool manager so both access functions can be used safely - void assignConstPointer(); -}; - -#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ +#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ +#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ + +#include "../storagemanager/ConstStorageAccessor.h" + +class StorageManagerIF; + +/** + * @brief Child class for modifyable data. Also has a normal pointer member. + */ +class StorageAccessor: public ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + StorageAccessor(store_address_t storeId); + StorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being freed prematurely. + * See: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + StorageAccessor& operator=(StorageAccessor&&); + StorageAccessor(StorageAccessor&&); + + ReturnValue_t write(uint8_t *data, size_t size, + uint16_t offset = 0); + uint8_t* data(); + ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize) override; + +private: + //! Non-const pointer for modifyable data. + uint8_t* dataPointer = nullptr; + //! For modifyable data, the const pointer is assigned to the normal + //! pointer by the pool manager so both access functions can be used safely + void assignConstPointer(); +}; + +#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 85341f2e..2229cdf8 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -1,167 +1,167 @@ -#ifndef STORAGEMANAGERIF_H_H -#define STORAGEMANAGERIF_H_H - -#include "../events/Event.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../storagemanager/StorageAccessor.h" -#include "../storagemanager/storeAddress.h" -#include -#include - -using AccessorPair = std::pair; -using ConstAccessorPair = std::pair; - -/** - * @brief This class provides an interface for intermediate data storage. - * @details The Storage manager classes shall be used to store larger chunks of - * data in RAM for exchange between tasks. This interface expects the - * data to be stored in one consecutive block of memory, so tasks can - * write directly to the destination pointer. - * For interprocess communication, the stores must be locked during - * insertion and deletion. If the receiving storage identifier is - * passed token-like between tasks, a lock during read and write - * operations is not necessary. - * @author Bastian Baetz - * @date 18.09.2012 - */ -class StorageManagerIF : public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::STORAGE_MANAGER_IF; //!< The unique ID for return codes for this interface. - static const ReturnValue_t DATA_TOO_LARGE = MAKE_RETURN_CODE(1); //!< This return code indicates that the data to be stored is too large for the store. - static const ReturnValue_t DATA_STORAGE_FULL = MAKE_RETURN_CODE(2); //!< This return code indicates that a data storage is full. - static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. - static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. - static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); - static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. - - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; - static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); - static const Event STORE_DATA_FAILED = MAKE_EVENT(1, SEVERITY::LOW); - - static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address. - /** - * @brief This is the empty virtual destructor as required for C++ interfaces. - */ - virtual ~StorageManagerIF() { - } - ; - /** - * @brief With addData, a free storage position is allocated and data - * stored there. - * @details During the allocation, the StorageManager is blocked. - * @param storageId A pointer to the storageId to retrieve. - * @param data The data to be stored in the StorageManager. - * @param size The amount of data to be stored. - * @return Returns @li RETURN_OK if data was added. - * @li RETURN_FAILED if data could not be added. - * storageId is unchanged then. - */ - virtual ReturnValue_t addData(store_address_t* storageId, - const uint8_t * data, size_t size, bool ignoreFault = false) = 0; - /** - * @brief With deleteData, the storageManager frees the memory region - * identified by packet_id. - * @param packet_id The identifier of the memory region to be freed. - * @return @li RETURN_OK on success. - * @li RETURN_FAILED if deletion did not work - * (e.g. an illegal packet_id was passed). - */ - virtual ReturnValue_t deleteData(store_address_t packet_id) = 0; - /** - * @brief Another deleteData which uses the pointer and size of the - * stored data to delete the content. - * @param buffer Pointer to the data. - * @param size Size of data to be stored. - * @param storeId Store id of the deleted element (optional) - * @return @li RETURN_OK on success. - * @li failure code if deletion did not work - */ - virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, - store_address_t* storeId = nullptr) = 0; - - - /** - * @brief Access the data by supplying a store ID. - * @details - * A pair consisting of the retrieval result and an instance of a - * ConstStorageAccessor class is returned - * @param storeId - * @return Pair of return value and a ConstStorageAccessor instance - */ - virtual ConstAccessorPair getData(store_address_t storeId) = 0; - - /** - * @brief Access the data by supplying a store ID and a helper - * instance - * @param storeId - * @param constAccessor Wrapper function to access store data. - * @return - */ - virtual ReturnValue_t getData(store_address_t storeId, - ConstStorageAccessor& constAccessor) = 0; - - - /** - * @brief getData returns an address to data and the size of the data - * for a given packet_id. - * @param packet_id The id of the data to be returned - * @param packet_ptr The passed pointer address is set to the the memory - * position - * @param size The exact size of the stored data is returned here. - * @return @li RETURN_OK on success. - * @li RETURN_FAILED if fetching data did not work - * (e.g. an illegal packet_id was passed). - */ - virtual ReturnValue_t getData(store_address_t packet_id, - const uint8_t** packet_ptr, size_t* size) = 0; - - - /** - * Modify data by supplying a store ID - * @param storeId - * @return Pair of return value and StorageAccessor helper - */ - virtual AccessorPair modifyData(store_address_t storeId) = 0; - - /** - * Modify data by supplying a store ID and a StorageAccessor helper instance. - * @param storeId - * @param accessor Helper class to access the modifiable data. - * @return - */ - virtual ReturnValue_t modifyData(store_address_t storeId, - StorageAccessor& accessor) = 0; - - /** - * Get pointer and size of modifiable data by supplying the storeId - * @param packet_id - * @param packet_ptr [out] Pointer to pointer of data to set - * @param size [out] Pointer to size to set - * @return - */ - virtual ReturnValue_t modifyData(store_address_t packet_id, - uint8_t** packet_ptr, size_t* size) = 0; - /** - * This method reserves an element of \c size. - * - * It returns the packet id of this element as well as a direct pointer to the - * data of the element. It must be assured that exactly \c size data is - * written to p_data! - * @param storageId A pointer to the storageId to retrieve. - * @param size The size of the space to be reserved. - * @param p_data A pointer to the element data is returned here. - * @return Returns @li RETURN_OK if data was added. - * @li RETURN_FAILED if data could not be added. - * storageId is unchanged then. - */ - virtual ReturnValue_t getFreeElement(store_address_t* storageId, - const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; - - /** - * Clears the whole store. - * Use with care! - */ - virtual void clearStore() = 0; -}; - -#endif /* STORAGEMANAGERIF_H_ */ +#ifndef STORAGEMANAGERIF_H_H +#define STORAGEMANAGERIF_H_H + +#include "../events/Event.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../storagemanager/StorageAccessor.h" +#include "../storagemanager/storeAddress.h" +#include +#include + +using AccessorPair = std::pair; +using ConstAccessorPair = std::pair; + +/** + * @brief This class provides an interface for intermediate data storage. + * @details The Storage manager classes shall be used to store larger chunks of + * data in RAM for exchange between tasks. This interface expects the + * data to be stored in one consecutive block of memory, so tasks can + * write directly to the destination pointer. + * For interprocess communication, the stores must be locked during + * insertion and deletion. If the receiving storage identifier is + * passed token-like between tasks, a lock during read and write + * operations is not necessary. + * @author Bastian Baetz + * @date 18.09.2012 + */ +class StorageManagerIF : public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::STORAGE_MANAGER_IF; //!< The unique ID for return codes for this interface. + static const ReturnValue_t DATA_TOO_LARGE = MAKE_RETURN_CODE(1); //!< This return code indicates that the data to be stored is too large for the store. + static const ReturnValue_t DATA_STORAGE_FULL = MAKE_RETURN_CODE(2); //!< This return code indicates that a data storage is full. + static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. + static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. + static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); + static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; + static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); + static const Event STORE_DATA_FAILED = MAKE_EVENT(1, SEVERITY::LOW); + + static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address. + /** + * @brief This is the empty virtual destructor as required for C++ interfaces. + */ + virtual ~StorageManagerIF() { + } + ; + /** + * @brief With addData, a free storage position is allocated and data + * stored there. + * @details During the allocation, the StorageManager is blocked. + * @param storageId A pointer to the storageId to retrieve. + * @param data The data to be stored in the StorageManager. + * @param size The amount of data to be stored. + * @return Returns @li RETURN_OK if data was added. + * @li RETURN_FAILED if data could not be added. + * storageId is unchanged then. + */ + virtual ReturnValue_t addData(store_address_t* storageId, + const uint8_t * data, size_t size, bool ignoreFault = false) = 0; + /** + * @brief With deleteData, the storageManager frees the memory region + * identified by packet_id. + * @param packet_id The identifier of the memory region to be freed. + * @return @li RETURN_OK on success. + * @li RETURN_FAILED if deletion did not work + * (e.g. an illegal packet_id was passed). + */ + virtual ReturnValue_t deleteData(store_address_t packet_id) = 0; + /** + * @brief Another deleteData which uses the pointer and size of the + * stored data to delete the content. + * @param buffer Pointer to the data. + * @param size Size of data to be stored. + * @param storeId Store id of the deleted element (optional) + * @return @li RETURN_OK on success. + * @li failure code if deletion did not work + */ + virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, + store_address_t* storeId = nullptr) = 0; + + + /** + * @brief Access the data by supplying a store ID. + * @details + * A pair consisting of the retrieval result and an instance of a + * ConstStorageAccessor class is returned + * @param storeId + * @return Pair of return value and a ConstStorageAccessor instance + */ + virtual ConstAccessorPair getData(store_address_t storeId) = 0; + + /** + * @brief Access the data by supplying a store ID and a helper + * instance + * @param storeId + * @param constAccessor Wrapper function to access store data. + * @return + */ + virtual ReturnValue_t getData(store_address_t storeId, + ConstStorageAccessor& constAccessor) = 0; + + + /** + * @brief getData returns an address to data and the size of the data + * for a given packet_id. + * @param packet_id The id of the data to be returned + * @param packet_ptr The passed pointer address is set to the the memory + * position + * @param size The exact size of the stored data is returned here. + * @return @li RETURN_OK on success. + * @li RETURN_FAILED if fetching data did not work + * (e.g. an illegal packet_id was passed). + */ + virtual ReturnValue_t getData(store_address_t packet_id, + const uint8_t** packet_ptr, size_t* size) = 0; + + + /** + * Modify data by supplying a store ID + * @param storeId + * @return Pair of return value and StorageAccessor helper + */ + virtual AccessorPair modifyData(store_address_t storeId) = 0; + + /** + * Modify data by supplying a store ID and a StorageAccessor helper instance. + * @param storeId + * @param accessor Helper class to access the modifiable data. + * @return + */ + virtual ReturnValue_t modifyData(store_address_t storeId, + StorageAccessor& accessor) = 0; + + /** + * Get pointer and size of modifiable data by supplying the storeId + * @param packet_id + * @param packet_ptr [out] Pointer to pointer of data to set + * @param size [out] Pointer to size to set + * @return + */ + virtual ReturnValue_t modifyData(store_address_t packet_id, + uint8_t** packet_ptr, size_t* size) = 0; + /** + * This method reserves an element of \c size. + * + * It returns the packet id of this element as well as a direct pointer to the + * data of the element. It must be assured that exactly \c size data is + * written to p_data! + * @param storageId A pointer to the storageId to retrieve. + * @param size The size of the space to be reserved. + * @param p_data A pointer to the element data is returned here. + * @return Returns @li RETURN_OK if data was added. + * @li RETURN_FAILED if data could not be added. + * storageId is unchanged then. + */ + virtual ReturnValue_t getFreeElement(store_address_t* storageId, + const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; + + /** + * Clears the whole store. + * Use with care! + */ + virtual void clearStore() = 0; +}; + +#endif /* STORAGEMANAGERIF_H_ */ From 1ff85c88b2e05749050aabea2dcb91ed544f9ab3 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 14:42:48 +0200 Subject: [PATCH 48/53] store accessor small changes --- storagemanager/ConstStorageAccessor.cpp | 5 +++-- storagemanager/ConstStorageAccessor.h | 8 ++++---- storagemanager/LocalPool.h | 6 +++--- storagemanager/LocalPool.tpp | 8 ++++---- storagemanager/PoolManager.h | 19 ++++++++++++------- storagemanager/PoolManager.tpp | 4 ++-- storagemanager/StorageAccessor.cpp | 4 ++-- storagemanager/StorageAccessor.h | 8 ++++---- storagemanager/StorageManagerIF.h | 12 +++++++----- 9 files changed, 41 insertions(+), 33 deletions(-) diff --git a/storagemanager/ConstStorageAccessor.cpp b/storagemanager/ConstStorageAccessor.cpp index 4ada7f80..71d732bf 100644 --- a/storagemanager/ConstStorageAccessor.cpp +++ b/storagemanager/ConstStorageAccessor.cpp @@ -1,6 +1,7 @@ +#include "ConstStorageAccessor.h" +#include "StorageManagerIF.h" + #include "../serviceinterface/ServiceInterfaceStream.h" -#include "../storagemanager/ConstStorageAccessor.h" -#include "../storagemanager/StorageManagerIF.h" #include "../globalfunctions/arrayprinter.h" ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): diff --git a/storagemanager/ConstStorageAccessor.h b/storagemanager/ConstStorageAccessor.h index 573892da..96d2dca2 100644 --- a/storagemanager/ConstStorageAccessor.h +++ b/storagemanager/ConstStorageAccessor.h @@ -1,7 +1,7 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ +#ifndef FSFW_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ +#define FSFW_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ -#include "../storagemanager/storeAddress.h" +#include "storeAddress.h" #include "../returnvalues/HasReturnvaluesIF.h" #include @@ -113,4 +113,4 @@ protected: }; -#endif /* FRAMEWORK_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ +#endif /* FSFW_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index 8d300f8f..3a94c03d 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -#define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ +#ifndef FSFW_STORAGEMANAGER_LOCALPOOL_H_ +#define FSFW_STORAGEMANAGER_LOCALPOOL_H_ #include "StorageManagerIF.h" #include "../objectmanager/SystemObject.h" @@ -187,4 +187,4 @@ private: #include "LocalPool.tpp" -#endif /* FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ */ +#endif /* FSFW_STORAGEMANAGER_LOCALPOOL_H_ */ diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index 764bd7be..83c7a718 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -1,7 +1,7 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ -#define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ +#ifndef FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ +#define FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ -#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ +#ifndef FSFW_STORAGEMANAGER_LOCALPOOL_H_ #error Include LocalPool.h before LocalPool.tpp! #endif @@ -301,4 +301,4 @@ inline ReturnValue_t LocalPool::initialize() { return RETURN_OK; } -#endif +#endif /* FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ */ diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index ae719e87..84c88682 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -1,9 +1,9 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ -#define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ +#ifndef FSFW_STORAGEMANAGER_POOLMANAGER_H_ +#define FSFW_STORAGEMANAGER_POOLMANAGER_H_ #include "LocalPool.h" +#include "StorageAccessor.h" #include "../ipc/MutexHelper.h" -#include "../storagemanager/StorageAccessor.h" /** @@ -20,11 +20,16 @@ public: const uint16_t element_sizes[NUMBER_OF_POOLS], const uint16_t n_elements[NUMBER_OF_POOLS]); - //! @brief In the PoolManager's destructor all allocated memory is freed. + /** + * @brief In the PoolManager's destructor all allocated memory + * is freed. + */ virtual ~PoolManager(); - //! @brief LocalPool overrides for thread-safety. Decorator function which - //! wraps LocalPool calls with a mutex protection. + /** + * @brief LocalPool overrides for thread-safety. Decorator function + * which wraps LocalPool calls with a mutex protection. + */ ReturnValue_t deleteData(store_address_t) override; ReturnValue_t deleteData(uint8_t* buffer, size_t size, store_address_t* storeId = nullptr) override; @@ -47,4 +52,4 @@ protected: #include "PoolManager.tpp" -#endif /* POOLMANAGER_H_ */ +#endif /* FSFW_STORAGEMANAGER_POOLMANAGER_H_ */ diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index d72346d3..ba7f63b7 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -1,7 +1,7 @@ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ -#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ +#ifndef FSFW_STORAGEMANAGER_POOLMANAGER_H_ #error Include PoolManager.h before PoolManager.tpp! #endif @@ -48,4 +48,4 @@ inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, } -#endif +#endif /* FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ */ diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp index 60bd4130..9c2f936a 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/storagemanager/StorageAccessor.cpp @@ -1,5 +1,5 @@ -#include "../storagemanager/StorageAccessor.h" -#include "../storagemanager/StorageManagerIF.h" +#include "StorageAccessor.h" +#include "StorageManagerIF.h" #include "../serviceinterface/ServiceInterfaceStream.h" StorageAccessor::StorageAccessor(store_address_t storeId): diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index a65427b8..5cf15d50 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -1,7 +1,7 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ -#define FRAMEWORK_STORAGEMANAGER_STORAGEACCESSOR_H_ +#ifndef FSFW_STORAGEMANAGER_STORAGEACCESSOR_H_ +#define FSFW_STORAGEMANAGER_STORAGEACCESSOR_H_ -#include "../storagemanager/ConstStorageAccessor.h" +#include "ConstStorageAccessor.h" class StorageManagerIF; @@ -42,4 +42,4 @@ private: void assignConstPointer(); }; -#endif /* TEST_PROTOTYPES_STORAGEACCESSOR_H_ */ +#endif /* FSFW_STORAGEMANAGER_STORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 2229cdf8..834e7563 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -1,10 +1,12 @@ -#ifndef STORAGEMANAGERIF_H_H -#define STORAGEMANAGERIF_H_H +#ifndef FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ +#define FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ + +#include "StorageAccessor.h" +#include "storeAddress.h" #include "../events/Event.h" #include "../returnvalues/HasReturnvaluesIF.h" -#include "../storagemanager/StorageAccessor.h" -#include "../storagemanager/storeAddress.h" + #include #include @@ -164,4 +166,4 @@ public: virtual void clearStore() = 0; }; -#endif /* STORAGEMANAGERIF_H_ */ +#endif /* FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ */ From bed4e7affa0b0a832f877768b18a57a463a89b0a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 14:43:23 +0200 Subject: [PATCH 49/53] nullptr replacement --- storagemanager/LocalPool.tpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index 83c7a718..7a6c5c9c 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -171,7 +171,7 @@ inline ReturnValue_t LocalPool::getData(store_address_t storeId template inline ReturnValue_t LocalPool::getData( store_address_t packet_id, const uint8_t** packet_ptr, size_t* size) { - uint8_t* tempData = NULL; + uint8_t* tempData = nullptr; ReturnValue_t status = modifyData(packet_id, &tempData, size); *packet_ptr = tempData; return status; From 622c7a5a0d5db90cf27a8b06a21888dd3ffd0eb8 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 14:45:23 +0200 Subject: [PATCH 50/53] debug output removed --- storagemanager/ConstStorageAccessor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storagemanager/ConstStorageAccessor.cpp b/storagemanager/ConstStorageAccessor.cpp index 71d732bf..842f1ce8 100644 --- a/storagemanager/ConstStorageAccessor.cpp +++ b/storagemanager/ConstStorageAccessor.cpp @@ -15,7 +15,6 @@ ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, ConstStorageAccessor::~ConstStorageAccessor() { if(deleteData and store != nullptr) { - sif::debug << "deleting store data" << std::endl; store->deleteData(storeId); } } @@ -59,7 +58,8 @@ ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, return HasReturnvaluesIF::RETURN_FAILED; } if(size_ > maxSize) { - sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; + sif::error << "StorageAccessor: Supplied buffer not large enough" + << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } std::copy(constDataPointer, constDataPointer + size_, pointer); From a58e47623f7bfec389da6d05d35fe1e9831cb462 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 14:50:16 +0200 Subject: [PATCH 51/53] update --- storagemanager/LocalPool.tpp | 7 ++++--- storagemanager/PoolManager.h | 3 ++- storagemanager/PoolManager.tpp | 11 ++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index 7a6c5c9c..5e61efe4 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -125,9 +125,10 @@ inline LocalPool::~LocalPool(void) { } } -template inline -ReturnValue_t LocalPool::addData(store_address_t* storageId, - const uint8_t* data, size_t size, bool ignoreFault) { +template +inline ReturnValue_t LocalPool::addData( + store_address_t* storageId, const uint8_t* data, size_t size, + bool ignoreFault) { ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); if (status == RETURN_OK) { write(*storageId, data, size); diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 84c88682..8cc6c065 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -34,9 +34,10 @@ public: ReturnValue_t deleteData(uint8_t* buffer, size_t size, store_address_t* storeId = nullptr) override; + void setMutexTimeout(uint32_t mutexTimeoutMs); protected: //! Default mutex timeout value to prevent permanent blocking. - static constexpr uint32_t mutexTimeout = 50; + uint32_t mutexTimeoutMs = 20; ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault) override; diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index ba7f63b7..2be44ece 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -21,7 +21,7 @@ inline PoolManager::~PoolManager(void) { template inline ReturnValue_t PoolManager::reserveSpace( const uint32_t size, store_address_t* address, bool ignoreFault) { - MutexHelper mutexHelper(mutex,MutexIF::BLOCKING); + MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); ReturnValue_t status = LocalPool::reserveSpace(size, address,ignoreFault); return status; @@ -33,7 +33,7 @@ inline ReturnValue_t PoolManager::deleteData( // debug << "PoolManager( " << translateObject(getObjectId()) << // " )::deleteData from store " << packet_id.pool_index << // ". id is "<< packet_id.packet_index << std::endl; - MutexHelper mutexHelper(mutex,MutexIF::BLOCKING); + MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); ReturnValue_t status = LocalPool::deleteData(packet_id); return status; } @@ -41,11 +41,16 @@ inline ReturnValue_t PoolManager::deleteData( template inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, size_t size, store_address_t* storeId) { - MutexHelper mutexHelper(mutex,MutexIF::BLOCKING); + MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId); return status; } +template +inline void PoolManager::setMutexTimeout( + uint32_t mutexTimeoutMs) { + this->mutexTimeout = mutexTimeoutMs; +} #endif /* FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ */ From 1ed1b7ea06fca6199ea5957e0b91affb4dfce47f Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 14:51:08 +0200 Subject: [PATCH 52/53] include guard fix --- storagemanager/storeAddress.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/storagemanager/storeAddress.h b/storagemanager/storeAddress.h index 5dd785a3..044c0790 100644 --- a/storagemanager/storeAddress.h +++ b/storagemanager/storeAddress.h @@ -1,5 +1,6 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ -#define FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ +#ifndef FSFW_STORAGEMANAGER_STOREADDRESS_H_ +#define FSFW_STORAGEMANAGER_STOREADDRESS_H_ + #include /** @@ -51,4 +52,4 @@ union store_address_t { } }; -#endif /* FRAMEWORK_STORAGEMANAGER_STOREADDRESS_H_ */ +#endif /* FSFW_STORAGEMANAGER_STOREADDRESS_H_ */ From 352ce13fb391d13b3b4ccfd94437e9b3a189bc03 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 29 Sep 2020 14:55:17 +0200 Subject: [PATCH 53/53] removed line break --- ipc/messageQueueDefinitions.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ipc/messageQueueDefinitions.h b/ipc/messageQueueDefinitions.h index b4f861b8..d250da8a 100644 --- a/ipc/messageQueueDefinitions.h +++ b/ipc/messageQueueDefinitions.h @@ -15,5 +15,4 @@ */ using MessageQueueId_t = uint32_t; - #endif /* FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ */