#pragma once #include "config.hpp" #include "hardware.hpp" #define FORCE_INLINE __attribute__((always_inline)) namespace uart { namespace detail { #if defined(__AVR_ATmega1284P__) struct Registers0 { static constexpr volatile auto *IO_REG = &UDR0; static constexpr volatile auto *CTRL_STAT_REG_A = &UCSR0A; static constexpr volatile auto *CTRL_STAT_REG_B = &UCSR0B; static constexpr volatile auto *CTRL_STAT_REG_C = &UCSR0C; static constexpr volatile auto *BAUD_REG_L = &UBRR0L; static constexpr volatile auto *BAUD_REG_H = &UBRR0H; }; enum class ControlFlagsA0 { MULTI_PROC_COMM_MODE = MPCM0, SPEED_2X = U2X0, PARITY_ERROR = UPE0, DATA_OVER_RUN = DOR0, FRAME_ERROR = FE0, DATA_REG_EMPTY = UDRE0, TRANSMIT_COMPLETE = TXC0, RECEIVE_COMPLETE = RXC0, }; enum class ControlFlagsB0 { TX_DATA_BIT_8 = TXB80, RX_DATA_BIT_8 = RXB80, CHAR_SIZE_2 = UCSZ02, TX_ENABLE = TXEN0, RX_ENABLE = RXEN0, DATA_REG_EMPTY_INT_ENABLE = UDRIE0, TX_INT_ENABLE = TXCIE0, RX_INT_ENABLE = RXCIE0, }; enum class ControlFlagsC0 { CLK_POLARITY = UCPOL0, CHAR_SIZE_0 = UCSZ00, CHAR_SIZE_1 = UCSZ01, STOP_BIT_SEL = USBS0, PARITY_MODE_0 = UPM00, PARITY_MODE_1 = UPM01, MODE_SEL_0 = UMSEL00, MODE_SEL_1 = UMSEL01, }; // clang-format off constexpr int operator<<(const int &lhs, const ControlFlagsA0 &rhs) { return lhs << static_cast(rhs); } constexpr int operator<<(const int &lhs, const ControlFlagsB0 &rhs) { return lhs << static_cast(rhs); } constexpr int operator<<(const int &lhs, const ControlFlagsC0 &rhs) { return lhs << static_cast(rhs); } // clang-format on static void (*fnRx0IntHandler)() = nullptr; static void (*fnDataReg0EmptyIntHandler)() = nullptr; ISR(USART0_RX_vect) { if (fnRx0IntHandler) fnRx0IntHandler(); } ISR(USART0_UDRE_vect) { if (fnDataReg0EmptyIntHandler) fnDataReg0EmptyIntHandler(); } #else #error "This chip is not supported" #endif } // namespace detail template , Driven driven = Driven::INTERRUPT> 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 false; } static data_t peek() FORCE_INLINE {} private: using HardwareImpl = detail::Hardware; }; template class Hardware0 { public: using data_t = typename cfg::data_t; static constexpr auto DATA_BITS = cfg::DATA_BITS; static void init() FORCE_INLINE { detail::fnRx0IntHandler = rxIntHandler; detail::fnDataReg0EmptyIntHandler = dataRegEmptyIntHandler; HardwareImpl::init(); } 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 data_t peek() FORCE_INLINE {} 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() { uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE; if (tmpHead != sm_rxBuf.tail) { sm_rxBuf.head = tmpHead; sm_rxBuf.buf[tmpHead] = HardwareImpl::rxByteInterrupt(); } } 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