#ifndef UART_HARDWARE_0_HPP #define UART_HARDWARE_0_HPP #include #include #include #include #include "config.hpp" #include "hardware.hpp" #define FORCE_INLINE __attribute__((always_inline)) namespace uart { namespace detail { #if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega328P__) /* The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's: constexpr auto *foo = ptr; Workaround is to store the the address of the ptr in a uintptr_t and reinterpret_cast it at call site. The _SFR_ADDR macro in sfr_defs.h would give the address, but it does that by taking the address of the dereferenced pointer and casts it to uint16_t, which is still not a legal constexpr. The workaround therefore is to disable the pointer cast and dereference macro _MMIO_BYTE temporarily. */ #pragma push_macro("_MMIO_BYTE") #undef _MMIO_BYTE #define _MMIO_BYTE struct Registers0 { static constexpr uintptr_t IO_REG_ADDR = UDR0; static constexpr uintptr_t CTRL_STAT_REG_A_ADDR = UCSR0A; static constexpr uintptr_t CTRL_STAT_REG_B_ADDR = UCSR0B; static constexpr uintptr_t CTRL_STAT_REG_C_ADDR = UCSR0C; static constexpr uintptr_t BAUD_REG_L_ADDR = UBRR0L; static constexpr uintptr_t BAUD_REG_H_ADDR = UBRR0H; }; #pragma pop_macro("_MMIO_BYTE") 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 extern void (*fnRx0IntHandler)(); extern void (*fnDataReg0EmptyIntHandler)(); #else #error "This chip is not supported" #endif } // namespace detail template , Driven driven = Driven::INTERRUPT, Mode mode = Mode::ASYNCHRONOUS> class Hardware0 : public detail::BlockingHardware { }; template 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; detail::fnDataReg0EmptyIntHandler = dataRegEmptyIntHandler; HardwareImpl::init(); sei(); } }; } // namespace uart #undef FORCE_INLINE #endif ////////////////////////////////////////////////////////////////////////// #ifndef UART0_NO_INT_VECTORS #include namespace uart { namespace detail { #if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega328P__) #if defined(__AVR_ATmega328P__) #define USART0_RX_vect USART_RX_vect #define USART0_UDRE_vect USART_UDRE_vect #endif void (*fnRx0IntHandler)() = nullptr; 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 } // namespace uart #endif