diff --git a/Template Project/lib/ESPMegaPRO/AnalogCard.cpp b/Template Project/lib/ESPMegaPRO/AnalogCard.cpp index e7bf577..682e4c6 100644 --- a/Template Project/lib/ESPMegaPRO/AnalogCard.cpp +++ b/Template Project/lib/ESPMegaPRO/AnalogCard.cpp @@ -1,4 +1,3 @@ -#include #include AnalogCard::AnalogCard() : dac0(DAC0_ADDRESS), diff --git a/Template Project/lib/ESPMegaPRO/AnalogCard.hpp b/Template Project/lib/ESPMegaPRO/AnalogCard.hpp index 3417528..6c0854e 100644 --- a/Template Project/lib/ESPMegaPRO/AnalogCard.hpp +++ b/Template Project/lib/ESPMegaPRO/AnalogCard.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include @@ -10,7 +10,7 @@ #define DAC2_ADDRESS 0x62 #define DAC3_ADDRESS 0x63 -class AnalogCard { +class AnalogCard : public ExpansionCard { public: AnalogCard(); void dacWrite(uint8_t pin, uint16_t value); diff --git a/Template Project/lib/ESPMegaPRO/DigitalInputCard.cpp b/Template Project/lib/ESPMegaPRO/DigitalInputCard.cpp index 6d451f4..68cf825 100644 --- a/Template Project/lib/ESPMegaPRO/DigitalInputCard.cpp +++ b/Template Project/lib/ESPMegaPRO/DigitalInputCard.cpp @@ -1,96 +1,188 @@ #pragma once -#include #include // Instantiate the card with the specified address -DigitalInputCard::DigitalInputCard(uint8_t address_a, uint8_t address_b) { +DigitalInputCard::DigitalInputCard(uint8_t address_a, uint8_t address_b) +{ this->address_a = address_a; this->address_b = address_b; } // Instantiate the card with the specified position on the dip switch // Bit 0,1,2 are for bank A // Bit 3,4,5 are for bank B -DigitalInputCard::DigitalInputCard(bool bit0, bool bit1, bool bit2, bool bit3, bool bit4, bool bit5) { +DigitalInputCard::DigitalInputCard(bool bit0, bool bit1, bool bit2, bool bit3, bool bit4, bool bit5) +{ this->address_a = 0x20; this->address_b = 0x20; - if (bit0) this->address_a += 1; - if (bit1) this->address_a += 2; - if (bit2) this->address_a += 4; - if (bit3) this->address_b += 1; - if (bit4) this->address_b += 2; - if (bit5) this->address_b += 4; - + this->inputBufferA = 0; + this->inputBufferB = 0; + if (bit0) + this->address_a += 1; + if (bit1) + this->address_a += 2; + if (bit2) + this->address_a += 4; + if (bit3) + this->address_b += 1; + if (bit4) + this->address_b += 2; + if (bit5) + this->address_b += 4; } // Initialize the card -void DigitalInputCard::begin() { +void DigitalInputCard::begin() +{ this->inputBankA = PCF8574(this->address_a); this->inputBankB = PCF8574(this->address_b); this->inputBankA.begin(); this->inputBankB.begin(); + // Set the debounce time for all pins to 50ms + for (int i = 0; i < 16; i++) + { + this->debounceTime[i] = 50; + this->lastDebounceTime[i] = 0; + } + // Initialize the pin map to the default values + for (int i = 0; i < 16; i++) + { + this->pinMap[i] = i; + this->virtualPinMap[i] = i; + } } // Refresh and Read the input from the specified pin, always refresh the input buffers -uint8_t DigitalInputCard::digitalRead(uint8_t pin) { - digitalRead(pin, true); +bool DigitalInputCard::digitalRead(uint8_t pin) +{ + return this->digitalRead(pin, true); } // Read the input from the specified pin, also refresh the input buffers if refresh is true -uint8_t DigitalInputCard::digitalRead(uint8_t pin, bool refresh) { +bool DigitalInputCard::digitalRead(uint8_t pin, bool refresh) +{ + pin = pinMap[pin]; // First check if the pin is in bank A or B - if (pin >= 0 && pin <= 7) { + if (pin >= 0 && pin <= 7) + { // Refresh the input buffers if refresh is true - if (refresh) refreshInputBankA(); + if (refresh) + refreshInputBankA(); // Extract the bit from the buffer return ((inputBufferA >> (7 - pin)) & 1); - } else if (pin >= 8 && pin <= 15) { + } + else if (pin >= 8 && pin <= 15) + { // Refresh the input buffers if refresh is true - if (refresh) refreshInputBankB(); + if (refresh) + refreshInputBankB(); // Extract the bit from the buffer return ((inputBufferB >> (15 - pin)) & 1); } + return 255; } + +void DigitalInputCard::handlePinChange(int pin, uint8_t ¤tBuffer, uint8_t &previousBuffer) +{ + // Get the index of the pin in the pin map + uint8_t virtualPin = virtualPinMap[pin]; + // Handle Bank A + if (((previousBuffer >> (7 - pin)) & 1) != ((currentBuffer >> (7 - pin)) & 1)) + { + if (millis() - lastDebounceTime[pin] > debounceTime[pin]) + { + lastDebounceTime[pin] = millis(); + previousBuffer ^= (-((currentBuffer >> (7 - pin)) & 1) ^ previousBuffer) & (1UL << (7 - pin)); + if (callback != NULL) + callback(virtualPin, ((currentBuffer >> (7 - pin)) & 1)); + } + } + // Handle Bank B + if (((previousBuffer >> (15 - pin)) & 1) != ((currentBuffer >> (15 - pin)) & 1)) + { + if (millis() - lastDebounceTime[pin] > debounceTime[pin]) + { + lastDebounceTime[pin] = millis(); + previousBuffer ^= (-((currentBuffer >> (15 - pin)) & 1) ^ previousBuffer) & (1UL << (15 - pin)); + if (callback != NULL) + callback(virtualPin, ((currentBuffer >> (15 - pin)) & 1)); + } + } +} + // Preform a loop to refresh the input buffers -void DigitalInputCard::loop() { - // Store the current input buffers - uint8_t inputBufferA_old = inputBufferA; - uint8_t inputBufferB_old = inputBufferB; +void DigitalInputCard::loop() +{ // Refresh the input buffers refreshInputBankA(); refreshInputBankB(); // Iterate over all pins and check if they changed - for (int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { // Check which bank the pin is in - if (i<8) { - // Check if the pin changed - if (((inputBufferA_old >> (7 - i)) & 1) != ((inputBufferA >> (7 - i)) & 1)) { - // Call the callback function if it is not null and pass the pin and the new value - if (callback != NULL) callback(i, ((inputBufferA >> (7 - i)) & 1)); - } - } else { - // Check if the pin changed - if (((inputBufferB_old >> (15 - i)) & 1) != ((inputBufferB >> (15 - i)) & 1)) { - // Call the callback function if it is not null and pass the pin and the new value - if (callback != NULL) callback(i, ((inputBufferB >> (15 - i)) & 1)); - } + if (i < 8) + { + handlePinChange(i, inputBufferA, previousInputBufferA); + } + else if (i >= 8 && i <= 15) + { + handlePinChange(i, inputBufferB, previousInputBufferB); } } } // Get the input buffer for bank A -uint8_t DigitalInputCard::getInputBufferA() { - return inputBufferA; +uint8_t DigitalInputCard::getInputBufferA() +{ + // Rearrange the bits to match the pin map + uint8_t inputBufferA_rearranged = 0; + for (int i = 0; i < 8; i++) + { + inputBufferA_rearranged |= ((inputBufferA >> i) & 1) << (7 - i); + } + return inputBufferA_rearranged; } // Get the input buffer for bank B -uint8_t DigitalInputCard::getInputBufferB() { - return inputBufferB; +uint8_t DigitalInputCard::getInputBufferB() +{ + // Rearrange the bits to match the pin map + uint8_t inputBufferB_rearranged = 0; + for (int i = 0; i < 8; i++) + { + inputBufferB_rearranged |= ((inputBufferB >> i) & 1) << (7 - i); + } + return inputBufferB_rearranged; } // Register a callback function to be called when a pin changes -void DigitalInputCard::registerCallback(void (*callback)(int, bool)) { +void DigitalInputCard::registerCallback(void (*callback)(uint8_t, bool)) +{ this->callback = callback; } // Refresh the input buffer for bank A -void DigitalInputCard::refreshInputBankA() { +void DigitalInputCard::refreshInputBankA() +{ inputBufferA = inputBankA.read8(); } // Refresh the input buffer for bank B -void DigitalInputCard::refreshInputBankB() { +void DigitalInputCard::refreshInputBankB() +{ inputBufferB = inputBankB.read8(); +} + +void DigitalInputCard::setDebounceTime(uint8_t pin, uint32_t debounceTime) +{ + pin = pinMap[pin]; + this->debounceTime[pin] = debounceTime; +} + +void DigitalInputCard::unregisterCallback() +{ + this->callback = NULL; +} + +void DigitalInputCard::loadPinMap(uint8_t pinMap[16]) +{ + for (int i = 0; i < 16; i++) + { + // Load the pin map (physical pin to virtual pin) + this->pinMap[i] = pinMap[i]; + // Load the virtual pin map (virtual pin to physical pin) + this->virtualPinMap[pinMap[i]] = i; + } } \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/DigitalInputCard.hpp b/Template Project/lib/ESPMegaPRO/DigitalInputCard.hpp index d5821e0..f022bff 100644 --- a/Template Project/lib/ESPMegaPRO/DigitalInputCard.hpp +++ b/Template Project/lib/ESPMegaPRO/DigitalInputCard.hpp @@ -1,8 +1,8 @@ #pragma once -#include +#include #include -class DigitalInputCard { +class DigitalInputCard : public ExpansionCard { public: // Instantiate the card with the specified address DigitalInputCard(uint8_t address_a, uint8_t address_b); @@ -11,17 +11,23 @@ class DigitalInputCard { // Initialize the card void begin(); // Refresh and Read the input from the specified pin, always refresh the input buffers - uint8_t digitalRead(uint8_t pin); + bool digitalRead(uint8_t pin); // Read the input from the specified pin, also refresh the input buffers if refresh is true - uint8_t digitalRead(uint8_t pin, bool refresh); + bool digitalRead(uint8_t pin, bool refresh); // Preform a loop to refresh the input buffers void loop(); // Get the input buffer for bank A uint8_t getInputBufferA(); // Get the input buffer for bank B uint8_t getInputBufferB(); + // Set the debounce time for the specified pin + void setDebounceTime(uint8_t pin, uint32_t debounceTime); // Register a callback function to be called when a pin changes - void registerCallback(void (*callback)(int, bool)); + void registerCallback(void (*callback)(uint8_t, bool)); + // Unregister the callback function + void unregisterCallback(); + // Load a new pin map + void loadPinMap(uint8_t pinMap[16]); private: PCF8574 inputBankA; PCF8574 inputBankB; @@ -29,7 +35,16 @@ class DigitalInputCard { uint8_t address_b; uint8_t inputBufferA; uint8_t inputBufferB; - void (*callback)(int, bool); + uint8_t previousInputBufferA; + uint8_t previousInputBufferB; + uint32_t debounceTime[16]; + uint32_t lastDebounceTime[16]; + // A map of the physical pin to the virtual pin + uint8_t pinMap[16]; + // A map of the virtual pin to the physical pin + uint8_t virtualPinMap[16]; + void (*callback)(uint8_t, bool); void refreshInputBankA(); void refreshInputBankB(); + void handlePinChange(int pin, uint8_t& currentBuffer, uint8_t& previousBuffer); }; \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/DigitalOutputCard.hpp b/Template Project/lib/ESPMegaPRO/DigitalOutputCard.hpp index 4908008..8cc445b 100644 --- a/Template Project/lib/ESPMegaPRO/DigitalOutputCard.hpp +++ b/Template Project/lib/ESPMegaPRO/DigitalOutputCard.hpp @@ -1,7 +1,7 @@ #pragma once -#include +#include #include -class DigitalOutputCard +class DigitalOutputCard : public ExpansionCard { public: // Instantiate the card with the specified address diff --git a/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.cpp b/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.hpp b/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.hpp new file mode 100644 index 0000000..953d626 --- /dev/null +++ b/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.hpp @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rtctime_t { + uint8_t hours; + uint8_t minutes; + uint8_t seconds; + uint8_t day; + uint8_t month; + uint16_t year; +}; + +#define FRAM_ADDRESS 0x56 +#define INPUT_BANK_A_ADDRESS 0x21 +#define INPUT_BANK_B_ADDRESS 0x22 +#define PWM_BANK_ADDRESS 0x5F +#define RTC_ADDRESS 0x68 + +class ESPMegaPRO { + public: + ESPMegaPRO(); + void begin(); + void loop(); + void installCard(uint8_t slot, ExpansionCard* card); + bool updateTimeFromNTP(); + rtctime_t getTime(); + FRAM fram; + private: + ExpansionCard* cards[255]; + uint8_t cardCount = 0; + DigitalInputCard inputs = DigitalInputCard(INPUT_BANK_A_ADDRESS, INPUT_BANK_B_ADDRESS); + DigitalOutputCard outputs = DigitalOutputCard(PWM_BANK_ADDRESS); +}; \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/ExpansionCard.hpp b/Template Project/lib/ESPMegaPRO/ExpansionCard.hpp new file mode 100644 index 0000000..ab21939 --- /dev/null +++ b/Template Project/lib/ESPMegaPRO/ExpansionCard.hpp @@ -0,0 +1,11 @@ +#pragma once +#include + +class ExpansionCard { + public: + // Instantiate the card with the specified address + ExpansionCard() {} + virtual void begin() {} + // Preform a loop to refresh the input buffers + virtual void loop() {} +}; \ No newline at end of file diff --git a/Template Project/src/cardsdemo.cpp b/Template Project/src/cardsdemo.cpp index f0c1ca5..72b8445 100644 --- a/Template Project/src/cardsdemo.cpp +++ b/Template Project/src/cardsdemo.cpp @@ -5,24 +5,19 @@ // This code demonstrates how to use the cards +uint8_t pinMap[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 14, 13, 12}; + DigitalInputCard icard = DigitalInputCard(0x21, 0x22); DigitalOutputCard ocard = DigitalOutputCard(0x5F); -AnalogCard acard = AnalogCard(); -void setup() { - Serial.begin(115200); - // Instantiate Input Card - icard.begin(); - // Instantiate Output Card - ocard.begin(); - // Instantiate Analog Card - acard.begin(); - // Set output 0 to 4095 - ocard.analogWrite(0, 4095); +void inputCallback(uint8_t pin, bool state) { + Serial.print("Input "); + Serial.print(pin); + Serial.print(" changed to "); + Serial.println(state); } -void loop() { - // put your main code here, to run repeatedly: +void printInputs() { for (int i = 0; i < 16; i++) { Serial.print("Input "); Serial.print(i); @@ -30,9 +25,49 @@ void loop() { Serial.print(icard.digitalRead(i)); Serial.println(); } - // Pad the output - Serial.println(); - Serial.println(); - // Delay for 1 second - delay(1000); +} + +void setup() { + Serial.begin(115200); + Wire.begin(14, 33); + // Instantiate Input Card + Serial.println("Initializing Input Card"); + icard.begin(); + Serial.println("Initialized Input Card"); + // Instantiate Output Card + Serial.println("Initializing Output Card"); + ocard.begin(); + Serial.println("Initialized Output Card"); + + icard.loadPinMap(pinMap); + + // Read all the inputs and print them + printInputs(); + + // Turn on all the outputs + for (int i = 0; i < 16; i++) { + ocard.digitalWrite(i, true); + } + + // Set the debounce time for all inputs to 200ms + for (int i = 0; i < 16; i++) { + icard.setDebounceTime(i, 200); + } + + // Register the callback function + icard.registerCallback(inputCallback); +} + +unsigned long previousMillis = 0; +const unsigned long interval = 1000; // 1 second + +void loop() { + unsigned long currentMillis = millis(); + + if (currentMillis - previousMillis >= interval) { + previousMillis = currentMillis; + printInputs(); + } + icard.loop(); + } \ No newline at end of file