# Importation de la bibliothèque RPi.GPIO pour contrôler les broches GPIO du Raspberry Pi
import RPi.GPIO as GPIO

# Importation de time pour utiliser des temporisations (sleep)
import time


# -----------------------------
# Configuration des GPIO
# -----------------------------

# Mode de numérotation BCM (numéros des GPIO et non des pins physiques)
GPIO.setmode(GPIO.BCM)

# Définition des numéros GPIO utilisés
RELAIS_A = 17     # Relais permettant le sens AVANT
RELAIS_B = 27     # Relais permettant le sens ARRIERE
FIN_A = 22        # Fin de course avant
FIN_B = 23        # Fin de course arrière

# Déclaration des relais comme SORTIES
GPIO.setup(RELAIS_A, GPIO.OUT)
GPIO.setup(RELAIS_B, GPIO.OUT)

# Déclaration des fins de course comme ENTREE avec résistance pull-up interne
# Cela signifie que l'entrée est à 1 logique tant que le contact est ouvert
# et passe à 0 logique lorsque le bouton/fin de course est pressé.
GPIO.setup(FIN_A, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(FIN_B, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# On désactive les relais au démarrage pour éviter un mouvement intempestif
GPIO.output(RELAIS_A, GPIO.LOW)
GPIO.output(RELAIS_B, GPIO.LOW)


# -----------------------------
# Fonctions moteur
# -----------------------------

# Fonction STOP : désactive les deux relais
def stop():
    GPIO.output(RELAIS_A, GPIO.LOW)  # Relais AVANT off
    GPIO.output(RELAIS_B, GPIO.LOW)  # Relais ARRIERE off
    print("Moteur arrêté")           # Message console


# Fonction AVANCE : active uniquement le relais A
def avance():
    GPIO.output(RELAIS_B, GPIO.LOW)   # On s'assure que le relais ARRIÈRE est off
    GPIO.output(RELAIS_A, GPIO.HIGH)  # Activation du relais AVANT
    print("Moteur en AVANCE")         # Message console


# Fonction RECULE : active uniquement le relais B
def recule():
    GPIO.output(RELAIS_A, GPIO.LOW)   # Sécurité : désactive le relais AVANT
    GPIO.output(RELAIS_B, GPIO.HIGH)  # Activation du relais ARRIERE
    print("Moteur en RECUL")          # Message console


# -----------------------------
# Fonctions de mouvement automatiques
# -----------------------------

# Déplacement en direction "avant" jusqu'à la fin de course AVANT
def aller_en_avant():
    print("→ Déplacement vers l’avant")   # Message console
    avance()                               # Lancement du moteur en avant

    # Boucle jusqu'à ce qu'on atteigne la fin de course FIN_A
    while True:
        # FIN_A = 0 lorsque le contact est appuyé
        if GPIO.input(FIN_A) == GPIO.LOW:
            print("Fin de course AVANT atteinte")  # Message console
            stop()                                  # Arrêt du moteur
            break                                   # Sortie de la boucle

        time.sleep(0.05)  # Petite pause pour éviter de saturer le CPU


# Déplacement en direction "arrière" jusqu'à la fin de course ARRIERE
def aller_en_arriere():
    print("→ Déplacement vers l’arrière")  # Message console
    recule()                                # Lance le moteur en arrière

    # Boucle jusqu'à ce que FIN_B soit atteint
    while True:
        # FIN_B = 0 lorsque la fin de course est appuyée
        if GPIO.input(FIN_B) == GPIO.LOW:
            print("Fin de course ARRIÈRE atteinte")  # Message console
            stop()                                    # Arrêt moteur
            break                                     # Sortie de la boucle

        time.sleep(0.05)  # Petite pause


# -----------------------------
# Programme principal
# -----------------------------

try:
    # Boucle principale du programme
    while True:
        # Lecture d'une commande clavier
        cmd = input("Commande (a=avant, r=arrière, s=stop, q=quit): ")

        # Si lettre "a", on va en avant
        if cmd == "a":
            aller_en_avant()

        # Si lettre "r", on va en arrière
        elif cmd == "r":
            aller_en_arriere()

        # Si "s", arrêt immédiat
        elif cmd == "s":
            stop()

        # Si "q", sortie de la boucle principale
        elif cmd == "q":
            break

        # Toute autre commande : message d’erreur
        else:
            print("Commande inconnue.")

# Permet d'interrompre proprement avec CTRL+C
except KeyboardInterrupt:
    pass

# Nettoyage des GPIO à la fin (important)
finally:
    stop()              # Arrêt moteur
    GPIO.cleanup()      # Libère tous les GPIO
    print("GPIO nettoyés, programme terminé.")
