// QuickCharge 3.0 demo
// Use the library from https://github.com/vdeconinck/QC3Control/blob/master/src/QC3Control.cpp
// to control a Quick Charge power controller
// Copied the QC3Control.h and QC3Control.cpp to this Wokwi
//
// Should control QuickCharge/FastCharge power block
// https://en.wikipedia.org/wiki/Quick_Charge
// See https://forum.arduino.cc/t/hacking-qualcomm-quick-charge-3-0/906880/11
// for a prototype

// The resistors aren't electronically simulated in Wokwi, but per the library's
// diagram, they form voltage dividers to control the D+ and D- voltages on
// a QC2/QC3 charger's data lines.  This is simulated here with wokwiSim().
//
// DaveX 2022-03-06 CC BY-SA
// See https://forum.arduino.cc/t/quickcharge-3-0-as-adjustable-voltage-source/966276
// for discussion

const bool inWokwi = true;

#include "QC3Control.h" // quotes for local files in Wokwi

//
// External Connections: 
// A0 to D- on QC3
// A1 to D+ on QC3
// Vin is simulating Vbus on the QC3.  In real life, disconnect this.
// 
//Pin 4 for Data+ 470R to VCC+10K+1K5+GND
//Pin 5 for Data- 470R to VCC+10K+1K5+GND
//See How to connect in the documentation for more details.
QC3Control quickCharge(4, 5);

float Vcc = 5;
float Vbus = 0;

float simVbus = 0;
int simA0, simA1, simA2;

void wokwiSim(void){
  // Simulate the the QC3 device and voltage dividers on WokWi
  const float r10kP470 = 1/(1.0/10000+1.0/470); // 10K || 470
  const float r1k5P470 = 1/(1.0/1500+1.0/470);  // 1K5 || 470
  
  simVbus = constrain(quickCharge.getMilliVoltage(),3900,12600)/1000.0; 
  simA0 = 1024.0*(digitalRead(5) ? (1500/(r10kP470+1500)) : (r1k5P470/(r1k5P470+10000)) );
  simA1 = 1024.0*(digitalRead(4) ? (1500/(r10kP470+1500)) : (r1k5P470/(r1k5P470+10000)) );
  simA2 = 1024.0*simVbus*10000/(10000.0+47000)/Vcc;
}

void printMVolts() {
  int rA0 = analogRead(A0);
  int rA1 = analogRead(A1);
  int rA2 = analogRead(A2);
  if(inWokwi){ // override the analogRead on WokWi with simulated values
    wokwiSim();
    rA0 = simA0;
    rA1 = simA1;
    rA2 = simA2;
  }

  Vcc = readVcc() / 1000.0;
  Serial.print(quickCharge.getMilliVoltage());
  Serial.print("mV, D-: ");
  Serial.print((rA0 + 0.5) * Vcc / 1024);
  Serial.print("V, D+: ");
  Serial.print((rA1 + 0.5) * Vcc / 1024);
  Serial.print("V, VBus: ");
  Serial.print(Vbus = (rA2 + 0.5) / 1024.0 * Vcc * (46.29 + 9.89) / 9.89 ); //
  Serial.print("V, Vcc=");
  Serial.print(Vcc); //
  Serial.println("V ");
}

long readVcc() {
  // https://forum.arduino.cc/t/how-to-know-vcc-voltage-in-arduino/344001/3
  long result;
  byte ADMUXsave = ADMUX;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA, ADSC));
  result = ADCL;
  result |= ADCH << 8;
  ADMUX = ADMUXsave;
  result = 1126400L / result; // Back-calculate AVcc in mV
  //Serial.println(result);
  return result;
}


void setup() {
  Vcc = readVcc() / 1000.0;
  quickCharge.begin();

  Serial.begin(115200);
  //set voltage to 12V

  quickCharge.set5V();
  //delay(5000);
  //quickCharge.set12V();
  Serial.print("QuickChargeControl.ino -- Control a QuickCharge3\n"
  "3.9-12V variable power supply with an Arduino.\n"
  "Setup: ");
  printMVolts();
  delay(5000);
}

void demoModes(void) {
  const int interval = 1000;
  static unsigned long last = 0;
  static int mode = 0;
  static int ii = 0;
  unsigned long now = millis();
  if (now - last > interval) {
    if (now - last > 4 * interval) {
      last = now ;
    }
    else {
      last += interval;
    }
    Serial.print("Mode ");
    Serial.print(mode);
    Serial.print(": ");
    printMVolts();
    switch (mode) {
      case 0:
        quickCharge.set5V();
        mode++;
        break;
      case 1:
        quickCharge.set9V();
        mode++;
        break;
      case 2:
        quickCharge.set12V();
        mode++;
        break;
      case 3:
        quickCharge.setMilliVoltage(3200);
        mode++;
        break;
      case 4:
        quickCharge.setMilliVoltage(12000);
        mode++;
        break;
      case 5:  // decrementing 0.2v/step
        if (ii < 50) {
          ii++;
          quickCharge.decrementVoltage();
        }
        else
        {
          mode++;
          //ii = 60; //override
        }
        break;
      case 6:
        if (ii > 0) {
          ii--;
          quickCharge.incrementVoltage();
        }
        else
        {
          mode++;
        }
        break;
      case 7:
        quickCharge.set5V();
        mode = 0;
        break;
      default:
        mode = 0;
        break;
    }
  }
}

// loopCounter from https://forum.arduino.cc/t/while-loop-as-a-condition-for-limit-switches/963899/11
void LoopCounter() // tells the average response speed of void loop()
{ // inside a function, static variables keep their value from run to run
  const unsigned long microsInOneSecond = 1000000UL;
  static unsigned long count, countStartMicros; // only this function sees these

  count++; // adds 1 to count after any use in an expression, here it just adds 1.
  if ( micros() - countStartMicros >= microsInOneSecond ) // 1 second
  {
    countStartMicros += microsInOneSecond; // for a regular second
    Serial.println( count ); // 32-bit binary into decimal text = many micros
    count = 0; // don't forget to reset the counter
  }
}


void loop() {
  //And you can change it on the fly
  demoModes();
  //LoopCounter();
}