/* * PCF8575.cpp * * Created on: 26.02.2022 * Author: steffen * SPDX-FileCopyrightText: 2022 MDC Service * SPDX-License-Identifier: GPL-3.0-or-later */ #include "PCF8575.h" #include "Wire.h" /** * Constructor * @param address: i2c address */ PCF8575::PCF8575(uint8_t address){ _wire = &Wire; _address = address; }; /** * Construcor * @param address: i2c address * @param interruptPin: pin to set interrupt * @param interruptFunction: function to call when interrupt raised */ PCF8575::PCF8575(uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ){ _wire = &Wire; _address = address; _interruptPin = interruptPin; _interruptFunction = interruptFunction; _usingInterrupt = true; }; #if !defined(__AVR) && !defined(__STM32F1__) /** * Constructor * @param address: i2c address * @param sda: sda pin * @param scl: scl pin */ PCF8575::PCF8575(uint8_t address, uint8_t sda, uint8_t scl){ _wire = &Wire; _address = address; _sda = sda; _scl = scl; }; /** * Constructor * @param address: i2c address * @param sda: sda pin * @param scl: scl pin * @param interruptPin: pin to set interrupt * @param interruptFunction: function to call when interrupt raised */ PCF8575::PCF8575(uint8_t address, uint8_t sda, uint8_t scl, uint8_t interruptPin, void (*interruptFunction)() ){ _wire = &Wire; _address = address; _sda = sda; _scl = scl; _interruptPin = interruptPin; _interruptFunction = interruptFunction; _usingInterrupt = true; }; #endif #ifdef ESP32 /** * Constructor * @param address: i2c address */ PCF8575::PCF8575(TwoWire *pWire, uint8_t address){ _wire = pWire; _address = address; }; /** * Construcor * @param address: i2c address * @param interruptPin: pin to set interrupt * @param interruptFunction: function to call when interrupt raised */ PCF8575::PCF8575(TwoWire *pWire, uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ){ _wire = pWire; _address = address; _interruptPin = interruptPin; _interruptFunction = interruptFunction; _usingInterrupt = true; }; /** * Constructor * @param address: i2c address * @param sda: sda pin * @param scl: scl pin */ PCF8575::PCF8575(TwoWire *pWire, uint8_t address, uint8_t sda, uint8_t scl){ _wire = pWire; _address = address; _sda = sda; _scl = scl; }; /** * Constructor * @param address: i2c address * @param sda: sda pin * @param scl: scl pin * @param interruptPin: pin to set interrupt * @param interruptFunction: function to call when interrupt raised */ PCF8575::PCF8575(TwoWire *pWire, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interruptPin, void (*interruptFunction)() ){ _wire = pWire; _address = address; _sda = sda; _scl = scl; _interruptPin = interruptPin; _interruptFunction = interruptFunction; _usingInterrupt = true; }; #endif /** * wake up i2c controller */ void PCF8575::begin(){ #if !defined(__AVR) && !defined(__STM32F1__) _wire->begin(_sda, _scl); #else // Default pin for AVR some problem on software emulation // #define SCL_PIN _scl // #define SDA_PIN _sda _wire->begin(); #endif // Serial.println( writeMode, BIN); // Serial.println( readMode, BIN); // Check if there are pins to set low if (writeMode>0 || readMode>0){ DEBUG_PRINTLN("Set write mode"); _wire->beginTransmission(_address); DEBUG_PRINT(" "); DEBUG_PRINT("usedPin pin "); uint16_t usedPin = writeMode | readMode; DEBUG_PRINTLN( ~usedPin, BIN); // Serial.println( ~usedPin, BIN); _wire->write((uint8_t) ~usedPin); _wire->write((uint8_t) (~(usedPin >> 8))); DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor."); _wire->endTransmission(); } // If using interrupt set interrupt value to pin if (_usingInterrupt){ DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); ::pinMode(_interruptPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); } // inizialize last read lastReadMillis = millis(); } /** * Set if fin is OUTPUT or INPUT * @param pin: pin to set * @param mode: mode, supported only INPUT or OUTPUT (to semplify) */ void PCF8575::pinMode(uint8_t pin, uint8_t mode){ DEBUG_PRINT("Set pin "); DEBUG_PRINT(pin); DEBUG_PRINT(" as "); DEBUG_PRINTLN(mode); if (mode == OUTPUT){ writeMode = writeMode | bit(pin); readMode = readMode & ~bit(pin); // DEBUG_PRINT("writeMode: "); // DEBUG_PRINT(writeMode, BIN); // DEBUG_PRINT("readMode: "); // DEBUG_PRINTLN(readMode, BIN); }else if (mode == INPUT){ writeMode = writeMode & ~bit(pin); readMode = readMode | bit(pin); // DEBUG_PRINT("writeMode: "); // DEBUG_PRINT(writeMode, BIN); // DEBUG_PRINT("readMode: "); // DEBUG_PRINTLN(readMode, BIN); } else{ DEBUG_PRINTLN("Mode non supported by PCF8575") } DEBUG_PRINT("Write mode: "); DEBUG_PRINTLN(writeMode, BIN); }; /** * Read value from i2c and bufferize it * @param force */ void PCF8575::readBuffer(bool force){ if (millis() > PCF8575::lastReadMillis+READ_ELAPSED_TIME || _usingInterrupt || force){ _wire->requestFrom(_address,(uint8_t)2);// Begin transmission to PCF8575 with the buttons lastReadMillis = millis(); if(_wire->available()) // If uint16_ts are available to be recieved { uint16_t iInput = _wire->read();// Read a uint16_t iInput |= _wire->read() << 8;// Read a uint16_t if ((iInput & readMode)>0){ byteBuffered = byteBuffered | (uint16_t)iInput; } } } } #ifndef PCF8575_LOW_MEMORY /** * Read value of all INPUT pin * Debounce read more fast than 10millis, non managed for interrupt mode * @return */ PCF8575::DigitalInput PCF8575::digitalReadAll(void){ DEBUG_PRINTLN("Read from buffer"); _wire->requestFrom(_address,(uint8_t)2);// Begin transmission to PCF8575 with the buttons lastReadMillis = millis(); if(_wire->available()) // If uint16_ts are available to be recieved { DEBUG_PRINTLN("Data ready"); uint16_t iInput = _wire->read();// Read a uint16_t iInput |= _wire->read() << 8;// Read a uint16_t if ((iInput & readMode)>0){ DEBUG_PRINT("Input "); DEBUG_PRINTLN((uint16_t)iInput, BIN); byteBuffered = byteBuffered | (uint16_t)iInput; DEBUG_PRINT("byteBuffered "); DEBUG_PRINTLN(byteBuffered, BIN); } } DEBUG_PRINT("Buffer value "); DEBUG_PRINTLN(byteBuffered, BIN); #ifdef NOT_SEQUENTIAL_PINOUT if ((bit(0) & readMode)>0) digitalInput.p00 = ((byteBuffered & bit(0))>0)?HIGH:LOW; if ((bit(1) & readMode)>0) digitalInput.p01 = ((byteBuffered & bit(1))>0)?HIGH:LOW; if ((bit(2) & readMode)>0) digitalInput.p02 = ((byteBuffered & bit(2))>0)?HIGH:LOW; if ((bit(3) & readMode)>0) digitalInput.p03 = ((byteBuffered & bit(3))>0)?HIGH:LOW; if ((bit(4) & readMode)>0) digitalInput.p04 = ((byteBuffered & bit(4))>0)?HIGH:LOW; if ((bit(5) & readMode)>0) digitalInput.p05 = ((byteBuffered & bit(5))>0)?HIGH:LOW; if ((bit(6) & readMode)>0) digitalInput.p06 = ((byteBuffered & bit(6))>0)?HIGH:LOW; if ((bit(7) & readMode)>0) digitalInput.p07 = ((byteBuffered & bit(7))>0)?HIGH:LOW; if ((bit(8) & readMode)>0) digitalInput.p10 = ((byteBuffered & bit(8))>0)?HIGH:LOW; if ((bit(9) & readMode)>0) digitalInput.p11 = ((byteBuffered & bit(9))>0)?HIGH:LOW; if ((bit(10) & readMode)>0) digitalInput.p12 = ((byteBuffered & bit(10))>0)?HIGH:LOW; if ((bit(11) & readMode)>0) digitalInput.p13 = ((byteBuffered & bit(11))>0)?HIGH:LOW; if ((bit(12) & readMode)>0) digitalInput.p14 = ((byteBuffered & bit(12))>0)?HIGH:LOW; if ((bit(13) & readMode)>0) digitalInput.p15 = ((byteBuffered & bit(13))>0)?HIGH:LOW; if ((bit(14) & readMode)>0) digitalInput.p16 = ((byteBuffered & bit(14))>0)?HIGH:LOW; if ((bit(15) & readMode)>0) digitalInput.p17 = ((byteBuffered & bit(15))>0)?HIGH:LOW; #else if ((bit(0) & readMode)>0) digitalInput.p0 = ((byteBuffered & bit(0))>0)?HIGH:LOW; if ((bit(1) & readMode)>0) digitalInput.p1 = ((byteBuffered & bit(1))>0)?HIGH:LOW; if ((bit(2) & readMode)>0) digitalInput.p2 = ((byteBuffered & bit(2))>0)?HIGH:LOW; if ((bit(3) & readMode)>0) digitalInput.p3 = ((byteBuffered & bit(3))>0)?HIGH:LOW; if ((bit(4) & readMode)>0) digitalInput.p4 = ((byteBuffered & bit(4))>0)?HIGH:LOW; if ((bit(5) & readMode)>0) digitalInput.p5 = ((byteBuffered & bit(5))>0)?HIGH:LOW; if ((bit(6) & readMode)>0) digitalInput.p6 = ((byteBuffered & bit(6))>0)?HIGH:LOW; if ((bit(7) & readMode)>0) digitalInput.p7 = ((byteBuffered & bit(7))>0)?HIGH:LOW; if ((bit(8) & readMode)>0) digitalInput.p8 = ((byteBuffered & bit(8))>0)?HIGH:LOW; if ((bit(9) & readMode)>0) digitalInput.p9 = ((byteBuffered & bit(9))>0)?HIGH:LOW; if ((bit(10) & readMode)>0) digitalInput.p10 = ((byteBuffered & bit(10))>0)?HIGH:LOW; if ((bit(11) & readMode)>0) digitalInput.p11 = ((byteBuffered & bit(11))>0)?HIGH:LOW; if ((bit(12) & readMode)>0) digitalInput.p12 = ((byteBuffered & bit(12))>0)?HIGH:LOW; if ((bit(13) & readMode)>0) digitalInput.p13 = ((byteBuffered & bit(13))>0)?HIGH:LOW; if ((bit(14) & readMode)>0) digitalInput.p14 = ((byteBuffered & bit(14))>0)?HIGH:LOW; if ((bit(15) & readMode)>0) digitalInput.p15 = ((byteBuffered & bit(15))>0)?HIGH:LOW; #endif if ((readMode & byteBuffered)>0){ byteBuffered = ~readMode & byteBuffered; DEBUG_PRINT("Buffer hight value readed set readed "); DEBUG_PRINTLN(byteBuffered, BIN); } DEBUG_PRINT("Return value "); return digitalInput; }; #else /** * Read value of all INPUT pin in byte format for low memory usage * Debounce read more fast than 10millis, non managed for interrupt mode * @return */ uint16_t PCF8575::digitalReadAll(void){ DEBUG_PRINTLN("Read from buffer"); _wire->requestFrom(_address,(uint8_t)2);// Begin transmission to PCF8575 with the buttons lastReadMillis = millis(); if(_wire->available()) // If uint16_ts are available to be recieved { DEBUG_PRINTLN("Data ready"); uint16_t iInput = _wire->read();// Read a uint16_t iInput |= _wire->read() << 8;// Read a uint16_t if ((iInput & readMode)>0){ DEBUG_PRINT("Input "); DEBUG_PRINTLN((uint16_t)iInput, BIN); byteBuffered = byteBuffered | (uint16_t)iInput; DEBUG_PRINT("byteBuffered "); DEBUG_PRINTLN(byteBuffered, BIN); } } DEBUG_PRINT("Buffer value "); DEBUG_PRINTLN(byteBuffered, BIN); uint16_t byteRead = byteBuffered; if ((readMode & byteBuffered)>0){ byteBuffered = ~readMode & byteBuffered; DEBUG_PRINT("Buffer hight value readed set readed "); DEBUG_PRINTLN(byteBuffered, BIN); } DEBUG_PRINT("Return value "); return byteRead; }; #endif /** * Read value of specified pin * Debounce read more fast than 10millis, non managed for interrupt mode * @param pin * @return */ uint8_t PCF8575::digitalRead(uint8_t pin){ uint8_t value = LOW; if ((bit(pin) & writeMode)>0){ DEBUG_PRINTLN("Pin in write mode, return value"); DEBUG_PRINT("Write data "); DEBUG_PRINT(writeByteBuffered, BIN); DEBUG_PRINT(" for pin "); DEBUG_PRINT(pin); DEBUG_PRINT(" bin value "); DEBUG_PRINT(bit(pin), BIN); DEBUG_PRINT(" value "); DEBUG_PRINTLN(value); if ((bit(pin) & writeByteBuffered)>0){ value = HIGH; }else{ value = LOW; } return value; } DEBUG_PRINT("Read pin "); DEBUG_PRINTLN(pin); // Check if pin already HIGH than read and prevent reread of i2c if ((bit(pin) & byteBuffered)>0){ DEBUG_PRINTLN("Pin already up"); value = HIGH; }else if ((/*(bit(pin) & byteBuffered)<=0 && */millis() > PCF8575::lastReadMillis+READ_ELAPSED_TIME) /*|| _usingInterrupt*/){ DEBUG_PRINTLN("Read from buffer"); _wire->requestFrom(_address,(uint8_t)2);// Begin transmission to PCF8575 with the buttons lastReadMillis = millis(); if(_wire->available()) // If bytes are available to be recieved { DEBUG_PRINTLN("Data ready"); uint16_t iInput = _wire->read();// Read a uint16_t iInput |= _wire->read() << 8;// Read a uint16_t // Serial.println(iInput, BIN); if ((iInput & readMode)>0){ DEBUG_PRINT("Input "); DEBUG_PRINTLN((uint16_t)iInput, BIN); byteBuffered = byteBuffered | (uint16_t)iInput; DEBUG_PRINT("byteBuffered "); DEBUG_PRINTLN(byteBuffered, BIN); if ((bit(pin) & byteBuffered)>0){ value = HIGH; } } } } DEBUG_PRINT("Buffer value "); DEBUG_PRINTLN(byteBuffered, BIN); // If HIGH set to low to read buffer only one time if (value==HIGH){ byteBuffered = ~bit(pin) & byteBuffered; DEBUG_PRINT("Buffer hight value readed set readed "); DEBUG_PRINTLN(byteBuffered, BIN); } DEBUG_PRINT("Return value "); DEBUG_PRINTLN(value); return value; }; /** * Write on pin * @param pin * @param value */ void PCF8575::digitalWrite(uint8_t pin, uint8_t value){ DEBUG_PRINTLN("Begin trasmission"); _wire->beginTransmission(_address); //Begin the transmission to PCF8575 if (value==HIGH){ writeByteBuffered = writeByteBuffered | bit(pin); }else{ writeByteBuffered = writeByteBuffered & ~bit(pin); } // DEBUG_PRINT("Write data "); // DEBUG_PRINT(writeByteBuffered, BIN); // DEBUG_PRINT(" for pin "); // DEBUG_PRINT(pin); // DEBUG_PRINT(" bin value "); // DEBUG_PRINT(bit(pin), BIN); // DEBUG_PRINT(" value "); // DEBUG_PRINTLN(value); // Serial.print(" --> "); // Serial.println(writeByteBuffered); // Serial.println((uint8_t) writeByteBuffered); // Serial.println((uint8_t) (writeByteBuffered >> 8)); writeByteBuffered = writeByteBuffered & writeMode; _wire->write((uint8_t) writeByteBuffered); _wire->write((uint8_t) (writeByteBuffered >> 8)); DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor."); _wire->endTransmission(); };