diff --git a/events/EventManager.cpp b/events/EventManager.cpp index e25e574f..5b2b31b5 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -6,6 +6,7 @@ #include "../ipc/QueueFactory.h" #include "../ipc/MutexFactory.h" +MessageQueueId_t EventManagerIF::eventmanagerQueue = MessageQueueIF::NO_QUEUE; // If one checks registerListener calls, there are around 40 (to max 50) // objects registering for certain events. diff --git a/events/EventManagerIF.h b/events/EventManagerIF.h index 253e6910..ea22f8ae 100644 --- a/events/EventManagerIF.h +++ b/events/EventManagerIF.h @@ -1,11 +1,12 @@ -#ifndef EVENTMANAGERIF_H_ -#define EVENTMANAGERIF_H_ +#ifndef FSFW_EVENTS_EVENTMANAGERIF_H_ +#define FSFW_EVENTS_EVENTMANAGERIF_H_ #include "EventMessage.h" #include "eventmatching/eventmatching.h" #include "../objectmanager/ObjectManagerIF.h" #include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueIF.h" +#include "../serviceinterface/ServiceInterface.h" class EventManagerIF { public: @@ -41,11 +42,19 @@ public: static void triggerEvent(EventMessage* message, MessageQueueId_t sentFrom = 0) { - static MessageQueueId_t eventmanagerQueue = MessageQueueIF::NO_QUEUE; if (eventmanagerQueue == MessageQueueIF::NO_QUEUE) { EventManagerIF *eventmanager = objectManager->get( objects::EVENT_MANAGER); if (eventmanager == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "EventManagerIF::triggerEvent: EventManager invalid or not found!" + << std::endl; +#else + sif::printWarning("EventManagerIF::triggerEvent: " + "EventManager invalid or not found!"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ return; } eventmanagerQueue = eventmanager->getEventReportQueue(); @@ -53,6 +62,10 @@ public: MessageQueueSenderIF::sendMessage(eventmanagerQueue, message, sentFrom); } +private: + //! Initialized by EventManager (C++11 does not allow header-only static member initialization). + static MessageQueueId_t eventmanagerQueue; + }; -#endif /* EVENTMANAGERIF_H_ */ +#endif /* FSFW_EVENTS_EVENTMANAGERIF_H_ */ diff --git a/globalfunctions/arrayprinter.cpp b/globalfunctions/arrayprinter.cpp index 25d6fcf4..7dc056b0 100644 --- a/globalfunctions/arrayprinter.cpp +++ b/globalfunctions/arrayprinter.cpp @@ -2,76 +2,124 @@ #include "../serviceinterface/ServiceInterface.h" #include + void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, - bool printInfo, size_t maxCharPerLine) { + bool printInfo, size_t maxCharPerLine) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - if(printInfo) { - sif::info << "Printing data with size " << size << ": "; - } - sif::info << "["; + if(printInfo) { + sif::info << "Printing data with size " << size << ": " << std::endl; + } #else - sif::printInfo("Printing data with size %zu: [", size); -#endif - if(type == OutputType::HEX) { - arrayprinter::printHex(data, size, maxCharPerLine); - } - else if (type == OutputType::DEC) { - arrayprinter::printDec(data, size, maxCharPerLine); - } - else if(type == OutputType::BIN) { - arrayprinter::printBin(data, size); - } +#if FSFW_NO_C99_IO == 1 + sif::printInfo("Printing data with size %lu: \n", static_cast(size)); +#else + sif::printInfo("Printing data with size %zu: \n", size); +#endif /* FSFW_NO_C99_IO == 1 */ +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + + if(type == OutputType::HEX) { + arrayprinter::printHex(data, size, maxCharPerLine); + } + else if (type == OutputType::DEC) { + arrayprinter::printDec(data, size, maxCharPerLine); + } + else if(type == OutputType::BIN) { + arrayprinter::printBin(data, size); + } } void arrayprinter::printHex(const uint8_t *data, size_t size, - size_t maxCharPerLine) { + size_t maxCharPerLine) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << std::hex; - for(size_t i = 0; i < size; i++) { - sif::info << "0x" << static_cast(data[i]); - if(i < size - 1){ - sif::info << " , "; - if(i > 0 and i % maxCharPerLine == 0) { - sif::info << std::endl; + if(sif::info.crAdditionEnabled()) { + std::cout << "\r" << std::endl; + } - } - } - } - sif::info << std::dec; - sif::info << "]" << std::endl; + std::cout << "[" << std::hex; + for(size_t i = 0; i < size; i++) { + std::cout << "0x" << static_cast(data[i]); + if(i < size - 1) { + std::cout << " , "; + if(i > 0 and (i + 1) % maxCharPerLine == 0) { + std::cout << std::endl; + + } + } + } + std::cout << std::dec; + std::cout << "]" << std::endl; #else - // how much memory to reserve for printout? + // General format: 0x01, 0x02, 0x03 so it is number of chars times 6 + // plus line break plus small safety margin. + char printBuffer[(size + 1) * 7 + 1]; + size_t currentPos = 0; + for(size_t i = 0; i < size; i++) { + // To avoid buffer overflows. + if(sizeof(printBuffer) - currentPos <= 7) { + break; + } + + currentPos += snprintf(printBuffer + currentPos, 6, "0x%02x", data[i]); + if(i < size - 1) { + currentPos += sprintf(printBuffer + currentPos, ", "); + if(i > 0 and (i + 1) % maxCharPerLine == 0) { + currentPos += sprintf(printBuffer + currentPos, "\n"); + } + } + } + printf("[%s]\n", printBuffer); #endif } void arrayprinter::printDec(const uint8_t *data, size_t size, - size_t maxCharPerLine) { + size_t maxCharPerLine) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << std::dec; - for(size_t i = 0; i < size; i++) { - sif::info << static_cast(data[i]); - if(i < size - 1){ - sif::info << " , "; - if(i > 0 and i % maxCharPerLine == 0) { - sif::info << std::endl; - } - } - } - sif::info << "]" << std::endl; + if(sif::info.crAdditionEnabled()) { + std::cout << "\r" << std::endl; + } + + std::cout << "[" << std::dec; + for(size_t i = 0; i < size; i++) { + std::cout << static_cast(data[i]); + if(i < size - 1){ + std::cout << " , "; + if(i > 0 and (i + 1) % maxCharPerLine == 0) { + std::cout << std::endl; + } + } + } + std::cout << "]" << std::endl; #else - // how much memory to reserve for printout? + // General format: 32, 243, -12 so it is number of chars times 5 + // plus line break plus small safety margin. + char printBuffer[(size + 1) * 5 + 1]; + size_t currentPos = 0; + for(size_t i = 0; i < size; i++) { + // To avoid buffer overflows. + if(sizeof(printBuffer) - currentPos <= 5) { + break; + } + + currentPos += snprintf(printBuffer + currentPos, 3, "%d", data[i]); + if(i < size - 1) { + currentPos += sprintf(printBuffer + currentPos, ", "); + if(i > 0 and (i + 1) % maxCharPerLine == 0) { + currentPos += sprintf(printBuffer + currentPos, "\n"); + } + } + } + printf("[%s]\n", printBuffer); #endif } void arrayprinter::printBin(const uint8_t *data, size_t size) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << "\n" << std::flush; for(size_t i = 0; i < size; i++) { - sif::info << "Byte " << i + 1 << ": 0b"<< - std::bitset<8>(data[i]) << ",\n" << std::flush; + sif::info << "Byte " << i + 1 << ": 0b" << std::bitset<8>(data[i]) << std::endl; } - sif::info << "]" << std::endl; #else - // how much memory to reserve for printout? + for(size_t i = 0; i < size; i++) { + sif::printInfo("Byte %d: 0b" BYTE_TO_BINARY_PATTERN "\n", i + 1, BYTE_TO_BINARY(data[i])); + } #endif } diff --git a/globalfunctions/arrayprinter.h b/globalfunctions/arrayprinter.h index e57d8e04..e6b3ea6b 100644 --- a/globalfunctions/arrayprinter.h +++ b/globalfunctions/arrayprinter.h @@ -1,20 +1,25 @@ #ifndef FRAMEWORK_GLOBALFUNCTIONS_ARRAYPRINTER_H_ #define FRAMEWORK_GLOBALFUNCTIONS_ARRAYPRINTER_H_ + #include #include enum class OutputType { - DEC, - HEX, - BIN + DEC, + HEX, + BIN }; namespace arrayprinter { + + + void print(const uint8_t* data, size_t size, OutputType type = OutputType::HEX, - bool printInfo = true, size_t maxCharPerLine = 12); -void printHex(const uint8_t* data, size_t size, size_t maxCharPerLine = 12); -void printDec(const uint8_t* data, size_t size, size_t maxCharPerLine = 12); + bool printInfo = true, size_t maxCharPerLine = 10); +void printHex(const uint8_t* data, size_t size, size_t maxCharPerLine = 10); +void printDec(const uint8_t* data, size_t size, size_t maxCharPerLine = 10); void printBin(const uint8_t* data, size_t size); + } #endif /* FRAMEWORK_GLOBALFUNCTIONS_ARRAYPRINTER_H_ */ diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp index 2499b442..bd8e7258 100644 --- a/osal/linux/PosixThread.cpp +++ b/osal/linux/PosixThread.cpp @@ -152,7 +152,7 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { " the requested " << stackMb << " MB" << std::endl; #else sif::printError("PosixThread::createTask: Insufficient memory for " - "the requested %zu MB\n", stackMb); + "the requested %lu MB\n", static_cast(stackMb)); #endif } else if(errno == EINVAL) { diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index 1a02d6e9..ccc051c3 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -29,7 +29,7 @@ ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage, #if FSFW_COLORED_OUTPUT == 1 if(setMessage.find("DEBUG") != std::string::npos) { - colorPrefix = sif::ANSI_COLOR_MAGENTA; + colorPrefix = sif::ANSI_COLOR_CYAN; } else if(setMessage.find("INFO") != std::string::npos) { colorPrefix = sif::ANSI_COLOR_GREEN; @@ -167,7 +167,9 @@ std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) { return &preamble; } - +bool ServiceInterfaceBuffer::crAdditionEnabled() const { + return addCrToPreamble; +} #ifdef UT699 #include "../osal/rtems/Interrupt.h" diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index b1a50848..9d3ce069 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -70,6 +70,8 @@ private: void putChars(char const* begin, char const* end); std::string* getPreamble(size_t * preambleSize = nullptr); + + bool crAdditionEnabled() const; }; #endif diff --git a/serviceinterface/ServiceInterfacePrinter.cpp b/serviceinterface/ServiceInterfacePrinter.cpp index a12f49e3..ce797f1c 100644 --- a/serviceinterface/ServiceInterfacePrinter.cpp +++ b/serviceinterface/ServiceInterfacePrinter.cpp @@ -45,7 +45,7 @@ void fsfwPrint(sif::PrintLevel printType, const char* fmt, va_list arg) { len += sprintf(bufferPosition, sif::ANSI_COLOR_GREEN); } else if(printType == sif::PrintLevel::DEBUG_LEVEL) { - len += sprintf(bufferPosition, sif::ANSI_COLOR_MAGENTA); + len += sprintf(bufferPosition, sif::ANSI_COLOR_CYAN); } else if(printType == sif::PrintLevel::WARNING_LEVEL) { len += sprintf(bufferPosition, sif::ANSI_COLOR_YELLOW); diff --git a/serviceinterface/ServiceInterfacePrinter.h b/serviceinterface/ServiceInterfacePrinter.h index fbdccdd1..6b062108 100644 --- a/serviceinterface/ServiceInterfacePrinter.h +++ b/serviceinterface/ServiceInterfacePrinter.h @@ -1,7 +1,24 @@ +#ifndef FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER +#define FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER + #if FSFW_DISABLE_PRINTOUT == 0 #include #endif +//! https://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format +//! Can be used to print out binary numbers in human-readable format. +#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" +#define BYTE_TO_BINARY(byte) \ + (byte & 0x80 ? '1' : '0'), \ + (byte & 0x40 ? '1' : '0'), \ + (byte & 0x20 ? '1' : '0'), \ + (byte & 0x10 ? '1' : '0'), \ + (byte & 0x08 ? '1' : '0'), \ + (byte & 0x04 ? '1' : '0'), \ + (byte & 0x02 ? '1' : '0'), \ + (byte & 0x01 ? '1' : '0') + + namespace sif { enum PrintLevel { @@ -38,3 +55,4 @@ void printError(const char* fmt, ...); } +#endif /* FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER */ diff --git a/serviceinterface/ServiceInterfaceStream.cpp b/serviceinterface/ServiceInterfaceStream.cpp index 59526536..ad14cd04 100644 --- a/serviceinterface/ServiceInterfaceStream.cpp +++ b/serviceinterface/ServiceInterfaceStream.cpp @@ -15,5 +15,9 @@ std::string* ServiceInterfaceStream::getPreamble() { return streambuf.getPreamble(); } +bool ServiceInterfaceStream::crAdditionEnabled() const { + return streambuf.crAdditionEnabled(); +} + #endif diff --git a/serviceinterface/ServiceInterfaceStream.h b/serviceinterface/ServiceInterfaceStream.h index f3cb2cd0..0ea44f0b 100644 --- a/serviceinterface/ServiceInterfaceStream.h +++ b/serviceinterface/ServiceInterfaceStream.h @@ -39,6 +39,13 @@ public: */ std::string* getPreamble(); + /** + * Can be used to determine if the stream was configured to add CR characters in addition + * to newline characters. + * @return + */ + bool crAdditionEnabled() const; + protected: ServiceInterfaceBuffer streambuf; }; diff --git a/storagemanager/LocalPool.cpp b/storagemanager/LocalPool.cpp index cc7c9266..2b733548 100644 --- a/storagemanager/LocalPool.cpp +++ b/storagemanager/LocalPool.cpp @@ -5,15 +5,15 @@ LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig, bool registered, bool spillsToHigherPools): SystemObject(setObjectId, registered), - NUMBER_OF_POOLS(poolConfig.size()), + NUMBER_OF_SUBPOOLS(poolConfig.size()), spillsToHigherPools(spillsToHigherPools) { - if(NUMBER_OF_POOLS == 0) { + if(NUMBER_OF_SUBPOOLS == 0) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPool::LocalPool: Passed pool configuration is " << " invalid!" << std::endl; #endif } - max_pools_t index = 0; + max_subpools_t index = 0; for (const auto& currentPoolConfig: poolConfig) { this->numberOfElements[index] = currentPoolConfig.first; this->elementSizes[index] = currentPoolConfig.second; @@ -98,7 +98,7 @@ ReturnValue_t LocalPool::modifyData(store_address_t storeId, ReturnValue_t LocalPool::modifyData(store_address_t storeId, uint8_t **packetPtr, size_t *size) { ReturnValue_t status = RETURN_FAILED; - if (storeId.poolIndex >= NUMBER_OF_POOLS) { + if (storeId.poolIndex >= NUMBER_OF_SUBPOOLS) { return ILLEGAL_STORAGE_ID; } if ((storeId.packetIndex >= numberOfElements[storeId.poolIndex])) { @@ -127,7 +127,7 @@ ReturnValue_t LocalPool::deleteData(store_address_t storeId) { #endif ReturnValue_t status = RETURN_OK; - size_type pageSize = getPageSize(storeId.poolIndex); + size_type pageSize = getSubpoolElementSize(storeId.poolIndex); if ((pageSize != 0) and (storeId.packetIndex < numberOfElements[storeId.poolIndex])) { uint16_t packetPosition = getRawPosition(storeId); @@ -151,7 +151,7 @@ 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++) { + for (uint16_t n = 0; n < NUMBER_OF_SUBPOOLS; n++) { //Not sure if new allocates all stores in order. so better be careful. if ((store[n].data() <= ptr) and (&store[n][numberOfElements[n]*elementSizes[n]] > ptr)) { @@ -192,7 +192,7 @@ ReturnValue_t LocalPool::initialize() { } //Check if any pool size is large than the maximum allowed. - for (uint8_t count = 0; count < NUMBER_OF_POOLS; count++) { + for (uint8_t count = 0; count < NUMBER_OF_SUBPOOLS; count++) { if (elementSizes[count] >= STORAGE_FREE) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPool::initialize: Pool is too large! " @@ -217,7 +217,7 @@ void LocalPool::clearStore() { ReturnValue_t LocalPool::reserveSpace(const size_t size, store_address_t *storeId, bool ignoreFault) { - ReturnValue_t status = getPoolIndex(size, &storeId->poolIndex); + ReturnValue_t status = getSubPoolIndex(size, &storeId->poolIndex); if (status != RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec @@ -227,7 +227,7 @@ ReturnValue_t LocalPool::reserveSpace(const size_t size, } status = findEmpty(storeId->poolIndex, &storeId->packetIndex); while (status != RETURN_OK && spillsToHigherPools) { - status = getPoolIndex(size, &storeId->poolIndex, storeId->poolIndex + 1); + status = getSubPoolIndex(size, &storeId->poolIndex, storeId->poolIndex + 1); if (status != RETURN_OK) { //We don't find any fitting pool anymore. break; @@ -263,9 +263,9 @@ void LocalPool::write(store_address_t storeId, const uint8_t *data, sizeLists[storeId.poolIndex][storeId.packetIndex] = size; } -LocalPool::size_type LocalPool::getPageSize(max_pools_t poolIndex) { - if (poolIndex < NUMBER_OF_POOLS) { - return elementSizes[poolIndex]; +LocalPool::size_type LocalPool::getSubpoolElementSize(max_subpools_t subpoolIndex) { + if (subpoolIndex < NUMBER_OF_SUBPOOLS) { + return elementSizes[subpoolIndex]; } else { return 0; @@ -276,9 +276,9 @@ void LocalPool::setToSpillToHigherPools(bool enable) { this->spillsToHigherPools = enable; } -ReturnValue_t LocalPool::getPoolIndex(size_t packetSize, uint16_t *poolIndex, +ReturnValue_t LocalPool::getSubPoolIndex(size_t packetSize, uint16_t *subpoolIndex, uint16_t startAtIndex) { - for (uint16_t n = startAtIndex; n < NUMBER_OF_POOLS; n++) { + for (uint16_t n = startAtIndex; n < NUMBER_OF_SUBPOOLS; n++) { #if FSFW_VERBOSE_PRINTOUT == 2 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " @@ -286,7 +286,7 @@ ReturnValue_t LocalPool::getPoolIndex(size_t packetSize, uint16_t *poolIndex, #endif #endif if (elementSizes[n] >= packetSize) { - *poolIndex = n; + *subpoolIndex = n; return RETURN_OK; } } @@ -313,7 +313,7 @@ ReturnValue_t LocalPool::findEmpty(n_pool_elem_t poolIndex, uint16_t *element) { size_t LocalPool::getTotalSize(size_t* additionalSize) { size_t totalSize = 0; size_t sizesSize = 0; - for(uint8_t idx = 0; idx < NUMBER_OF_POOLS; idx ++) { + for(uint8_t idx = 0; idx < NUMBER_OF_SUBPOOLS; idx ++) { totalSize += elementSizes[idx] * numberOfElements[idx]; sizesSize += numberOfElements[idx] * sizeof(size_type); } @@ -331,7 +331,7 @@ void LocalPool::getFillCount(uint8_t *buffer, uint8_t *bytesWritten) { uint16_t reservedHits = 0; uint8_t idx = 0; uint16_t sum = 0; - for(; idx < NUMBER_OF_POOLS; idx ++) { + for(; idx < NUMBER_OF_SUBPOOLS; idx ++) { for(const auto& size: sizeLists[idx]) { if(size != STORAGE_FREE) { reservedHits++; @@ -343,21 +343,25 @@ void LocalPool::getFillCount(uint8_t *buffer, uint8_t *bytesWritten) { sum += buffer[idx]; reservedHits = 0; } - buffer[idx] = sum / NUMBER_OF_POOLS; + buffer[idx] = sum / NUMBER_OF_SUBPOOLS; *bytesWritten += 1; } -void LocalPool::clearPage(max_pools_t pageIndex) { - if(pageIndex >= NUMBER_OF_POOLS) { +void LocalPool::clearSubPool(max_subpools_t subpoolIndex) { + if(subpoolIndex >= NUMBER_OF_SUBPOOLS) { return; } // Mark the storage as free - for(auto& size: sizeLists[pageIndex]) { + for(auto& size: sizeLists[subpoolIndex]) { size = STORAGE_FREE; } // Set all the page content to 0. - std::memset(store[pageIndex].data(), 0, elementSizes[pageIndex]); + std::memset(store[subpoolIndex].data(), 0, elementSizes[subpoolIndex]); +} + +LocalPool::max_subpools_t LocalPool::getNumberOfSubPools() const { + return NUMBER_OF_SUBPOOLS; } diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index db771152..6a666485 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -60,15 +60,6 @@ public: }; using LocalPoolConfig = std::multiset; - /** - * @brief This definition generally sets the number of - * different sized pools. It is derived from the number of pairs - * inside the LocalPoolConfig set on object creation. - * @details - * This must be less than the maximum number of pools (currently 0xff). - */ - const max_pools_t NUMBER_OF_POOLS; - /** * @brief This is the default constructor for a pool manager instance. * @details @@ -143,9 +134,15 @@ public: void getFillCount(uint8_t* buffer, uint8_t* bytesWritten) override; void clearStore() override; - void clearPage(max_pools_t pageIndex) override; + void clearSubPool(max_subpools_t poolIndex) override; ReturnValue_t initialize() override; + + /** + * Get number sub pools. Each pool has pages with a specific bucket size. + * @return + */ + max_subpools_t getNumberOfSubPools() const override; protected: /** * With this helper method, a free element of @c size is reserved. @@ -158,6 +155,16 @@ protected: store_address_t* address, bool ignoreFault); private: + + /** + * @brief This definition generally sets the number of + * different sized pools. It is derived from the number of pairs + * inside the LocalPoolConfig set on object creation. + * @details + * This must be less than the maximum number of pools (currently 0xff). + */ + const max_subpools_t NUMBER_OF_SUBPOOLS; + /** * Indicates that this element is free. * This value limits the maximum size of a pool. @@ -170,20 +177,20 @@ private: * must be set in ascending order on construction. */ std::vector elementSizes = - std::vector(NUMBER_OF_POOLS); + std::vector(NUMBER_OF_SUBPOOLS); /** * @brief n_elements stores the number of elements per pool. * @details These numbers are maintained for internal pool management. */ std::vector numberOfElements = - std::vector(NUMBER_OF_POOLS); + std::vector(NUMBER_OF_SUBPOOLS); /** * @brief store represents the actual memory pool. * @details It is an array of pointers to memory, which was allocated with * a @c new call on construction. */ std::vector> store = - std::vector>(NUMBER_OF_POOLS); + std::vector>(NUMBER_OF_SUBPOOLS); /** * @brief The size_list attribute stores the size values of every pool element. @@ -191,7 +198,7 @@ private: * is also dynamically allocated there. */ std::vector> sizeLists = - std::vector>(NUMBER_OF_POOLS); + std::vector>(NUMBER_OF_SUBPOOLS); //! A variable to determine whether higher n pools are used if //! the store is full. @@ -210,7 +217,7 @@ private: * @param pool_index The pool in which to look. * @return Returns the size of an element or 0. */ - size_type getPageSize(max_pools_t poolIndex); + size_type getSubpoolElementSize(max_subpools_t subpoolIndex); /** * @brief This helper method looks up a fitting pool for a given size. @@ -221,7 +228,7 @@ private: * @return - @c RETURN_OK on success, * - @c DATA_TOO_LARGE otherwise. */ - ReturnValue_t getPoolIndex(size_t packetSize, uint16_t* poolIndex, + ReturnValue_t getSubPoolIndex(size_t packetSize, uint16_t* subpoolIndex, uint16_t startAtIndex = 0); /** * @brief This helper method calculates the true array position in store diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 62251933..da7ce01d 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -29,7 +29,7 @@ using ConstAccessorPair = std::pair; class StorageManagerIF : public HasReturnvaluesIF { public: using size_type = size_t; - using max_pools_t = uint8_t; + using max_subpools_t = uint8_t; 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. @@ -149,10 +149,10 @@ public: 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. + * 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 + * 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. @@ -171,20 +171,29 @@ public: virtual void clearStore() = 0; /** - * Clears a page in the store. Use with care! + * Clears a pool in the store with the given pool index. Use with care! * @param pageIndex */ - virtual void clearPage(uint8_t pageIndex) = 0; + virtual void clearSubPool(uint8_t poolIndex) = 0; /** - * Get the fill count of the pool. The exact form will be implementation - * dependant. + * Get the fill count of the pool. Each character inside the provided + * buffer will be assigned to a rounded percentage fill count for each + * page. The last written byte (at the index bytesWritten - 1) + * will contain the total fill count of the pool as a mean of the + * percentages of single pages. * @param buffer - * @param bytesWritten + * @param maxSize */ virtual void getFillCount(uint8_t* buffer, uint8_t* bytesWritten) = 0; virtual size_t getTotalSize(size_t* additionalSize) = 0; + + /** + * Get number of pools. + * @return + */ + virtual max_subpools_t getNumberOfSubPools() const = 0; }; #endif /* FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ */ diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 119ef243..24f8ef6f 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -1,2 +1,5 @@ add_subdirectory(internal) -add_subdirectory(tests) \ No newline at end of file + +if(LINK_CATCH2) + add_subdirectory(tests) +endif() \ No newline at end of file diff --git a/unittest/internal/CMakeLists.txt b/unittest/internal/CMakeLists.txt index 9c24317f..11fd2b2f 100644 --- a/unittest/internal/CMakeLists.txt +++ b/unittest/internal/CMakeLists.txt @@ -4,4 +4,5 @@ target_sources(${TARGET_NAME} PRIVATE ) add_subdirectory(osal) -add_subdirectory(serialize) \ No newline at end of file +add_subdirectory(serialize) +add_subdirectory(globalfunctions) \ No newline at end of file diff --git a/unittest/internal/InternalUnitTester.cpp b/unittest/internal/InternalUnitTester.cpp index bd41969c..a9394ad3 100644 --- a/unittest/internal/InternalUnitTester.cpp +++ b/unittest/internal/InternalUnitTester.cpp @@ -5,6 +5,7 @@ #include "osal/IntTestSemaphore.h" #include "osal/IntTestMutex.h" #include "serialize/IntTestSerialization.h" +#include "globalfunctions/TestArrayPrinter.h" #include @@ -12,17 +13,26 @@ InternalUnitTester::InternalUnitTester() {} InternalUnitTester::~InternalUnitTester() {} -ReturnValue_t InternalUnitTester::performTests() { +ReturnValue_t InternalUnitTester::performTests(struct InternalUnitTester::TestConfig& testConfig) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "Running internal unit tests.." << std::endl; +#else + sif::printInfo("Running internal unit tests..\n"); #endif + testserialize::test_serialization(); testmq::testMq(); testsemaph::testBinSemaph(); testsemaph::testCountingSemaph(); testmutex::testMutex(); + if(testConfig.testArrayPrinter) { + arrayprinter::testArrayPrinter(); + } + #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "Internal unit tests finished." << std::endl; +#else + sif::printInfo("Internal unit tests finished.\n"); #endif return RETURN_OK; } diff --git a/unittest/internal/InternalUnitTester.h b/unittest/internal/InternalUnitTester.h index d0b1c106..ae954c6a 100644 --- a/unittest/internal/InternalUnitTester.h +++ b/unittest/internal/InternalUnitTester.h @@ -4,6 +4,7 @@ #include "UnittDefinitions.h" #include "../../returnvalues/HasReturnvaluesIF.h" + /** * @brief Can be used for internal testing, for example for hardware specific * tests which can not be run on a host-machine. @@ -15,6 +16,10 @@ */ class InternalUnitTester: public HasReturnvaluesIF { public: + struct TestConfig { + bool testArrayPrinter; + }; + InternalUnitTester(); virtual~ InternalUnitTester(); @@ -22,7 +27,7 @@ public: * Some function which calls all other tests * @return */ - virtual ReturnValue_t performTests(); + virtual ReturnValue_t performTests(struct InternalUnitTester::TestConfig& testConfig); }; diff --git a/unittest/internal/UnittDefinitions.cpp b/unittest/internal/UnittDefinitions.cpp index 517f561a..ed4b59c1 100644 --- a/unittest/internal/UnittDefinitions.cpp +++ b/unittest/internal/UnittDefinitions.cpp @@ -5,7 +5,7 @@ sif::error << "Unit Tester error: Failed at test ID " << errorId << std::endl; #else - sif::printError("Unit Tester error: Failed at test ID 0x%08x", errorId); + sif::printError("Unit Tester error: Failed at test ID %s\n", errorId.c_str()); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/unittest/internal/globalfunctions/CMakeLists.txt b/unittest/internal/globalfunctions/CMakeLists.txt new file mode 100644 index 00000000..4ea49bf7 --- /dev/null +++ b/unittest/internal/globalfunctions/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${TARGET_NAME} PRIVATE + TestArrayPrinter.cpp +) diff --git a/unittest/internal/globalfunctions/TestArrayPrinter.cpp b/unittest/internal/globalfunctions/TestArrayPrinter.cpp new file mode 100644 index 00000000..de016d19 --- /dev/null +++ b/unittest/internal/globalfunctions/TestArrayPrinter.cpp @@ -0,0 +1,29 @@ +#include "TestArrayPrinter.h" + +void arrayprinter::testArrayPrinter() { + { + const std::array testDataSmall = {0x01, 0x02, 0x03, 0x04, 0x05}; + arrayprinter::print(testDataSmall.data(), testDataSmall.size()); + arrayprinter::print(testDataSmall.data(), testDataSmall.size(), OutputType::DEC); + arrayprinter::print(testDataSmall.data(), testDataSmall.size(), OutputType::BIN); + } + + { + std::array testDataMed; + for(size_t idx = 0; idx < testDataMed.size(); idx ++) { + testDataMed[idx] = testDataMed.size() - idx; + } + arrayprinter::print(testDataMed.data(), testDataMed.size()); + arrayprinter::print(testDataMed.data(), testDataMed.size(), OutputType::DEC, 8); + } + + { + std::array testDataLarge; + for(size_t idx = 0; idx < testDataLarge.size(); idx ++) { + testDataLarge[idx] = idx; + } + arrayprinter::print(testDataLarge.data(), testDataLarge.size()); + arrayprinter::print(testDataLarge.data(), testDataLarge.size(), OutputType::DEC); + } + +} diff --git a/unittest/internal/globalfunctions/TestArrayPrinter.h b/unittest/internal/globalfunctions/TestArrayPrinter.h new file mode 100644 index 00000000..50b82ca0 --- /dev/null +++ b/unittest/internal/globalfunctions/TestArrayPrinter.h @@ -0,0 +1,13 @@ +#ifndef FSFW_UNITTEST_INTERNAL_GLOBALFUNCTIONS_TESTARRAYPRINTER_H_ +#define FSFW_UNITTEST_INTERNAL_GLOBALFUNCTIONS_TESTARRAYPRINTER_H_ + +#include +#include + +namespace arrayprinter { + +void testArrayPrinter(); + +} + +#endif /* FSFW_UNITTEST_INTERNAL_GLOBALFUNCTIONS_TESTARRAYPRINTER_H_ */ diff --git a/unittest/internal/internal.mk b/unittest/internal/internal.mk index 799fd796..1d4c9c99 100644 --- a/unittest/internal/internal.mk +++ b/unittest/internal/internal.mk @@ -1,3 +1,4 @@ CXXSRC += $(wildcard $(CURRENTPATH)/osal/*.cpp) CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/globalfunctions/*.cpp) CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) \ No newline at end of file diff --git a/unittest/internal/osal/IntTestMutex.cpp b/unittest/internal/osal/IntTestMutex.cpp index 2a1584b8..13d87a8b 100644 --- a/unittest/internal/osal/IntTestMutex.cpp +++ b/unittest/internal/osal/IntTestMutex.cpp @@ -3,8 +3,8 @@ #include #include -#if defined(hosted) -#include +#if defined(WIN32) || defined(UNIX) +#include #include #include #endif @@ -19,10 +19,11 @@ void testmutex::testMutex() { } // timed_mutex from the C++ library specifies undefined behaviour if // the timed mutex is locked twice from the same thread. -#if defined(hosted) + // TODO: we should pass a define like FSFW_OSAL_HOST to the build. +#if defined(WIN32) || defined(UNIX) // This calls the function from // another thread and stores the returnvalue in a future. - auto future = std::async(&MutexIF::lockMutex, mutex, 1); + auto future = std::async(&MutexIF::lockMutex, mutex, MutexIF::TimeoutType::WAITING, 1); result = future.get(); #else result = mutex->lockMutex(MutexIF::TimeoutType::WAITING, 1); @@ -35,8 +36,12 @@ void testmutex::testMutex() { if(result != HasReturnvaluesIF::RETURN_OK) { unitt::put_error(id); } - result = mutex->unlockMutex(); + + // TODO: we should pass a define like FSFW_OSAL_HOST to the build. +#if !defined(WIN32) && !defined(UNIX) + result = mutex->unlockMutex(); if(result != MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX) { unitt::put_error(id); } +#endif } diff --git a/unittest/tests/globalfunctions/CMakeLists.txt b/unittest/tests/globalfunctions/CMakeLists.txt new file mode 100644 index 00000000..4ea49bf7 --- /dev/null +++ b/unittest/tests/globalfunctions/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${TARGET_NAME} PRIVATE + TestArrayPrinter.cpp +)