/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

  tranquille yéyé xav et les autres avant aussi
  version 5.0
  utiliser avec ESP32
  balise en mode station, arret wifi entre les trames, merci JCB.
  vitesse fixée à 6Mb
  ATTENTION, pour que cette version fonctionne avec le forçage de la vitesse à 6Mb, il faut modifier le fichier sdkconfig.h
  il est situé en général dans:
  C:\Users\monnomutilisateur\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.5\tools\sdk\include\config
  modifier la ligne: #define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 1
  mettre: #define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 0
  ensuite il faut décommenter la ligne suivante, plus loin dans le code:
  //  ESP_ERROR_CHECK(esp_wifi_internal_set_fix_rate(WIFI_IF_STA, true, WIFI_PHY_RATE_6M));  //VITESSE 6MB
*/
/*
fait en v5:
le code info mis à 0 si tout ok et initialisé à 9, doc du site web ok
ligne 325: correction puissance en db doit être *0.25
ligne 259: déplacement de l'appel de la fonction d'affichage CONF de balise pour que ça marche quand le wifi est allumé

reste à faire pour la v5:
envoyer les coordonnées gps sur le récepteur via une autre trame
vérifier pour l'alimentation la frequence et la quantité des messages du gps j'ai trouvé un site pour ça
*/

//décommenter la ligne suivante si on veut utiliser pdop plutôt que hdop dans la précision gps:
#define PDOP

//#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
//#define TIME_TO_SLEEP  10        /* Time ESP32 will go to sleep (in seconds) */

#include <WiFi.h>
#include "esp_event.h"
#include <nvs_flash.h>
#include "esp_bt_main.h"
#include "esp_bt.h"

extern "C"
{
#include "esp_wifi.h"
  //#include "esp_wifi_internal.h"
  //#include "esp_now.h"
  esp_err_t esp_wifi_80211_tx(wifi_interface_t ifx, const void *buffer, int len, bool en_sys_seq);
  esp_err_t esp_wifi_internal_set_fix_rate(wifi_interface_t ifx, bool en, wifi_phy_rate_t rate);
  //esp_err_t esp_wifi_config_espnow_rate(wifi_interface_t ifx, wifi_phy_rate_t rate);
}


void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) 
{
  /*if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) 
  {
    Serial.println("WiFi Started");
  }*/
  // gérer d’autres événements ici
}

/*
static esp_err_t event_handler(void *ctx, system_event_t *event);
esp_err_t event_handler(void *ctx, system_event_t *event)
{
  return ESP_OK;
}
*/


#define LED 2
#define ON HIGH
#define OFF LOW
#define GPS_RX_PIN 16 // fil vert du gps, TX du gps
#define GPS_TX_PIN 17 // fil blanc du gps, RX du gps, inutilisé en général

#define GPS_BAUD_RATE 9600

#include <TinyGPS++.h>
#include "balise_dgac_esp32_noweb.h"

TinyGPSPlus gps;
//TinyGPSCustom pdop(gps, "GPGSA", 15); // $GPGSA sentence, 15th element -> GPS
TinyGPSCustom pdop(gps, "GNGSA", 15); // $GNGSA sentence, 15th element -> GPS + GLONASS + Galileo aussi
droneIDFR drone_idfr;


/********************************************************************************************************************
   MODIFIEZ LES VALEURS ICI
 ********************************************************************************************************************
    CHANGEZ l'ID du drone par celui que Alphatango vous a fourni (Trigramme + Modèle + numéro série) !
  ILLEGAL_DRONE_APPELEZ_POLICE17
*/
char ssid[] = ""; //il en faut un pour mettre dans la trame beacon, on met un truc vide... //const char ssid[]
//id de la balise, à modifier, doit faire 30 caractères pile
//
//XAVB0100000000XXXXXXXXXAVIER99
const char drone_id[] = "ILLEGAL_DRONE_APPELEZ_POLICE17";
// vérification de la taille de l'id de la balise
static_assert((sizeof(drone_id) / sizeof(*drone_id)) == 31, "l'id de la balise doit être égal à 30 caractères deux lignes au dessus!"); // 30 lettres + null termination
// B0x est le modele de la balise selon la version ex B04 v4
// il faut rajouter le numéro de la balise en fin de nom ex XAVIER06 est la balise 06

//canal wifi 6 fixé par le décret
const int wifi_channel = 6;

/********************************************************************************************************************
   XAV
 ********************************************************************************************************************/
// beacon frame definition
static constexpr uint16_t MAX_BEACON_SIZE = 40 + 32 + droneIDFR::FRAME_PAYLOAD_LEN_MAX;  // default beaconPacket size + max ssid size + max drone id frame size
uint8_t beaconPacket[MAX_BEACON_SIZE] = {
  0x80, 0x00,                         // 0-1: Frame Control
  0x00, 0x00,                         // 2-3: Duration
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,       // 4-9: Destination address (broadcast)
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,       // 10-15: Source address FAKE  // TODO should bet set manually
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,       // 16-21: Source address FAKE
  0x00, 0x00,                         // 22-23: Sequence / fragment number (done by the SDK)
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 24-31: Timestamp (GETS OVERWRITTEN TO 0 BY HARDWARE)
  //0xB8, 0x0B,                         // 32-33: Beacon interval: set to 3s == 3000TU== BB8, bytes in reverse order  // TODO: manually set it
  0x71, 0x0B,                         // 32-33: Beacon interval: moins de 3s == 2929TU== B71, bytes in reverse order  // modifié suite analyse trame naveol
  //0x21, 0x04,                         // 34-35: Capability info
  0x14, 0x22,                         // 34-35: Capability info, modifié suite analayse de ce qu'il faut y mettre...
  //ci dessous enlevé pour être comme naveol pour tests -> non car modifier d'autres trucs après
  0x03, 0x01, 0x06,                   // 36-38: DS Parameter set, current channel 6 (= 0x06), // TODO: manually set it
  0x00, 0x20,                             // 39-40: SSID parameter set, 0x20:maxlength:content
  // 41-XX: SSID (max 32)
};

// activer ou non le DEBUG
boolean DEBUG = true;

const int ClignoteErreur = 25;
boolean IsErreur = false;
// si erreur sur gps, on pause un certain temps et on retente, pas la peine d'interroger toutes les millisecondes...
// mis à 0 car sinon problème de lecture du gps avec les délais...
const int delayErreur = 0;
// mettre plutôt le code info à 9 et si tout ok mettre à 0
// comme ça on n'envoie rien si tout est ok est on reste dans les normes
double codeinfo = 9;

// dès que la position home a été mise, on passe à true et on y reste
bool has_set_home = false;
double home_alt = 0;
//les positions précédentes:
double lat_prev = 0;
double lon_prev = 0;
int16_t alt_prev = 0;
int16_t dir_prev = 0;
double vit_prev = 0;

uint64_t beaconSec = 0;

//gestion de l'énergie
void  Reveiller_Balise(void)
{
  // relance le WiFi
  ESP_ERROR_CHECK(esp_wifi_start());
  // On resélectionne canal 6 (va savoir pourquoi il l'a perdu ...)
  ESP_ERROR_CHECK(esp_wifi_set_channel(wifi_channel, WIFI_SECOND_CHAN_NONE));
}

void  Endormir_Balise()
{
  //ESP_ERROR_CHECK(esp_light_sleep_start());
  ESP_ERROR_CHECK(esp_wifi_stop());
}

// lecture des données du GPS, la led s'allume puis s'éteint brièvement quand on est dans cette fonction
//du coup elle reste bien allumée car on y passe souvent...
static void RecupDonneesGPS()
{
  // si on est en erreur, on laisse la led éteinte
  // sinon on l'allume
  if (!IsErreur) digitalWrite(LED, ON);
  //récup des données gps
  while (Serial2.available())
  {
    gps.encode(Serial2.read());
  }
  // on n'écrit rien ça sert à rien, même en débug
  //if (DEBUG) Serial.println("... Récupération données du GPS ... ");
}

static void EnvoiTrame(double lat_actu, double lon_actu, int16_t alt_actu, int16_t dir_actu, double vit_actu)
{
  //on définit le code info dans la trame:
  drone_idfr.set_codeinfo(codeinfo);
  //on envoie les données à la biblio pour fomattage:
  drone_idfr.set_current_position(lat_actu, lon_actu, alt_actu);
  drone_idfr.set_heading(dir_actu);
  drone_idfr.set_ground_speed(vit_actu);
  drone_idfr.set_heigth(alt_actu - home_alt);

  /**
    On regarde s'il est temps d'envoyer la trame d'identification drone: soit toutes les 3s soit si le drones s'est déplacé de 30m en moins de 3s.
     - soit toutes les 3s,
     - soit si le drone s'est déplacé de 30m en moins de 30s soit 10m/s ou 36km/h,
     - uniquement si la position Home est déjà définie,
     - et dans le cas où les données GPS sont nouvelles.
  */

  // on envoie une trame dès qu'il est temps d'en envoyer une
  if (drone_idfr.time_to_send())
  {
    // si aucune erreur et que la trame est la bonne:
    if (codeinfo == 0)
    {
      // LED allumée en fonctionnement normal,
      // deux brefs clignotements pendant l'envoi de la trame
      digitalWrite(LED, ON);
      delay(25);
      digitalWrite(LED, OFF);
      delay(25);
      digitalWrite(LED, ON);
      delay(25);
      digitalWrite(LED, OFF);
      delay(25);
      digitalWrite(LED, ON);
    }
    //On commence par renseigner le ssid du wifi dans la trame
    // write new SSID into beacon frame
    const size_t ssid_size = (sizeof(ssid) / sizeof(*ssid)) - 1; // remove trailling null termination
    beaconPacket[40] = ssid_size;  // set size
    memcpy(&beaconPacket[41], ssid, ssid_size); // set ssid
    const uint8_t header_size = 41 + ssid_size;  //TODO: remove 41 for a marker

    //On génère la trame wifi avec l'identification
    const uint8_t to_send = drone_idfr.generate_beacon_frame(beaconPacket, header_size);  // override the null termination

    // Ici on ecrit sur le port USB les données GPS pour visualisation seulement.
    Serial.println("Temps UTC: " + String(gps.date.day()) + "/" + String(gps.date.month()) + "/"  + String(gps.date.year()) + " " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":"  + String(gps.time.second()));
    Serial.println("Position de départ: " + drone_idfr.get_home_position());
    Serial.println("Position actuelle : " + drone_idfr.get_position_actuelle());
    Serial.println("Nb de satellites: " + String(gps.satellites.value()));

#ifdef PDOP
    Serial.println("pdop: " + String(pdop.value()));
#else
    Serial.println("hdop: " + String(gps.hdop.value()));
#endif
    Serial.println("Code info: " + String(codeinfo, 0)); //pas de décimales
    Serial.println("--------------------------");

    //allume wifi
    Reveiller_Balise();

    //lire la conf
    if (DEBUG) {print_wifi_config(WIFI_IF_STA);}
    
    //envoi trame
    ESP_ERROR_CHECK(esp_wifi_80211_tx(WIFI_IF_STA, beaconPacket, to_send, true));
    //éteindre wifi
    Endormir_Balise();

    //On reset la condition d'envoi
    drone_idfr.set_last_send();

    // si aucune erreur et que la trame est la bonne:
    if (codeinfo == 0)
    {
      // LED allumée en fonctionnement normal,
      // deux brefs clignotements pendant l'envoi de la trame
      digitalWrite(LED, OFF);
      delay(25);
      digitalWrite(LED, ON);
      delay(25);
      digitalWrite(LED, OFF);
      delay(25);
      digitalWrite(LED, ON);
      delay(25);
      digitalWrite(LED, OFF);
    }
  }
}

void print_wifi_config(wifi_interface_t ifx) 
{
    wifi_config_t config;
    esp_err_t ret = esp_wifi_get_config(ifx, &config);
    
    if (ret == ESP_OK) {
        Serial.printf("SSID: %s\n", config.sta.ssid);          // Pour interface station (STA)
        Serial.printf("Password: %s\n", config.sta.password);  // Mot de passe
        Serial.printf("Channel: %d\n", config.sta.channel);
    } else {
        Serial.printf("Failed to get config: %d\n", ret);
    }

    uint8_t primary_channel;
    wifi_second_chan_t second_channel;
    esp_wifi_get_channel(&primary_channel, &second_channel);
    Serial.printf("Canal Wi-Fi principal: %d\n", primary_channel);
    Serial.printf("Second canal: %d\n", second_channel);

    wifi_bandwidth_t bw;
    ret = esp_wifi_get_bandwidth(WIFI_IF_STA, &bw);
    if (ret == ESP_OK) 
    {
        if (bw == WIFI_BW_HT20) 
        {
            Serial.println("La largeur de bande actuelle est : 20 MHz");
        }
        else 
        {
            Serial.printf("La largeur de bande actuelle est : %d\n", bw);
        }
    } 
    else 
    {
        Serial.printf("Erreur de lecture de la largeur de bande : %d\n", ret);
    }

    int8_t power_dbm;
    ret = esp_wifi_get_max_tx_power(&power_dbm);
    float real_power = power_dbm * 0.25;  

    if (ret == ESP_OK) 
    {
        Serial.printf("Puissance de transmission max actuelle : %.1f dBm\n", real_power);
    } 
    else 
    {
        Serial.printf("Erreur lors de la lecture de la puissance max : %d\n", ret);
    }
}


/**
   Phase de configuration.
*/
void setup()
{
  Serial.begin(115200);
  delay(5000);

  //initialisation du GPS. Bien penser à croiser Rx et Tx entre ESPxx et le GPS!
  Serial2.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);

  //définition de la led bleue ou jaune
  pinMode(LED, OUTPUT);

  //init wifi
  Serial.println("--------------------------");
  Serial.println("Mise en place du wifi:");
  //désactivation du BT inutile sur cette balise (merci JCB)
  // Le Bluetooth a peut-être servi pour configurer le WiFi. Il ne sert plus à rien maintenant => désinstaller complètement.
  esp_bluedroid_status_t esp_bluedroid_status = esp_bluedroid_get_status();
  switch (esp_bluedroid_status)
  {
    case ESP_BLUEDROID_STATUS_ENABLED:
      ESP_ERROR_CHECK(esp_bluedroid_disable());
      ESP_ERROR_CHECK(esp_bluedroid_deinit());
      break;
    case ESP_BLUEDROID_STATUS_INITIALIZED:
      ESP_ERROR_CHECK(esp_bluedroid_deinit());
      break;
  }
  esp_bt_controller_status_t esp_bt_controller_status = esp_bt_controller_get_status();
  switch (esp_bt_controller_status )
  {
    case ESP_BT_CONTROLLER_STATUS_ENABLED:
      ESP_ERROR_CHECK(esp_bt_controller_disable());
      ESP_ERROR_CHECK(esp_bt_controller_deinit());
      break;
    case ESP_BT_CONTROLLER_STATUS_INITED:
      ESP_ERROR_CHECK(esp_bt_controller_deinit());
      break;
  }

  //init du wifi avec une conf par défaut
  nvs_flash_init();
  //tcpip_adapter_init(); //obsolete, remplace par ci dessous
  esp_netif_init();
  // ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) ); //event_handler

  // Initialiser la pile d’événements
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    // Enregistrer le gestionnaire d’événements Wi-Fi
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));

  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  ESP_ERROR_CHECK( esp_wifi_init(&cfg));
  //stockage conf en ram
  ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));
  //mode station
  ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
  //mode long range:
  ESP_ERROR_CHECK(esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_LR));
  // application de configurations:
  wifi_config_t conf_current;
  esp_wifi_get_config(WIFI_IF_STA, &conf_current);
  // beacon 1s.
  conf_current.ap.beacon_interval = 1000;
  //ssid
  //conf_current.ap.ssid = ""; //pas besoin, quand absent pas de ssid c'est mieux
  ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &conf_current));
  //delay(2000);
  //vitesse
  // ne trouve pas la fonction dans le wifi.h !!! question de version, on fixe la vitesse plus loin autrement
  //ESP_ERROR_CHECK(esp_wifi_config_espnow_rate(WIFI_IF_STA, WIFI_PHY_RATE_6M ));

  //démarrage wifi
  esp_wifi_start();
  //canal 6
  ESP_ERROR_CHECK(esp_wifi_set_channel(wifi_channel, WIFI_SECOND_CHAN_NONE));
  //power tx:
  ESP_ERROR_CHECK ( esp_wifi_set_max_tx_power(80));

  //la vitesse
  //ESP_ERROR_CHECK(esp_wifi_internal_set_fix_rate(WIFI_IF_STA, true, WIFI_PHY_RATE_6M));  //VITESSE 6MB

  //largeur de bande
  //défini la largeur de bande à 20MHz
  ESP_ERROR_CHECK(esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT20));

  //mode éco énergie:
  //plutôt wifi start et stop
  //ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR));

  //affichage des infos
  Serial.print("Nom de la balise: "); Serial.println(drone_id);

  // définition de l'id de la balise:
  drone_idfr.set_drone_id(drone_id);
  delay(2000);

  Serial.println("--------------------------");

  //éteindre balise:
  Endormir_Balise();
} // fin setup

/**
   Début du code principal. C'est une boucle infinie.
*/
void loop()
{
  // on attend un peu que tout s'init bien (5s à partir du démarrage de la balise, en général quand on est ici c'est déjà passé les 10s)
  // ne s'exec qu'une seule fois au démarrage de la balise ce délai:
  while (millis() < 10000)
  {
    digitalWrite(LED, ON);
    Serial.print(".");
    delay(100);
    digitalWrite(LED, OFF);
    delay(100);
  }

  // on récupère les données du GPS
  RecupDonneesGPS();

  if (gps.charsProcessed() < 10)
  {
    //if (DEBUG) Serial.println("GPS non détecté, aucune donnée GPS reçue");
    digitalWrite(LED, OFF);
    IsErreur = true;
    //if (DEBUG) Serial.println("--------------------------");
    delay(delayErreur);
    //envoyer la trame
    codeinfo = 1;
    EnvoiTrame(lat_prev, lon_prev, alt_prev, dir_prev, vit_prev);
    return;
  }

  if (!gps.location.isValid())
  {
    //if (DEBUG) Serial.println("Positionnement du GPS non valide (fix en cours?)");
    digitalWrite(LED, OFF);
    IsErreur = true;
    //if (DEBUG) Serial.println("--------------------------");
    delay(delayErreur);
    //envoyer la trame
    codeinfo = 2;
    EnvoiTrame(lat_prev, lon_prev, alt_prev, dir_prev, vit_prev);
    return;
  }
  if (gps.location.age() > 3000)
  {
    //if (DEBUG) Serial.println("Fix du GPS perdu...");
    digitalWrite(LED, OFF);
    IsErreur = true;
    //if (DEBUG) Serial.println("--------------------------");
    delay(delayErreur);
    //envoyer la trame
    codeinfo = 3;
    EnvoiTrame(lat_prev, lon_prev, alt_prev, dir_prev, vit_prev);
    return;
  }

  // test si précision ok, sinon on remonte au début afin de ne pas encore fixer la home position
  if (gps.satellites.value() < 4)
  {
    digitalWrite(LED, OFF);
    IsErreur = true;
    //if (DEBUG) Serial.println("La précision du GPS n'est pas bonne");
    //if (DEBUG) Serial.println("Nb de satellites (doit être supérieur à 3): " + String(gps.satellites.value()));
    //if (DEBUG) Serial.println("--------------------------");
    delay(delayErreur);
    //envoyer la trame
    codeinfo = 4;
    EnvoiTrame(lat_prev, lon_prev, alt_prev, dir_prev, vit_prev);
    return;
  }


#ifdef PDOP
  // convertir char to double:
  //  double dbl_pdop;
  //  dbl_pdop = strtod(pdop.value(),NULL);
  //  if ((dbl_pdop == 0) || (String(pdop.value()) == "") || (dbl_pdop > 5))
  // plus simple maintenant:
  if ((String(pdop.value()).toDouble() == 0) || (String(pdop.value()) == "") || (String(pdop.value()).toDouble() > 5))
#else
  if (gps.hdop.hdop() > 5)
#endif
  {
    digitalWrite(LED, OFF);
    IsErreur = true;
    /*
    if (DEBUG) Serial.println("La précision du GPS n'est pas bonne");
#ifdef PDOP
    if (DEBUG) Serial.println("Précision 3D (doit être inférieure à 5.0): " + String(pdop.value()));
#else
    if (DEBUG) Serial.println("Précision 3D (doit être inférieure à 5.0): " + String(gps.hdop.hdop()));
#endif
    if (DEBUG) Serial.println("--------------------------");
    */
    delay(delayErreur);
    //envoyer la trame
    codeinfo = 5;
    EnvoiTrame(lat_prev, lon_prev, alt_prev, dir_prev, vit_prev);
    return;
  }
  if (gps.altitude.meters() == 0)
  {
    digitalWrite(LED, OFF);
    IsErreur = true;
    /*
    if (DEBUG) Serial.println("La précision du GPS n'est pas bonne");
    if (DEBUG) Serial.println("Altitude non récupérée: " + String(gps.altitude.meters()));
    if (DEBUG) Serial.println("--------------------------");
    */
    delay(delayErreur);
    //envoyer la trame
    codeinfo = 6;
    EnvoiTrame(lat_prev, lon_prev, alt_prev, dir_prev, vit_prev);
    return;
  }

  // ici on n'est plus en erreur
  IsErreur = false;

  // On renseigne une première et unique fois le point de démarrage dès que la précision est satisfaisante
  //
  if (!has_set_home)
  {
    Serial.println("Stockage de la position de départ");
    Serial.println("Nb de satellites (doit être supérieur à 3): " + String(gps.satellites.value()));
#ifdef PDOP
    Serial.println("Précision 3D (doit être inférieure à 5.0): " + String(pdop.value()));
#else
    Serial.println("Précision 3D (doit être inférieure à 5.0): " + String(gps.hdop.hdop()));
#endif
    home_alt = gps.altitude.meters();
    //on fixe la position home:
    drone_idfr.set_home_position(gps.location.lat(), gps.location.lng(), home_alt);
    has_set_home = true;

    //led bleue rythme rock'n'roll, tout est ok!
    int compteur = 20;
    while (compteur > 0)
    {
      digitalWrite(LED, ON);
      delay(50);
      digitalWrite(LED, OFF);
      delay(50);
      compteur--;
    }
    // on lit la position home pour controle
    Serial.println("Position de départ: " + drone_idfr.get_home_position());
    Serial.println("Stockage de la position de départ OK");
    Serial.println("--------------------------");
    //on envoie une trame
    codeinfo = 7;
    EnvoiTrame(gps.location.lat(), gps.location.lng(), home_alt, gps.course.deg(), gps.speed.mps());
    return;
  }

  // si ici, pas d'erreur donc et codeinfo passe à 0 pour garder la partie de la trame à 000000:
  codeinfo = 0;
  //envoi de la trame ici
  EnvoiTrame(gps.location.lat(), gps.location.lng(), gps.altitude.meters(), gps.course.deg(), gps.speed.mps());
  //on stocke les dernières positions
  lat_prev = gps.location.lat();
  lon_prev = gps.location.lng();
  alt_prev = gps.altitude.meters();
  dir_prev = gps.course.deg();
  vit_prev = gps.speed.mps();
}
