24#include "boards/board_traits.h"
30#if defined(UCSR0A) || defined(UCSR1A)
37#define REGISTER_UATX_ISR(UART_NUM) \
38 ISR(CAT3(USART, UART_NUM, _UDRE_vect)) \
40 serial::hard::isr_handler::uatx<UART_NUM>(); \
48#define REGISTER_UARX_ISR(UART_NUM) \
49 ISR(CAT3(USART, UART_NUM, _RX_vect)) \
51 serial::hard::isr_handler::uarx<UART_NUM>(); \
59#define REGISTER_UART_ISR(UART_NUM) \
60 ISR(CAT3(USART, UART_NUM, _UDRE_vect)) \
62 serial::hard::isr_handler::uart_tx<UART_NUM>(); \
65 ISR(CAT3(USART, UART_NUM, _RX_vect)) \
67 serial::hard::isr_handler::uart_rx<UART_NUM>(); \
90 AbstractUART() =
default;
91 AbstractUART(
const AbstractUART&) =
delete;
92 AbstractUART& operator=(
const AbstractUART&) =
delete;
96 constexpr SpeedSetup(uint16_t ubrr_value,
bool u2x) : ubrr_value_{ubrr_value}, u2x_{u2x} {}
97 const uint16_t ubrr_value_;
101 static constexpr SpeedSetup compute_speed(uint32_t rate)
103 const uint16_t double_rate = UBRR_double(rate);
104 if (double_rate < DOUBLE_SPEED_RATE_LIMIT)
105 return SpeedSetup(double_rate,
true);
107 return SpeedSetup(UBRR_single(rate),
false);
110 template<board::USART USART>
111 static void begin_(uint32_t rate, Parity parity, StopBits stop_bits,
114 using TRAIT = board_traits::USART_trait<USART>;
115 constexpr uint8_t UCSRB_TX = TRAIT::TX_ENABLE_MASK | TRAIT::UDRIE_MASK;
116 constexpr uint8_t UCSRB_RX = TRAIT::RX_ENABLE_MASK | TRAIT::RXCIE_MASK;
117 const uint8_t UCSRB_MASK = ((out !=
nullptr) ? UCSRB_TX : 0U) | ((in !=
nullptr) ? UCSRB_RX : 0U);
118 SpeedSetup setup = compute_speed(rate);
119 const uint8_t UCSRA_MASK = (setup.u2x_ ? TRAIT::U2X_MASK : 0);
122 TRAIT::UBRR = setup.ubrr_value_;
123 TRAIT::UCSRA = UCSRA_MASK;
124 TRAIT::UCSRB |= UCSRB_MASK;
125 TRAIT::UCSRC = TRAIT::UCSRC_value(parity, stop_bits);
127 if (out !=
nullptr) out->
queue().unlock();
130 template<board::USART USART>
133 using TRAIT = board_traits::USART_trait<USART>;
137 if (buffer_handling == BufferHandling::CLEAR)
138 out->
queue().clear();
139 else if (buffer_handling == BufferHandling::FLUSH)
142 constexpr uint8_t UCSRB_TX = TRAIT::TX_ENABLE_MASK | TRAIT::UDRIE_MASK;
143 constexpr uint8_t UCSRB_RX = TRAIT::RX_ENABLE_MASK | TRAIT::RXCIE_MASK;
144 const uint8_t UCSRB_MASK = ((out !=
nullptr) ? UCSRB_TX : 0U) | ((in !=
nullptr) ? UCSRB_RX : 0U);
145 synchronized TRAIT::UCSRB &= ~UCSRB_MASK;
146 if ((in !=
nullptr) && (buffer_handling == BufferHandling::CLEAR))
151 static constexpr const uint16_t DOUBLE_SPEED_RATE_LIMIT = 4096;
153 static constexpr uint16_t UBRR_double(uint32_t rate)
155 return ((F_CPU / 4 / rate) - 1) / 2;
157 static constexpr uint16_t UBRR_single(uint32_t rate)
159 return ((F_CPU / 8 / rate) - 1) / 2;
163 class AbstractUATX :
public AbstractUART
176 template<u
int8_t SIZE_TX>
177 explicit AbstractUATX(
char (&output)[SIZE_TX]) : obuf_{output} {}
184 template<board::USART USART>
185 void data_register_empty(Errors&
errors)
187 using TRAIT = board_traits::USART_trait<USART>;
190 if (obuf_.queue().pull_(value))
194 transmitting_ =
false;
200 template<board::USART USART>
201 void on_put(Errors&
errors)
203 using TRAIT = board_traits::USART_trait<USART>;
204 errors.queue_overflow = obuf_.overflow();
212 if (obuf_.queue().pull_(value))
215 TRAIT::UCSRB |= TRAIT::UDRIE_MASK;
217 transmitting_ =
true;
225 bool transmitting_ =
false;
240 template<board::USART USART_>
class UATX :
public AbstractUATX,
public UARTErrors
254 template<u
int8_t SIZE_TX>
explicit UATX(
char (&output)[SIZE_TX]) : AbstractUATX{output}
271 AbstractUART::begin_<USART>(rate, parity, stop_bits,
nullptr, &out_());
284 AbstractUART::end_<USART>(buffer_handling,
nullptr, &out_());
291 if (&obuf != &out_())
return false;
292 AbstractUATX::on_put<USART>(
errors());
296 void data_register_empty()
298 AbstractUATX::data_register_empty<USART>(
errors());
301 friend struct isr_handler;
306 class AbstractUARX :
public AbstractUART
319 template<u
int8_t SIZE_RX>
explicit AbstractUARX(
char (&input)[SIZE_RX]) : ibuf_{input} {}
326 template<board::USART USART>
327 void data_receive_complete(Errors&
errors)
329 using TRAIT = board_traits::USART_trait<USART>;
330 uint8_t status = TRAIT::UCSRA;
331 errors.data_overrun = status & TRAIT::DOR_MASK;
332 errors.frame_error = status & TRAIT::FE_MASK;
333 errors.parity_error = status & TRAIT::UPE_MASK;
334 uint8_t value = TRAIT::UDR;
335 errors.queue_overflow = !ibuf_.queue().push_(value);
351 template<board::USART USART_>
class UARX :
public AbstractUARX,
public UARTErrors
366 template<u
int8_t SIZE_RX>
explicit UARX(
char (&input)[SIZE_RX]) : AbstractUARX{input}
383 AbstractUART::begin_<USART>(rate, parity, stop_bits, &in_(),
nullptr);
396 AbstractUART::end_<USART>(buffer_handling, &in_(),
nullptr);
400 void data_receive_complete()
402 AbstractUARX::data_receive_complete<USART>(
errors());
405 friend struct isr_handler;
419 template<board::USART USART_>
class UART :
public AbstractUARX,
public AbstractUATX,
public UARTErrors
439 template<u
int8_t SIZE_RX, u
int8_t SIZE_TX>
440 UART(
char (&input)[SIZE_RX],
char (&output)[SIZE_TX])
441 : AbstractUARX{input}, AbstractUATX{output}
458 AbstractUART::begin_<USART>(rate, parity, stop_bits, &in_(), &out_());
471 AbstractUART::end_<USART>(buffer_handling, &in_(), &out_());
478 if (&obuf != &out_())
return false;
479 AbstractUATX::on_put<USART>(
errors());
483 void data_register_empty()
485 AbstractUATX::data_register_empty<USART>(
errors());
488 void data_receive_complete()
490 AbstractUARX::data_receive_complete<USART>(
errors());
493 friend struct isr_handler;
502 template<u
int8_t UART_NUM_>
static constexpr board::USART check_uart()
505 static_assert(board_traits::USART_trait<USART>::U2X_MASK != 0,
506 "UART_NUM must be an actual USART in target MCU");
510 template<u
int8_t UART_NUM_>
static void uatx()
513 interrupt::HandlerHolder<UATX<USART>>::handler()->data_register_empty();
516 template<u
int8_t UART_NUM_>
static void uarx()
519 interrupt::HandlerHolder<UARX<USART>>::handler()->data_receive_complete();
522 template<u
int8_t UART_NUM_>
static void uart_tx()
525 interrupt::HandlerHolder<UART<USART>>::handler()->data_register_empty();
528 template<u
int8_t UART_NUM_>
static void uart_rx()
531 interrupt::HandlerHolder<UART<USART>>::handler()->data_receive_complete();
541 template<board::USART USART>
struct UART_trait<hard::UATX<USART>>
543 static constexpr bool IS_UART =
true;
544 static constexpr bool IS_HW_UART =
true;
545 static constexpr bool IS_SW_UART =
false;
546 static constexpr bool HAS_TX =
true;
547 static constexpr bool HAS_RX =
false;
549 template<board::USART USART>
struct UART_trait<hard::UARX<USART>>
551 static constexpr bool IS_UART =
true;
552 static constexpr bool IS_HW_UART =
true;
553 static constexpr bool IS_SW_UART =
false;
554 static constexpr bool HAS_TX =
false;
555 static constexpr bool HAS_RX =
true;
557 template<board::USART USART>
struct UART_trait<hard::UART<USART>>
559 static constexpr bool IS_UART =
true;
560 static constexpr bool IS_HW_UART =
true;
561 static constexpr bool IS_SW_UART =
false;
562 static constexpr bool HAS_TX =
true;
563 static constexpr bool HAS_RX =
true;
Holder of latest UART errors.
Hardware serial receiver/transceiver API.
void end(BufferHandling buffer_handling=BufferHandling::KEEP)
Stop all transmissions and receptions.
UART(char(&input)[SIZE_RX], char(&output)[SIZE_TX])
Construct a new hardware serial receiver/transceiver and provide it with 2 buffers,...
static constexpr const board::USART USART
The hardware board::USART used by this UART.
void begin(uint32_t rate, Parity parity=Parity::NONE, StopBits stop_bits=StopBits::ONE)
Enable the receiver/transceiver.
Hardware serial receiver API.
static constexpr const board::USART USART
The hardware board::USART used by this UARX.
UARX(char(&input)[SIZE_RX])
Construct a new hardware serial receiver and provide it with a buffer for interrupt-based reception.
void begin(uint32_t rate, Parity parity=Parity::NONE, StopBits stop_bits=StopBits::ONE)
Enable the receiver.
void end(BufferHandling buffer_handling=BufferHandling::KEEP)
Stop reception.
Hardware serial transmitter API.
void end(BufferHandling buffer_handling=BufferHandling::KEEP)
Stop all transmissions.
void begin(uint32_t rate, Parity parity=Parity::NONE, StopBits stop_bits=StopBits::ONE)
Enable the transmitter.
UATX(char(&output)[SIZE_TX])
Construct a new hardware serial transmitter and provide it with a buffer for interrupt-based transmis...
static constexpr const board::USART USART
The hardware board::USART used by this UATX.
Input stream wrapper to provide formatted input API, a la C++.
Input API based on a ring buffer.
QUEUE & queue()
Return the underlying queue.
Output stream wrapper to provide formatted output API, a la C++.
Output API based on a ring buffer.
void pubsync()
Wait until all buffer content has been pulled by a consumer.
QUEUE & queue()
Return the underlying queue.
General API for handling AVR interrupt vectors.
static constexpr uint8_t COMPL(uint8_t value)
Return the uint8_t 2-complement of a byte.
USART
Defines all USART modules of target MCU.
This namespace defines common errors that can be returned by some FastArduino API methods,...
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Defines API types used by hardware UART features.
Defines all API for UART features.
BufferHandling
How the TX/RX buffer should be handled when ending transmission (see end() methods) on UATX/UARX.
@ KEEP
Stop transmission immediately, keep buffer as-is.
StopBits
Number of stop bits used for serial transmission.
Parity
Parity used for serial transmission.
#define DECL_OSTREAMBUF_LISTENERS_FRIEND
This macro shall be used in a class containing a private callback method bool on_put(streams::ostream...
C++-like std::iostream facilities.
Common definitions for serial API.