Compare commits

...

2 Commits

190
io.hpp
View File

@ -45,8 +45,6 @@
#define PIN_C7_AVAILABLE
#endif
#define FORCE_INLINE __attribute__((always_inline))
//////////////////////////////////////////////////////////////////////////
// Library implementation
@ -104,6 +102,8 @@ enum class P {
D6 = 0x36,
D7 = 0x37,
#endif
NONE,
};
enum class Bus {
@ -119,6 +119,8 @@ enum class Bus {
#ifdef PORT_D_AVAILABLE
D = 0x03,
#endif
NONE,
};
//////////////////////////////////////////////////////////////////////////
@ -250,7 +252,7 @@ static inline reg_ptr_t getRegPtr()
template <template <P, uint8_t> typename Func, P pin, P... pins>
struct CallHelper {
template <typename... Args>
FORCE_INLINE static inline void call(Args... args)
[[gnu::always_inline]] static inline void call(Args... args)
{
Func<pin, sizeof...(pins)>::call(args...);
CallHelper<Func, pins...>::call(args...);
@ -260,7 +262,7 @@ struct CallHelper {
template <template <P, uint8_t> typename Func, P pin>
struct CallHelper<Func, pin> {
template <typename... Args>
FORCE_INLINE static inline void call(Args... args)
[[gnu::always_inline]] static inline void call(Args... args)
{
Func<pin, 0>::call(args...);
}
@ -268,7 +270,7 @@ struct CallHelper<Func, pin> {
template <template <P> typename Func, P pin, P... pins>
struct ReadCallHelper {
static inline uint8_t call() FORCE_INLINE
[[gnu::always_inline]] static inline uint8_t call()
{
return Func<pin>::call() << sizeof...(pins) | ReadCallHelper<Func, pins...>::call();
}
@ -276,7 +278,7 @@ struct ReadCallHelper {
template <template <P> typename Func, P pin>
struct ReadCallHelper<Func, pin> {
static inline uint8_t call() FORCE_INLINE
[[gnu::always_inline]] static inline uint8_t call()
{
return Func<pin>::call();
}
@ -299,79 +301,88 @@ class Pin {
// The only valid way to create a Pin object is with the default constructor
Pin() = default;
static inline void dir(const Dir dir) FORCE_INLINE
[[gnu::always_inline]] static inline void dir(const Dir dir)
{
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
if constexpr (pin != P::NONE) {
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
detail::reg_ptr_t dirRegPtr = detail::getRegPtr<detail::getDDR(bus)>();
detail::reg_ptr_t dirRegPtr = detail::getRegPtr<detail::getDDR(bus)>();
if (dir == Dir::IN)
*dirRegPtr &= ~(1 << pinBit);
else if (dir == Dir::OUT)
*dirRegPtr |= (1 << pinBit);
if (dir == Dir::IN)
*dirRegPtr &= ~(1 << pinBit);
else if (dir == Dir::OUT)
*dirRegPtr |= (1 << pinBit);
}
}
static inline void pullup(const bool enable) FORCE_INLINE
[[gnu::always_inline]] static inline void pullup(const bool enable)
{
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
if constexpr (pin != P::NONE) {
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(bus)>();
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(bus)>();
if (enable)
*portRegPtr |= (1 << pinBit);
else
*portRegPtr &= ~(1 << pinBit);
if (enable)
*portRegPtr |= (1 << pinBit);
else
*portRegPtr &= ~(1 << pinBit);
}
}
static inline void write(const bool value) FORCE_INLINE
[[gnu::always_inline]] static inline void write(const bool value)
{
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
if constexpr (pin != P::NONE) {
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(bus)>();
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(bus)>();
if (value)
*portRegPtr |= (1 << pinBit);
else
*portRegPtr &= ~(1 << pinBit);
if (value)
*portRegPtr |= (1 << pinBit);
else
*portRegPtr &= ~(1 << pinBit);
}
}
static inline void toggle() FORCE_INLINE
[[gnu::always_inline]] static inline void toggle()
{
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
if constexpr (pin != P::NONE) {
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
#ifdef HARDWARE_TOGGLE
detail::reg_ptr_t pinRegPtr = detail::getRegPtr<detail::getPIN(bus)>();
*pinRegPtr |= (1 << pinBit);
detail::reg_ptr_t pinRegPtr = detail::getRegPtr<detail::getPIN(bus)>();
*pinRegPtr |= (1 << pinBit);
#else
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(bus)>();
*portRegPtr ^= (1 << pinBit);
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(bus)>();
*portRegPtr ^= (1 << pinBit);
#endif
}
}
static inline bool read() FORCE_INLINE
[[gnu::always_inline]] static inline bool read()
{
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
if constexpr (pin != P::NONE) {
constexpr auto bus = detail::getBus(pin);
constexpr auto pinBit = detail::getPinBit(pin);
detail::reg_ptr_t pinRegPtr = detail::getRegPtr<detail::getPIN(bus)>();
if (*pinRegPtr >> pinBit & 1)
return true;
detail::reg_ptr_t pinRegPtr = detail::getRegPtr<detail::getPIN(bus)>();
if (*pinRegPtr >> pinBit & 1)
return true;
}
return false;
}
Pin &operator=(const bool value) FORCE_INLINE
[[gnu::always_inline]] Pin &operator=(const bool value)
{
write(value);
return *this;
}
operator bool() const FORCE_INLINE
[[gnu::always_inline]] operator bool() const
{
return read();
}
@ -392,57 +403,68 @@ class Port {
// The only valid way to create a Port object is with the default constructor
Port() = default;
static inline void dir(const Dir dir) FORCE_INLINE
[[gnu::always_inline]] static inline void dir(const Dir dir)
{
detail::reg_ptr_t dirRegPtr = detail::getRegPtr<detail::getDDR(port)>();
if constexpr (port != Bus::NONE) {
detail::reg_ptr_t dirRegPtr = detail::getRegPtr<detail::getDDR(port)>();
if (dir == Dir::IN)
*dirRegPtr = 0x00;
else if (dir == Dir::OUT)
*dirRegPtr = 0xFF;
if (dir == Dir::IN)
*dirRegPtr = 0x00;
else if (dir == Dir::OUT)
*dirRegPtr = 0xFF;
}
}
static inline void pullup(const bool enable) FORCE_INLINE
[[gnu::always_inline]] static inline void pullup(const bool enable)
{
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(port)>();
if constexpr (port != Bus::NONE) {
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(port)>();
if (enable)
*portRegPtr = 0xFF;
else
*portRegPtr = 0x00;
if (enable)
*portRegPtr = 0xFF;
else
*portRegPtr = 0x00;
}
}
static inline void write(const uint8_t value) FORCE_INLINE
[[gnu::always_inline]] static inline void write([[maybe_unused]] const uint8_t value)
{
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(port)>();
*portRegPtr = value;
if constexpr (port != Bus::NONE) {
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(port)>();
*portRegPtr = value;
}
}
static inline void invert() FORCE_INLINE
[[gnu::always_inline]] static inline void invert()
{
if constexpr (port != Bus::NONE) {
#ifdef HARDWARE_TOGGLE
detail::reg_ptr_t pinRegPtr = detail::getRegPtr<detail::getPIN(port)>();
*pinRegPtr = 0xFF;
detail::reg_ptr_t pinRegPtr = detail::getRegPtr<detail::getPIN(port)>();
*pinRegPtr = 0xFF;
#else
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(port)>();
*portRegPtr = ~(*portRegPtr);
detail::reg_ptr_t portRegPtr = detail::getRegPtr<detail::getPORT(port)>();
*portRegPtr = ~(*portRegPtr);
#endif
}
}
static inline uint8_t read() FORCE_INLINE
[[gnu::always_inline]] static inline uint8_t read()
{
detail::reg_ptr_t pinRegPtr = detail::getRegPtr<detail::getPIN(port)>();
if constexpr (port != Bus::NONE) {
detail::reg_ptr_t pinRegPtr = detail::getRegPtr<detail::getPIN(port)>();
return *pinRegPtr;
return *pinRegPtr;
}
return 0x00;
}
inline Port &operator=(const uint8_t value) FORCE_INLINE
[[gnu::always_inline]] inline Port &operator=(const uint8_t value)
{
write(value);
return *this;
}
inline operator uint8_t() const FORCE_INLINE
[[gnu::always_inline]] inline operator uint8_t() const
{
return read();
}
@ -455,22 +477,22 @@ namespace detail {
template <P pin, uint8_t offset>
struct Callers {
static void call(const Dir dir) FORCE_INLINE
[[gnu::always_inline]] static void call(const Dir dir)
{
Pin<pin>::dir(dir);
};
static void call(const bool enable) FORCE_INLINE
[[gnu::always_inline]] static void call(const bool enable)
{
Pin<pin>::pullup(enable);
};
static void call(const uint8_t value) FORCE_INLINE
[[gnu::always_inline]] static void call(const uint8_t value)
{
Pin<pin>::write(value >> offset & 1);
};
static void call() FORCE_INLINE
[[gnu::always_inline]] static void call()
{
Pin<pin>::toggle();
};
@ -478,7 +500,7 @@ struct Callers {
template <P pin>
struct readCaller {
static bool call() FORCE_INLINE
[[gnu::always_inline]] static bool call()
{
return Pin<pin>::read();
};
@ -500,38 +522,38 @@ class VirtPort {
// The only valid way to create a VirtPort object is with the default constructor
VirtPort() = default;
static inline void dir(const Dir dir) FORCE_INLINE
[[gnu::always_inline]] static inline void dir(const Dir dir)
{
detail::CallHelper<detail::Callers, pins...>::call(dir);
}
static inline void pullup(const bool enable) FORCE_INLINE
[[gnu::always_inline]] static inline void pullup(const bool enable)
{
detail::CallHelper<detail::Callers, pins...>::call(enable);
}
static inline void write(const uint8_t value) FORCE_INLINE
[[gnu::always_inline]] static inline void write(const uint8_t value)
{
detail::CallHelper<detail::Callers, pins...>::call(value);
}
static inline void invert() FORCE_INLINE
[[gnu::always_inline]] static inline void invert()
{
detail::CallHelper<detail::Callers, pins...>::call();
}
static inline uint8_t read() FORCE_INLINE
[[gnu::always_inline]] static inline uint8_t read()
{
return detail::ReadCallHelper<detail::readCaller, pins...>::call();
}
inline VirtPort &operator=(const uint8_t value) FORCE_INLINE
[[gnu::always_inline]] inline VirtPort &operator=(const uint8_t value)
{
write(value);
return *this;
}
inline operator uint8_t() const FORCE_INLINE
[[gnu::always_inline]] inline operator uint8_t() const
{
return read();
}
@ -553,5 +575,3 @@ class VirtPort {
#undef PIN_B6_AVAILABLE
#undef PIN_B7_AVAILABLE
#undef PIN_C7_AVAILABLE
#undef FORCE_INLINE