/** * @file fifo_buffer.h * @brief A FIFO buffer (base on cyclic_buffer) * * https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics) * * @date Aug 6, 2020 * @author andreika * @author Andrey Belomutskiy * */ #ifndef FIFO_BUFFER_H #define FIFO_BUFFER_H #include "cyclic_buffer.h" #if EFI_UNIT_TEST #include "global.h" #endif // EFI_UNIT_TEST // todo: this is not a thread-safe version! template class fifo_buffer : public cyclic_buffer { using cyclic_buffer::add; using cyclic_buffer::getSize; using cyclic_buffer::elements; using cyclic_buffer::size, cyclic_buffer::count; public: fifo_buffer() : currentIndexRead(0) { } virtual bool put(T item); T get(); void clear() /*override*/; virtual bool put(const T *items, int numItems); bool isEmpty() const { return getCount() == 0; } bool isFull() const { return getCount() >= getSize(); } int getCount() const { return cyclic_buffer::getCount(); } int getSize() const { return cyclic_buffer::getSize(); } const volatile T* getElements() const { return elements; } public: volatile int currentIndexRead; // FIFO "tail" }; template bool fifo_buffer::put(T item) { // check if full if (!isFull()) { add(item); return true; } return false; } template bool fifo_buffer::put(const T *items, int numItems) { for (int i = 0; i < numItems; i++) { if (!put(items[i])) return false; } return true; } template T fifo_buffer::get() { T &ret = (T &)elements[currentIndexRead]; if (!isEmpty()) { currentIndexRead = (currentIndexRead + 1) % size; count--; } return ret; } template void fifo_buffer::clear() { cyclic_buffer::clear(); currentIndexRead = 0; } template class fifo_buffer_sync : public fifo_buffer { public: fifo_buffer_sync() { #if !EFI_UNIT_TEST osalThreadQueueObjectInit(&q_waiting); #endif // EFI_UNIT_TEST } bool put(T item) override { chSysLock(); if (fifo_buffer::isFull()) { chSysUnlock(); return false; } fifo_buffer::put(item); osalThreadDequeueNextI(&q_waiting, MSG_OK); chSysUnlock(); return true; } bool put(const T *items, int numItems) override { for (int i = 0; i < numItems; i++) { if (!put(items[i])) return false; } return true; } bool get(T &item, int timeout) { #if !EFI_UNIT_TEST chSysLock(); while (fifo_buffer::isEmpty()) { msg_t msg = osalThreadEnqueueTimeoutS(&q_waiting, timeout); if (msg != MSG_OK) { chSysUnlock(); return false; } } item = fifo_buffer::get(); chSysUnlock(); return true; #endif // EFI_UNIT_TEST } void clear() { chSysLock(); fifo_buffer::clear(); #if !EFI_UNIT_TEST osalThreadDequeueAllI(&q_waiting, MSG_RESET); #endif // EFI_UNIT_TEST chSysUnlock(); } protected: #if !EFI_UNIT_TEST threads_queue_t q_waiting; #endif // EFI_UNIT_TEST }; #endif /* FIFO_BUFFER_H */