#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");
}
}
}