// Original: https://wokwi.com/projects/389082239442601985

// Replaced for loops with a state machine.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Servo.h>
#include <SPI.h>

#define SCREEN_WIDTH 128 // Largeur de l'écran en pixels
#define SCREEN_HEIGHT 64 // Hauteur de l'écran en pixels

// Adresse I2C par défaut de l'écran SSD1306 (0x3C)
#define OLED_ADDR 0x3C

// Création d'une instance de l'écran SSD1306
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_ADDR);

// Définition des broches pour le capteur ultrasonique
const int trigPin = 10;
const int echoPin = 11;

// Variables pour la durée et la distance
long duration;
int distance;

Servo myServo; // Crée un objet servo pour contrôler le servo-moteur

class Timer
{
private:
    uint32_t timestamp;
    uint32_t timespan;

public:
    Timer()
    {
    }

    void Start(uint32_t timespan)
    {
        this->timespan = timespan;
        timestamp = millis();
    }

    bool Expired()
    {
        return (millis() - timestamp) >= timespan;
    }
};

Timer timer;

enum class States : byte
{
    Wait30,
    Wait500
};

States state;
States nextState;
int angle;
int delta;
const int MIN_ANGLE = 15;
const int MAX_ANGLE = 165;
const int DELTA = 1;

void setup()
{
    // Initialisation de la communication série
    Serial.begin(9600);

    // Initialisation de l'écran OLED
    if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR))
    {
        Serial.println(F("Erreur lors de l'initialisation de l'écran OLED"));
        while (true)
            ; // Boucle infinie en cas d'erreur
    }

    display.setTextSize(1);      // text size
    display.setTextColor(WHITE); // text color
    display.setCursor(0, 0);     // position to display
    display.clearDisplay();
    display.print("RADAR:"); // text to display
    display.display();       // show on OLED
    delay(2000);
    display.clearDisplay();

    // Initialisation des broches pour le capteur ultrasonique
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);

    // Attachement du servo-moteur à la broche 12
    myServo.attach(12);
    display.setTextSize(1);      // text size
    display.setTextColor(WHITE); // text color

    // Initialise servo angle.
    angle = MIN_ANGLE;
    myServo.write(angle);
    timer.Start(30);
    state = States::Wait30;
}

void loop()
{
    switch (state)
    {
    case States::Wait30:
        if (timer.Expired())
        {
            distance = calculateDistance(); // Appel d'une fonction pour calculer la distance mesurée par le capteur ultrasonique pour chaque degré

            // Affichage des valeurs dans le moniteur série
            Serial.print(angle);
            Serial.print(",");
            Serial.print(distance);
            Serial.println(".");

            display.setCursor(0, 0); // position to display
            display.print("Angle:"); // text to display
            display.println(angle);

            display.print("Dist:"); // text to display
            display.print(distance);
            display.display(); // show on OLED

            timer.Start(500);
            nextState = States::Wait500;
        }
        break;

    case States::Wait500:
        if (timer.Expired())
        {
            display.clearDisplay();

            if (angle >= MAX_ANGLE)
            {
                angle = MAX_ANGLE;
                delta = -DELTA;
            }
            else if (angle <= MIN_ANGLE)
            {
                angle = MIN_ANGLE;
                delta = +DELTA;
            }
            angle += delta;
            myServo.write(angle);

            timer.Start(30);
            nextState = States::Wait30;
        }
        break;
    }

    state = nextState;
}

// Fonction pour calculer la distance mesurée par le capteur ultrasonique
int calculateDistance()
{
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);

    duration = pulseIn(echoPin, HIGH); // Lecture de l'écho, renvoie le temps de trajet de l'onde sonore en microsecondes
    distance = duration * 0.034 / 2;   // Calcul de la distance en centimètres
    return distance;
}
$abcdeabcde151015202530354045505560fghijfghij
mega:SCL
mega:SDA
mega:AREF
mega:GND.1
mega:13
mega:12
mega:11
mega:10
mega:9
mega:8
mega:7
mega:6
mega:5
mega:4
mega:3
mega:2
mega:1
mega:0
mega:14
mega:15
mega:16
mega:17
mega:18
mega:19
mega:20
mega:21
mega:5V.1
mega:5V.2
mega:22
mega:23
mega:24
mega:25
mega:26
mega:27
mega:28
mega:29
mega:30
mega:31
mega:32
mega:33
mega:34
mega:35
mega:36
mega:37
mega:38
mega:39
mega:40
mega:41
mega:42
mega:43
mega:44
mega:45
mega:46
mega:47
mega:48
mega:49
mega:50
mega:51
mega:52
mega:53
mega:GND.4
mega:GND.5
mega:IOREF
mega:RESET
mega:3.3V
mega:5V
mega:GND.2
mega:GND.3
mega:VIN
mega:A0
mega:A1
mega:A2
mega:A3
mega:A4
mega:A5
mega:A6
mega:A7
mega:A8
mega:A9
mega:A10
mega:A11
mega:A12
mega:A13
mega:A14
mega:A15
ultrasonic1:VCC
ultrasonic1:TRIG
ultrasonic1:ECHO
ultrasonic1:GND
servo1:GND
servo1:V+
servo1:PWM
oled1:GND
oled1:VCC
oled1:SCL
oled1:SDA