#include <Wire.h> 
#include <FS.h>
#include <SD.h>
#include <SPI.h>
#include <EEPROM.h>
#include <Adafruit_FT6206.h>
#include <Adafruit_ILI9341.h>
#include "Touch_Handler.h"
#include "TCA64_Expander.h"
#include "BQ24_Charger_Control.h"
#include "TLV3204_Audio_Controller.h"
//I2S Uses Philips Format
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "driver/sdspi_host.h"
/*
  esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, size_t *bytes_read, uint32_t timeout_ms)
  I2S read data.
  Note: Only allowed to be called when the channel state is RUNNING but the RUNNING only stands for the software state, 
  it doesn’t mean there is no the signal transporting on line.
  Parameters
    handle – [in] I2S channel handler
    dest – [in] The pointer of receiving data buffer
    size – [in] Max data buffer length
    bytes_read – [out] Byte number that actually be read
    timeout_ms – [in] Max block time
  Returns
    ESP_OK Read successfully
    ESP_ERR_INVALID_ARG NULL pointer or this handle is not rx handle
    ESP_ERR_TIMEOUT Reading timeout, no reading event received from ISR within ticks_to_wait
    ESP_ERR_INVALID_STATE I2S is not ready to read
  esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t size, size_t *bytes_written, uint32_t timeout_ms)
  I2S write data.
  Note: Only allowed to be called when the channel state is RUNNING, (i.e., tx channel has been started and is not writing now) 
  but the RUNNING only stands for the software state, it doesn’t mean there is no the signal transporting on line.
  Parameters
    handle – [in] I2S channel handler
    src – [in] The pointer of sent data buffer
    size – [in] Max data buffer length
    bytes_written – [out] Byte number that actually be sent
    timeout_ms – [in] Max block time
  Returns
    ESP_OK Write successfully
    ESP_ERR_INVALID_ARG NULL pointer or this handle is not tx handle
    ESP_ERR_TIMEOUT Writing timeout, no writing event received from ISR within ticks_to_wait
    ESP_ERR_INVALID_STATE I2S is not ready to write
*/
//Charger, Expander, Audio
static const byte DEVICE_ADDRESS[3] = { 0x6B, 0x20, 0x18 };
//TODO: Find the optimal Headset Detection and Button Debounce times
static const int HEADSET_DETECT_DEBOUNCE = 16;// In milliseconds
static const int HEADSET_BUTTON_DEBOUNCE = 8;// In milliseconds
//Left Volume, Right Volume, Master Setting, Frequency and Duration
static const int WARNING_BEEP_DURATION = 100;
static const float WARNING_BEEP_FREQUENCY = 50.0;
static const int WARNING_BEEP_VOLUME = -20;
static const int WARNING_BEEP_SETTING = 2;
static const int SD_FREQUENCY = 4000;//In kHz, only integers
static const int I2S_TIMEOUT = 50;//In milliseconds
static size_t BUFFER_SIZE = 4;
static const int SAMPLE_RATE = 44000;//In samples per second
static const float AVERAGE_CHANNEL_ERROR = 0.5;//Valueless, represetns how much devieation the different averages can have
enum PINS{
  EXPANDER_INT = GPIO_NUM_4, 
  SPI_DIN = GPIO_NUM_2, 
  SPI_DOUT = GPIO_NUM_7, 
  I2C_SDA = GPIO_NUM_3,
  I2S_BCLK = GPIO_NUM_0, 
  I2S_DIN = GPIO_NUM_1, 
  I2S_MCLK = GPIO_NUM_10, 
  I2S_WCLK = GPIO_NUM_9, 
  I2S_DOUT = GPIO_NUM_18,
  DISPLAY_CS = GPIO_NUM_5, 
  DISPLAY_DC = GPIO_NUM_8, 
  CLK = GPIO_NUM_6
};
enum EXPANDER_PINS{
  MEM_CS = 0,
  CONVERT_INT1 = 1,
  CONVERT_INT2 = 2,
  SD_CS = 3,
  TP_CS = 4,
  TP_INT = 5,
  LCD_RST = 6,
  MNTR_INT = 7,
  CHGR_CE = 8,
  CHGR_STAT = 9,
  CHGR_INT = 10,
  LED_EN = 11,
  LED_VSEL1 = 12,
  LED_VSEL2 = 13,
  LED_VSEL3 = 14,
  LED_VSEL4 = 15
};
//Holds the prevous data about the six input pins
bool previousStates[6];
//If true, pause any recording/playing. If false, continue playing
bool isPaused;
//If true, recording and saving to the MEM chip. If false, go to other things
bool isRecording;
//If [0] true, there was a noise trigger. If [1] is true, right. Else the left
bool noiseTriggerFlag[2];
//If [0] true, there was a signal trigger. If [1] is true, right. Else the left
bool signalTriggerFlag[2];
//Used as a flag to determine if a headset is inserted on the output(s)
bool headsetInserted = false;
//A setting that atumatically switches to Mono data storage when it is detected
bool isDetectMonoEnabled = true;
//Signifies that the data being read from the TLV is okay to write to the MEM chip
bool isMEMWriteOkay = true;
//[0]Sticky flag to signal that Mono has been detected, and will now write to MEM in Mono style
//[1]Which channel to record from. false for left, true for right
//These values are set to false after EVERY recording
bool monoDetected[2] = {false, false};
//Brightness. Persists after a restart.
byte percentBrightness;
//Display object, the ILI9341
Adafruit_ILI9341 display = Adafruit_ILI9341(DISPLAY_CS, DISPLAY_DC, SPI_DOUT, CLK, -1, SPI_DIN);
//Touch screen object, the FT6206 ControlLer IC
Adafruit_FT6206 touch = Adafruit_FT6206();
//My TLV3204 Controller
TLV3204 audio = TLV3204_Controller();
//Creates the object used for I2C interface to the TCA Expander
TCA64_Expander tc = TCA64_Expander(DEVICE_ADDRESS[1], I2C_SDA, CLK);
//Charger Controller
BQ24_Charger_Control bq = BQ24_Controller(DEVICE_ADDRESS[0], I2C_SDA, CLK);
//My SD Card controller
//SD_Card sd = SD_Card();
//Touch handler for the various buttons
Touch_Handler handler = Touch_Handler(display, touch);
i2s_chan_handle_t txHandle;
i2s_chan_handle_t rxHandle;
/* Get the default channel configuration by helper macro.
 * This helper macro is defined in 'i2s_common.h' and shared by all the i2s communication mode.
 * It can help to specify the I2S role, and port id 
 */
i2s_chan_config_t channelConfig = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
/* Setting the configurations, the slot configuration and clock configuration can be generated by the macros
 * These two helper macros is defined in 'i2s_std.h' which can only be used in STD mode.
 * They can help to specify the slot and clock configurations for initialization or updating 
 */
i2s_std_config_t standardConfig = {
  .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(48000),
  .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO),
  .gpio_cfg = {
    .mclk = I2S_MCLK,
    .bclk = I2S_BCLK,
    .ws = I2S_GPIO_UNUSED,
    .dout = I2S_DOUT,
    .din = I2S_DIN,
    .invert_flags = {
      .mclk_inv = false,
      .bclk_inv = false,
      .ws_inv = false,
    },
  },
};
//Allocate a new tx and rx channel and get the handle of this channel 
i2s_new_channel(&channelConfig, &txHandle, &rxHandle);
//Initialize the channel
i2s_channel_init_std_mode(txHandle, &standardConfig);
i2s_channel_init_std_mode(rxHandle, &standardConfig);
//Configure the pins of the bus
spi_bus_config_t spiConfig = {
  .mosi_io_num = SPI_DOUT, .miso_io_num = SPI_DIN, 
  .sclk_io_num = CLK, .max_transfer_size = 4092,
};
//Creates the config for the SD card and the Memory IC
sdspi_device_config_t externalMemConfig = {
  .host_id = SPI2_HOST,
  .gpio_cs = SDSPI_SLOT_NO_CS, .gpio_cd = SDSPI_SLOT_NO_CD,
  .gpio_wp = SDSPI_SLOT_NO_WP, .gpio_int = SDSPI_SLOT_NO_INT,
};
//Handles for each of the Memory Thingys
sdspi_dev_handle_t sdHandle; 
sdspi_dev_handle_t memHandle;
sdmmc_card_t sdCard;
sdmmc_card_t memChip;
//Initalizes the SPI bus
spi_bus_initalize(SPI2_HOST, spiConfig, SPI_DMA_CH_AUTO);
void setup(){
  int time = millis();
  Wire.begin(I2C_SDA, CLK);
  display.begin();  touch.begin(128,&Wire);
  tc.setExpanderPins(EXPANDER_PINS);
  byte regConfig[2][8] = {
    {0,1,1,0,0,1,0,0},
    {1,0,0,0,0,0,0,0}
  };
  tc.configureReg(regConfig);
  display.setCursor(0,0);
  display.println("Setting up SD Card...");
  //Sets MEM_CS to low, SD_CS to high to create the card handle
  activateSD();
  sdHandle = printMemInfo(sdHandle);
  sdspi_host_init_device(externalMemConfig, sdHandle);
  sdmmc_card_init(SPI2_HOST, sdCard);
  display.println("Setting up MEM chip...");
  //Sets MEM_CS to high, SD_CS to low to create the card handle
  activateMEM();
  memHandle = printMemInfo(memHandle);
  sdspi_host_init_device(externalMemConfig, memHandle);
  sdmmc_card_init(SPI2_HOST, memChip);
  deactivateExternalMem();//CS pins low
  
  attachInterrupt(digitalPinToInterrupt(EXPANDER_INT),readInterrupt,RISING);
  display.println("Creating log folder...");
  beginLog();
  Log("Created log folder");
  //updateDate(date,time);
  //Getting the brightness from the last power down
  if(EEPROM.read(0x01) != 255) percentBrightness = EEPROM.read(0x01);
  else percentBrightness = 100;//Device has not been powered on before
  
  //255 means that the selected address has not been written to
  if(EEPROM.read(0x00) == 255){
    display.setCursor(0,0); display.setTextColor(0xFFFFFF);
    display.setTextSize(1);
    display.print("Enter date, dd/mm/yy");
    display.setCursor(0,25); display.setTextSize(3);
    display.print("0 1 2 3 4 5 6 7 8 9 <=");
    //Do stuff to get the date
    tc.setOutput(LCD_RST, true);
    delayMicroseconds(5);//Allow the display to reset
    tc.setOutput(LCD_RST, false);
    display.setCursor(0,0); display.setTextColor(0xFFFFFF);
    display.setTextSize(1);
    display.print("Enter time, hh/mm");
    display.setCursor(0,25); display.setTextSize(3);
    display.print("0 1 2 3 4 5 6 7 8 9 <=");
    //Do stuff to get the time
    /*time_t now;
    char strftime_buf[64];
    struct tm timeinfo;
    time(&now);
    // Set timezone to China Standard Time
    setenv("TZ", "CST-8", 1);
    tzset();
    localtime_r(&now, &timeinfo);
    strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);*/
    //Configure the TLV320
    audio.audioInterface(audio.KEYWORDS.I2S,32);//I2S Interface, 32 bit bus
    audio.generalInputOutput(audio.KEYWORDS.INT1);//Set GPIO to INT1
    audio.dataInSPIControl(audio.KEYWORDS.INT2);//Set MISO to INT2
    audio.headsetDetectDebounce(HEADSET_DETECT_DEBOUNCE);
    audio.headsetButtonDebounce(HEADSET_BUTTON_DEBOUNCE);
    audio.headsetInsertion(true,false);
    audio.buttonPress(true,false);
    audio.headphoneOverCurrent(true,false);
    //INT1 will generate an interrupt whenever a headset insertion event, button
    //press, or an over-current on the headset is detected
    audio.analogOutDRCSignalThreshold(true,true);
    audio.autoGainControl(true,true);
    audio.analogOverflow(true,true);
    //INT2 will generate an interrupt whenever the DRC exceeds the set Signal 
    //Threshold, the AGC has noise that exceeds the Noise Threshold, or either
    //of the Analog converters has an overflow.
    EEPROM.write(0x00,0);//Writes a zero to address 0x00 to signify that stuff has been set up
  }
  Log("Startup time: " + time);
  tc.setOutput(LCD_RST, true);
  delay(25);
  tc.setOutput(LCD_RST, false);
  //Display the start-up image
}
/*!
  This is where everything should happen. Keep things pretty fast when going between differnt
  methods and classes
*/
void loop(){
  if(touch.touched()){
    //Gets the point that was touched
    //Split into 8 sectors to make finding where things were touched a tad eaiser
  }
  //Recording
  /*
  while(If in recording mode){
    if(If the play area is touched while paused && !isRecording){}
    if(If the pause area is touched while playing && isRecording){}
    if(If the stop area is touched while paused or playing){}
  }*/
  //Playback
  /*
  while(If in Playing mode){
    if(If the play area is touched while paused && !isPlaying){}
    if(If the pause area is touched while playing && isPlaying){}
    if(If the stop area is touched while paused or playing){
      //Exit the song, go back to the menu
    }
  }
  */
  /*
  This is for updating the slider stuff
  //Waits until a touch or a time out
  int startTime = millis();
  while(startTime + TIME_OUT * 1000 >= millis()){
    //Get the point
    if(tp.touched()){
      TS_Point point = tp.getPoint();//Get the touch coordinates
      if((point.x < SLIDER_X[0] || point.x > SLIDER_X[1]) || (point.y < SLIDER_Y[0] || point.y > SLIDER_Y[1])){
        this -> display();//Removes the slider
        return;//Breaks out of this method
      }else{
        //Get where it touched, and if the slider should be updated
        
      }
      startTime = millis();//Reset Timer
    }
  }
  */
}
/*
  Media data structure:
  Addresses are 0x X X X X X X X X, 8 HEX bytes
  The first byte(s) of the mem chip indicate where the open section is.
  - Starts at the memory address listed in the directory section
  - The maximum length of any media is 256 minutes or 15360 seconds or 15360000(15.36 million) milliseconds,
which can be stored in a 24 bit integer
  - If less than an hour, displayed as 00:00.000, or a setting can turn off the miliseconds view
  - If more than an hour, displayed as 0:00:00. Millisecond view is not allowed, but the amount is known.
  - Since the sample rate is known, the total amount of bits to skip over can be calculated
  Address Layout:
         0     : A single bit that signifies if a saved song is Mono or Stereo. The channel does not matter, it
                 will play on both.
         1     : A single bit that signifies if there is "whitespace" at the start of the song. 0 signifies that it is 
                 to be played like normal, 1 is where the first 24 bits of the song represent where it ACTUALLY starts,
                 or where something changes.
     2   -  25 : Address of where the media ends
     26  -  49 : The total length of the media. 
     50  - 1073: Name; limit of 128 characters. Given in the HEX location on the Code Page 437(cp437)
                 The 0 - 1072 section is first used to identify when a noise is detected, and at what time.
    1074 - UDEFINED: The song. Size is determined AFTER the song ends. First is the Left, then the Right
*/
//Have it set up so that each cahnnel is read individually. If one channel sees more activity, use that cahnnel. 
//If not, then contue in Stereo.
//Maybe use the SD card if the designated space for noise triggers is full. Since the log file contains all of the 
//triggers, have something that goes through each line until the last detected noise that is stored in the MEM chip
//0 is the starting time, 1 is the time at which the last sample was read
int recordStartTime[2];
void* dataBuffer[2];
//0 is the new buffer, 1 is the old
int leftBuffer[2], rightBuffer[2];
//Represents the averagevalue of a channel for a few seconds to determine which channel is active
//0 is Left, 1 is Right
float averageChannelValue[2];
//0: The next avalable address to which data can be written to on the MEM chip, the 8 HEX bytes
//1: The start of the info about the song, in the 8 HEX bytes
//2: The last address 
int currentAddress[3];
//The time in which the ESP will detect weather Mono or Stereo
int detectChannelTime = 2000;
void record(){
  deactivateExternalMem();
  //Update the play to pause
  //Show the stop
  //Display the current length/time
  //Get the audio data from the TLV, filling up an internal buffer, emptying it as fast as it can into the 
  //mem chip
  //Left data is the first half of the data, Right is the second half
  i2s_channel_enable(rxHandle);//Enables channel
  i2s_channel_read(rxHandle,dataBuffer[0],1,&BUFFER_SIZE,I2S_TIMEOUT);//Reads data
  i2s_channel_disable(rxHandle);//Disable channel
  //Seperating the channel data:
  //Since the Left data is half the total bits(32), shift over that amount
  leftBuffer[0] = dataBuffer[0] << 32;
  //Removes the Left data by inverting it, shifting over 32 bits, then XOR-ing it together
  rightBuffer[0] = ~(leftBuffer[0] >> 32) ^ int(dataBuffer[0]);
  //Ensure that something is on a channel, and notify the user that there is nothing being played/recorded
  //Write to a file on the SD until something is detected
  //Only does this stuff if Detect Mono is Enabled
  if(!isDetectMonoEnabled){
    //After two seconds, stop getting the average
    if(recordStartTime[1] - recordStartTime[0] <= detectChannelTime){
                              //Gets the previous totals, factoring in the Sample Fate                         Adds the new value          Divides it by the time
      averageChannelValue[0] = (averageChannelValue[0] * (recordStartTime[1] - recordStartTime[0]) * SAMPLE_RATE + leftBuffer[0]) / ((recordStartTime[1] - recordStartTime[0]) * SAMPLE_RATE);
      averageChannelValue[1] = (averageChannelValue[1] * (recordStartTime[1] - recordStartTime[0]) * SAMPLE_RATE + rightBuffer[0]) / ((recordStartTime[1] - recordStartTime[0]) * SAMPLE_RATE);
    }else if(recordStartTime[1] - recordStartTime[0] <= detectChannelTime + 25){//A little buffer time
      //If the averages are the same, assume Mono is being played through both channels
      if(averageChannelValue[0] <= averageChannelValue[1] + AVERAGE_CHANNEL_ERROR || averageChannelValue[0] >= averageChannelValue[1] - AVERAGE_CHANNEL_ERROR){
        monoDetected[0] = true;
        monoDetected[1] = false;//Uses the Left channel for storage
      }
      //Sees if the Left channel is close to 0, within an error
      if(averageChannelValue[0] <= AVERAGE_CHANNEL_ERROR && averageChannelValue[0] >= -AVERAGE_CHANNEL_ERROR){
        monoDetected[0] = true;
        monoDetected[1] = true;//Uses the Right channel for stoage
      }
      //Checking if the Right channel is not used. If both channels are not used, does NOT write anything to mem and increases the Detect Channel Time
      //The last two are to check if the Left Channel has already been detected as 0
      if(averageChannelValue[1] <= AVERAGE_CHANNEL_ERROR && averageChannelValue[1] >= -AVERAGE_CHANNEL_ERROR && monoDetected[0] && monoDetected[1]){
        isMEMWriteOkay = false;
        detectChannelTime += 1000;//Adds an extra second
        handler.warning("Mono Detect Time increased");
        String temp = "Mono Detect Time increased to: "+detectChannelTime; 
        Log(temp);
      }else{
        isDetectMonoEnabled = false;//Stop Mono Detection, a result has been found
        isMEMWriteOkay = true;
      }
    }
  }
  if(isMEMWriteOkay){
    //Mono has been detected, write the selected channel to memory
    if(monoDetected[0]){
      //Use right for storage
      activateMEM();
      if(monoDetected[1]){
        sdmmc_io_write_bytes(memChip, 53, currentAddress[0], rightBuffer[0], 2);//Use right for storage
        rightBuffer[1] = rightBuffer[0];//Update buffer
      }else{
        sdmmc_io_write_bytes(memChip, 53, currentAddress[0], leftBuffer[0], 2);//Use left for storage
        leftBuffer[1] = leftBuffer[0];//Update buffer
      }
      currentAddress[0] += 16;//Increment the address by 16 bits
    }else{//Mono has NOT been detected, write all data to memory
      sdmmc_io_write_bytes(memChip, 53, currentAddress[0], dataBuffer[0], 4);
      dataBuffer[1] = dataBuffer[0];
      currentAddress[0] += 32;//Increment the address by 32 bits
    }
  }
}
void startPlayback(){
  //Reads and updates to variables...
    //Type of song(Mono or Stereo)
    //If it's been transformed*Maybe
    //Name
    //Length
    
}
/****************************** SD CARD STUFF ******************************/
  FS fileSystem;
  File file;
  String currentLogName;
  /*!
    Opens a file on the SD Card, if there is one. If a card is not present, or was not properly
    set up, a 1 will be returned. Otherwise, a 0. Names the file the current date.
  */
  byte beginLog(){
    SPIClass spi = SPIClass(VSPI);
    activateSD();
    spi.begin(CLK, SPI_DIN, SPI_DOUT, 0);
    if(!SD.begin(0,spi,80000000)){
      display.println("No SD Card!");
      return 1;
    }
    //Checks if a directory called "logs" exists
    file = SD.open("logs/");
    //If it doesn't, makes a new one
    if(!file) SD.mkdir("logs/"); 
    SD.open("logs/Pending_Date.txt");
    currentLogName = "Pending_Date";
    deactivateExternalMem();
    return 0;
  }
  /*!
    Puts information about an event to a log. Timestamp is collected from the millis() after start
    @param  info  What to put into the log.
  */
  void Log(String info){
    activateSD();
    file = fileSystem.open("logs/" + currentLogName +".txt", FILE_WRITE);
    file.println((millis() / 1000) + ": " + info);
    deactivateExternalMem();
  }
  /*!
    Updates the name of the file after the current date has been set
    @param  date  An array with three members: the day, month, and year.
    @param  time  An array with two members: the hour and the minute, in 24 hour format.
  */
  void updateDate(byte date[3], byte time[2]){
    activateSD();
    String name[2] = { "logs/", "logs/" + currentLogName };
    for(byte i = 0; i < 3; i++) name[0] += date[i] + "_";
    name[0] += "_" + time[0] + "_" + time[1];
    fileSystem.rename(name[1], name[0]);
    currentLogName = name[0];
    deactivateExternalMem();
  }
  /*!
    Ends the log
  */
  void close(){ 
    activateSD();
    file.close();
    deactivateExternalMem();
  }
  //The following is for accesing the memory cards
  EXPANDER_PINS memChipSelect[2] = {MEM_CS, SD_CS};
  bool states[2];
  void activateSD(){ 
    states[0] = false;
    states[1] = true;
    tc.setOutput(memChipSelect, states); 
  }
  void activateMEM(){ 
    states[0] = true;
    states[1] = false;
    tc.setOutput(memChipSelect, states); 
  }
  void deactivateExternalMem(){ 
    states[0] = false;
    states[1] = false;
    tc.setOutput(memChipSelect, states); 
  }
  sdspi_dev_handle_t printMemInfo(sdspi_dev_handle_t handle){
    sdmmc_card_t card;
    sdspi_host_init_device(&externalMemConfig, handle);
    sdmmc_card_init(SPI2_HOST, card);
    display.println("Manufacturer ID: "+card.cid.mfg_id);
    display.println("OEM ID: "+card.cid.oem_id);
    String name;
    for(byte i = 0; i < 8; i++) name += card.cid.name[i];
    display.println("Name: "+name);
    display.println("Rev. Num: "+card.cid.revision);
    display.println("display Num: "+card.cid.serial);
    display.println("Manufac. Date: "+card.cid.date);
    Log("Manufacturer ID: "+card.cid.mfg_id);
    Log("OEM ID: "+card.cid.oem_id);
    name = "";
    for(byte i = 0; i < 8; i++) name += card.cid.name[i];
    Log("Name:"+name);
    Log("Rev. Num: "+card.cid.revision);
    Log("display Num: "+card.cid.serial);
    Log("Manufac. Date: "+card.cid.date);
    return handle;
  }
  
/**************************** INTERRUPT HANDLER ****************************/
  int statStartTime;
  //Things to look for:
  //INT always goes low when reading from the Expander
  void readInterrupt(){
    //All INT's will generate a tone that overwrites the current audio being
    //played, as well as display the error on the upper left corner of the screen
    audio.beepTime(WARNING_BEEP_DURATION);//Duration to the set time
    audio.beepFrequency(WARNING_BEEP_FREQUENCY);// Frequency of the beep
    //Left volume, and the master setting
    audio.beepVolumeControl(WARNING_BEEP_VOLUME, 0, WARNING_BEEP_SETTING);
    //The beep will immediatly play
    bool currentStates[6] = {
      tc.readPin(CONVERT_INT1),
      tc.readPin(CONVERT_INT2),
      tc.readPin(TP_INT),
      tc.readPin(MNTR_INT),
      tc.readPin(CHGR_STAT),
      tc.readPin(CHGR_INT)
    };
  for(byte i = 0; i < 6; i++) previousStates[i] = currentStates[i];//Updating the read data
    //Convert Int 1
    if(currentStates[0]){
      //Headset Button Press
      if(audio.toggleable(0,44,5)){
        Log("Headset Button press");
      }
      //Headset Removal/insertion
      if(audio.toggleable(0,44,4)){
        Log("Headset inserted");
      }
      //Headset HPL Overcurrent
      if(audio.toggleable(0,44,7)){
        Log("Over current on Left Channel");
      }
      //Headset HPR Overcurrent
      if(audio.toggleable(0,44,6)){
        Log("Over current on Right Channel");
      }
    }
    //Convert Int 2
    if(currentStates[1]){
      //Left DRC Exceeded Signal Threshold
      if(audio.toggleable(0,44,3)){
        signalTriggerFlag[0] = true;
        signalTriggerFlag[1] = false;
        Log("Left DRC Excceded set Signal Threshold");
      }
      //Right DRC Exceeded Signal Threshold
      if(audio.toggleable(0,44,2)){
        signalTriggerFlag[0] = true;
        signalTriggerFlag[1] = true;
        Log("Right DRC Excceded set Signal Threshold");
      }
      //Left AGC Exceeded Noise Threshold
      if(audio.toggleable(0,45,6)){
        noiseTriggerFlag[0] = true;
        noiseTriggerFlag[1] = false;
        Log("Left AGC Excceded set Noise Threshold");
      }
      //Right AGC Exceeded Noise Threshold
      if(audio.toggleable(0,45,5)){
        noiseTriggerFlag[0] = true;
        noiseTriggerFlag[1] = true;
        Log("Right AGC Excceded set Noise Threshold");
      }
      //Left DAC Data Overflow
      if(audio.toggleable(0,42,7)){
        Log("Left DAC Overflow!");
      }
      //Right DAC Data Overflow
      if(audio.toggleable(0,42,6)){
        Log("Right DAC Overflow!");
      }
      //Left ADC Data Overflow
      if(audio.toggleable(0,42,3)){
        Log("Left ADC Overflow!");
      }
      //Right ADC Data Overflow
      if(audio.toggleable(0,42,2)){
        Log("Right ADC Overflow!");
      }
    }
    //Moniter Int
    if(currentStates[3]){}
    //Charger Stat
    if(currentStates[4]){
      //Gets the current time to determine if the STAT pin is blinking at 1 Hz
      if(statStartTime == 0) statStartTime = millis();
      else if(statStartTime >= millis() - 1000){
        bq.STAT currentStatus[6] = bq.statusRegister();
        switch(currentStatus[0]){
          case bq.STAT.UNKNOWN: 
            Log("Unknown Voltage Source");
          break;
          case bq.STAT.USB_HOST: 
            Log("USB Host");
          break;
          case bq.STAT.ADAPTER_SOURCE: 
            Log("Adapter Source");
          break;
          case bq.STAT.OTG_SOURCE:
            Log("USB On the Go Source");
          break;
        }
        switch(currentStatus[1]){
          case bq.STAT.NCHARGING: 
            Log("No Charge");
          break;
          case bq.STAT.PRECHARGE: 
            Log("Precharging");
          break;
          case bq.STAT.FAST_CHARGE: 
            Log("Fast Charging");
          break;
          case bq.STAT.CHARGE_DONE: 
            Log("Charging complete");
          break;
        }
        if(currentStatus[2] == bq.STAT.IN_DPM){
          Log("In Dynamic Power Management");
        }
        if(currentStatus[3] == bq.STAT.POWER_NGOOD){
          Log("Power is not good");
        }
        if(currentStatus[4] == bq.STAT.THERMAL_NGOOD){
          Log("Thermals are not good");
        }
        if(currentStatus[5] == bq.STAT.VSYS_REGULATION){
          Log("VSYS is in regulation");
        }
        statStartTime = 0;
      }
    }
    //Charger Int
    if(currentStates[5]){
      bq.FAULT currentFault[3] = bq.getFault();
      if(currentFault[0] != bq.FAULT.NO_FAULT){
        Log("Voltage Bus Overloaded");
      }
      switch(currentFault[1]){
        case bq.FAULT.INPUT_FAULT: 
          Log("Input Fault");
        break;
        case bq.FAULT.THERMAL_SHUTDOWN: 
          Log("Thermal Shutdown");
        break;
        case bq.FAULT.TIMER_EXPIRATION: 
          Log("Charger Timer Expired");
        break; 
      }
      if(currentFault[2] != bq.FAULT.NO_FAULT){
        Log("Battery Over-Voltage");
      }
    }
  }
Loading
esp32-c3-devkitm-1
esp32-c3-devkitm-1
Loading
ili9341-cap-touch
ili9341-cap-touch