text: // Copyright (c) M5Stack. All rights reserved.
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  
  #include "AXP192_Class.hpp"
  
  #include <esp_log.h>
  #include <algorithm>
  
  namespace m5
  {
  /*
    DCDC1 : 0.7-3.5V，  25mV/step  1200mA
    DCDC2 : 0.7-2.275V，25mV/step  1600mA
    DCDC3 : 0.7-3.5V，  25mV/step   700mA
  
    LDOio0: 1.8-3.3V,  100mV/step    50mA
    LDO1  :                          30mA always on
    LDO2  : 1.8-3.3V， 100mV/step   200mA
    LDO3  : 1.8-3.3V， 100mV/step   200mA
  */
    bool AXP192_Class::begin(void)
    {
      std::uint8_t val;
      _init = readRegister(0x03, &val, 1);
      if (_init)
      {
        ESP_LOGI("AXP192", "reg03h:%02x", val);
        _init = (val == 0x03);
      }
      return _init;
    }
  
    /// @param num 0=DCDC1 / 1=DCDC2 / 2=DCDC3
    void AXP192_Class::_set_DCDC(std::uint8_t num, int voltage)
    {
      static constexpr uint8_t reg12bit_tbl[] = { 0x01, 0x10, 0x02 };
      static constexpr uint8_t volt_reg_tbl[] = { 0x26, 0x23, 0x27 };
      static constexpr uint8_t volt_max_tbl[] = { 0x7F, 0x3F, 0x7F };
  
      voltage -= 700;
      std::uint_fast8_t val = (voltage < 0) ? 0 : std::min(voltage / 25, (int)volt_max_tbl[num]);
      writeRegister8(volt_reg_tbl[num], val);
      if (voltage < 0)
      {
        bitOff(0x12, reg12bit_tbl[num]);
      }
      else
      {
        bitOn(0x12, reg12bit_tbl[num]);
      }
    }
  
    /// @param num 0:LDOio0 ; 2:LDO2 ; 3=LDO3
    void AXP192_Class::_set_LDO(std::uint8_t num, int voltage)
    {
      if (num > 3 || num == 1) return;
      std::uint8_t reg_volt = (num == 0) ? 0x91 : 0x28;
      voltage -= 1800;
      /// convert voltage to value
      std::uint_fast8_t val = (voltage < 0) ? 0 : std::min(voltage / 100, 0x0F);
      std::uint_fast8_t now = readRegister8(reg_volt);
      if (num == 3)
      { /// LDO3
        now = (now & 0xF0) + val;
      }
      else
      { /// LDOio0 , LDO2
        now = (now & 0x0F) | (val << 4);
      }
      writeRegister8(reg_volt, now);
  
      if (num)
      { // LDO2 , LDO3
        std::uint_fast8_t reg12bit = 1 << num;
        if (voltage < 0)
        {
          bitOff(0x12, reg12bit);
        }
        else
        {
          bitOn(0x12, reg12bit);
        }
      }
      else
      { // LDOio0
        writeRegister8(0x90, (voltage < 0) ? 0x07 : 0x02 ); /// floating or LDO
      }
    }
  
    /// @param num 0=LDO2 / 1=LDO3
    void AXP192_Class::_set_LDO2_LDO3(std::uint8_t num, int voltage)
    {
      voltage -= 1800;
      std::uint_fast8_t val = (voltage < 0) ? 0 : std::min(voltage / 100, 0x0F);
      std::uint_fast8_t now = readRegister8(0x28);
      if (num == 1)
      { /// LDO3
        now = (now & 0xF0) + val;
      }
      else
      { /// LDO2
        now = (now & 0x0F) | (val << 4);
      }
      writeRegister8(0x28, now);
  
      std::uint_fast8_t reg12bit = 1 << (num + 2);
      if (voltage < 0)
      {
        bitOff(0x12, reg12bit);
      }
      else
      {
        bitOn(0x12, reg12bit);
      }
    }
  
    /// @param num 0=GPIO0 / 1=GPIO1 / 2=GPIO2
    void AXP192_Class::_set_GPIO0_2(std::uint8_t num, bool state)
    {
      static constexpr uint8_t reg[] = { 0x90, 0x92, 0x93 };
      writeRegister8(reg[num], state ? 0x06 : 0x05); // floating or LOW
    }
  
    /// @param num 0=GPIO3 / 1=GPIO4
    void AXP192_Class::_set_GPIO3_4(std::uint8_t num, bool state)
    {
      uint32_t bit = num ? 2 : 1;
      if (state)
      {
        bitOn(0x96, bit);
      }
      else
      {
        bitOff(0x96, bit);
      }
      uint_fast8_t mask = num ? ~0x0C : ~0x03;
      uint_fast8_t reg0x95 = readRegister8(0x95) & mask;
      writeRegister8(0x95, reg0x95 | (num ? 0x84 : 0x81)); // set GPIO mode
    }
  
    void AXP192_Class::setBatteryCharge(bool enable)
    {
      std::uint8_t val = 0;
      if (readRegister(0x33, &val, 1))
      {
        writeRegister8(0x33, (val & 0x7F) + (enable ? 0x80 : 0x00));
      }
    }
  
    void AXP192_Class::setChargeCurrent(std::uint16_t max_mA)
    {
      max_mA /= 10;
      if (max_mA > 132) { max_mA = 132; }
      static constexpr std::uint8_t table[] = { 19, 28, 36, 45, 55, 63, 70, 78, 88, 96, 100, 108, 116, 124, 132, 255 };
  
      size_t i = 0;
      while (table[i] <= max_mA) { ++i; }
  
      std::uint8_t val = 0;
      if (readRegister(0x33, &val, 1))
      {
        writeRegister8(0x33, (val & 0xF0) + i);
      }
    }
  
    void AXP192_Class::setChargeVoltage(std::uint16_t max_mV)
    {
      max_mV = (max_mV / 10) - 410;
      if (max_mV > 436 - 410) { max_mV = 436 - 410; }
      static constexpr std::uint8_t table[] =
        { 415 - 410  /// 4150mV
        , 420 - 410  /// 4200mV
        , 436 - 410  /// 4360mV
        , 255
        };
      size_t i = 0;
      while (table[i] <= max_mV) { ++i; }
  
      std::uint8_t val = 0;
      if (readRegister(0x33, &val, 1))
      {
        writeRegister8(0x33, (val & 0x9F) + (i << 5));
      }
    }
  
    std::int8_t AXP192_Class::getBatteryLevel(void)
    {
      std::uint8_t buf[4];
      if (!readRegister(0x78, buf, 4)) { return -1; }
  
      std::uint_fast16_t voltage = (buf[0] << 4) + buf[1];
      std::uint_fast16_t current = (buf[2] << 5) + buf[3];
  
      std::int_fast16_t res = (voltage > 3150) ? (( voltage - 3075 ) * 0.16f  )
                            : (voltage > 2690) ? (( voltage - 2690 ) * 0.027f )
                            : 0;
      if (current > 16) { res -= 16; }
  
      return (res < 100) ? res : 100;
    }
  
    bool AXP192_Class::isCharging(void)
    {
      return readRegister8(0x00) & 0x04;
    }
  
    void AXP192_Class::powerOff(void)
    {
      bitOn(0x32, 0x80);
    }
  
    void AXP192_Class::setAdcState(bool enable)
    {
      writeRegister8(0x82, enable ? 0xff : 0x00);
    }
  
    void AXP192_Class::setAdcRate( std::uint8_t rate )
    {
      std::uint_fast8_t buf = readRegister8(0x84);
      writeRegister8(0x84, (buf & ~(0xc0)) | (rate & 0xc0));
    }
  
    void AXP192_Class::setEXTEN(bool enable)
    {
      static constexpr std::uint8_t add = 0x12;
      static constexpr std::uint8_t bit = 1 << 6;
      if (enable)
      {
        bitOn(add, bit);
      }
      else
      {
        bitOff(add, bit);
      }
    }
  
    bool AXP192_Class::getEXTEN(void)
    {
      return readRegister8(0x12) & (1 << 6);
    }
  
    void AXP192_Class::setBACKUP(bool enable)
    {
      static constexpr std::uint8_t add = 0x35;
      static constexpr std::uint8_t bit = 1 << 7;
      if (enable)
      { // Enable
        bitOn(add, bit);
      }
      else
      { // Disable
        bitOff(add, bit);
      }
    }
  
    bool AXP192_Class::isACIN(void)
    {
      return readRegister8(0x00) & 0x80;
    }
    bool AXP192_Class::isVBUS(void)
    {
      return readRegister8(0x00) & 0x20;
    }
  
    bool AXP192_Class::getBatState(void)
    {
      return readRegister8(0x01) & 0x20;
    }
  
    std::uint8_t AXP192_Class::getPekPress(void)
    {
      std::uint8_t val = readRegister8(0x46) & 0x03;
      if (val) { writeRegister8(0x46, val); }
      return val;
    }
  
    float AXP192_Class::getACINVolatge(void)
    {
      return 1.7f * readRegister12(0x56) / 1000.0f;
    }
  
    float AXP192_Class::getACINCurrent(void)
    {
      return 0.625f * readRegister12(0x58);
    }
  
    float AXP192_Class::getVBUSVoltage(void)
    {
      return 1.7f * readRegister12(0x5a) / 1000.0f;
    }
  
    float AXP192_Class::getVBUSCurrent(void)
    {
      return 0.375f * readRegister12(0x5c);
    }
  
    float AXP192_Class::getInternalTemperature(void)
    {
      return -144.7 + 0.1f * readRegister12(0x5e);
    }
  
    float AXP192_Class::getBatteryPower(void)
    {
      return  1.1f * 0.5f * readRegister24(0x70) / 1000.0f;
    }
  
    float AXP192_Class::getBatteryVoltage(void)
    {
      return 1.1f * readRegister12(0x78) / 1000.0f;
    }
  
    float AXP192_Class::getBatteryChargeCurrent(void)
    {
      return 0.5f * readRegister13(0x7a);
    }
  
    float AXP192_Class::getBatteryDischargeCurrent(void)
    {
      return 0.5f * readRegister13(0x7c);
    }
  
    float AXP192_Class::getAPSVoltage(void)
    {
      return 1.4f * readRegister12(0x7e) / 1000.0f;
    }
  
  
    std::size_t AXP192_Class::readRegister12(std::uint8_t addr)
    {
      std::uint8_t buf[2] = {0};
      readRegister(addr, buf, 2);
      return buf[0] << 4 | buf[1];
    }
    std::size_t AXP192_Class::readRegister13(std::uint8_t addr)
    {
      std::uint8_t buf[2] = {0};
      readRegister(addr, buf, 2);
      return buf[0] << 5 | buf[1];
    }
    std::size_t AXP192_Class::readRegister16(std::uint8_t addr)
    {
      std::uint8_t buf[2] = {0};
      readRegister(addr, buf, 2);
      return buf[0] << 8 | buf[1];
    }
    std::size_t AXP192_Class::readRegister24(std::uint8_t addr)
    {
      std::uint8_t buf[3] = {0};
      readRegister(addr, buf, 3);
      return buf[0] << 16 | buf[1] << 8 | buf[2];
    }
    std::size_t AXP192_Class::readRegister32(std::uint8_t addr)
    {
      std::uint8_t buf[4] = {0};
      readRegister(addr, buf, 4);
      return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
    }
  }
  