Import initial du projet shipheart_appli

This commit is contained in:
2026-08-13 10:33:28 +02:00
commit 8fe204361b
62 changed files with 32339 additions and 0 deletions
+387
View File
@@ -0,0 +1,387 @@
//***********************************************************************************************************************************************************************************
// Fichier MAIN.C
//
// Contient les fonctions principales...
//**********************************************************************************************************************************************************************************/
// Include :
#include "main.h"
// Prototypes :
int8_t init(void);
void sigintHandler(int dummy);
void lancement_reinit(uint16_t tempo);
int8_t analyse_signal(void);
int8_t init_signaux(void);
// Variables globales :
/**********************************************************************************************************************************************************************************
Fonction MAIN
Fonction principale...
**********************************************************************************************************************************************************************************/
int main(int argc, char **argv)
{
// Initialisation globale :
if (init() < 0)
{
if (bdd.pointeur != NULL) // Utile si l'erreur d'init est déclarée avant l'initialisation de la BDD...
{
// Mise à jour du flag d'état du CM3P (si l'accès à la BDD est possible...) :
mysql_query(bdd.pointeur, "UPDATE TB_Systeme SET Valeur='-1' WHERE Nom=Etat_cm3p ");
// Ernegistrement dans l'historique (si possible...) :
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CONFIGURATION_INVALIDE_DEMARRAGE_IMPOSSIBLE, 0, 0, NULL);
}
printf("\n\033[31m----------Initialisation arrêtée - Application non lancée----------\033[0m\n\n");
exit (-1);
}
// Boucle principale :
while (1)
{
synchro_bdd();
gestion_rx_serial0();
gestion_rx_serial1();
gestion_entrees();
gestion_c_bus();
gestion_g_bus();
gestion_m_bus();
gestion_nmea();
gestion_gnss();
gestion_modem();
gestion_capteurs(); // A priori, plus logique de traiter les capteurs avant les circuits
gestion_circuits();
gestion_batteries();
gestion_reservoirs();
gestion_events();
gestion_usb();
gestion_reseaux();
gestion_ecran();
gestion_audio();
gestion_systeme();
supervision();
if (analyse_signal() != 0) break;
}
arret_programme();
}
/**********************************************************************************************************************************************************************************
Fonction INIT
Fonction d'initialisation, elle-même faisaint appel à des fonctions d'initialisation dédiées...
**********************************************************************************************************************************************************************************/
int8_t init(void)
{
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// Init système et hardware
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// Init des variables de supervision de la boucle principale :
supervision_boucle_principale.nb_boucles = 0;
supervision_boucle_principale.attente_premieres_mesures = SYSTEME_ATTENTE_DEMARRAGE_COMPTEUR_BOUCLE_PRINCIPALE;
// Interception des signaux vers la fonction de traitement dédiée (Refer http://en.cppreference.com/w/c/program/signal) :
if (init_signaux() < 0) return(-1);
// Intitialisation du mode Debug immédiatement (doit être initialisé avant toute autre action pour être disponible dès le départ...) :
// Les paramètres correspondants sont en dur (et non en BDD) car s'ils sont corrompus, on peut perdre accès à tout Log, voire planter le démarrage.
// De plus, par expérience, on les modifie assez peu...
debug.mode = AFFICHAGE_DEBUG_ECRAN_ET_FICHIER;
strcpy(debug.nom_fichier, NOM_FICHIER_DEBUG);
if (init_affichage_debug() < 0) return(-1);
// Recherche de la version matérielle :
if (version_compute_module() < 0) return(-1);
// Recherche du package en cours (fichier JSON) et du numéro de package en cours (1.2.3) :
strcpy(systeme.package_version, "Inconnue"); // Valeur par défaut
struct dirent *dir; // Les types 'dirent' ou 'DIR' sont déclarés dans le header <dirent.h>
DIR *repertoire;
repertoire = opendir(REPERTOIRE_VERSIONS_CURRENT); // Ouverture du répertoire
if (repertoire != NULL)
{
while ((dir = readdir(repertoire)) != NULL) // Lecture de tous les fichiers du répertoire :
{
if (strcmp(dir->d_name, ".") == 0) continue; // On ne traite pas le répertoire '.' ...
if (strcmp(dir->d_name, "..") == 0) continue; // ... ni le répertoire '..'
if (strstr(dir->d_name, MARQUEUR_FICHIER_JSON) != NULL) // Recherche d'un fichier de type JSON
{
strcpy(systeme.package_version, dir->d_name);
*strstr(systeme.package_version, MARQUEUR_FICHIER_JSON) = 0; // Mise à 0 de la première position du marqueur JSON (donc on coupe la chaine avant le '.json').
sprintf(tmp, "Version de package en cours\t\t\t\t\t\t\t: %s", systeme.package_version);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
// Recherche du n° de la version dans le fichier JSON :
char nom_fichier[MAX_LONGUEUR_NOM_REPERTOIRE_LOCAL + MAX_LONGUEUR_NOM_FICHIER];
struct Struct_json_version json_version;
sprintf(nom_fichier, "%s/%s%s", REPERTOIRE_VERSIONS_CURRENT, systeme.package_version, MARQUEUR_FICHIER_JSON);
json_version = parse_json_version(nom_fichier, false);
strcpy(systeme.package_no_version, json_version.no_version); // NB : si le parsing du fichier JSON a rencontré une erreur, le N° de version remonté est "ERREUR"
sprintf(tmp, "N° de version de package en cours\t\t\t\t\t\t: %s", systeme.package_no_version);
if (strstr(systeme.package_no_version, "ERREUR") == NULL) affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
else affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); // Si la lecture du fichier de version a rencontré une erreur
break;
}
}
closedir(repertoire); // Fermeture du répertoire
}
// Mise à jour de la version de logiciel :
// Cette fonction est délocalisée dans '_version.c' pour être mise à jour à chaque make tout en évitant de tout recompiler systématiquement.
// C'est la raison pour laquelle l'affichage de la version se fait ici (et pas dans la fonction) car on veut la garder aussi épurée que possible.
sprintf(systeme.cm3p_soft_version, "%s", maj_version_logiciel());
sprintf(tmp, "Version d'application lancée\t\t\t\t\t\t: %s", systeme.cm3p_soft_version);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
// Initialisation du handler de signal SIGALRM et lancement du timer Linux :
// Nécessaire d'être lancé 'tôt' car peut être utilisé dans certaines routines d'init. Dans tous les cas, la construction des timers fait que
// les variables globales (initialisées à 0 par le compilateur) sont inactives tant qu'aucun gestionnaire ne les charge.
if (init_timer() < 0) return(-1);
// Initialisation des pointeur physique du SOC du processeur (GPIO, BSC1, SPI, ...) afin d'accéder directement à ses registres :
if (init_memory_map() < 0) return(-1);
// Initialisation des accès à la base de données (+ lecture de certains paramètres de configuration):
// Cette initialisation est faite très 'tôt' car elle ouvre l'accès au mode de débug notamment qui est utilisé ensuite par les différents programmes d'init.
if (init_bdd(BDD_MODE_INIT_RESET) < 0) return(-1);
// initialisation des sorties :
if (init_sorties() < 0) return(-1);
// initialisation des entrées :
if (init_entrees() < 0) return(-1);
// initialisation des UARTs (les GPIOs doivent être configurées AVANT) :
if (init_serial0() < 0) return(-1);
if (init_serial1() < 0) return(-1);
//---------------------------------------------------------
// Activations effectuées directement dans config.txt mais qu'il faut répéter ici sinon le gestionnaire de sortie va les positionner à 0 par défaut...
//---------------------------------------------------------
// Ecran :
if (init_ecran() < 0) return(-1);
// Audio :
if (init_audio() < 0) return(-1);
// initialisation des ports USB :
if (init_usb() < 0) return(-1);
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// Init des fonctions haut niveau
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// initialisation du C_Bus :
if (init_c_bus() < 0) return(-1);
// initialisation du G_Bus :
if (init_g_bus() < 0) return(-1);
// initialisation du Gnss :
if (init_gnss() < 0) return(-1);
// initialisation du M_Bus :
if (init_m_bus() < 0) return(-1);
// initialisation du Modem :
if (init_modem() < 0) return(-1);
// initialisation du Wifi :
if (init_reseaux() < 0) return(-1);
// initialisation des capteurs :
if (init_capteurs() < 0) return(-1);
// initialisation des circuits :
if (init_circuits() < 0) return(-1);
// initialisation des niveaux :
if (init_reservoirs() < 0) return(-1);
// initialisation des batteries :
if (init_batteries() < 0) return(-1);
// initialisation des évènements :
if (init_events() < 0) return(-1);
// initialisation du réseau NMEA2000 :
if (init_nmea() < 0) return(-1);
// initialisation Système :
if (init_systeme() < 0) return(-1);
// Enregistrement dans l'historique de la bonne fin de l'initialisation :
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_REINIT, 0, 0, NULL);
affichage_debug(__FILE__, __LINE__, "Fin d'initialisation de tous les gestionnaires", TYPE_MESSAGE_DEBUG_OK);
return(0);
}
//==================================================================================================================================================================
// Fonction : Demande une réinit au Compagnon (qui va la temporiser à réception d'environ 5s). Lance un compteur pour laisser tourner l'application pendant
// un certain temps avant d'arrêter la boucle principale.
// Reçoit : La valeur de tempo, en 100ms (0 = valeur par défaut)
// Retour : Rien
//==================================================================================================================================================================
void lancement_reinit(uint16_t tempo)
{
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
systeme.faucheuse.flag_demande_reinit = TRUE;
systeme.faucheuse.id_message_user = enregistrement_message_users(MESSAGE_USERS_CODE_REDEMARRAGE, "", MESSAGE_USERS_ETAT_ALERTE);
if (tempo == 0) systeme.faucheuse.compteur = SYSTEME_TEMPO_ATTENTE_REINIT_PAR_DEFAUT;
else systeme.faucheuse.compteur = tempo;
c_bus_down_commande_reset(); // Demande de réinit (elle est temporisée au niveau du Compagnon pour permettre le traitement des dernières fonctions)
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_DEMANDE_REINIT, 0, 0, NULL); // Enregistrement dans l'historique
sprintf(tmp, "\t----------------------------------------------------------------------------");
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
sprintf(tmp, "\t!!!!! Une demande de réinit a été lancée et sera effective dans %i ms !!!!", (systeme.faucheuse.compteur * 100));
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
sprintf(tmp, "\t----------------------------------------------------------------------------");
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
}
//==================================================================================================================================================================
// Fonction : Analyse la valeur de signal reçu et renvoit une valeur non nulle si le signal est considéré comme devant arrêter l'application (notamment SIGINT qui
// est reçu suite à l'appui sur CTRL+C au clavier). Dans tous les cas, la réception du signal est archivé dans l'historique.
// Reçoit : Rien
// Retour : 0 si pas de signal d'arrêt reçu, -1 si un signal d'arrêt a été reçu
//==================================================================================================================================================================
int8_t analyse_signal(void)
{
char commande[MAX_TAILLE_COMMANDE_SHELL];
int8_t retour = 0;
if (systeme.faucheuse.flag_demande_reinit == TRUE)
{
if (systeme.faucheuse.compteur == 0)
{
systeme.faucheuse.flag_demande_reinit = FALSE; // Utile surtout en debug...
maj_message_users(systeme.faucheuse.id_message_user, "", MESSAGE_USERS_ETAT_SUPPRESSION); // Suppression du message juste avant la réinit...
sprintf(commande, "sudo sync"); // Permet de s'assurer que tous les fichiers sont bien répliqués sur le disque.
commande_shell(commande);
return (-1); // On est arrivé au bout... C'est la fin.
}
}
if (systeme.faucheuse.signal_recu == SYSTEME_SIGNAL_AUCUN) return (0); // Cas normal
// Cas où on a reçu un signal :
switch(systeme.faucheuse.signal_recu)
{
case SIGINT : { retour = -1; break; } // CTRL+C notamment...
case SIGQUIT : { retour = -1; break; }
case SIGABRT : { retour = -1; break; }
case SIGTERM : { retour = -1; break; }
case SIGKILL : { retour = -1; break; } // A priori inutile car on n'aura pas le temps d'arriver ici...
default : retour = 0;
}
// Enregistrement dans l'historique, quel que soit le signal (et s'il nous en laisse l'occasion...) :
if (systeme.faucheuse.signal_recu != SIGCHLD)
{
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_SIGNAL_RECU, 0, systeme.faucheuse.signal_recu, NULL);
}
systeme.faucheuse.signal_recu = SYSTEME_SIGNAL_AUCUN;
return(retour);
}
//==================================================================================================================================================================
// Fonction : Initialisation des handlers de signaux (vers une seule et même fonction).
// Reçoit : Rien
// Retour : 0 si pas d'erreur, -1 si erreur
//==================================================================================================================================================================
int8_t init_signaux(void)
{
systeme.faucheuse.signal_recu = SYSTEME_SIGNAL_AUCUN;
signal(SIGHUP, sigintHandler); // 1 SIGHUP Instruction (HANG UP) - Fin de session
signal(SIGINT, sigintHandler); // 2 SIGINT Interruption
signal(SIGQUIT, sigintHandler); // 3 SIGQUIT Instruction (QUIT)
signal(SIGILL, sigintHandler); // 4 SIGILL Instruction illégale
signal(SIGTRAP, sigintHandler); // 5 SIGTRAP Trace trap
signal(SIGABRT, sigintHandler); // 6 SIGABRT (ANSI) Instruction (ABORT)
signal(SIGIOT, sigintHandler); // 6 SIGIOT (BSD) IOT Trap
signal(SIGBUS, sigintHandler); // 7 SIGBUS Bus error
signal(SIGFPE, sigintHandler); // 8 SIGFPE Floating-point exception - Exception arithmétique
signal(SIGKILL, sigintHandler); // 9 SIGKILL Instruction (KILL) - termine le processus immédiatement
signal(SIGUSR1, sigintHandler); // 10 SIGUSR1 Signal utilisateur 1
signal(SIGSEGV, sigintHandler); // 11 SIGSEGV Violation de mémoire
signal(SIGUSR2, sigintHandler); // 12 SIGUSR2 Signal utilisateur 2
signal(SIGPIPE, sigintHandler); // 13 SIGPIPE Broken PIPE - Erreur PIPE sans lecteur
signal(SIGALRM, sigintHandler); // 14 SIGALRM Alarme horloge
signal(SIGTERM, sigintHandler); // 15 SIGTERM Signal de terminaison
signal(SIGSTKFLT, sigintHandler); // 16 SIGSTKFLT Stack Fault
signal(SIGCHLD, sigintHandler); // 17 SIGCHLD ou SIGCLD modification du statut d'un processus fils
signal(SIGCLD, sigintHandler); // 17 SIGCHLD ou SIGCLD modification du statut d'un processus fils
signal(SIGCONT, sigintHandler); // 18 SIGCONT Demande de reprise du processus
signal(SIGSTOP, sigintHandler); // 19 SIGSTOP Demande de suspension imbloquable
signal(SIGTSTP, sigintHandler); // 20 SIGTSTP Demande de suspension depuis le clavier
signal(SIGTTIN, sigintHandler); // 21 SIGTTIN lecture terminal en arrière-plan
signal(SIGTTOU, sigintHandler); // 22 SIGTTOU écriture terminal en arrière-plan
signal(SIGURG, sigintHandler); // 23 SIGURG évènement urgent sur socket
signal(SIGXCPU, sigintHandler); // 24 SIGXCPU temps maximum CPU écoulé
signal(SIGXFSZ, sigintHandler); // 25 SIGXFSZ taille maximale de fichier atteinte
signal(SIGVTALRM, sigintHandler); // 26 SIGVTALRM alarme horloge virtuelle
signal(SIGPROF, sigintHandler); // 27 SIGPROF Profiling alarm clock
signal(SIGWINCH, sigintHandler); // 28 SIGWINCH changement de taille de fenêtre
signal(SIGPOLL, sigintHandler); // 29 SIGPOLL (System V) occurence d'un évènement attendu
signal(SIGIO, sigintHandler); // 29 SIGIO (BSD) I/O possible actuellement
signal(SIGPWR, sigintHandler); // 30 SIGPWR Power failure restart
signal(SIGSYS, sigintHandler); // 31 SIGSYS Erreur d'appel système
return(0);
}
//==================================================================================================================================================================
// Fonction : Handler unique de tous les signaux. Récupére la valeur du signal et met à jour la variable globale correspondante.
// ATTENTION : il ne faut PAS faire de printf (ou équivalent) ici car il y a des restrictions dans les signals handlers.
// En l'occurence, le traitement en fonction du numéro de signal est fait dans la fonction 'analyse_signal()' ci-dessus.
// Reçoit : Rien
// Retour : Rien
//==================================================================================================================================================================
void sigintHandler(int32_t signal)
{
systeme.faucheuse.signal_recu = signal; // Permet de passer l'information de réception du signal à la boucle infinie du MAIN.
}