Compare commits

...

17 Commits

Author SHA1 Message Date
dd37fa0411 Expose baud rate for use by protocol implementations 2026-08-05 22:02:16 +02:00
430ad479fc Fix volatile compound assignments being deprecated in C++20 2026-08-05 22:02:16 +02:00
8f88cdccea Fix misaligned ifdef-endif pair 2020-04-13 17:17:17 +02:00
dfb076cda8 Change interrupt handler technique to not rely on function pointer and instead use user-facing macros 2020-04-13 16:43:04 +02:00
6d9ef6e4be Make variables const 2020-04-13 16:41:16 +02:00
bcd18db494 Fix double speed flag not being cleared if not used 2020-04-13 13:06:11 +02:00
04b6782ec4 Add automatic selection of double speed based on error 2020-04-12 23:57:16 +02:00
ae03c8d43e Adapt to new std compliant naming of numeric_limits 2020-04-07 19:15:05 +02:00
41b9ef74f9 Moved uart utils to separate type submodule 2020-04-07 03:50:29 +02:00
6f592dd098 Fixed missing const qualifier 2020-04-06 21:45:20 +02:00
fa0a65a94c Capitalized local constexpr variables to be more consistent 2020-04-05 03:36:05 +02:00
0e128bcb7d Made variable const 2020-04-05 03:30:22 +02:00
0a52110d47 Moved buffer closer to where needed 2020-04-05 03:28:45 +02:00
f751833a88 Made variables constexpr 2020-04-05 03:25:25 +02:00
1bd49f65fa Fixed template variable capitalization 2020-04-05 03:23:12 +02:00
cb436b11a8 Changed static assert to indicate impossible usage 2020-02-21 17:46:28 +01:00
2a2b9b8817 Added MIT license file 2020-02-01 15:36:20 +01:00
7 changed files with 238 additions and 320 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 BlackMark
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -2,9 +2,10 @@
#include "../clock.hpp"
#include <stdint.h>
#include "../type/type.hpp"
#include "utils.hpp"
#include <math.h>
#include <stdint.h>
#define FORCE_INLINE __attribute__((always_inline))
@@ -12,7 +13,6 @@ namespace uart {
enum class Mode {
ASYNCHRONOUS,
ASYNCHRONOUS_2X,
SYNCHRONOUS_MASTER,
SYNCHRONOUS_SLAVE,
SPI,
@@ -46,24 +46,36 @@ class Hardware {
public:
static void init() FORCE_INLINE
{
constexpr auto baudVal = calcBaud();
constexpr auto AbsDoubleError = fabs(calcBaudError<true>());
constexpr auto AbsNormalError = fabs(calcBaudError<false>());
static_assert(AbsDoubleError <= 3.0 || AbsNormalError <= 3.0, "Baud rate error over 3%, probably unusable");
*getRegPtr<Registers::BAUD_REG_H_ADDR>() = static_cast<uint8_t>(baudVal >> 8);
*getRegPtr<Registers::BAUD_REG_L_ADDR>() = static_cast<uint8_t>(baudVal);
constexpr auto UseDoubleSpeed = (AbsDoubleError < AbsNormalError);
constexpr auto BaudVal = calcBaudVal<UseDoubleSpeed>();
constexpr auto dataBitsVal = calcDataBits();
constexpr auto parityVal = calcParity();
constexpr auto stopBitsVal = calcStopBits();
constexpr auto modeVal = calcMode();
constexpr auto enableRx = calcRxState<true>();
constexpr auto enableTx = calcTxState<true>();
constexpr auto interruptVal = calcInterrupt();
*getRegPtr<Registers::BAUD_REG_H_ADDR>() = static_cast<uint8_t>(BaudVal >> 8);
*getRegPtr<Registers::BAUD_REG_L_ADDR>() = static_cast<uint8_t>(BaudVal);
constexpr uint8_t controlRegB = dataBitsVal.regBVal | enableRx | enableTx | interruptVal;
constexpr uint8_t controlRegC = dataBitsVal.regCVal | parityVal | stopBitsVal | modeVal;
constexpr auto DataBitsValues = calcDataBits();
constexpr auto ParityVal = calcParity();
constexpr auto StopBitsVal = calcStopBits();
constexpr auto ModeVal = calcMode();
constexpr auto EnableRx = calcRxState<true>();
constexpr auto EnableTx = calcTxState<true>();
constexpr auto InterruptVal = calcInterrupt();
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() = controlRegB;
*getRegPtr<Registers::CTRL_STAT_REG_C_ADDR>() = controlRegC;
constexpr uint8_t ControlRegB = DataBitsValues.regBVal | EnableRx | EnableTx | InterruptVal;
constexpr uint8_t ControlRegC = DataBitsValues.regCVal | ParityVal | StopBitsVal | ModeVal;
if constexpr (UseDoubleSpeed)
*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() =
*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() | (1 << CtrlFlagsA::SPEED_2X);
else
*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() =
*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & ~(1 << CtrlFlagsA::SPEED_2X);
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() = ControlRegB;
*getRegPtr<Registers::CTRL_STAT_REG_C_ADDR>() = ControlRegC;
}
static bool rxByteBlocking(typename cfg::data_t &byte) FORCE_INLINE
@@ -120,12 +132,14 @@ class Hardware {
static void enableDataRegEmptyInt() FORCE_INLINE
{
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() |= (1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() =
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() | (1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
}
static void disableDataRegEmptyInt() FORCE_INLINE
{
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() &= ~(1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() =
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() & ~(1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
}
private:
@@ -134,11 +148,37 @@ class Hardware {
uint8_t regBVal = 0;
};
static constexpr auto calcBaud()
template <bool DoubleSpeed = true>
static constexpr auto calcBaudVal()
{
// The actual formula is (F_CPU / (16 * baudRate)) - 1, but this one has the advantage of rounding correctly
constexpr auto baudVal = (F_CPU + 8 * cfg::BAUD_RATE) / (16 * cfg::BAUD_RATE) - 1;
return baudVal;
if constexpr (DoubleSpeed) {
constexpr auto BaudVal = static_cast<uint16_t>(round(F_CPU / (8.0 * cfg::BAUD_RATE) - 1));
return BaudVal;
}
constexpr auto BaudVal = static_cast<uint16_t>(round(F_CPU / (16.0 * cfg::BAUD_RATE) - 1));
return BaudVal;
}
template <uint16_t BaudVal, bool DoubleSpeed = true>
static constexpr auto calcBaudRate()
{
if constexpr (DoubleSpeed) {
constexpr auto BaudRate = static_cast<uint32_t>(round(F_CPU / (8.0 * (BaudVal + 1))));
return BaudRate;
}
constexpr auto BaudRate = static_cast<uint32_t>(round(F_CPU / (16.0 * (BaudVal + 1))));
return BaudRate;
}
template <bool DoubleSpeed = true>
static constexpr auto calcBaudError()
{
constexpr auto BaudVal = calcBaudVal<DoubleSpeed>();
constexpr auto ClosestBaudRate = calcBaudRate<BaudVal, DoubleSpeed>();
constexpr auto BaudError = (static_cast<double>(ClosestBaudRate) / cfg::BAUD_RATE - 1) * 100;
return BaudError;
}
static constexpr auto calcDataBits()
@@ -202,23 +242,23 @@ class Hardware {
return modeVal;
}
template <bool enable>
template <bool Enable>
static constexpr auto calcRxState()
{
uint8_t enableVal = 0;
if (enable)
if (Enable)
enableVal = (1 << CtrlFlagsB::RX_ENABLE);
return enableVal;
}
template <bool enable>
template <bool Enable>
static constexpr auto calcTxState()
{
uint8_t enableVal = 0;
if (enable)
if (Enable)
enableVal = (1 << CtrlFlagsB::TX_ENABLE);
return enableVal;
@@ -239,6 +279,7 @@ template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename Ct
class BlockingHardware {
public:
using data_t = typename cfg::data_t;
static constexpr auto BAUD_RATE = cfg::BAUD_RATE;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
static void init() FORCE_INLINE
@@ -258,7 +299,7 @@ class BlockingHardware {
static bool peek(data_t &) FORCE_INLINE
{
static_assert(util::always_false_v<data_t>, "Peek with data is not supported in blocking mode");
static_assert(type::always_false_v<data_t>, "Peek with data is not supported in blocking mode");
return false;
}
@@ -284,6 +325,7 @@ template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename Ct
class InterruptHardware {
public:
using data_t = typename cfg::data_t;
static constexpr auto BAUD_RATE = cfg::BAUD_RATE;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
static void txByte(const data_t &byte) FORCE_INLINE
@@ -340,9 +382,9 @@ class InterruptHardware {
protected:
static void rxIntHandler() FORCE_INLINE
{
auto data = HardwareImpl::rxByteInterrupt();
const auto data = HardwareImpl::rxByteInterrupt();
uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE;
const uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE;
if (tmpHead != sm_rxBuf.tail) {
sm_rxBuf.head = tmpHead;
@@ -355,7 +397,7 @@ class InterruptHardware {
static void dataRegEmptyIntHandler() FORCE_INLINE
{
if (sm_txBuf.head != sm_txBuf.tail) {
uint8_t tmpTail = (sm_txBuf.tail + 1) % TX_BUFFER_SIZE;
const uint8_t tmpTail = (sm_txBuf.tail + 1) % TX_BUFFER_SIZE;
sm_txBuf.tail = tmpTail;
HardwareImpl::txByteInterrupt(sm_txBuf.buf[tmpTail]);
} else

View File

@@ -1,5 +1,4 @@
#ifndef UART_HARDWARE_0_HPP
#define UART_HARDWARE_0_HPP
#pragma once
#include <stdint.h>
@@ -82,8 +81,10 @@ constexpr int operator<<(const int &lhs, const ControlFlagsB0 &rhs) { return lhs
constexpr int operator<<(const int &lhs, const ControlFlagsC0 &rhs) { return lhs << static_cast<int>(rhs); }
// clang-format on
extern void (*fnRx0IntHandler)();
extern void (*fnDataReg0EmptyIntHandler)();
#if defined(__AVR_ATmega328P__)
#define USART0_RX_vect USART_RX_vect
#define USART0_UDRE_vect USART_UDRE_vect
#endif
#else
#error "This chip is not supported"
@@ -100,70 +101,56 @@ template <class cfg, Mode mode>
class Hardware0<cfg, Driven::INTERRUPT, mode>
: public detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode> {
using detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode>::rxIntHandler;
using detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode>::dataRegEmptyIntHandler;
using HardwareImpl = detail::Hardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, Driven::INTERRUPT, mode>;
public:
static void init() FORCE_INLINE
{
detail::fnRx0IntHandler = rxIntHandler;
detail::fnDataReg0EmptyIntHandler = dataRegEmptyIntHandler;
HardwareImpl::init();
sei();
}
private:
using HardwareImpl = detail::Hardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, Driven::INTERRUPT, mode>;
using InterruptHardwareImpl = detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0,
detail::ControlFlagsB0, detail::ControlFlagsC0, cfg, mode>;
// Must be friends with Uart interface to call these private handlers
template <class Driver>
friend class Uart;
static void rxIntHandler() FORCE_INLINE
{
InterruptHardwareImpl::rxIntHandler();
}
static void dataRegEmptyIntHandler() FORCE_INLINE
{
InterruptHardwareImpl::dataRegEmptyIntHandler();
}
};
} // namespace uart
#undef FORCE_INLINE
#endif
//////////////////////////////////////////////////////////////////////////
#ifdef UART0_INT_VECTORS
#include <avr/interrupt.h>
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();
// Forward declare interrupt functions to allow adding them as friends
extern "C" {
void USART0_RX_vect() __attribute__((signal));
void USART0_UDRE_vect() __attribute__((signal));
}
ISR(USART0_UDRE_vect)
{
if (fnDataReg0EmptyIntHandler)
fnDataReg0EmptyIntHandler();
}
// clang-format off
#define REGISTER_UART0_INT_VECTORS(uart_type) \
ISR(USART0_RX_vect) \
{ \
uart_type::rxIntHandler(); \
} \
ISR(USART0_UDRE_vect) \
{ \
uart_type::dataRegEmptyIntHandler(); \
} \
struct _##uart_type {}
// clang-format on
#else
#error "This chip is not supported"
#endif
} // namespace detail
} // namespace uart
#undef UART0_INT_VECTORS
#endif
#undef FORCE_INLINE

View File

@@ -1,5 +1,4 @@
#ifndef UART_HARDWARE_1_HPP
#define UART_HARDWARE_1_HPP
#pragma once
#include <stdint.h>
@@ -82,9 +81,6 @@ constexpr int operator<<(const int &lhs, const ControlFlagsB1 &rhs) { return lhs
constexpr int operator<<(const int &lhs, const ControlFlagsC1 &rhs) { return lhs << static_cast<int>(rhs); }
// clang-format on
extern void (*fnRx1IntHandler)();
extern void (*fnDataReg1EmptyIntHandler)();
#define HAS_UART1
#endif
@@ -102,65 +98,64 @@ template <class cfg, Mode mode>
class Hardware1<cfg, Driven::INTERRUPT, mode>
: public detail::InterruptHardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode> {
using detail::InterruptHardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode>::rxIntHandler;
using detail::InterruptHardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode>::dataRegEmptyIntHandler;
using HardwareImpl = detail::Hardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, Driven::INTERRUPT, mode>;
public:
static void init() FORCE_INLINE
{
detail::fnRx1IntHandler = rxIntHandler;
detail::fnDataReg1EmptyIntHandler = dataRegEmptyIntHandler;
HardwareImpl::init();
sei();
}
private:
using HardwareImpl = detail::Hardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, Driven::INTERRUPT, mode>;
using InterruptHardwareImpl = detail::InterruptHardware<detail::Registers1, detail::ControlFlagsA1,
detail::ControlFlagsB1, detail::ControlFlagsC1, cfg, mode>;
// Must be friends with Uart interface to call these private handlers
template <class Driver>
friend class Uart;
static void rxIntHandler() FORCE_INLINE
{
InterruptHardwareImpl::rxIntHandler();
}
static void dataRegEmptyIntHandler() FORCE_INLINE
{
InterruptHardwareImpl::dataRegEmptyIntHandler();
}
};
#endif
} // namespace uart
#undef FORCE_INLINE
#endif
//////////////////////////////////////////////////////////////////////////
#ifdef UART1_INT_VECTORS
#ifdef HAS_UART1
#include <avr/interrupt.h>
namespace uart {
namespace detail {
#if defined(__AVR_ATmega1284P__)
void (*fnRx1IntHandler)() = nullptr;
void (*fnDataReg1EmptyIntHandler)() = nullptr;
ISR(USART1_RX_vect)
{
if (fnRx1IntHandler)
fnRx1IntHandler();
// Forward declare interrupt functions to allow adding them as friends
extern "C" {
void USART1_RX_vect() __attribute__((signal));
void USART1_UDRE_vect() __attribute__((signal));
}
ISR(USART1_UDRE_vect)
{
if (fnDataReg1EmptyIntHandler)
fnDataReg1EmptyIntHandler();
}
// clang-format off
#define REGISTER_UART1_INT_VECTORS(uart_type) \
ISR(USART1_RX_vect) \
{ \
uart_type::rxIntHandler(); \
} \
ISR(USART1_UDRE_vect) \
{ \
uart_type::dataRegEmptyIntHandler(); \
} \
struct _##uart_type { \
}
// clang-format off
#endif
} // namespace detail
} // namespace uart
#undef FORCE_INLINE
#undef UART1_INT_VECTORS
#endif

View File

@@ -1,15 +1,15 @@
#pragma once
#include "config.hpp"
#include "utils.hpp"
#include "../io/io.hpp"
#include "../type/type.hpp"
namespace uart {
template <io::P rxPin, io::P txPin, class cfg = Config<>>
class Software {
static_assert(util::always_false_v<cfg>, "Not implemented");
static_assert(type::always_false_v<cfg>, "Not implemented");
public:
using data_t = typename cfg::data_t;

100
uart.hpp
View File

@@ -4,11 +4,8 @@
#include "config.hpp"
#include "software.hpp"
#include "utils.hpp"
#undef UART0_INT_VECTORS
#include "hardware0.hpp"
#undef UART1_INT_VECTORS
#include "hardware1.hpp"
#include "../flash/flash.hpp"
@@ -19,10 +16,10 @@ namespace uart {
namespace detail {
template <typename T, T limit, size_t Base>
template <typename T, T Limit, size_t Base>
static constexpr size_t cntDigits()
{
T num = limit;
T num = Limit;
size_t cnt = 0;
do {
@@ -36,13 +33,13 @@ static constexpr size_t cntDigits()
template <typename T, size_t Base>
static constexpr size_t maxNumDigits()
{
constexpr T minVal = util::NumericLimits<T>::min();
constexpr T maxVal = util::NumericLimits<T>::max();
constexpr T MinVal = type::numeric_limits<T>::min();
constexpr T MaxVal = type::numeric_limits<T>::max();
T minDigits = cntDigits<T, minVal, Base>();
T maxDigits = cntDigits<T, maxVal, Base>();
constexpr T MinDigits = cntDigits<T, MinVal, Base>();
constexpr T MaxDigits = cntDigits<T, MaxVal, Base>();
return (minDigits < maxDigits) ? maxDigits : minDigits;
return (MinDigits < MaxDigits) ? MaxDigits : MinDigits;
}
} // namespace detail
@@ -115,16 +112,13 @@ class Uart {
template <typename T, size_t Base = 10, size_t Padding = 0, char PadChar = '0', bool LowerCase = true>
static void txNumber(const T &val)
{
static_assert(util::is_integral_v<T>, "Only supported on integral types");
static_assert(type::is_integral_v<T>, "Only supported on integral types");
static_assert(Base >= 2, "Numbers with base less than 2 make no sense");
static_assert(Base <= 16, "Numbers with base higher than 16 are not supported");
static_assert(Padding <= detail::maxNumDigits<T, Base>(), "Cannot pad more than maximum length of number");
constexpr char alphaChar = (LowerCase) ? 'a' : 'A';
constexpr size_t numDigits = detail::maxNumDigits<T, Base>();
data_t buffer[numDigits];
data_t *bufEnd = buffer + numDigits - 1;
constexpr char AlphaChar = (LowerCase) ? 'a' : 'A';
constexpr size_t NumDigits = detail::maxNumDigits<T, Base>();
T digits = val;
@@ -133,14 +127,17 @@ class Uart {
txByte('-');
}
data_t buffer[NumDigits];
data_t *bufEnd = buffer + NumDigits - 1;
do {
data_t lastDigit = digits % Base;
*bufEnd-- = (lastDigit < 10) ? ('0' + lastDigit) : (alphaChar + lastDigit - 10);
const data_t lastDigit = digits % Base;
*bufEnd-- = (lastDigit < 10) ? ('0' + lastDigit) : (AlphaChar + lastDigit - 10);
digits /= Base;
} while (digits > 0);
if (Padding > 0) {
size_t strLen = buffer + numDigits - (bufEnd + 1);
size_t strLen = buffer + NumDigits - (bufEnd + 1);
if (Padding > strLen) {
for (size_t i = Padding; i > strLen && bufEnd >= buffer; --i) {
@@ -149,7 +146,7 @@ class Uart {
}
}
for (data_t *buf = bufEnd + 1; buf < buffer + numDigits; ++buf)
for (data_t *buf = bufEnd + 1; buf < buffer + NumDigits; ++buf)
txByte(*buf);
}
@@ -192,7 +189,7 @@ class Uart {
return *this;
}
Uart &operator<<(unsigned short &val)
Uart &operator<<(const unsigned short &val)
{
txNumber(val);
return *this;
@@ -216,19 +213,19 @@ class Uart {
return *this;
}
Uart &operator<<(unsigned long &val)
Uart &operator<<(const unsigned long &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(long long &val)
Uart &operator<<(const long long &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(unsigned long long &val)
Uart &operator<<(const unsigned long long &val)
{
txNumber(val);
return *this;
@@ -237,19 +234,19 @@ class Uart {
template <typename... Ts>
Uart &operator<<(float) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator<<(double) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator<<(long double) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not supported by hardware");
}
Uart &operator<<(const bool &val)
@@ -271,91 +268,110 @@ class Uart {
template <typename... Ts>
Uart &operator>>(char &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned char &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(short &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned short &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(int &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned int &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(long &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned long &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(long long &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned long long &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(float &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator>>(double &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator>>(long double &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator>>(bool &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(const void *&) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
static_assert(type::always_false_v<Ts...>, "Not implemented");
}
private:
friend void ::USART0_RX_vect();
friend void ::USART0_UDRE_vect();
#ifdef HAS_UART1
friend void ::USART1_RX_vect();
friend void ::USART1_UDRE_vect();
#endif
static void rxIntHandler() FORCE_INLINE
{
Driver::rxIntHandler();
}
static void dataRegEmptyIntHandler() FORCE_INLINE
{
Driver::dataRegEmptyIntHandler();
}
};

143
utils.hpp
View File

@@ -1,143 +0,0 @@
#pragma once
// Fix for limits.h not exposing LLONG_MIN, LLONG_MIN, and ULLONG_MAX to C++ context
#ifdef __cplusplus
#define __STDC_VERSION__ 201112L
#endif
#include <float.h>
#include <limits.h>
namespace uart {
namespace util {
// clang-format off
template <bool Val> struct set_bool { static constexpr auto value = Val; };
struct true_type : set_bool<true> {};
struct false_type : set_bool<false> {};
template <typename...> struct always_false : false_type {};
template <typename... Ts> static constexpr auto always_false_v = always_false<Ts...>::value;
template <typename T> struct is_integral : false_type {};
template <> struct is_integral<bool> : true_type {};
template <> struct is_integral<char> : true_type {};
template <> struct is_integral<signed char> : true_type {};
template <> struct is_integral<unsigned char> : true_type {};
template <> struct is_integral<short> : true_type {};
template <> struct is_integral<int> : true_type {};
template <> struct is_integral<long int> : true_type {};
template <> struct is_integral<long long int> : true_type {};
template <> struct is_integral<unsigned short> : true_type {};
template <> struct is_integral<unsigned int> : true_type {};
template <> struct is_integral<unsigned long int> : true_type {};
template <> struct is_integral<unsigned long long int> : true_type {};
template <typename T> static constexpr auto is_integral_v = is_integral<T>::value;
template <typename T, typename U> struct is_same : false_type {};
template <typename T> struct is_same<T, T> : true_type {};
template <typename T, typename U> static constexpr auto is_same_v = is_same<T, U>::value;
template <typename T>
struct NumericLimits {
static constexpr T min() { return T(); }
static constexpr T max() { return T(); }
};
template <>
struct NumericLimits<bool> {
static constexpr bool min() { return false; }
static constexpr bool max() { return true; }
};
template <>
struct NumericLimits<char> {
static constexpr char min() { return CHAR_MIN; }
static constexpr char max() { return CHAR_MAX; }
};
template <>
struct NumericLimits<signed char> {
static constexpr signed char min() { return SCHAR_MIN; }
static constexpr signed char max() { return SCHAR_MAX; }
};
template <>
struct NumericLimits<unsigned char> {
static constexpr unsigned char min() { return 0; }
static constexpr unsigned char max() { return UCHAR_MAX; }
};
template <>
struct NumericLimits<short> {
static constexpr short min() { return SHRT_MIN; }
static constexpr short max() { return SHRT_MAX; }
};
template <>
struct NumericLimits<int> {
static constexpr int min() { return INT_MIN; }
static constexpr int max() { return INT_MAX; }
};
template <>
struct NumericLimits<long> {
static constexpr long int min() { return LONG_MIN; }
static constexpr long int max() { return LONG_MAX; }
};
template <>
struct NumericLimits<long long int> {
static constexpr long long int min() { return LLONG_MIN; }
static constexpr long long int max() { return LLONG_MAX; }
};
template <>
struct NumericLimits<unsigned short> {
static constexpr unsigned short min() { return 0; }
static constexpr unsigned short max() { return USHRT_MAX; }
};
template <>
struct NumericLimits<unsigned int> {
static constexpr unsigned int min() { return 0; }
static constexpr unsigned int max() { return UINT_MAX; }
};
template <>
struct NumericLimits<unsigned long int> {
static constexpr unsigned long int min() { return 0; }
static constexpr unsigned long int max() { return ULONG_MAX; }
};
template <>
struct NumericLimits<unsigned long long int> {
static constexpr unsigned long long int min() { return 0; }
static constexpr unsigned long long int max() { return ULLONG_MAX; }
};
template <>
struct NumericLimits<float> {
template <typename... Ts> static constexpr float min() { return FLT_MIN; }
template <typename... Ts> static constexpr float max() { return FLT_MAX; }
};
template <>
struct NumericLimits<double> {
template <typename... Ts> static constexpr double min() { return DBL_MIN; }
template <typename... Ts> static constexpr double max() { return DBL_MAX; }
};
template <>
struct NumericLimits<long double> {
template <typename... Ts> static constexpr long double min() { return LDBL_MIN; }
template <typename... Ts> static constexpr long double max() { return LDBL_MAX; }
};
// clang-format on
} // namespace util
} // namespace uart