diff --git a/Grbl_Esp32/src/Motors/TrinamicDriver.cpp b/Grbl_Esp32/src/Motors/TrinamicDriver.cpp index 0cb06290..c8d278bb 100644 --- a/Grbl_Esp32/src/Motors/TrinamicDriver.cpp +++ b/Grbl_Esp32/src/Motors/TrinamicDriver.cpp @@ -60,8 +60,6 @@ void TMC2130Stepper::switchCSpin(bool state) { } } -void IRAM_ATTR pinMode(uint8_t pin, uint8_t mode) {} - namespace Motors { uint8_t TrinamicDriver::get_next_index() { #ifdef TRINAMIC_DAISY_CHAIN diff --git a/Grbl_Esp32/src/PinMapper.cpp b/Grbl_Esp32/src/PinMapper.cpp new file mode 100644 index 00000000..2f0bdb71 --- /dev/null +++ b/Grbl_Esp32/src/PinMapper.cpp @@ -0,0 +1,101 @@ +#include "PinMapper.h" + +#include "Assert.h" + +#include + +// Pin mapping. Pretty straight forward, it's just a thing that + +namespace { + class Mapping { + public: + Pin* _mapping[256]; + + Mapping() { + for (int i = 0; i < 256; ++i) { + _mapping[i] = nullptr; + } + } + + uint8_t Claim(Pin* pin) { + // Let's not use 0. 1 is the first pin we'll allocate. + for (int i = 1; i < 256; ++i) { + if (_mapping[i] == nullptr) { + _mapping[i] = pin; + return i; + } + } + return 0; + } + + void Release(uint8_t idx) { _mapping[idx] = nullptr; } + + static Mapping& instance() { + static Mapping instance; + return instance; + } + }; +} + +PinMapper::PinMapper() : _mappedId(0) {} + +PinMapper::PinMapper(Pin& pin) { + _mappedId = Mapping::instance().Claim(&pin); + Assert(_mappedId != 0, "Cannot claim pin. We've reached the limit of 255 mapped pins."); +} + +PinMapper::PinMapper(PinMapper&& o) : _mappedId(0) { + std::swap(_mappedId, o._mappedId); +} + +PinMapper& PinMapper::operator=(PinMapper&& o) { + if (&o != this) { + if (_mappedId != 0) { + Mapping::instance().Release(_mappedId); + _mappedId = 0; + } + std::swap(_mappedId, o._mappedId); + } + return *this; +} + +PinMapper::~PinMapper() { + if (_mappedId != 0) { + Mapping::instance().Release(_mappedId); + } +} + +// Arduino compatibility functions, which basically forward the call to the mapper: + +void IRAM_ATTR digitalWrite(uint8_t pin, uint8_t val) { + auto thePin = Mapping::instance()._mapping[pin]; + if (thePin) { + thePin->write(val); + } +} + +void IRAM_ATTR pinMode(uint8_t pin, uint8_t mode) { + Pins::PinAttributes attr = Pins::PinAttributes::None; + if ((mode & OUTPUT) == OUTPUT) { + attr = attr | Pins::PinAttributes::Output; + } + if ((mode & INPUT) == INPUT) { + attr = attr | Pins::PinAttributes::Input; + } + if ((mode & PULLUP) == PULLUP) { + attr = attr | Pins::PinAttributes::PullUp; + } + if ((mode & PULLDOWN) == PULLDOWN) { + attr = attr | Pins::PinAttributes::PullDown; + } + + auto thePin = Mapping::instance()._mapping[pin]; + if (thePin) { + thePin->setAttr(attr); + } +} + +int IRAM_ATTR digitalRead(uint8_t pin) { + auto thePin = Mapping::instance()._mapping[pin]; + return (thePin) ? thePin->read() : 0; +} diff --git a/Grbl_Esp32/src/PinMapper.h b/Grbl_Esp32/src/PinMapper.h new file mode 100644 index 00000000..51a6a397 --- /dev/null +++ b/Grbl_Esp32/src/PinMapper.h @@ -0,0 +1,24 @@ +#pragma once + +// Pin mapper is a class that maps 'Pin' objects to Arduino digitalWrite / digitalRead / setMode. This +// can be useful for support of external libraries, while keeping all the things that Pin has to offer. + +#include "Pin.h" + +class PinMapper { + uint8_t _mappedId; + +public: + PinMapper(); + PinMapper(Pin& pin); + + PinMapper(const Pin& o) = delete; + PinMapper& operator=(const Pin& o) = delete; + + PinMapper(PinMapper&& o); + PinMapper& operator=(PinMapper&& o); + + inline uint8_t pinId() const { return _mappedId; } + + ~PinMapper(); +}; diff --git a/Grbl_Esp32/test/Pins/GPIO.cpp b/Grbl_Esp32/test/Pins/GPIO.cpp index 4031de38..c17acdde 100644 --- a/Grbl_Esp32/test/Pins/GPIO.cpp +++ b/Grbl_Esp32/test/Pins/GPIO.cpp @@ -1,6 +1,7 @@ #include "../TestFramework.h" #include +#include #ifdef ESP32 extern "C" void __pinMode(uint8_t pin, uint8_t mode); @@ -39,9 +40,9 @@ struct GPIONative { inline static bool read(int pin) { return SoftwareGPIO::instance().read(pin); } }; -//void digitalWrite(uint8_t pin, uint8_t val); -//void pinMode(uint8_t pin, uint8_t mode); -//int digitalRead(uint8_t pin); +void digitalWrite(uint8_t pin, uint8_t val); +void pinMode(uint8_t pin, uint8_t mode); +int digitalRead(uint8_t pin); #endif @@ -176,68 +177,70 @@ namespace Pins { Test(GPIO, ISRChangePin) { TestISR(1, 1, CHANGE); } - /* Test(GPIO, NativeForwardingInput) { GPIONative::initialize(); Pin gpio16 = Pin::create("gpio.16"); Pin gpio17 = Pin::create("gpio.17"); - pinMode(16, INPUT); + PinMapper map1(gpio16); + PinMapper map2(gpio17); + + pinMode(map1.pinId(), INPUT); gpio17.setAttr(Pin::Attr::Output); - Assert(LOW == digitalRead(16)); + Assert(LOW == digitalRead(map1.pinId())); Assert(false == gpio17.read()); Assert(false == GPIONative::read(16)); Assert(false == GPIONative::read(17)); gpio17.on(); - Assert(HIGH == digitalRead(16)); + Assert(HIGH == digitalRead(map1.pinId())); Assert(true == gpio17.read()); Assert(true == GPIONative::read(16)); Assert(true == GPIONative::read(17)); gpio17.off(); - Assert(LOW == digitalRead(16)); + Assert(LOW == digitalRead(map1.pinId())); Assert(false == gpio17.read()); Assert(false == GPIONative::read(16)); Assert(false == GPIONative::read(17)); } - */ - /* Test(GPIO, NativeForwardingOutput) { GPIONative::initialize(); Pin gpio16 = Pin::create("gpio.16"); Pin gpio17 = Pin::create("gpio.17"); - pinMode(16, OUTPUT); + PinMapper map1(gpio16); + PinMapper map2(gpio17); + + pinMode(map1.pinId(), OUTPUT); gpio17.setAttr(Pin::Attr::Input); - digitalWrite(16, LOW); - Assert(LOW == digitalRead(16)); + digitalWrite(map1.pinId(), LOW); + Assert(LOW == digitalRead(map1.pinId())); Assert(false == gpio17.read()); Assert(false == GPIONative::read(16)); Assert(false == GPIONative::read(17)); - digitalWrite(16, HIGH); + digitalWrite(map1.pinId(), HIGH); - Assert(HIGH == digitalRead(16)); + Assert(HIGH == digitalRead(map1.pinId())); Assert(true == gpio17.read()); Assert(true == GPIONative::read(16)); Assert(true == GPIONative::read(17)); - digitalWrite(16, LOW); + digitalWrite(map1.pinId(), LOW); - Assert(LOW == digitalRead(16)); + Assert(LOW == digitalRead(map1.pinId())); Assert(false == gpio17.read()); Assert(false == GPIONative::read(16)); Assert(false == GPIONative::read(17)); } - */ Test(GPIO, Name) { GPIONative::initialize(); diff --git a/Grbl_Esp32/test/Pins/Undefined.cpp b/Grbl_Esp32/test/Pins/Undefined.cpp index 22e4ae16..01d6a940 100644 --- a/Grbl_Esp32/test/Pins/Undefined.cpp +++ b/Grbl_Esp32/test/Pins/Undefined.cpp @@ -25,7 +25,8 @@ namespace Pins { AssertThrow(unassigned.detachInterrupt()); Assert(unassigned.capabilities().has(Pin::Capabilities::Void)); - Assert(unassigned.name().equals("")); + auto name = unassigned.name(); + Assert(unassigned.name().equals("NO_PIN")); } Test(Undefined, MultipleInstances) { diff --git a/UnitTests.vcxproj b/UnitTests.vcxproj index 7c7df0d7..fb929204 100644 --- a/UnitTests.vcxproj +++ b/UnitTests.vcxproj @@ -46,6 +46,7 @@ + @@ -69,6 +70,7 @@ + diff --git a/UnitTests.vcxproj.filters b/UnitTests.vcxproj.filters index 91d5202e..f9b2507b 100644 --- a/UnitTests.vcxproj.filters +++ b/UnitTests.vcxproj.filters @@ -99,6 +99,9 @@ src + + src + @@ -188,6 +191,9 @@ src + + src +