/*
   LE GOURRIEREC Titouan
   25/03/2024
   DESCRIPTION :
   ========================================
   Exercise 3 Summary:

   Objective:
   Learn to efficiently manage a set of data using a circular buffer, important for
   applications requiring continuous data management.

   Task:
   Implement a circular buffer to store the last N sensor pressure readings.
   Write functions to add a new reading to the buffer, read the oldest reading,
   and calculate the average of the readings in the buffer.
   ========================================
*/

#define BUFFER_SIZE 5

// Structure to hold sensor data
struct SensorData {
  float temperature;
  float humidity;
  unsigned int time;
};

// Circular buffer to store sensor readings
struct SensorData buffer[BUFFER_SIZE];
int front = 0; // Index of the front element in the circular buffer
int rear = -1; // Index of the rear element in the circular buffer
int itemCount = 0; // Number of items currently in the circular buffer

// Function prototypes
float getTemperature();
float getHumidity();
void addToBuffer(float temperature, float humidity);
struct SensorData readOldestFromBuffer();
struct SensorData calculateAverage();

void setup() {
  Serial.begin(9600);
  Serial.println("Starting... Started");
}

void loop() {
  // Read sensor data
  float temperature = getTemperature();
  float humidity = getHumidity();
  addToBuffer(temperature, humidity);

  // Calculate average temperature and humidity
  struct SensorData avgSensorData = calculateAverage();

  // Print average temperature and humidity
  Serial.print("Average Temperature: ");
  Serial.print(avgSensorData.temperature);
  Serial.print(" °C, Average Humidity: ");
  Serial.print(avgSensorData.humidity);
  Serial.println(" %");

  delay(1000); // Delay for 1 second before next sensor reading
}

// Generate random temperature value
float getTemperature() {
  return random(0, 40);
}

// Generate random humidity value
float getHumidity() {
  return random(50, 100);
}

// Add a new reading to the circular buffer
void addToBuffer(float temperature, float humidity) {
  rear = (rear + 1) % BUFFER_SIZE; // Increment rear index in circular manner
  buffer[rear].temperature = temperature;
  buffer[rear].humidity = humidity;
  buffer[rear].time = millis();
  if (itemCount < BUFFER_SIZE) {
    itemCount++;
  } else {
    front = (front + 1) % BUFFER_SIZE; // Move front index when buffer is full
  }
}

// Read the oldest reading from the circular buffer
struct SensorData readOldestFromBuffer() {
  struct SensorData oldestSensorData = buffer[front];
  front = (front + 1) % BUFFER_SIZE;
  itemCount--;
  return oldestSensorData;
}

// Calculate the average temperature and humidity in the circular buffer
struct SensorData calculateAverage() {
  struct SensorData sumSensorData = {0.0, 0.0, 0}; // Initialize sum of temperature and humidity
  for (int i = 0; i < itemCount; i++) {
    sumSensorData.temperature += buffer[(front + i) % BUFFER_SIZE].temperature;
    sumSensorData.humidity += buffer[(front + i) % BUFFER_SIZE].humidity;
  }
  struct SensorData avgSensorData;
  avgSensorData.temperature = sumSensorData.temperature / itemCount;
  avgSensorData.humidity = sumSensorData.humidity / itemCount;
  return avgSensorData;
}