/**
 * @file main.cpp
 * @author Jonnie Walker iTE  
 * @brief  ESP32-C6_MSensor-Test 
 * @version 0.1
 * @date 2024-07-1
 * 
 * @copyright Copyright (c) 2024   edit
 * 
 * --------------------------------------------------------------------/
 * 
 * Core control is ESP32-C6-mode-N4
 * 
 * I2C: Wire.begin(6, 7); // GPIO6 indicates SDA and GPIO7 indicates SCL
 * 
 *  Sensor:
 * 1.BH1750
 * 2.AHT20
 * 3.SCD40/41
 * 4.QMI8658C
 * 5.AGS10MA
 * 6.BMP280
 * 7.BS5820
 * 
 * 
 */

#include <SPI.h>
#include <Wire.h>
#include <BH1750.h>
#include "SparkFun_SCD4x_Arduino_Library.h"
#include <Adafruit_AHTX0.h>
#include "SensorQMI8658.hpp"
#include <Adafruit_BMP280.h>
#include "Adafruit_AGS02MA.h"
//#include <ArduinoOTA.h>// LAN OTA upgrade
//#include <WiFi.h>
//#include "esp_sleep.h"
#include "TaskScheduler.h"// Multi-tasking system
#include <OneButton.h>



#define USE_WIRE

#ifndef SENSOR_SDA
#define SENSOR_SDA  6
#endif

#ifndef SENSOR_SCL
#define SENSOR_SCL  7
#endif

#ifndef SENSOR_IRQ
#define SENSOR_IRQ  -1
#endif

//#define IMU_CS       5

#define USER_LED     5
#define H_M_sensor  4
#define USER_BUTTON  10

#define ADC_PIN_V1  2
#define ADC_PIN_V2  0


SensorQMI8658 qmi;

IMUdata acc;
IMUdata gyr;

int stateg4_HM, stateg10_UB;

int adcValue_2, adcValue_0;
float voltage_2, voltage_0;


Adafruit_AGS02MA ags;
 
Adafruit_BMP280 bmp; // I2C

// Create an AHT20 object with the address 0x38
Adafruit_AHTX0 aht;

// Create a BH1750 object
BH1750 lightMeter;

SCD4x mySensor(SCD4x_SENSOR_SCD41); // Tell the library we have a SCD41 connected

OneButton button1(USER_BUTTON, true);

// Define function prototypes for task execution
void blinkLED();
void printTime();
void readSensor();

Scheduler runner; // Create a scheduler

// Create task objects
Task t1(4000 * TASK_MILLISECOND, TASK_FOREVER, &blinkLED, &runner, true);
Task t2(400 * TASK_MILLISECOND, TASK_FOREVER, &printTime, &runner, true);
Task t3(2000 * TASK_MILLISECOND, TASK_FOREVER, &readSensor, &runner, true);


void bh1750_1_sensor();
void scd4x_2_sensor();
void aht20_3_sensor();
void qmi8658_4_sensor();
void bmp280_5_sensor();
void ags20ma_6_sensor();
void Human_motion_sensor();
void button_user();
void adc_read();


void blinkLED() {
  static bool ledState = false;
  digitalWrite(USER_LED , ledState = !ledState); // Switch LED status

}

void printTime() {
     //button1.tick();
     button_user(); 
     //adc_read();
 // Serial.println(millis() / 1000); // Print the number of seconds since startup
}

void readSensor() {
  adc_read();
  bh1750_1_sensor();
  scd4x_2_sensor();
  aht20_3_sensor();
  qmi8658_4_sensor();
  bmp280_5_sensor();
  ags20ma_6_sensor();
  Human_motion_sensor();
 // button_user(); 

}


void setup() {
  // put your setup code here, to run once:
   Serial.begin(115200);

 // Initializes the I2C
  Wire.begin(SENSOR_SDA, SENSOR_SCL); // SDA, SCL
  
  pinMode(USER_LED, OUTPUT);
  pinMode(H_M_sensor , INPUT_PULLDOWN); // Set GPIO4 to input drop-down mode
  pinMode(USER_BUTTON , INPUT_PULLUP); // Set GPIO10 to input pull-up mode

  
  analogReadResolution(12); // Set ADC resolution to 12 bits
  analogSetAttenuation(ADC_0db); // Set the attenuation to 0dB


//----------BH1750------------------------------------------------/
  // Initializes the BH1750 sensor
  if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
    Serial.println("BH1750 was successfully initialized!");
  } else {
    Serial.println("BH1750 failed to initialize!");
  }

//------SDC4x------------------------------------------------/
  //mySensor.enableDebugging(); // Uncomment this line to get helpful debug messages on Serial
  if (mySensor.begin(false, true, false) == false) // Do not start periodic measurements
  //measBegin_________/     |     |
  //autoCalibrate__________/      |
  //skipStopPeriodicMeasurements_/
  {
    Serial.println(F("Sensor not detected. Please check wiring. Freezing..."));
    while (1)
      ;
  }

  //Let's call measureSingleShot to start the first conversion
  bool success = mySensor.measureSingleShot();
  if (success == false)
  {
    Serial.println(F("measureSingleShot failed. Are you sure you have a SCD41 connected? Freezing..."));
    while (1)
      ;    
  } 

//-------------------AHT20-------------------------------------------/
  // Initializes the AHT20 sensor
  if (!aht.begin()) {
    Serial.println("AHT20 initialization failed!");
    while (1) delay(10);
  }
  Serial.println("AHT20 initialization success!");

//--------------- QMI8658-----------------------------------------------/
   #ifdef USE_WIRE
    //Using WIRE !!
    if (!qmi.begin(Wire, QMI8658_L_SLAVE_ADDRESS, SENSOR_SDA, SENSOR_SCL)) {
        Serial.println("Failed to find QMI8658 - check your wiring!");
        while (1) {
            delay(1000);
        }
    }
#else
    if (!qmi.begin(IMU_CS)) {
        Serial.println("Failed to find QMI8658 - check your wiring!");
        while (1) {
            delay(1000);
        }
    }
#endif

    /* Get chip id*/
    Serial.print("Device ID:");
    Serial.println(qmi.getChipID(), HEX);

    qmi.configAccelerometer(
        /*
         * ACC_RANGE_2G
         * ACC_RANGE_4G
         * ACC_RANGE_8G
         * ACC_RANGE_16G
         * */
        SensorQMI8658::ACC_RANGE_4G,
        /*
         * ACC_ODR_1000H
         * ACC_ODR_500Hz
         * ACC_ODR_250Hz
         * ACC_ODR_125Hz
         * ACC_ODR_62_5Hz
         * ACC_ODR_31_25Hz
         * ACC_ODR_LOWPOWER_128Hz
         * ACC_ODR_LOWPOWER_21Hz
         * ACC_ODR_LOWPOWER_11Hz
         * ACC_ODR_LOWPOWER_3H
        * */
        SensorQMI8658::ACC_ODR_1000Hz,
        /*
        *  LPF_MODE_0     //2.66% of ODR
        *  LPF_MODE_1     //3.63% of ODR
        *  LPF_MODE_2     //5.39% of ODR
        *  LPF_MODE_3     //13.37% of ODR
        * */
        SensorQMI8658::LPF_MODE_0,
        // selfTest enable
        true);


    qmi.configGyroscope(
        /*
        * GYR_RANGE_16DPS
        * GYR_RANGE_32DPS
        * GYR_RANGE_64DPS
        * GYR_RANGE_128DPS
        * GYR_RANGE_256DPS
        * GYR_RANGE_512DPS
        * GYR_RANGE_1024DPS
        * */
        SensorQMI8658::GYR_RANGE_64DPS,
        /*
         * GYR_ODR_7174_4Hz
         * GYR_ODR_3587_2Hz
         * GYR_ODR_1793_6Hz
         * GYR_ODR_896_8Hz
         * GYR_ODR_448_4Hz
         * GYR_ODR_224_2Hz
         * GYR_ODR_112_1Hz
         * GYR_ODR_56_05Hz
         * GYR_ODR_28_025H
         * */
        SensorQMI8658::GYR_ODR_896_8Hz,
        /*
        *  LPF_MODE_0     //2.66% of ODR
        *  LPF_MODE_1     //3.63% of ODR
        *  LPF_MODE_2     //5.39% of ODR
        *  LPF_MODE_3     //13.37% of ODR
        * */
        SensorQMI8658::LPF_MODE_3,
        // selfTest enable
        true);


    // In 6DOF mode (accelerometer and gyroscope are both enabled),
    // the output data rate is derived from the nature frequency of gyroscope
    qmi.enableGyroscope();
    qmi.enableAccelerometer();

    // Print register configuration information
    qmi.dumpCtrlRegister();

//----------------BMP280----------------------------------------------------------/
    unsigned status;
  //status = bmp.begin(BMP280_ADDRESS_ALT, BMP280_CHIPID);
  status = bmp.begin(0x77);
  if (!status) {
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring or "
                      "try a different address!"));
    Serial.print("SensorID was: 0x"); Serial.println(bmp.sensorID(),16);
    Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
    Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
    Serial.print("        ID of 0x60 represents a BME 280.\n");
    Serial.print("        ID of 0x61 represents a BME 680.\n");
    while (1) delay(10);
  }

  /* Default settings from datasheet. */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                  Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                  Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                  Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                  Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */

//-----------AGS02MA---------------------------------------------------------------------/
 if (! ags.begin(&Wire, 0x1A)) {
  //if (! ags.begin(&Wire1, 0x1A)) { // or use Wire1 instead!
    Serial.println("Couldn't find AGS20MA sensor, check your wiring and pullup resistors!");
    while (1) yield();
  }

  if (ags.getFirmwareVersion() == 0) {
    Serial.println(F("Could not read firmware, I2C communications issue?"));
    while (1) yield();
  }

  Serial.print("Firmware version: 0x");
  Serial.println(ags.getFirmwareVersion(), HEX);
  ags.printSensorDetails();
 // uncomment to change address, will need to restart and update the begin() argument!
  //ags.setAddress(0x1A); while (1);
//---------------------Button---------------------------------------------------------/
 // link the button 1 functions.
  button1.attachClick(click1);
  button1.attachDoubleClick(doubleclick1);
  button1.attachLongPressStart(longPressStart1);
  //button1.attachLongPressStop(longPressStop1);
  //button1.attachDuringLongPress(longPress1);


}
void loop() {
  // put your main code here, to run repeatedly:
  runner.execute(); // Run the task scheduler in the main loop
}

void adc_read(){

  adcValue_2 = analogRead(ADC_PIN_V1); // Read simulated values
  adcValue_0 = analogRead(ADC_PIN_V2);

  voltage_2 = adcValue_2 * (3.3 / 4095.0); // Convert ADC values to voltage values
  voltage_0 = adcValue_0 * (3.3 / 4095.0); 

  Serial.print("ADC Value_2: ");
  Serial.print(adcValue_2);
  Serial.print(" - Voltage_2: ");
  Serial.print(voltage_2);
  Serial.println(" V");
  
  Serial.print("ADC Value_0: ");
  Serial.print(adcValue_0);
  Serial.print(" - Voltage_0: ");
  Serial.print(voltage_0);
  Serial.println(" V");


}


void bh1750_1_sensor(){

// Read the light intensity
  float lux = lightMeter.readLightLevel();
  if (lux != BH1750::UNCONFIGURED) {
    Serial.print("Light intensity: ");
    Serial.print(lux);
    Serial.println(" lx");
  } else {
    Serial.println("Read error, please check sensor!");
  }

  //delay(500); 


}

void scd4x_2_sensor(){

 while (mySensor.readMeasurement() == false) // readMeasurement will return true when fresh data is available
 {
    Serial.print(F("."));
    delay(500);
  }

  Serial.println();

  Serial.print(F("CO2(ppm):"));
  Serial.print(mySensor.getCO2());

  Serial.print(F("\tTemperature(C):"));
  Serial.print(mySensor.getTemperature(), 1);

  Serial.print(F("\tHumidity(%RH):"));
  Serial.print(mySensor.getHumidity(), 1);

  Serial.println();
  
  mySensor.measureSingleShotRHTOnly(); // Request just the RH and the Temperature (should take 50ms)

  while (mySensor.readMeasurement() == false) // readMeasurement will return true when fresh data is available
  {
    Serial.print(F("."));
    delay(5);
  }

  Serial.println();

  Serial.print(F("Temperature(C):"));
  Serial.print(mySensor.getTemperature(), 1);

  Serial.print(F("\tHumidity(%RH):"));
  Serial.print(mySensor.getHumidity(), 1);

  Serial.println();
  
  mySensor.measureSingleShot(); // Request fresh data (should take 5 seconds)

}

void aht20_3_sensor(){

  sensors_event_t  humidity, temp;
  aht.getEvent(&humidity, &temp); // Read the data
//Temperature and humidity
  Serial.print("Temperature: ");
  Serial.print(temp.temperature);
  Serial.println(" °C");

  Serial.print("humidity: ");
  Serial.print(humidity.relative_humidity);
  Serial.println(" %");
  
  //delay(2000); 

}


void qmi8658_4_sensor(){

   if (qmi.getDataReady()) {

        if (qmi.getAccelerometer(acc.x, acc.y, acc.z)) {
            Serial.print("{ACCEL: ");
            Serial.print(acc.x);
            Serial.print(",");
            Serial.print(acc.y);
            Serial.print(",");
            Serial.print(acc.z);
            Serial.println("}");
        }

        if (qmi.getGyroscope(gyr.x, gyr.y, gyr.z)) {
            Serial.print("{GYRO: ");
            Serial.print(gyr.x);
            Serial.print(",");
            Serial.print(gyr.y );
            Serial.print(",");
            Serial.print(gyr.z);
            Serial.println("}");
        }
        Serial.printf("\t\t\t\t > %lu  %.2f *C\n", qmi.getTimestamp(), qmi.getTemperature_C());
    }
    delay(100);


}

void bmp280_5_sensor(){

    Serial.print(F("Temperature = "));
    Serial.print(bmp.readTemperature());
    Serial.println(" *C");

    Serial.print(F("Pressure = "));
    Serial.print(bmp.readPressure());
    Serial.println(" Pa");

    Serial.print(F("Approx altitude = "));
    Serial.print(bmp.readAltitude(1013.25)); /* Adjusted to local forecast! */
    Serial.println(" m");

    Serial.println();


}


void ags20ma_6_sensor(){
  
  uint32_t resistance = ags.getGasResistance();
  uint32_t tvoc = ags.getTVOC();
  
  if (resistance == 0) {
    Serial.println(F("Failure reading resistance, I2C communications issue?"));
  } else {
    float kohm = resistance / 1000.0;
    Serial.print(F("Gas resistance: "));
    Serial.print(kohm);
    Serial.println(" Kohms");
  }

  if (tvoc == 0) {
    Serial.println(F("Failure reading TVOC, I2C communications issue?"));
  } else {
    Serial.print(F("TVOC: "));
    Serial.print(tvoc);
    Serial.println(" ppb");
  }



}


void Human_motion_sensor(){
   stateg4_HM =  digitalRead(H_M_sensor); // Read the status of GPIO4
   
  Serial.print("status-sensor: ");
  Serial.println(stateg4_HM);

}

void button_user(){
  stateg10_UB = digitalRead(USER_BUTTON); 
  
  Serial.print("status-button: ");
  Serial.println( stateg10_UB ); 

}



// ----- button 1 callback functions
// This function will be called when the button1 was pressed 1 time (and no 2. button press followed).
void click1() {
  Serial.println("Button 1 click.");
}  // click1


// This function will be called when the button1 was pressed 2 times in a short timeframe.
void doubleclick1() {
  Serial.println("Button 1 doubleclick.");
}  // doubleclick1


// This function will be called once, when the button1 is pressed for a long time.
void longPressStart1() {
  Serial.println("Button 1 longPress start");
}  // longPressStart1


// This function will be called often, while the button1 is pressed for a long time.
//void longPress1() {
  //Serial.println("Button 1 longPress...");
//}  // longPress1


// This function will be called once, when the button1 is released after beeing pressed for a long time.
//void longPressStop1() {
 // Serial.println("Button 1 longPress stop");
//}  // longPressStop1




