#include "PCF8574.h"

PCF8574::PCF8574(uint8_t address, TwoWire &twc) : _twc(twc), _address(address), _pinConfig(0b11111111), _pddr(0b00000000) //Inputs by default
{
  
}

boolean PCF8574::begin()
{
  _twc.begin();
  _twc.beginTransmission(_address);
  _twc.write(_pinConfig);
  return _twc.endTransmission() == 0;
}

void PCF8574::pinMode(Pin pin, boolean mode)
{
  uint8_t mask = mode ? pin : pin; //0 INPUT - 1 OUTPUT

  if(mode)//OUTPUT
  {
    _pinConfig = _pinConfig | mask;
	_pddr = _pddr | pin;
  }
  else
  {
    _pinConfig = _pinConfig | mask;
	_pddr = _pddr & ~pin;
  }
  
  _pinConfig = _pinConfig | mask;
  _twc.beginTransmission(_address);
  _twc.write(_pinConfig);
  _twc.endTransmission();
}

void PCF8574::digitalWrite(Pin pin, boolean mode)
{
  //We first check that the pin is an output
  if((_pddr & pin) == 0)
    return;
	  
  uint8_t mask = mode ? pin : ~pin; //0 LOW, 1 HIGH
  if(mode)
    _pinConfig = _pinConfig | mask;
  else
    _pinConfig = _pinConfig & mask;

  _twc.beginTransmission(_address);
  _twc.write(_pinConfig);
  _twc.endTransmission();
}

void PCF8574::togglePin(Pin pin)
{
	//We first check that the pin is an output
  if((_pddr & pin) == 0)
    return;

  _pinConfig = (_pinConfig & pin) == 0 ? _pinConfig | pin : _pinConfig & ~pin;
	
  _twc.beginTransmission(_address);
  _twc.write(_pinConfig);
  _twc.endTransmission();
}

boolean PCF8574::digitalRead(Pin pin)
{
  uint8_t reg = 0b00000000;
  _twc.requestFrom((uint8_t)_address,(uint8_t)1,(uint8_t)true);
  while(_twc.available())reg = _twc.read();
  return (reg & pin) == 0 ? 0 : 1;
}

void PCF8574::digitalReadAll(boolean array[8])
{
	uint8_t reg = 0b00000000;
	_twc.requestFrom((uint8_t)_address,(uint8_t)1,(uint8_t)true);
	while(_twc.available())reg = _twc.read();
	
	array[0] = (reg & P0) == 0 ? 0 : 1;
	array[1] = (reg & P1) == 0 ? 0 : 1;
	array[2] = (reg & P2) == 0 ? 0 : 1;
	array[3] = (reg & P3) == 0 ? 0 : 1;
	array[4] = (reg & P4) == 0 ? 0 : 1;
	array[5] = (reg & P5) == 0 ? 0 : 1;
	array[6] = (reg & P6) == 0 ? 0 : 1;
	array[7] = (reg & P7) == 0 ? 0 : 1;
}

boolean PCF8574::getPinMode(Pin pin)
{
	return _pddr & pin == 0 ? INPUT : OUTPUT;
}

void PCF8574::getPinModeAll(boolean array[8])
{
	array[0] = (_pddr & P0) == 0 ? INPUT : OUTPUT;
	array[1] = (_pddr & P1) == 0 ? INPUT : OUTPUT;
	array[2] = (_pddr & P2) == 0 ? INPUT : OUTPUT;
	array[3] = (_pddr & P3) == 0 ? INPUT : OUTPUT;
	array[4] = (_pddr & P4) == 0 ? INPUT : OUTPUT;
	array[5] = (_pddr & P5) == 0 ? INPUT : OUTPUT;
	array[6] = (_pddr & P6) == 0 ? INPUT : OUTPUT;
	array[7] = (_pddr & P7) == 0 ? INPUT : OUTPUT;
}

void PCF8574::resetIRQ()
{
	//We request 1 byte in order to reset the IRQ
	_twc.requestFrom((uint8_t)_address,(uint8_t)1,(uint8_t)true);
	 while(_twc.available())_twc.read();
}
