Shared by Polytech Marseille to contribute to the improvement of the mbed community !

Dependencies:   Adafruit_SGP30_mbed mbed GSM X_NUCLEO_IKS01A2 max31865 GroveGPS SDFileSystem DFPlayerMini BME280 DS1820

main.cpp

Committer:
ayoubzahir
Date:
2019-04-30
Revision:
3:cb77ea3370e8
Parent:
0:d7a683cf76d9

File content as of revision 3:cb77ea3370e8:

/////////////////////////////////////////////////////////////////////////
// AMU - Aix-Marseille Université
// Polytech Marseille - Microelectronique & Telecommunications (MT)
// Projet MT5A "STM32 In the Sky - HAB", 2018-2019
// Enseignants : C.Dufaza & H. Aziza
// Etudiants : ...
/////////////////////////////////////////////////////////////////////////
// Version avril 2019, C.Dufaza
/*  todo :
- resoudre incompatibilité mbed thermomètre DS18
- utilisation de l'entrée Reset du module GSM
- check si le lecteur MP3 est bien actif
*/

/////////////////////////////////////////////////////////////////////////
//// ... Includes

// Activation des différents modules de ce code (via directives de compilation)
#include "define_myMODULES.h"
// Assignation des entrées/sorties des différents modules
#include "define_myIO.h"
// Include usuels ...
#include <stdio.h>
#include <string>
#include "mbed.h"

/////////////////////////////////////////////////////////////////////////
//// Main code
/////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////
//// Variables globales ...

// Compteur du nombre de recolte de données depuis le démarrage
unsigned int hab_frame_counter = 1;
// Mesure de la tension de la batterie
float vbatt = 0.0;
AnalogIn pin_vbatt(IO_VBATT);
// Trame des données des capteurs à stocker sur la carte sd et au GPRS
char sd_gprs_data[SD_GPRS_DATA_SIZE];
// GPS variables
unsigned int timeUTC = 0;
float lat = 0, lon = 0, alt = 0, speed = 0;
// Xnucleo variables
float xnuc_t = 0.0, xnuc_h = 0.0, xnuc_t2 = 0.0, xnuc_p = 0.0;
int32_t xnuc_acc[3];
// PT100 variables
double tempPT100 = 0;
// SGP30 variables
int eco2 = 0, tvoc = 0;
// Temperature DS18 variable
float tempDS18 = 0;
// UV & Photo variables
float uv = 0, photores = 0;
// BME280 variables (temperature, pression, humidité exterieure)
float bosch_t = 0, bosch_p = 0, bosch_h = 0;
// Ozone variable
double ozone = 0;

/////////////////////////////////////////////////////////////////////////
//// Tickers d'interruption

// Ticker executé toute les xx s pour recolter toute les données des capteurs,
// les enregistrer sur la carte SD et les envoyer en UART à la carte LoRa
#ifdef HAB_FUNCTION   // Debut directive de compilation module HAB
  Ticker ticker_hab;          // Object Ticker
  void isr_ticker_hab();      // Routine ISR appellée lors du tick
  void f_ticker_hab();        // Fonction utile appellée à la suite du tick
  bool flag_ticker_hab = 0;   // Flag levé par l'ISR pour appeller la fonction utile
#endif  // Fin directive de compilation module HAB

// Ticker executé toute les xx s pour vérifier l'etat du module GSM
#ifdef GSM_FUNCTION   // Debut directive de compilation module GSM
  Ticker ticker_check_gsm;        // Object Ticker
  void isr_ticker_check_gsm();    // Routine ISR appellée lors du tick
  void f_ticker_check_gsm();      // Fonction utile appellée à la suite du tick
  bool flag_ticker_check_gsm = 0; // Flag levé par l'ISR pour appeller la fonction utile
#endif  // Fin directive de compilation module GSM

// Ticker executé toute les 10 min pour vérifier l'etat du module GPRS SMS
#ifdef SMS_FUNCTION  // Debut directive de compilation SMS de données toutes les 10 min
  Ticker ticker_sms_data;        // Object Ticker
  void isr_ticker_sms_data();    // Routine ISR appellée lors du tick
  void f_ticker_sms_data();      // Fonction utile appellée à la suite du tick
  bool flag_ticker_sms_data = 0; // Flag levé par l'ISR pour appeller la fonction utile
#endif  // Fin directive de compilation SMS de données toutes les 10 min

/////////////////////////////////////////////////////////////////////////
// UART PC Debug
#ifdef DEBUG_SERIAL_PC // ACtivation de la liaison UART PC pour Debug
  Serial serial_pc(SERIAL_TX, SERIAL_RX, DEBUG_SERIAL_PC_BAUDRATE);
#endif

/////////////////////////////////////////////////////////////////////////
// Buzzer digital Out pin
#ifdef BUZZ_FUNCTION    // Debut directive de compilation buzzer
  DigitalOut pin_buzzer(IO_BUZZER,0);
#endif  // Fin directive de compilation buzzer

/////////////////////////////////////////////////////////////////////////
// Carte SD
#ifdef SD_FUNCTION   // Debut directive de compilation carte SD
  #include "SDFileSystem.h"
  // MOSI, MISO, SCK, SS
  SDFileSystem sd(IO_SD_MOSI, IO_SD_MISO, IO_SD_SCK, IO_SD_CS, SD_FUNCTION_SDNAME);
  // flag_sd_ok = 1 après la 1ere initialisation reussie de la carte SD
  bool flag_sd_ok = 0;
#endif  // Fin directive de compilation carte SD

/////////////////////////////////////////////////////////////////////////
// Lecteur MP3 DFPlayer
#ifdef MP3_FUNCTION   // Debut directive de compilation lecteur MP3
  #include "DFPlayerMini.h"
  DFPlayerMini mp3(IO_MP3_TX, IO_MP3_RX); //TX, RX
#endif  // Fin directive de compilation MP3

/////////////////////////////////////////////////////////////////////////
// Module GSM
#ifdef GSM_FUNCTION   // Debut directive de compilation module GSM
  #include <GSM.h>    // GSM Library
  // Flag mis à jour par interruption externe sur la LED NET.
  // Passe a true lorsque sa période de clignotement est d'environ 3s
  bool flag_gsm_network_ok = 0; 
  // Flag a abaisser lors de la 1ere réponse materielle du module GSM
  bool flag_gsm_absent = 1;
  // Flag à lever lors de la confirmation de la présence matérielle du module GSM
  // et de son démarrage en cours, et à abaisser lorsque celui ci a également démarrer logiciellement
  bool flag_gsm_starting = 0;
  // Compteur calé sur le ticker HAB de période ~5 s, qui compte le temps depuis
  // le dernier reset du module GSM, pour eviter un reset trop fréquent si la connexion est mauvaise.
  unsigned int last_reset_gsm = 0;
  // GSM I/O PinInOut
  DigitalOut gsm_pwr(IO_GSM_PWR);     // Sortie d'allumage du GSM
  // todo sortie RESET du GSM
  InterruptIn gsm_net(IO_GSM_NET);    // Entrée de la LED "NET"
  DigitalIn gsm_status(IO_GSM_STAT);  // Entrée de la LED "STATUS"
  //TX, RX, PWR, NET, STATUS, baudrate, num par defaut
  GSM gsm(IO_GSM_TX, IO_GSM_RX, GSM_BAUDRATE, GSM_SIM_NUMBER);
  // URL du serveur web
  char * url_srv_polytech = POLYTECH_SERVER;
#endif  // Fin directive de compilation module GSM

/////////////////////////////////////////////////////////////////////////
// Module GPS
#ifdef GPS_FUNCTION   // Debut directive de compilation module GPS
  #include "GroveGPS.h"
  //TX, RX, liaison STM --> GPS
  Serial gps_serial(IO_GPS_TX, IO_GPS_RX, GPS_BAUDRATE); 
  GroveGPS gps;
  void isr_gps_serial(); // Fonction d'interuption de reception sur le port UART GPS
  char timeUTCBuffer[16], latBuffer[16], lonBuffer[16], altBuffer[16], speedBuffer[16];
#endif  // Fin directive de compilation module GPS

/////////////////////////////////////////////////////////////////////////
// Shield capteurs ST X_NUCLEO_IKS01A2
#ifdef XNUCLEO_FUNCTION   // Debut directive de compilation shield capteurs XNUCLEO
  #include "XNucleoIKS01A2.h"
  // Instantiate the expansion board: SDA, SCL, option(INT1, INT2)
  static XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(IO_XNUC_SDA, IO_XNUC_SCL);
  static HTS221Sensor *hum_temp = mems_expansion_board->ht_sensor;
  static LPS22HBSensor *press_temp = mems_expansion_board->pt_sensor;
  static LSM303AGRAccSensor *accelerometer = mems_expansion_board->accelerometer;
#endif  // Fin directive de compilation shield capteurs XNUCLEO

/////////////////////////////////////////////////////////////////////////
// Sonde de température PT100 sur ampli MAX31865
#ifdef PT100_FUNCTION   // Debut directive de compilation module PT100
  #include "MAX31865.h"
  // MOSI, MISO, SCK, SS : SPI du MAX311865
  MAX31865_RTD PT100(MAX31865_RTD::RTD_PT100,IO_PT100_MOSI, IO_PT100_MISO, IO_PT100_SCK, IO_PT100_CS);
#endif  // Fin directive de compilation module PT100

/////////////////////////////////////////////////////////////////////////
// Capteur de temperature (exterieur haut) DS181B20
#ifdef DS18_FUNCTION   // Debut directive de compilation DS181B20
  #include "DS1820.h"
  DS1820  ds18(IO_DS18);
#endif  // Fin directive de compilation DS181B20

/////////////////////////////////////////////////////////////////////////
// Capteurs lumière (UV et photoresistance)
#ifdef UV_FUNCTION   // Debut directive de compilation capteur UV
  AnalogIn pin_UV(IO_UV);
#endif  // Fin directive de compilation capteur UV
#ifdef PHOTORES_FUNCTION   // Debut directive de compilation capteur lumière
  AnalogIn pin_photores(IO_PHOTORES);
#endif  // Fin directive de compilation capteur lumière

/////////////////////////////////////////////////////////////////////////
// Capteur Bosch BME280 (temperature, pression, humidité exterieure)
#ifdef BOSCH_FUNCTION   // Debut directive de compilation Bosch
  #include "BME280.h"
  BME280 bosch(IO_BOSCH_SDA, IO_BOSCH_SCL);    // SDA, SCL
#endif  // Fin directive de compilation Bosch

/////////////////////////////////////////////////////////////////////////
// Capteur eCO2/TVOC SGP30, voir note :
// Le module eCO2/TVOC produira pendant ~20 s des resultats invalides
// eCO2=400 et TVOC=0, patientez quelques instants
// module à allumer 48h à l'avance pour résultats optimums
#ifdef CO2_FUNCTION   // Debut directive de compilation module CO2
  #include "Adafruit_SGP30.h"
  Adafruit_SGP30 co2(IO_CO2_SDA, IO_CO2_SCL);   // SDA, SCL
#endif  // Fin directive de compilation module CO2

/////////////////////////////////////////////////////////////////////////
// Capteur Ozone O3
// ... todo
#ifdef O3_FUNCTION   // Debut directive de compilation spi_ozone
  SPI spi_ozone(PB_15, PB_14, PB_13); // MOSI, MISO, SCK
  DigitalOut ozone_SS(IO_O3_CS,1);
#endif  // Fin directive de compilation spi_ozone

/////////////////////////////////////////////////////////////////////////
// LORA Module
#ifdef LORA_FUNCTION    // Debut directive de compilation LoRa
  // todo: liaison UART avec carte LoRa + watchdog carte mère
  Serial lora_serial(IO_LORA_TX, IO_LORA_RX, LORA_FUNCTION_BAUDRATE);
  // Chaine de char contenant la trame des données des capteurs à envoyer
  char lora_data_tx[LORA_FUNCTION_DATASIZE]; 
#endif  // Fin directive de compilation LoRa

/////////////////////////////////////////////////////////////////////////
//// Fonctions annexes

////////////////////////////////////////////////////////////////////////
// Pression - Altitude
double sealevel(double P, double A)
// Given a pressure P (mb) taken at a specific altitude (meters),
// return the equivalent pressure (mb) at sea level.
// This produces pressure readings that can be used for weather measurements.
{ return (P / pow(1 - (A / 44330.0), 5.255));
}

double altitude(double P, double P0)
// Given a pressure measurement P (mb) and the pressure at a baseline P0 (mb),
// return altitude (meters) above baseline.
{ return (44330.0 * (1 - pow(P / P0, 1 / 5.255)));
}

// Initialise l'interruption GPS ... pré-déclaration
void irq_gps_on(); 
void irq_gps_off(); 

// Permet de gérer les modes On-Off des Interruption & Tickers
void all_irq_on_off(int gps_on_off, int gsm_on_off, int ticker_hab_on_off, int ticker_gsm_on_off) {
  // Interruption GPS On ou Off
  if(gps_on_off == 1) { irq_gps_on();  }
  if(gps_on_off == 0) { irq_gps_off(); }
  // Module GSM Enable ou Disable
  if(gsm_on_off == 1) { gsm_net.enable_irq();  }
  if(gsm_on_off == 0) { gsm_net.disable_irq(); }
  // Ticker HAB Attach ou Detach
  if(ticker_hab_on_off == 1) { ticker_hab.attach(&isr_ticker_hab, TICKER_HAB_TIME); }
  if(ticker_hab_on_off == 0) { ticker_hab.detach(); }
  // Ticker GSM Attach ou Detach
  if(ticker_gsm_on_off == 1) { ticker_check_gsm.attach(&isr_ticker_check_gsm, TICKER_CHECK_GSM_TIME); }
  if(ticker_gsm_on_off == 0) { ticker_check_gsm.detach(); }
}
  
/////////////////////////////////////////////////////////////////////////
// SD
#ifdef SD_FUNCTION   // Debut directive de compilation carte SD

// Fonction qui ecrit le message dans le fichier passés en arguments sur la carte SD initialisée
void ecriture_sd(char * fichier, char * message) {
  // Si la carte SD n'est pas initialisée on quitte
  if(flag_sd_ok == 0) return;
  // On désactive l'interruption UART pour GPS
  all_irq_on_off(0, 2, 2, 2); // irq_gps_off(); 
  // Fichier en mode a - append ... du type "/sd/data.txt"
  FILE *fp = fopen(fichier, "a");
  if(fp == NULL) { // Erreur d'ouverture du fichier
    #ifdef DEBUG_SERIAL_PC 
      serial_pc.printf("<<<< ERREUR >>>> carte SD, ouverture fichier impossible\n");
    #endif
  }
  else { // Fichier correctement ouvert en mode append, écriture puis fermeture
      fprintf(fp, message); fprintf(fp, "\n");
      fclose(fp);
  }
  // Ré-activation de l'interruption UART pour GPS
    all_irq_on_off(1, 2, 2, 2); // irq_gps_on(); 
}

#endif  // Fin directive de compilation carte SD

/////////////////////////////////////////////////////////////////////////
// GSM
#ifdef GSM_FUNCTION   // Debut directive de compilation module GSM

// Initialise le GSM ... pré-déclaration
void init_GSM(); 

// Variables GSM
Timer timer_gsm_network; // Compteur de la période de clignotement de la LED "NET"
unsigned int last_time_gsm_network = 0;

void isr_network_gsm() {
  // Arret de toute les sources d'interruptions
   all_irq_on_off(0, 0, 2, 2);
  //irq_gps_off();            // Interruption GPS off
  //gsm_net.disable_irq();    // Disable interrupt GSM
     
  timer_gsm_network.stop(); // Arret du timer GSM
  last_time_gsm_network = timer_gsm_network.read_ms(); // Lecture du timer GSM
  #ifdef DEBUG_SERIAL_PC
    //debug_if(DEBUG_SERIAL_PC, "Timer GSM Network (ms) : %d\n", last_time_gsm_network);
    //serial_pc.printf("Timer GSM Network (ms) : %d\n", last_time_gsm_network);
  #endif
  // Seulement si la période de clignotement est d'environs 3s alors le module 
  // GSM est bien connecté au réseau et est pret a etre utilisé.
  if(last_time_gsm_network > 2800 && last_time_gsm_network < 3200) {
     #ifdef DEBUG_SERIAL_PC
       //serial_pc.printf("> Timer GSM Network (ms) : %d\n", last_time_gsm_network);
     #endif
     flag_gsm_network_ok = 1; // le GSM est ok
     if(flag_gsm_starting == 1) { // est-il tjs en démarrage ?
        init_GSM();
        flag_gsm_starting = 0;
  }  }
  else flag_gsm_network_ok = 0; // le GSM n'est pas ok
    
  timer_gsm_network.reset();  // Raz et nouveau départ du timer GSM
  timer_gsm_network.start();
    
  // On autorise de nouveau les interruptions GPS et GSM
  all_irq_on_off(1, 1, 2, 2);
  //irq_gps_on();
  //gsm_net.enable_irq();
}

// On initialise le GSM
void init_GSM() {
  // Initialise (logiciellement) le module GSM
  if(gsm_status == 0) return;    // Si module GSM arreté ou absent c'est inutile
   
  // Arret de toute les sources d'interruptions
  all_irq_on_off(0, 0, 0, 0);
  //irq_gps_off();              // Int sur RX UART
  //gsm_net.disable_irq();      // Int sur LED NET GSM
  //ticker_hab.detach();        // Ticker HAB
  //ticker_check_gsm.detach();  // Ticker check GSM
    
  #ifdef DEBUG_SERIAL_PC
    serial_pc.printf(">>> GSM Initialisation <<<\n");
    serial_pc.printf(" Init GSM : %d\n",gsm.init());
    serial_pc.printf(" Statut SIM : %d\n",gsm.checkSIMStatus());
    serial_pc.printf(" Force signal : %d\n",gsm.checkSignalStrength());
    serial_pc.printf(" Reglage SMS : %d\n",gsm.settingSMS());
    //serial_pc.printf(" Test SMS : %d\n",gsm.sendSMS(GSM_SEND_NUMBER, GSM_SEND_SMS_HELLO));
  #endif
  
  // On considere le GSM initialisé et n'est donc plus en phase de démarrage
  flag_gsm_starting = 0;
    
  // On autorise de nouveau les interruptions GPS et GSM, ticker HAB
  all_irq_on_off(1, 1, 1, 1);
  //irq_gps_on();
  //gsm_net.enable_irq();
  //ticker_hab.attach(&isr_ticker_hab, TICKER_HAB_TIME);
  //ticker_check_gsm.attach(&isr_ticker_check_gsm, TICKER_CHECK_GSM_TIME);
}

// Fonction qui allume le module GSM (matériellement)
void gsm_pwr_on() {
  // Entrée : "bool attendre", specifie si la fonction doit attendre que le
  // module GSM démarre.
  if(gsm_status == 0) {
    // Arret de toute les sources d'interruptions
    all_irq_on_off(0, 0, 0, 0);

    // Creation et lancement d'un timer de time out du démarrage du module GSM
    Timer timer_gsm_init;
    timer_gsm_init.start();

    // On considere que le GSM est sous-tension, on verifiera ...     
    gsm_pwr = 1;

    while(gsm_status == 0) {
      wait(0.5);
      if(timer_gsm_init.read() > 5) { // Si après 5s ... ?
        #ifdef DEBUG_SERIAL_PC
          serial_pc.printf("<<<< ERREUR >>>> module GSM absent\n");
        #endif
        flag_gsm_absent = 1;      // Constatation de l'absence du module GSM
        timer_gsm_network.stop(); // Arrêt du timer GSM
        gsm_pwr = 0;              // le GSM n'est donc pas sous tension                
        // On autorise de nouveau les interruptions GPS et GSM, ticker HAB
        all_irq_on_off(1, 1, 1, 1);
        return;
      }
    }
    gsm_pwr = 0;
    timer_gsm_network.stop(); 
  }
  else     
    #ifdef DEBUG_SERIAL_PC 
      serial_pc.printf("Module GSM deja allume ");
    #endif
    // Constatation de la présence du module GSM
    flag_gsm_absent = 0;  
    // Indication que le module GSM est en train de démarrer materiellement
    // ou du moins qu'il faudra bientot faire l'init logiciel dès qu'il
    // sera pret (NET LED avec bonne période de 3s.
    flag_gsm_starting = 1;  
    
    // On autorise de nouveau les interruptions GPS et GSM, ticker HAB
    all_irq_on_off(1, 1, 1, 1);

}

#endif  // Fin directive de compilation module GSM

/////////////////////////////////////////////////////////////////////////
// Ozone O3
#ifdef O3_FUNCTION   // Debut directive de compilation spi_ozone

double lecture_ozone() {
  // Variables
  double resultat = 0.0;    
  uint32_t chiffre=0;
  uint8_t Buff[4];
  for(int i=0; i<3;i++) Buff[i] = 0;
  
  // Paramètres Ozone
  spi_ozone.format(8,3);
  spi_ozone.frequency(1000000); 
  ozone_SS.write(0);  // Selection de l'esclave
  //spi_ozone.write(0x8F);
  wait_ms(100);      
  Buff[0] = spi_ozone.write(0);
  Buff[1] = spi_ozone.write(0);
  Buff[2] = spi_ozone.write(0);
  Buff[3] = spi_ozone.write(0);
  ozone_SS.write(1);  // Deselection de l'esclave
    
  chiffre = ((uint32_t)(Buff[0]) << 24) | ((uint32_t)(Buff[1]) << 16) | ((uint32_t)(Buff[2]) << 8) | (uint32_t)(Buff[3]);
  chiffre = chiffre >> 7;
  resultat = 100 - (chiffre/41943.040);   // Conversion en %ADC
  return resultat;    
}

#endif  // Fin directive de compilation spi_ozone

/////////////////////////////////////////////////////////////////////////
//// Tickers, Interruptions, Threads

/////////////////////////////////////////////////////////////////////////
// GSM
#ifdef GSM_FUNCTION   // Debut directive de compilation module GSM

void f_ticker_check_gsm() {
  // Fonction du ticker de surveillance du module GSM, lancée toute les .. s
        
  // Si module GSM absent, on retourne
  if(flag_gsm_absent == 1) return;
        
  // Arret de toute les sources d'interruptions
  all_irq_on_off(0, 2, 2, 2);
    
  // Si le module GSM est éteint, on l'allume
  if(gsm_status == 0) gsm_pwr_on();
    
  // Si module GSM non connecté
  if(flag_gsm_network_ok == 0) {      
    // Si cela fait plus de 15 trames que l'on a démarré alors
    if(hab_frame_counter - last_reset_gsm > 15) {
      #ifdef DEBUG_SERIAL_PC 
        serial_pc.printf("\n Reset du module GSM ...");
      #endif
      // todo : appui sur bouton reset du module gsm          
      last_reset_gsm = hab_frame_counter;      
  } }
     
  // met fin à l'envoi d'un sms, le module reste parfois bloqué dans la
  // commande d'envoi et ne répond pas "OK" lorsqu'on check power en envoyant "AT"
  gsm.gprsSerial.putc((char)0x1A); 
    
  int sim_status = gsm.checkSIMStatus();
  #ifdef DEBUG_SERIAL_PC 
    serial_pc.printf("\n>>> Check statut SIM : %d\n", sim_status);
  #endif
  if(sim_status != 0) { init_GSM(); } // Il est nécessaire d'initialiser de nouveau le GSM
        
  // On autorise de nouveau les interruptions GPS et GSM, ticker HAB
  all_irq_on_off(1, 2, 2, 2);
  // Flag ticker GSM inactif
  flag_ticker_check_gsm = 0;
}

#endif  // Fin directive de compilation module GSM

/////////////////////////////////////////////////////////////////////////
// GPS
#ifdef GPS_FUNCTION   // Debut directive de compilation module GPS
/////////////////////////////////////////////////////////////////////////

// GPS = fonctions d'activation et de desactivation de l'interruption UART
void irq_gps_off() {
  // IRQ OFF : desactivation de l'interruption pour le port UART du GPS
  gps_serial.attach(NULL);
}
void irq_gps_on() {
  // IRQ ON : activation de l'interruption pour le port UART du GPS
  gps_serial.attach(&isr_gps_serial,Serial::RxIrq);
}

// Routine d'interruption (ISR) pour la reception sur port UART du GPS
void isr_gps_serial() { 
  if(gps_serial.readable()) {        
    #ifdef GPS_DEBUG
      char c = gps_serial.getc();
      serial_pc.putc(c);
      gps.readCharacter(c);
    #else
      gps.readCharacter(gps_serial.getc());
    #endif
  }
}

#endif  // Fin directive de compilation module GPS

////////////////////////////////////////////////////////////////////////
// SMS (GSM)
// Ticker executé toute les xx sec pour envoi des données par sms
#ifdef SMS_FUNCTION   // Debut directive de compilation module SMS

void f_ticker_sms_data() {
  if(flag_gsm_network_ok == 1) {
    #ifdef DEBUG_SERIAL_PC 
      serial_pc.printf(">>>>>> Send HAB data to SMS\n");
    #endif
    // Portable personnel de Dufaza
    gsm.sendSMS(GSM_SEND_NUMBER, sd_gprs_data);
    // Le SMS a ete envoyé ...
    flag_ticker_sms_data = 0;
} }

#endif  // Fin directive de compilation module SMS

////////////////////////////////////////////////////////////////////////
// HAB
// Ticker executé toute les 5 s pour recolter toute les données,
// les enregistrer sur la carte SD et les envoyer en UART à la carte LoRa
#ifdef HAB_FUNCTION   // Debut directive de compilation module HAB

void f_ticker_hab() {        
  //DS18 thermomètre pt1 (en 2 parties pour eviter d'attendre)
  #ifdef DS18_FUNCTION   // Debut directive de compilation DS181B20    
    // todo 
  #endif  // Fin directive de compilation DS181B20
         
  // Recuperation donnees capteurs ST X_NUCLEO_IKS01A2
  #ifdef XNUCLEO_FUNCTION   // Debut directive de compilation shield capteurs XNUCLEO
    hum_temp->get_temperature(&xnuc_t);
    hum_temp->get_humidity(&xnuc_h);
    press_temp->get_temperature(&xnuc_t2);
    press_temp->get_pressure(&xnuc_p);
  #endif  // Fin directive de compilation shield capteurs XNUCLEO
      
  //PT100
  #ifdef PT100_FUNCTION   // Debut directive de compilation module PT100
    PT100.read_all();
    if(PT100.status() == 0) {
       tempPT100 = PT100.temperature();
       #ifdef DEBUG_SERIAL_PC 
         //serial_pc.printf(">>>>>> Temp PT100 = %f degC \r\n",tempPT100);
       #endif
    }
    else {
       tempPT100 = 0;
       #ifdef DEBUG_SERIAL_PC 
          serial_pc.printf("<<< ERREUR >>> Registre d'erreur PT100 : %d - ",PT100.status( ));
          if(PT100.status() & MAX31865_FAULT_HIGH_THRESHOLD) {
               serial_pc.printf("ERREUR PT100 seuil haut franchi\n");
          }
          else if(PT100.status() & MAX31865_FAULT_LOW_THRESHOLD) {
               serial_pc.printf("ERREUR PT100 seuil bas franchi\n");
          }
          else if(PT100.status() & MAX31865_FAULT_REFIN) {
               serial_pc.printf("ERREUR REFIN- > 0,85 x V_BIAS\n");
          }
          else if(PT100.status( ) & MAX31865_FAULT_REFIN_FORCE) {
               serial_pc.printf("ERREUR REFIN- < 0,85 x V_BIAS, FORCE- ouvert\n");
          }
          else if(PT100.status( ) & MAX31865_FAULT_RTDIN_FORCE ) {
               serial_pc.printf("ERREUR RTDIN- < 0,85 x V_BIAS, FORCE- ouvert\n");
          }
          else if(PT100.status( ) & MAX31865_FAULT_VOLTAGE) {
               serial_pc.printf("ERREUR sur/sous-tension\n");
          }
          else serial_pc.printf("ERREUR inconnue\n");
       #endif
       }
  #endif  // Fin directive de compilation module PT100
                
  // CO2
  #ifdef CO2_FUNCTION   // Debut directive de compilation module CO2
    co2.IAQmeasure();
    #ifdef DEBUG_SERIAL_PC 
      /*serial_pc.printf("TVOC : %d\n", co2.TVOC);
      serial_pc.printf("eCO2: %d\n", co2.eCO2);*/
    #endif
    eco2 = co2.eCO2;
    tvoc = co2.TVOC;
  #endif  // Fin directive de compilation module CO2
              
  //DS18 thermomètre pt2 (en 2 parties pour eviter d'attendre)
  #ifdef DS18_FUNCTION   // Debut directive de compilation DS181B20      
    // todo 
  #endif  // Fin directive de compilation DS181B20
        
  // Capteurs UV et lumiere
  #ifdef UV_FUNCTION   // Debut directive de compilation capteur UV
    uv = pin_UV.read();
  #endif  // Fin directive de compilation capteur UV
  #ifdef PHOTORES_FUNCTION   // Debut directive de compilation capteur lumière
     photores = pin_photores.read();
  #endif  // Fin directive de compilation capteur lumière
                
  // Triple capteur Bosch BME280
  #ifdef BOSCH_FUNCTION   // Debut directive de compilation Bosch
     bosch_t = bosch.getTemperature();
     //bosch_p = bosch.getPressure();
     bosch_p = 900.0 ;

     bosch_h = bosch.getHumidity();
     #ifdef DEBUG_SERIAL_PC 
       //serial_pc.printf("-> Bosch : %.2f *C, %.2f mbar, %.2f %%\n", bosch.getTemperature(), bosch.getPressure(), bosch.getHumidity());
     #endif
  #endif  // Fin directive de compilation Bosch
              
  // Ozone
  #ifdef O3_FUNCTION   // Debut directive de compilation spi_ozone
    ozone = lecture_ozone();
  #endif  // Fin directive de compilation spi_ozone
        
  // Mesure tension batterie (tension ref* pont diviseur + chute diode)
  vbatt = ((double) pin_vbatt.read())*3.3*11.07+0.52;
        
  // Recuperation données GPS
  #ifdef GPS_FUNCTION   // Debut directive de compilation module GPS
    gps.getTimestamp(timeUTCBuffer);
    gps.getLatitude(latBuffer);
    gps.getLongitude(lonBuffer);
    gps.getAltitude(altBuffer);
    gps.getSpeed(speedBuffer);
    //printf("UTC: %s\t Latitude: %s\t Longitude: %s\t altitude: %s\t speed: %s\n", timeUTCBuffer, latBuffer, lonBuffer, altBuffer, speedBuffer);
    // Convertion des chaine en entier et flottant
    timeUTC = atoi(timeUTCBuffer);
    lat = (float)atof(latBuffer);
    lon = (float)atof(lonBuffer);
    alt = (float)atof(altBuffer);
    speed = (float)atof(speedBuffer);
  #endif  // Fin directive de compilation module GPS
              
  // Mise en forme dans un tableau de caractères
  sprintf((char*) sd_gprs_data, "%d-%.2f-%d-%f-%f-%.1f-%.1f-%.1f-%.1f-%.3f-%.3f-%.3f-%.1f-%.3f-%.2f-%.2f-%d-%d-%f-%.3f-%.3f", 
          hab_frame_counter, vbatt, timeUTC, lat, lon, alt, speed, 
          xnuc_t, xnuc_t2, tempPT100, tempDS18, bosch_t, xnuc_h, bosch_h, xnuc_p, bosch_p, eco2, tvoc, ozone, (double)uv*100.0, (double)photores*100.0);
        
  #ifdef DEBUG_SERIAL_PC   
    // Affichage des données sur port série debug
    serial_pc.printf("\n>>> HAB Frame Counter : %d\n", hab_frame_counter);
    serial_pc.printf("> Tension batterie : %f V\n", vbatt);
    #ifdef GPS_FUNCTION   // Debut directive de compilation module GPS
      serial_pc.printf("> Temps UTC : %d\n", timeUTC);
      serial_pc.printf("> Latitude : %f\n", lat);
      serial_pc.printf("> Longitude : %f\n", lon);
      serial_pc.printf("> Altitude : %.2f m\n", alt);
      serial_pc.printf("> Vitesse : %.2f km/h\n", speed);
    #endif  // Fin directive de compilation module GPS
      
    #ifdef XNUCLEO_FUNCTION   // Debut directive de compilation shield capteurs XNUCLEO
      serial_pc.printf("> Temperature 1 (XNUCLEO) : %.3f *C\n", xnuc_t);
      serial_pc.printf("> Temperature 2 (XNUCLEO) : %.3f *C\n", xnuc_t2);
    #endif  // Fin directive de compilation shield capteurs XNUCLEO
  
    #ifdef PT100_FUNCTION   // Debut directive de compilation module PT100
      serial_pc.printf("> Temperature 3 (PT100) : %.3f *C\n", tempPT100);
    #endif  // Fin directive de compilation module PT100
  
    #ifdef DS18_FUNCTION   // Debut directive de compilation DS181B20
      serial_pc.printf("> Temperature 4 (DS18) : %.3f *C\n", tempDS18);
    #endif  // Fin directive de compilation DS181B20
  
    #ifdef BOSCH_FUNCTION   // Debut directive de compilation Bosch
      serial_pc.printf("> Temperature 5 (Bosch) : %.3f *C\n",bosch_t);
    #endif  // Fin directive de compilation Bosch
  
    #ifdef XNUCLEO_FUNCTION   // Debut directive de compilation shield capteurs XNUCLEO
      serial_pc.printf("> Humidite 1 (XNUCLEO) : %.2f %%\n", xnuc_h);
    #endif  // Fin directive de compilation shield capteurs XNUCLEO
  
    #ifdef BOSCH_FUNCTION   // Debut directive de compilation Bosch
      serial_pc.printf("> Humidite 2 (Bosch) : %.2f %%\n",bosch_h);
    #endif  // Fin directive de compilation Bosch
  
    #ifdef XNUCLEO_FUNCTION   // Debut directive de compilation shield capteurs XNUCLEO
      serial_pc.printf("> Pression 1 (XNUCLEO) : %.2f mbar - altitude calculee : %.2f m\n", xnuc_p, altitude(xnuc_p, BASE_PRESSURE));
    #endif  // Fin directive de compilation shield capteurs XNUCLEO
  
    #ifdef BOSCH_FUNCTION   // Debut directive de compilation Bosch
        serial_pc.printf("> Pression 2 (Bosch) : %.2f mbar - altitude calculee : %.2f m\n",bosch_p, altitude(bosch_p, BASE_PRESSURE));
    #endif  // Fin directive de compilation Bosch
  
    #ifdef CO2_FUNCTION   // Debut directive de compilation module CO2
      serial_pc.printf("> eCO2 : %d ppm\n", eco2);
      serial_pc.printf("> TVOC : %d ppb\n", tvoc);
    #endif  // Fin directive de compilation module CO2
  
    #ifdef UV_FUNCTION   // Debut directive de compilation capteur UV
      serial_pc.printf("> UV : %.3f %%ADC\n", (double)uv*100.0);
    #endif  // Fin directive de compilation capteur UV
  
    #ifdef PHOTORES_FUNCTION   // Debut directive de compilation capteur lumière
      serial_pc.printf("> Lum : %.3f %%ADC\n", (double)photores*100.0);
    #endif  // Fin directive de compilation capteur lumière
  
    #ifdef O3_FUNCTION   // Debut directive de compilation spi_ozone
      serial_pc.printf("> Ozone O3 : %f %%ADC\n", ozone);
    #endif  // Fin directive de compilation spi_ozone
           
    serial_pc.printf("%s\n", sd_gprs_data);
  #endif
        
  // Envoi de la chaine par GPRS au Polytech Server
  #ifdef GSM_FUNCTION   // Debut directive de compilation module GSM
    #ifdef GPRS_FUNCTION   // Debut directive de compilation données mobiles
      if(flag_gsm_network_ok == 1) {
        #ifdef DEBUG_SERIAL_PC 
          serial_pc.printf(">>>>>> Send HAB data to Polytech Server\n");
        #endif
        gsm.gprs_message(url_srv_polytech , sd_gprs_data);
      }
    #endif  // Fin directive de compilation données mobiles
    /*if(flag_gsm_network_ok == 1) {
         #ifdef DEBUG_SERIAL_PC   
           serial_pc.printf("SMS : %d\n",gsm.sendSMS("+33676040268", sd_gprs_data)); // Envoi de la chaine par SMS
         #endif
    */
  #endif  // Fin directive de compilation module GSM
        
  // Sauvegarde sur carte SD
  #ifdef SD_FUNCTION   // Debut directive de compilation carte SD
     ecriture_sd(SD_FUNCTION_FILENAME, sd_gprs_data);
  #endif  // Fin directive de compilation carte SD
              
  // Creation de la chaine à envoyer à la carte LoRa
  #ifdef LORA_FUNCTION    // Debut directive de compilation LoRa
    sprintf((char*) lora_data_tx, "%.2f-%f-%f-%.1f-%.3f", vbatt, lat, lon, alt, tempPT100);
    #ifdef DEBUG_SERIAL_PC   
      serial_pc.printf("%s\n", lora_data_tx);
    #endif
  #endif  // Fin directive de compilation LoRa
        
  #ifdef DEBUG_SERIAL_PC   
    //serial_pc.printf("------------------------------------------------\n");
    serial_pc.printf("\n");
  #endif

  // Increment du numéro de la trame transmise
  hab_frame_counter++;
  // Flag ticker HAB inactif
  flag_ticker_hab = 0;    
}

#endif  // Fin directive de compilation module HAB

/////////////////////////////////////////////////////////////////////////
// Routines d'interruption appelées au tick des tickers et servant juste à lever un flag
// Pensez à abaisser le flag dans f_ticker_hab() et f_ticker_gsm() !
#ifdef HAB_FUNCTION
  void isr_ticker_hab() { flag_ticker_hab = 1; }
#endif

#ifdef GSM_FUNCTION
  void isr_ticker_check_gsm() { flag_ticker_check_gsm = 1; }
#endif

#ifdef SMS_FUNCTION
  void isr_ticker_sms_data() { flag_ticker_sms_data = 1; }
#endif

/////////////////////////////////////////////////////////////////////////
// LoRa
#ifdef LORA_FUNCTION    // Debut directive de compilation LoRa

void envoi_lora_data_tx() { 
  lora_serial.printf("%s\n", lora_data_tx);
  #ifdef DEBUG_SERIAL_PC   
    serial_pc.printf("lora!\n");    // debug
  #endif
}

void isr_lora_serial() {  
  char c = lora_serial.getc();
  if(c == 'a') envoi_lora_data_tx();
  #ifdef MP3_FUNCTION   // Debut directive de compilation lecteur MP3
    elseif(c == 'b') mp3.mp3_play();
    elseif(c == 'c') mp3.mp3_pause();
  #endif  // Fin directive de compilation lecteur MP3
  #ifdef BUZZ_FUNCTION    // Debut directive de compilation buzzer
    elseif(c == 'd') pin_buzzer.write(1);
    elseif(c == 'e') pin_buzzer.write(0);
  #endif  // Fin directive de compilation buzzer  
}

#endif  // Fin directive de compilation LoRa


/////////////////////////////////////////////////////////////////////////
/////////////////////////////  MAIN  ////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

int main() {
    
  // Affichage/listage des modules compilés/activés sur port série STLINK
  #ifdef DEBUG_SERIAL_PC
    serial_pc.printf("\n\n-----------------------------------------------------------------------------------\n");
    serial_pc.printf("--- AMU Aix-Marseille Universit\xE9 - Polytech Marseille MT - STM32 in the Sky HAB ---\n");
    vbatt = ((double)pin_vbatt.read())*3.3*11.07+0.52;    // Tension batterie (tension ref * pont diviseur + chute diode)
    serial_pc.printf("- Tension batterie = %f V\n", vbatt);
    serial_pc.printf("- Liste des Fonctionalit\xE9s & Capteurs op\xE9rationnels ...\n");
  #endif
    
  //Buzzer, léger bip au démarrage
  #ifdef BUZZ_FUNCTION
    #ifdef DEBUG_SERIAL_PC   
      serial_pc.printf("-> Buzzer ON ... ");
    #endif
    for(int i=1; i<BUZZ_FUNCTION_DURATION; i++) // #périodes de 1,5kHz
    { // 333us x 2 = 1,5k Hz
      pin_buzzer.write(1); wait_us(BUZZ_FUNCTION_HZ);
      pin_buzzer.write(0); wait_us(BUZZ_FUNCTION_HZ);
    };
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("OFF\n");
    #endif
  #endif
    
  // Shield ST X_NUCLEO_IKS01A2
  #ifdef XNUCLEO_FUNCTION 
    // Hum, Temp, Press, Temp, Accelero enable
    hum_temp->enable();
    press_temp->enable();
    accelerometer->enable();
    // Lecture des capteurs
    hum_temp->get_temperature(&xnuc_t);
    hum_temp->get_humidity(&xnuc_h);
    press_temp->get_temperature(&xnuc_t2);
    press_temp->get_pressure(&xnuc_p);
    accelerometer->get_x_axes(xnuc_acc);
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> XNucleo = %.3f \xB0 C, %.3f \xB0 C, %.3f mbar, %.2f %%, ",xnuc_t, xnuc_t2, xnuc_p, xnuc_h);  
      serial_pc.printf("Acc x = %ld, y = %ld, z = %ld\n", xnuc_acc[0], xnuc_acc[1], xnuc_acc[2]);
    #endif
  #endif
    
  // GSM
  #ifdef GSM_FUNCTION
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> GSM ON ");
    #endif
    gsm_pwr_on();
  #endif

  // GPRS SMS
  #ifdef GPRS_FUNCTION
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("& GPRS ON\n");
    #endif
  #endif
    
  #ifdef PT100_FUNCTION
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> PT100 = ");
    #endif
    // Configuration initiale du MAX31865
    /*
    1: v_biais : Vbias (tension de polarisation) activée (true) ou non (false)
    2: conversion_mode : mode de conversion automatique activé (true) ou non (false)
    3: one_shot : mesure au coup par coup (true) ou en continue (false)
    4: three_wire : mesure 3 fils activée (true) ou 2/4 fils (false)
    5: fault_cycle : detection d'erreur (voir datasheet) activée (true) ou non (false)
    6: fault_clear : acquittement automatique des erreurs activée (true) ou non (false)
    7: filter_50hz : filtre 50 Hz activé (true) ou non (false)
    8: low_threshold : seuil d'erreur bas. (0x0000 = 0)
    9: high_threshold : seuil d'erreur haut. (0x7fff = 32767)
    */
    PT100.configure(true, true, false, false, MAX31865_FAULT_DETECTION_NONE, true, true, 0x0000, 0x7fff);
    PT100.read_all();
    #ifdef DEBUG_SERIAL_PC       
    if(PT100.status() == 0) {
        //serial_pc.printf("PT100 OK Temp = %.3f *C\n",PT100.temperature());
        serial_pc.printf("PT100 OK\n");
    }
    else {
        serial_pc.printf("\n!!! Registre d'erreur PT100 = %d - ",PT100.status( ));
        if(PT100.status() & MAX31865_FAULT_HIGH_THRESHOLD) {
             serial_pc.printf("ERREUR PT100 seuil haut franchi\n");
        }
        else if(PT100.status() & MAX31865_FAULT_LOW_THRESHOLD) {
            serial_pc.printf("ERREUR PT100 seuil bas franchi\n");
        }
        else if(PT100.status() & MAX31865_FAULT_REFIN) {
            serial_pc.printf("ERREUR REFIN- > 0,85 x V_BIAS\n");
        }
        else if(PT100.status( ) & MAX31865_FAULT_REFIN_FORCE) {
            serial_pc.printf("ERREUR REFIN- < 0,85 x V_BIAS, FORCE- ouvert\n");
        }
        else if(PT100.status( ) & MAX31865_FAULT_RTDIN_FORCE ) {
            serial_pc.printf("ERREUR RTDIN- < 0,85 x V_BIAS, FORCE- ouvert\n");
        }
        else if(PT100.status( ) & MAX31865_FAULT_VOLTAGE) {
            serial_pc.printf("ERREUR sur/sous-tension\n");
        }
        else serial_pc.printf("ERREUR inconnue\n");
      }
    #endif
  #endif
    
  // Carte SD, initialisation, et creation d'un fichier de test d'ecriture
  // /!\ Faire cette étape après l'initialisation du capteur PT100 qui partage le même SPI
  #ifdef SD_FUNCTION
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> SD = ");
    #endif
    //mkdir("/sd/TEST", 0777);
    FILE *fp = fopen(SD_FUNCTION_TESTFILENAME, "w");
    if(fp == NULL) {
        #ifdef DEBUG_SERIAL_PC       
          serial_pc.printf("ERREUR - Ecriture carte SD\n");
        #endif
        // Desactivation de la sauvegarde sur carte SD
        flag_sd_ok = 0;
    }
    else {
        fprintf(fp, "AMU - Polytech Marseille - HAB STM32 in the Sky - Test ecriture SD");
        fclose(fp); 
        #ifdef DEBUG_SERIAL_PC       
          serial_pc.printf("Ecriture carte SD - ok\n");
        #endif
        //Activation de la sauvegarde sur carte SD
        flag_sd_ok = 1;
    }
  #endif
    
  // CO2
  #ifdef CO2_FUNCTION
    co2.begin();
    co2.IAQmeasure();
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> CO2 = TVOC = %d, eCO2 = %d\n", co2.TVOC, co2.eCO2);
    #endif
  #endif
    
  //DS18 thermomètre
  #ifdef DS18_FUNCTION   // Debut directive de compilation DS181B20
    
    if (ds18.begin()) {
        while (1) {
            ds18.startConversion();   // start temperature conversion from analog to digital
            wait(1.0);                  // let DS1820 complete the temperature conversion
            result = ds18.read(tempDS18); // read temperature from DS1820 and perform cyclic redundancy check (CRC)
            switch (result) {
                case 0:                 // no errors -> 'tempDS18' contains the value of measured temperature
                    #ifdef DEBUG_SERIAL_PC       
                      serial_pc.printf("temp = %3.1f%cC\r\n", tempDS18, 176);
                    #endif
                    break;
                case 1:                 // no sensor present -> 'tempDS18' is not updated
                    #ifdef DEBUG_SERIAL_PC       
                      serial_pc.printf("no sensor present\n\r");
                    #endif
                    break;
                case 2:                 // CRC error -> 'tempDS18' is not updated
                    #ifdef DEBUG_SERIAL_PC       
                      serial_pc.printf("CRC error\r\n");
                    #endif
            }
        }
    }
    else
        #ifdef DEBUG_SERIAL_PC       
          serial_pc.printf("No DS1820 sensor found!\r\n");
        #endif
    
  #endif  // Fin directive de compilation DS181B20
    
  //UV
  #ifdef UV_FUNCTION
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> UV = %.3f %%ADC\n",pin_UV.read());
    #endif
  #endif
    
  //Photoresistance
  #ifdef PHOTORES_FUNCTION
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> Photoresistance = %.3f %%ADC\n",(double)pin_photores.read()*100.0);
    #endif
  #endif
    
  // Triple capteur Bosch BME280
  #ifdef BOSCH_FUNCTION   // Debut directive de compilation Bosch
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> Bosch = %.2f *C, %.2f mbar, %.2f %%\n", bosch.getTemperature(), bosch.getPressure(), bosch.getHumidity());
    #endif
  #endif  // Fin directive de compilation Bosch
    
  // Lecteur MP3
  // Creer un fichier 0.mp3 à la racine de la carte SD
  #ifdef MP3_FUNCTION   // Debut directive de compilation lecteur MP3
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> MP3 ON\n");
    #endif
    mp3.mp3_reset();
    wait(1);    
    mp3.mp3_set_EQ(0);
    wait(0.5);
    mp3.mp3_set_volume(20);
    wait(0.5);
    mp3.mp3_set_device(2);   // 1,2,3,4,5 : USB,SD,AUX,SLEEP,FLASH
    wait(0.5);
    mp3.mp3_single_loop(0);
    //mp3.mp3_single_play(0) ; 
    wait(0.5);
    //serial_pc.printf("We are in the MP3 func !!!!!\n\r");
    mp3.mp3_play();
  #endif  // Fin directive de compilation MP3
      
  #ifdef LORA_FUNCTION
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> LoRa ON\n");
    #endif
  #endif

  #ifdef GPS_FUNCTION
    #ifdef DEBUG_SERIAL_PC 
      serial_pc.printf("-> GPS ON\n");
    #endif
  #endif
    
  #ifdef O3_FUNCTION
    #ifdef DEBUG_SERIAL_PC       
      serial_pc.printf("-> Ozone O3 = %f %%ADC\n", lecture_ozone());
    #endif  
  #endif    

  #ifdef DEBUG_SERIAL_PC       
    serial_pc.printf("\n");
  #endif
      
  //////  Lancement des ticker et des interruptions  ////////

  // GPS
  // Mise en place de l'interruption pour le port UART du GPS
  #ifdef GPS_FUNCTION   // Debut directive de compilation module GPS
    gps_serial.attach(&isr_gps_serial,Serial::RxIrq);
  #endif  // Fin directive de compilation module GPS
      
  // Ticker de creation de la chaine de données toute les 5s
  ticker_hab.attach(&isr_ticker_hab, TICKER_HAB_TIME);

  // GSM
  #ifdef GSM_FUNCTION   // Debut directive de compilation module GSM
    if(flag_gsm_absent == 0) {
        
        // Interruption sur LED "NET" et compteur de sa période
        timer_gsm_network.reset();   // Démarrage du compteur de la période de clignotement de la LED "NET"
        timer_gsm_network.start();   
        gsm_net.rise(&isr_network_gsm);    // Attachement de l'interruption externe sur la LED "NET"
       
        // Ticker de surveillance GSM toute les xx sec
        ticker_check_gsm.attach(&isr_ticker_check_gsm, TICKER_CHECK_GSM_TIME);
        
        // Ticker d'envoi de données par sms toute les xx sec
        #ifdef SMS_FUNCTION   // Debut directive de compilation envoi SMS
          ticker_sms_data.attach(&isr_ticker_sms_data, TICKER_SMS_DATA_TIME);
        #endif  // Fin directive de compilation SMS de données toutes les xx sec      
    }
  #endif  // Fin directive de compilation module GSM
      
  // LoRa
  // Mise en place de l'interruption pour le port UART LoRa
  #ifdef LORA_FUNCTION    // Debut directive de compilation LoRa
    lora_serial.attach(&isr_lora_serial,Serial::RxIrq);
  #endif  // Fin directive de compilation LoRa
    
  ///////////////////  BOUCLE PRINCIPALE  /////////////////  
  while(1) {       
        
    // Vérification du flag d'interruption pour la routine de recuperation
    // des données des capteurs, enregistrement, envoi LoRa, etc.
    #ifdef HAB_FUNCTION
      if(flag_ticker_hab == 1) f_ticker_hab();
    #endif
    
    // Vérification du flag d'interruption pour la routine de vérification
    // de l'état du module
    #ifdef GSM_FUNCTION   // Debut directive de compilation module GSM
      if(flag_ticker_check_gsm == 1)  
      {  if ( (altitude(xnuc_p, BASE_PRESSURE) < GSM_START_ALTITUDE ) || (altitude(bosch_p, BASE_PRESSURE) < GSM_START_ALTITUDE) )
        { 
            #ifdef DEBUG_SERIAL_PC       
            serial_pc.printf("> Pression 1 (XNUCLEO) : %.2f mbar - altitude GSM : %.2f m\n", xnuc_p, altitude(xnuc_p, BASE_PRESSURE));
            serial_pc.printf("> Pression 1 (BOSCH) : %.2f mbar - altitude GSM : %.2f m\n", bosch_p, altitude(bosch_p, BASE_PRESSURE));
            #endif
            f_ticker_check_gsm();
        }
      }
    #endif  // Fin directive de compilation module GSM
        
    // Vérification du flag d'interruption pour la routine d'envoi de SMS
    // de donnée toute les 10 min
    #ifdef SMS_FUNCTION  // Debut directive de compilation SMS de données toutes les 10 min
        if(flag_ticker_sms_data == 1)  f_ticker_sms_data();
    #endif  // Fin directive de compilation SMS de données toutes les 10 min           
    }
}