diff --git a/hardware.hpp b/hardware.hpp index d78d6d0..e61dd6f 100644 --- a/hardware.hpp +++ b/hardware.hpp @@ -4,6 +4,8 @@ #include +#include "utils.hpp" + #define FORCE_INLINE __attribute__((always_inline)) namespace uart { @@ -31,6 +33,13 @@ static inline reg_ptr_t getRegPtr() return reinterpret_cast(Address); } +template +struct RingBuffer { + uint8_t head; + uint8_t tail; + data_t buf[Size]; +}; + template class Hardware { @@ -226,13 +235,153 @@ class Hardware { } }; -template -struct RingBuffer { - uint8_t head; - uint8_t tail; - data_t buf[Size]; +template +class BlockingHardware { + public: + using data_t = typename cfg::data_t; + static constexpr auto DATA_BITS = cfg::DATA_BITS; + + static void init() FORCE_INLINE + { + HardwareImpl::init(); + } + + static void txByte(const data_t &byte) FORCE_INLINE + { + HardwareImpl::txByteBlocking(byte); + } + + static bool rxByte(data_t &byte) FORCE_INLINE + { + return HardwareImpl::rxByteBlocking(byte); + } + + static bool peek([[maybe_unused]] data_t &byte) FORCE_INLINE + { + static_assert(util::always_false_v, "Peek with data is not supported in blocking mode"); + return false; + } + + static bool peek() FORCE_INLINE + { + return HardwareImpl::peekBlocking(); + } + + static void flushTx() FORCE_INLINE + { + while (!HardwareImpl::txEmpty()) + ; + while (!HardwareImpl::txComplete()) + ; + HardwareImpl::clearTxComplete(); + } + + private: + using HardwareImpl = Hardware; }; +template +class InterruptHardware { + public: + using data_t = typename cfg::data_t; + static constexpr auto DATA_BITS = cfg::DATA_BITS; + + static void txByte(const data_t &byte) FORCE_INLINE + { + uint8_t tmpHead = (sm_txBuf.head + 1) % TX_BUFFER_SIZE; + while (tmpHead == sm_txBuf.tail) + ; + + sm_txBuf.buf[tmpHead] = byte; + sm_txBuf.head = tmpHead; + + HardwareImpl::enableDataRegEmptyInt(); + } + + static bool rxByte(data_t &byte) FORCE_INLINE + { + if (sm_rxBuf.head == sm_rxBuf.tail) + return false; + + uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE; + byte = sm_rxBuf.buf[tmpTail]; + sm_rxBuf.tail = tmpTail; + + return true; + } + + static bool peek(data_t &byte) FORCE_INLINE + { + if (sm_rxBuf.head == sm_rxBuf.tail) + return false; + + uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE; + byte = sm_rxBuf.buf[tmpTail]; + + return true; + } + + static bool peek() FORCE_INLINE + { + return (sm_rxBuf.head != sm_rxBuf.tail); + } + + static void flushTx() FORCE_INLINE + { + while (sm_txBuf.head != sm_txBuf.tail) + ; + while (!HardwareImpl::txEmpty()) + ; + while (!HardwareImpl::txComplete()) + ; + HardwareImpl::clearTxComplete(); + } + + protected: + static void rxIntHandler() + { + auto data = HardwareImpl::rxByteInterrupt(); + + uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE; + + if (tmpHead != sm_rxBuf.tail) { + sm_rxBuf.head = tmpHead; + sm_rxBuf.buf[tmpHead] = data; + } else { + // TODO: Handle overflow + } + } + + static void dataRegEmptyIntHandler() FORCE_INLINE + { + if (sm_txBuf.head != sm_txBuf.tail) { + uint8_t tmpTail = (sm_txBuf.tail + 1) % TX_BUFFER_SIZE; + sm_txBuf.tail = tmpTail; + HardwareImpl::txByteInterrupt(sm_txBuf.buf[tmpTail]); + } else + HardwareImpl::disableDataRegEmptyInt(); + } + + private: + using HardwareImpl = Hardware; + + static constexpr auto TX_BUFFER_SIZE = 16; + static constexpr auto RX_BUFFER_SIZE = 16; + + static volatile RingBuffer sm_txBuf; + static volatile RingBuffer sm_rxBuf; +}; + +template +volatile RingBuffer::data_t, + InterruptHardware::TX_BUFFER_SIZE> + InterruptHardware::sm_txBuf = {0, 0, {0}}; + +template +volatile RingBuffer::data_t, + InterruptHardware::RX_BUFFER_SIZE> + InterruptHardware::sm_rxBuf = {0, 0, {0}}; + } // namespace detail } // namespace uart diff --git a/hardware0.hpp b/hardware0.hpp index 3acbbd0..abc9fcf 100644 --- a/hardware0.hpp +++ b/hardware0.hpp @@ -89,58 +89,24 @@ extern void (*fnDataReg0EmptyIntHandler)(); } // namespace detail template , Driven driven = Driven::INTERRUPT, Mode mode = Mode::ASYNCHRONOUS> -class Hardware0 { - public: - using data_t = typename cfg::data_t; - static constexpr auto DATA_BITS = cfg::DATA_BITS; - - static void init() FORCE_INLINE - { - HardwareImpl::init(); - } - - static void txByte(data_t byte) FORCE_INLINE - { - HardwareImpl::txByteBlocking(byte); - } - - static bool rxByte(data_t &byte) FORCE_INLINE - { - return HardwareImpl::rxByteBlocking(byte); - } - - static bool peek(data_t &byte) FORCE_INLINE - { - static_cast(byte); - static_assert(driven == Driven::BLOCKING, "Peek with data is not supported in blocking mode"); - return false; - } - - static bool peek() FORCE_INLINE - { - return HardwareImpl::peekBlocking(); - } - - static void flushTx() FORCE_INLINE - { - while (!HardwareImpl::txEmpty()) - ; - while (!HardwareImpl::txComplete()) - ; - HardwareImpl::clearTxComplete(); - } - - private: - using HardwareImpl = detail::Hardware; +class Hardware0 : public detail::BlockingHardware { }; template -class Hardware0 { - public: - using data_t = typename cfg::data_t; - static constexpr auto DATA_BITS = cfg::DATA_BITS; +class Hardware0 + : public detail::InterruptHardware { + using detail::InterruptHardware::rxIntHandler; + using detail::InterruptHardware::dataRegEmptyIntHandler; + + using HardwareImpl = detail::Hardware; + + public: static void init() FORCE_INLINE { detail::fnRx0IntHandler = rxIntHandler; @@ -149,103 +115,8 @@ class Hardware0 { HardwareImpl::init(); sei(); } - - static void txByte(const data_t &byte) FORCE_INLINE - { - uint8_t tmpHead = (sm_txBuf.head + 1) % TX_BUFFER_SIZE; - while (tmpHead == sm_txBuf.tail) - ; - - sm_txBuf.buf[tmpHead] = byte; - sm_txBuf.head = tmpHead; - - HardwareImpl::enableDataRegEmptyInt(); - } - - static bool rxByte(data_t &byte) FORCE_INLINE - { - if (sm_rxBuf.head == sm_rxBuf.tail) - return false; - - uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE; - byte = sm_rxBuf.buf[tmpTail]; - sm_rxBuf.tail = tmpTail; - - return true; - } - - static bool peek(data_t &byte) FORCE_INLINE - { - if (sm_rxBuf.head == sm_rxBuf.tail) - return false; - - uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE; - byte = sm_rxBuf.buf[tmpTail]; - - return true; - } - - static bool peek() FORCE_INLINE - { - return (sm_rxBuf.head != sm_rxBuf.tail); - } - - static void flushTx() FORCE_INLINE - { - while (sm_txBuf.head != sm_txBuf.tail) - ; - while (!HardwareImpl::txEmpty()) - ; - while (!HardwareImpl::txComplete()) - ; - HardwareImpl::clearTxComplete(); - } - - private: - using HardwareImpl = detail::Hardware; - - static constexpr auto TX_BUFFER_SIZE = 16; - static constexpr auto RX_BUFFER_SIZE = 16; - - static volatile detail::RingBuffer sm_txBuf; - static volatile detail::RingBuffer sm_rxBuf; - - static void rxIntHandler() - { - auto data = HardwareImpl::rxByteInterrupt(); - - uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE; - - if (tmpHead != sm_rxBuf.tail) { - sm_rxBuf.head = tmpHead; - sm_rxBuf.buf[tmpHead] = data; - } else { - // TODO: Handle overflow - } - } - - static void dataRegEmptyIntHandler() FORCE_INLINE - { - if (sm_txBuf.head != sm_txBuf.tail) { - uint8_t tmpTail = (sm_txBuf.tail + 1) % TX_BUFFER_SIZE; - sm_txBuf.tail = tmpTail; - HardwareImpl::txByteInterrupt(sm_txBuf.buf[tmpTail]); - } else - HardwareImpl::disableDataRegEmptyInt(); - } }; -template -volatile detail::RingBuffer::data_t, - Hardware0::TX_BUFFER_SIZE> - Hardware0::sm_txBuf = {0, 0, {0}}; - -template -volatile detail::RingBuffer::data_t, - Hardware0::RX_BUFFER_SIZE> - Hardware0::sm_rxBuf = {0, 0, {0}}; - } // namespace uart #undef FORCE_INLINE diff --git a/hardware1.hpp b/hardware1.hpp index 3dbe177..a8af41b 100644 --- a/hardware1.hpp +++ b/hardware1.hpp @@ -91,58 +91,24 @@ extern void (*fnDataReg1EmptyIntHandler)(); #ifdef HAS_UART1 template , Driven driven = Driven::INTERRUPT, Mode mode = Mode::ASYNCHRONOUS> -class Hardware1 { - public: - using data_t = typename cfg::data_t; - static constexpr auto DATA_BITS = cfg::DATA_BITS; - - static void init() FORCE_INLINE - { - HardwareImpl::init(); - } - - static void txByte(const data_t &byte) FORCE_INLINE - { - HardwareImpl::txByteBlocking(byte); - } - - static bool rxByte(data_t &byte) FORCE_INLINE - { - return HardwareImpl::rxByteBlocking(byte); - } - - static bool peek(data_t &byte) FORCE_INLINE - { - static_cast(byte); - static_assert(driven != Driven::BLOCKING, "Peek with data is not supported in blocking mode"); - return false; - } - - static bool peek() FORCE_INLINE - { - return HardwareImpl::peekBlocking(); - } - - static void flushTx() FORCE_INLINE - { - while (!HardwareImpl::txEmpty()) - ; - while (!HardwareImpl::txComplete()) - ; - HardwareImpl::clearTxComplete(); - } - - private: - using HardwareImpl = detail::Hardware; +class Hardware1 : public detail::BlockingHardware { }; template -class Hardware1 { - public: - using data_t = typename cfg::data_t; - static constexpr auto DATA_BITS = cfg::DATA_BITS; +class Hardware1 + : public detail::InterruptHardware { + using detail::InterruptHardware::rxIntHandler; + using detail::InterruptHardware::dataRegEmptyIntHandler; + + using HardwareImpl = detail::Hardware; + + public: static void init() FORCE_INLINE { detail::fnRx1IntHandler = rxIntHandler; @@ -151,103 +117,8 @@ class Hardware1 { HardwareImpl::init(); sei(); } - - static void txByte(const data_t &byte) FORCE_INLINE - { - uint8_t tmpHead = (sm_txBuf.head + 1) % TX_BUFFER_SIZE; - while (tmpHead == sm_txBuf.tail) - ; - - sm_txBuf.buf[tmpHead] = byte; - sm_txBuf.head = tmpHead; - - HardwareImpl::enableDataRegEmptyInt(); - } - - static bool rxByte(data_t &byte) FORCE_INLINE - { - if (sm_rxBuf.head == sm_rxBuf.tail) - return false; - - uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE; - byte = sm_rxBuf.buf[tmpTail]; - sm_rxBuf.tail = tmpTail; - - return true; - } - - static bool peek(data_t &byte) FORCE_INLINE - { - if (sm_rxBuf.head == sm_rxBuf.tail) - return false; - - uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE; - byte = sm_rxBuf.buf[tmpTail]; - - return true; - } - - static bool peek() FORCE_INLINE - { - return (sm_rxBuf.head != sm_rxBuf.tail); - } - - static void flushTx() FORCE_INLINE - { - while (sm_txBuf.head != sm_txBuf.tail) - ; - while (!HardwareImpl::txEmpty()) - ; - while (!HardwareImpl::txComplete()) - ; - HardwareImpl::clearTxComplete(); - } - - private: - using HardwareImpl = detail::Hardware; - - static constexpr auto TX_BUFFER_SIZE = 16; - static constexpr auto RX_BUFFER_SIZE = 16; - - static volatile detail::RingBuffer sm_txBuf; - static volatile detail::RingBuffer sm_rxBuf; - - static void rxIntHandler() - { - auto data = HardwareImpl::rxByteInterrupt(); - - uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE; - - if (tmpHead != sm_rxBuf.tail) { - sm_rxBuf.head = tmpHead; - sm_rxBuf.buf[tmpHead] = data; - } else { - // TODO: Handle overflow - } - } - - static void dataRegEmptyIntHandler() FORCE_INLINE - { - if (sm_txBuf.head != sm_txBuf.tail) { - uint8_t tmpTail = (sm_txBuf.tail + 1) % TX_BUFFER_SIZE; - sm_txBuf.tail = tmpTail; - HardwareImpl::txByteInterrupt(sm_txBuf.buf[tmpTail]); - } else - HardwareImpl::disableDataRegEmptyInt(); - } }; -template -volatile detail::RingBuffer::data_t, - Hardware1::TX_BUFFER_SIZE> - Hardware1::sm_txBuf = {0, 0, {0}}; - -template -volatile detail::RingBuffer::data_t, - Hardware1::RX_BUFFER_SIZE> - Hardware1::sm_rxBuf = {0, 0, {0}}; - #endif } // namespace uart