
DFRobot_GP8403::DFRobot_GP8403(TwoWire *pWire,uint8_t addr)
{
  _pWire = pWire;
	_addr  = addr;
}

uint8_t DFRobot_GP8403::begin(void)
{
  _pWire->begin();
  _pWire->setClock(400000);
  _pWire->beginTransmission(_addr);
  _pWire->write(OUTPUT_RANGE);
  if(_pWire->endTransmission() != 0){
	  Serial.println(_pWire->endTransmission());
    return 1;
  }
  return 0;
}

void DFRobot_GP8403::setDACOutRange(eOutPutRange_t range)
{
	if(range == eOutPutRange_t::eOutputRange5V)
	{
		voltage = 5000;
	}else{
		voltage = 10000;
	}
  writeReg(OUTPUT_RANGE,&range,1);
}
void DFRobot_GP8403::setDACOutVoltage(uint16_t data, uint8_t channel)
{
  uint16_t dataTransmission = (uint16_t)(((float)data / voltage) * 4095);
	DBG(dataTransmission);
	dataTransmission = dataTransmission << 4;
  sendData(dataTransmission,channel);
}


void DFRobot_GP8403::sendData(uint16_t data, uint8_t channel)
{
  if(channel == 0){
    _pWire->beginTransmission(_addr);
    _pWire->write(GP8302_CONFIG_CURRENT_REG);
    _pWire->write(data & 0xff);
    _pWire->write((data >>8) & 0xff);
    _pWire->endTransmission();
    DBG(channel);
  }else if(channel == 1){
		_pWire->beginTransmission(_addr);
    _pWire->write(GP8302_CONFIG_CURRENT_REG<<1);
    _pWire->write(data & 0xff);
    _pWire->write((data >>8) & 0xff);
    _pWire->endTransmission();
    DBG(channel);
  }else{
    _pWire->beginTransmission(_addr);
    _pWire->write(GP8302_CONFIG_CURRENT_REG);
    _pWire->write(data & 0xff);
    _pWire->write((data >>8) & 0xff);
    _pWire->write(data & 0xff);
    _pWire->write((data >>8) & 0xff);
    _pWire->endTransmission();
    DBG(channel);
  }
}


void DFRobot_GP8403::store(){
  #if defined(ESP32)
    _pWire->~TwoWire();
  #elif !defined(ESP8266)
    _pWire->end();
  #endif
  pinMode(_scl, OUTPUT);
  pinMode(_sda, OUTPUT);
  digitalWrite(_scl, HIGH);
  digitalWrite(_sda, HIGH);
  startSignal();
  sendByte(GP8302_STORE_TIMING_HEAD, 0, 3, false);
  stopSignal();
  startSignal();
  sendByte(GP8302_STORE_TIMING_ADDR);
  sendByte(GP8302_STORE_TIMING_CMD1);
  stopSignal();
  
  startSignal();
  sendByte(_addr<<1, 1);
  sendByte(GP8302_STORE_TIMING_CMD2, 1);
  sendByte(GP8302_STORE_TIMING_CMD2, 1);
  sendByte(GP8302_STORE_TIMING_CMD2, 1);
  sendByte(GP8302_STORE_TIMING_CMD2, 1);
  sendByte(GP8302_STORE_TIMING_CMD2, 1);
  sendByte(GP8302_STORE_TIMING_CMD2, 1);
  sendByte(GP8302_STORE_TIMING_CMD2, 1);
  sendByte(GP8302_STORE_TIMING_CMD2, 1);
  stopSignal();

  delay(GP8302_STORE_TIMING_DELAY);

  startSignal();
  sendByte(GP8302_STORE_TIMING_HEAD, 0, 3, false);
  stopSignal();
  startSignal();
  sendByte(GP8302_STORE_TIMING_ADDR);
  sendByte(GP8302_STORE_TIMING_CMD2);
  stopSignal();
  _pWire->begin();
}

void DFRobot_GP8403::startSignal(void){
  digitalWrite(_scl,HIGH);
  digitalWrite(_sda,HIGH);
  delayMicroseconds(I2C_CYCLE_BEFORE);
  digitalWrite(_sda,LOW);
  delayMicroseconds(I2C_CYCLE_AFTER);
  digitalWrite(_scl,LOW);
  delayMicroseconds(I2C_CYCLE_TOTAL);
}

void DFRobot_GP8403::stopSignal(void){
  digitalWrite(_sda,LOW);
  delayMicroseconds(I2C_CYCLE_BEFORE);
  digitalWrite(_scl,HIGH);
  delayMicroseconds(I2C_CYCLE_TOTAL);
  digitalWrite(_sda,HIGH);
  delayMicroseconds(I2C_CYCLE_TOTAL);
}


uint8_t DFRobot_GP8403::sendByte(uint8_t data, uint8_t ack, uint8_t bits, bool flag){
  for(int i=bits-1; i>=0;i--){  
    if(data & (1<<i)){
      digitalWrite(_sda,HIGH);//Change the status of sda level during scl low level, and it lasts for some time
    }else{
      digitalWrite(_sda,LOW);
    }
    delayMicroseconds(I2C_CYCLE_BEFORE); 
    digitalWrite(_scl,HIGH);
    delayMicroseconds(I2C_CYCLE_TOTAL);
    //while(digitalRead(_scl) == 0){
        //delayMicroseconds(1);
    //}
    digitalWrite(_scl,LOW);
    delayMicroseconds(I2C_CYCLE_AFTER); 
  }
  if(flag) return recvAck(ack);
  else {
    digitalWrite(_sda,LOW);//
    digitalWrite(_scl,HIGH);//
    return 0;
  }
}


uint8_t DFRobot_GP8403::recvAck(uint8_t ack){
  uint8_t ack_=0;
  uint16_t errorTime = 0;
  pinMode(_sda,INPUT_PULLUP);
  digitalWrite(_sda,HIGH);
  delayMicroseconds(I2C_CYCLE_BEFORE);
  digitalWrite(_scl,HIGH);
  delayMicroseconds(I2C_CYCLE_AFTER);
  while(digitalRead(_sda) != ack){
      delayMicroseconds(1);
      errorTime++;
      if(errorTime > 250) break;
  }
  ack_=digitalRead(_sda);
  delayMicroseconds(I2C_CYCLE_BEFORE);
  digitalWrite(_scl,LOW);
  delayMicroseconds(I2C_CYCLE_AFTER);
  pinMode(_sda,OUTPUT);
  return ack_;
}
void DFRobot_GP8403::writeReg(uint8_t reg, void *pBuf, size_t size)
{
  uint8_t *_pBuf = (uint8_t*)pBuf;
  _pWire->beginTransmission(_addr);
  _pWire->write(reg);

  for(size_t i = 0; i < size; i++){
    _pWire->write(_pBuf[i]);
  }
  _pWire->endTransmission();
}

