#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ThingSpeak.h>
#include <WiFi.h>

char ssid[] = "Wokwi-GUEST";
char pass[] = ""; 

WiFiClient client;
unsigned long myChannelNumber = 2484611
;
const char * myWriteAPIKey = "XDJDCALN6G624T16";
int statusCode;

LiquidCrystal_I2C lcd(0x27, 20, 4);

Adafruit_MPU6050 mpu;
Adafruit_Sensor *mpu_temp, *mpu_accel, *mpu_gyro;

int b,c,d ;

typedef struct {
  float temp;
  int accX;
  int accY;
  int accZ;
  float gyroX;
  float gyroY;
  float gyroZ;
} MPU6050;

MPU6050 mpu6050;

SemaphoreHandle_t xMutexMPU6050 = NULL; 
TickType_t timeOut = 1000; 


void mpu6050Task(void *pvParam) {

  mpu.begin();

  mpu_temp = mpu.getTemperatureSensor();
  mpu_temp->printSensorDetails();

  mpu_accel = mpu.getAccelerometerSensor();
  mpu_accel->printSensorDetails();

  mpu_gyro = mpu.getGyroSensor();
  mpu_gyro->printSensorDetails();

  sensors_event_t accel;
  sensors_event_t gyro;
  sensors_event_t temp;

  while (1) {

    if (xSemaphoreTake(xMutexMPU6050, timeOut) == pdPASS) {

    
      mpu_temp->getEvent(&temp);
      mpu_accel->getEvent(&accel);
      mpu_gyro->getEvent(&gyro);

      mpu6050.temp = temp.temperature;
      mpu6050.accX = accel.acceleration.x;
      mpu6050.accY = accel.acceleration.y;
      mpu6050.accZ = accel.acceleration.z;
      mpu6050.gyroX = gyro.gyro.x;
      mpu6050.gyroY = gyro.gyro.y;
      mpu6050.gyroZ = gyro.gyro.z;

      xSemaphoreGive(xMutexMPU6050);
    } else {
      //Unable to obtain MUTEX
    }

    vTaskDelay(500);
  }
}

void lcdTask(void *ptParam) {  

  lcd.init();
  lcd.backlight();


  byte lcdLine = 4;
  byte lcdChar = 20;

  char line0[lcdChar + 1], line1[lcdChar + 1], line2[lcdChar + 1], line3[lcdChar + 1];
  char * line[] = { line0, line1, line2, line3, };

  while (1) {

    if (xSemaphoreTake(xMutexMPU6050, timeOut) == pdPASS) {

      sprintf(line0, "     MPU6050 %d", xTaskGetTickCount() / 100);
      sprintf(line1, " Temperature  %.2f", mpu6050.temp);
      sprintf(line2, " ACC  %.2f %.2f %.2f", mpu6050.accX, mpu6050.accY, mpu6050.accZ);
      sprintf(line3, " GYRO %.2f %.2f %.2f", mpu6050.gyroX, mpu6050.gyroY, mpu6050.gyroZ);

      xSemaphoreGive(xMutexMPU6050); 
    } else {
      //Unable to obtain MUTEX
    }


    for (int i = 0; i < 4; i++) {
      lcd.setCursor(0, i);
      lcd.print(line[i]);
    }

    vTaskDelay(1000);
  }
}

void setup()
{
  Serial.begin(115200);

  xMutexMPU6050 = xSemaphoreCreateMutex(); 
  
  WiFi.mode(WIFI_STA);
  ThingSpeak.begin(client);
  mpu.setAccelerometerRange(MPU6050_RANGE_16_G);
  mpu.setGyroRange(MPU6050_RANGE_250_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);

  xTaskCreate(mpu6050Task, "MPU6050", 1024 * 8, NULL, 1, NULL);
  vTaskDelay(1000); 
  xTaskCreate(lcdTask, "lcd", 1024 * 8, NULL, 1, NULL);

}


void connectToCloud()
{
if(WiFi.status() != WL_CONNECTED) 
{
Serial.print("Attempting to connect");
while(WiFi.status() != WL_CONNECTED)
 {
WiFi.begin(ssid, pass);
for(int i=0;i<5;i++) 
{
Serial.print(".");
delay(1000);
}
}
Serial.println("\nConnected.");
}
}
void loop() {

  /* Get new sensor events with the readings */
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  connectToCloud();

  /* Print out the values */
  
b = a.acceleration.x;
c = a.acceleration.y;
d = a.acceleration.z;

  Serial.print(b);
  Serial.print(",");
  Serial.print(c);
  Serial.print(",");
  Serial.print(d);
  /*Serial.print(", ");
  Serial.print(g.gyro.x);
  Serial.print(",");
  Serial.print(g.gyro.y);
  Serial.print(",");
  Serial.print(g.gyro.z);*/
  Serial.println("");

ThingSpeak.setField(1,a.acceleration.x);
    ThingSpeak.setField(2,a.acceleration.y);
    ThingSpeak.setField(3,a.acceleration.z);
statusCode = ThingSpeak.writeFields(myChannelNumber,myWriteAPIKey);
    if(statusCode == 200) //successful writing code
    Serial.println("Channel update successful.");
    else
    Serial.println("Problem Writing data. HTTP error code :" +
    String(statusCode));
    delay(10000);
}