uart/hardware1.hpp

194 lines
4.5 KiB
C++

#pragma once
#include "config.hpp"
#include "hardware.hpp"
#define FORCE_INLINE __attribute__((always_inline))
namespace uart {
namespace detail {
#if defined(__AVR_ATmega1284P__)
struct Registers1 {
static constexpr volatile auto *IO_REG = &UDR1;
static constexpr volatile auto *CTRL_STAT_REG_A = &UCSR1A;
static constexpr volatile auto *CTRL_STAT_REG_B = &UCSR1B;
static constexpr volatile auto *CTRL_STAT_REG_C = &UCSR1C;
static constexpr volatile auto *BAUD_REG_L = &UBRR1L;
static constexpr volatile auto *BAUD_REG_H = &UBRR1H;
};
enum class ControlFlagsA1 {
MULTI_PROC_COMM_MODE = MPCM1,
SPEED_2X = U2X1,
PARITY_ERROR = UPE1,
DATA_OVER_RUN = DOR1,
FRAME_ERROR = FE1,
DATA_REG_EMPTY = UDRE1,
TRANSMIT_COMPLETE = TXC1,
RECEIVE_COMPLETE = RXC1,
};
enum class ControlFlagsB1 {
TX_DATA_BIT_8 = TXB81,
RX_DATA_BIT_8 = RXB81,
CHAR_SIZE_2 = UCSZ12,
TX_ENABLE = TXEN1,
RX_ENABLE = RXEN1,
DATA_REG_EMPTY_INT_ENABLE = UDRIE1,
TX_INT_ENABLE = TXCIE1,
RX_INT_ENABLE = RXCIE1,
};
enum class ControlFlagsC1 {
CLK_POLARITY = UCPOL1,
CHAR_SIZE_0 = UCSZ10,
CHAR_SIZE_1 = UCSZ11,
STOP_BIT_SEL = USBS1,
PARITY_MODE_0 = UPM10,
PARITY_MODE_1 = UPM11,
MODE_SEL_0 = UMSEL10,
MODE_SEL_1 = UMSEL11,
};
// clang-format off
constexpr int operator<<(const int &lhs, const ControlFlagsA1 &rhs) { return lhs << static_cast<int>(rhs); }
constexpr int operator<<(const int &lhs, const ControlFlagsB1 &rhs) { return lhs << static_cast<int>(rhs); }
constexpr int operator<<(const int &lhs, const ControlFlagsC1 &rhs) { return lhs << static_cast<int>(rhs); }
// clang-format on
static void (*fnRx1IntHandler)() = nullptr;
static void (*fnDataReg1EmptyIntHandler)() = nullptr;
static void (*fnTx1IntHandler)() = nullptr;
ISR(USART1_RX_vect)
{
if (fnRx1IntHandler)
fnRx1IntHandler();
}
ISR(USART1_UDRE_vect)
{
if (fnDataReg1EmptyIntHandler)
fnDataReg1EmptyIntHandler();
}
ISR(USART1_TX_vect)
{
if (fnTx1IntHandler)
fnTx1IntHandler();
}
#define HAS_UART1
#else
#error "This chip is not supported"
#endif
} // namespace detail
#ifdef HAS_UART1
template <Mode mode = Mode::ASYNCHRONOUS, class cfg = Config<>, Driven driven = Driven::INTERRUPT>
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 data_t rxByte() FORCE_INLINE {}
static data_t peek() FORCE_INLINE {}
private:
using HardwareImpl = detail::Hardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode, driven>;
};
template <Mode mode, class cfg>
class Hardware1<mode, cfg, Driven::INTERRUPT> {
public:
using data_t = typename cfg::data_t;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
static void init() FORCE_INLINE
{
detail::fnRx1IntHandler = rxIntHandler;
detail::fnDataReg1EmptyIntHandler = dataRegEmptyIntHandler;
detail::fnTx1IntHandler = txIntHandler;
HardwareImpl::init();
}
static void txByte(const data_t &byte) FORCE_INLINE
{
uint8_t tmpHead = (sm_txHead + 1) % TX_BUFFER_SIZE;
while (tmpHead == sm_txTail)
;
sm_txBuffer[tmpHead] = byte;
sm_txHead = tmpHead;
HardwareImpl::enableDataRegEmptyInt();
}
static data_t rxByte() FORCE_INLINE {}
static data_t peek() FORCE_INLINE {}
private:
using HardwareImpl = detail::Hardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode, Driven::INTERRUPT>;
static constexpr auto TX_BUFFER_SIZE = 16;
static volatile uint8_t sm_txHead;
static volatile uint8_t sm_txTail;
static volatile data_t sm_txBuffer[TX_BUFFER_SIZE];
static void rxIntHandler()
{
// TODO
}
static void dataRegEmptyIntHandler() FORCE_INLINE
{
if (sm_txHead != sm_txTail) {
uint8_t tmpTail = (sm_txTail + 1) % TX_BUFFER_SIZE;
sm_txTail = tmpTail;
HardwareImpl::txByteInterrupt(sm_txBuffer[tmpTail]);
} else
HardwareImpl::disableDataRegEmptyInt();
}
static void txIntHandler()
{
// TODO
}
};
template <Mode mode, class cfg>
volatile uint8_t Hardware1<mode, cfg, Driven::INTERRUPT>::sm_txHead = 0;
template <Mode mode, class cfg>
volatile uint8_t Hardware1<mode, cfg, Driven::INTERRUPT>::sm_txTail = 0;
template <Mode mode, class cfg>
volatile typename Hardware1<mode, cfg, Driven::INTERRUPT>::data_t
Hardware1<mode, cfg, Driven::INTERRUPT>::sm_txBuffer[TX_BUFFER_SIZE];
#endif
} // namespace uart
#undef FORCE_INLINE