diff --git a/src/shared/utils/Registry/BufferedFlashBackend.cpp b/src/shared/utils/Registry/BufferedFlashBackend.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dbec5885eed210cb6d9a5f34305fa6c2f5bc9b6c --- /dev/null +++ b/src/shared/utils/Registry/BufferedFlashBackend.cpp @@ -0,0 +1,88 @@ +/* Copyright (c) 2023 Skyward Experimental Rocketry + * Author: Nicolò Caruso + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include "BufferedFlashBackend.h" + +namespace Boardcore +{ + +void BufferedFlashBackend::write(std::vector<uint8_t> &vector) +{ + std::lock_guard<std::mutex> lockBuffers(mutexBuffers); + std::lock_guard<std::mutex> lockCurrent(currentBuffer->mutex); + + // Copy the vector to be then written and tell there is a needed write + currentBuffer->vector = vector; + currentBuffer->write = true; +} + +void BufferedFlashBackend::swap() +{ + std::lock_guard<std::mutex> lockBuffers(mutexBuffers); + + WriteBuffer *tmp; + tmp = busyBuffer; + busyBuffer = currentBuffer; + currentBuffer = tmp; +} + +void BufferedFlashBackend::run() +{ + while (true) + { + // Writes the busy buffer when it needs to be written + { + std::unique_lock<std::mutex> lockBusy(busyBuffer->mutex); + + // Waits until the busy buffer not needs to be written + while (!busyBuffer->write) + writeCondition.wait(lockBusy); + + // TODO: write to backend the busy buffer + busyBuffer->write = false; + } + + // Swaps the buffer to update and the one to be written + swap(); + } +} + +bool BufferedFlashBackend::load(std::vector<uint8_t> &vector) +{ + // TODO: will call the backend for load the configuration to the vector + return false; +} + +void BufferedFlashBackend::clear() +{ + std::lock_guard<std::mutex> lockBuffers(mutexBuffers); + std::lock_guard<std::mutex> lockBusy(busyBuffer->mutex); + std::lock_guard<std::mutex> lockCurrent(currentBuffer->mutex); + + busyBuffer->vector.clear(); + currentBuffer->vector.clear(); + + busyBuffer->write = false; + currentBuffer->write = false; +} + +} // namespace Boardcore \ No newline at end of file diff --git a/src/shared/utils/Registry/BufferedFlashBackend.h b/src/shared/utils/Registry/BufferedFlashBackend.h new file mode 100644 index 0000000000000000000000000000000000000000..558f99c558595efd6abdf7528aff0373feb5bc22 --- /dev/null +++ b/src/shared/utils/Registry/BufferedFlashBackend.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2023 Skyward Experimental Rocketry + * Author: Nicolò Caruso + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include <ActiveObject.h> +#include <stdint.h> +#include <utils/Debug.h> + +#include <condition_variable> +#include <mutex> +#include <thread> +#include <vector> + +namespace +{ +constexpr uint32_t entriesReserve = + 40; ///< The nr. of configuration entries to reserve in the vectors +constexpr uint32_t address = 0; ///< The backend's address for load/write +} // namespace + +namespace Boardcore +{ +/** + * @brief Write buffer structs wraps an std::vector<uint8_t> with also its mutex + * and a flag for specify if it changed from last write. + */ +struct WriteBuffer +{ + std::vector<uint8_t> vector; ///< vector with serialized data + std::mutex mutex; + bool write; ///< True if it is needed a write to the backend +}; + +/** + * @brief Buffered backend class that uses buffers to hide the write time, + * making it asynchronous. It decouples frontend and backend such that the + * frontend is blocked just while loading and while copying the vector to be + * written. This make the write asynchronous, while the blocking call is made by + * the Buffered backend. + */ +class BufferedFlashBackend : public ActiveObject +{ +public: + /** + * @brief Construct a new BufferedBackend object + */ + BufferedFlashBackend() + : ActiveObject(miosix::STACK_DEFAULT_FOR_PTHREAD, miosix::MAIN_PRIORITY) + { + // Allocates and initializes the two buffers + busyBuffer = static_cast<WriteBuffer *>(malloc(sizeof(WriteBuffer))); + busyBuffer->vector = std::vector<uint8_t>(); + busyBuffer->vector.reserve(entriesReserve); + busyBuffer->write = false; + busyBuffer->mutex.unlock(); + + currentBuffer = static_cast<WriteBuffer *>(malloc(sizeof(WriteBuffer))); + currentBuffer->vector = std::vector<uint8_t>(); + currentBuffer->vector.reserve(entriesReserve); + currentBuffer->write = false; + currentBuffer->mutex.unlock(); + } + + /** + * @brief Copies the vector to a buffer for write and then writes it + * asynchronously to the backend + * + * @param vector The vector to be written to backend + */ + virtual void write(std::vector<uint8_t> &vector) = 0; + + /** + * @brief Loads the configuration into the vector, if any configuration + * exists in the underlying backend. + * + * @param vector The vector where the configuration is loaded + * @return true If the vector has been loaded with a configuration + * @return false Otherwise + */ + virtual bool load(std::vector<uint8_t> &vector) = 0; + + /** + * @brief Clears the buffers + */ + virtual void clear() = 0; + + /** + * @brief Executed by the internal thread for write the buffers to backend + */ + virtual void run() override; + +private: + WriteBuffer *busyBuffer, ///< The buffer that will be written + *currentBuffer; ///< The buffer that will be used for updates + std::mutex mutexBuffers; + std::thread workerThread; + std::condition_variable writeCondition; + + /** + * @brief Swaps the two buffers. + */ + void swap(); +}; +} // namespace Boardcore \ No newline at end of file