// ********************************************************************************************************************************************************************************** // Fichier SYSTEME.C // // Contient toutes les fonctions système du projet. // ********************************************************************************************************************************************************************************** // #define __DEBUG_SYSTEME //Décommenter cette ligne pour avoir les messages de debug concernant le système //#define __DEBUG_SYSTEME_FICHIER_JSON //Décommenter cette ligne pour afficher le contenu du fichier JSON à l'init // #define __DEBUG_SYSTEME_MISE_A_JOUR //Décommenter cette ligne pour avoir les messages de debug concernant les mises à jour #define __DEBUG_SYSTEME_CHARGEMENT_CODE //Décommenter cette ligne pour avoir les messages de debug concernant le chargement de code // Include : #include "main.h" // Prototypes : int8_t init_systeme(void); void gestion_systeme(void); void check_mise_a_jour(void); void gestion_chargement_code(void); void supervision(void); void arret_programme(void); int8_t re_configuration_systeme(void); int32_t commande_shell(char * commande); struct Struct_json_version parse_json_version(char * nom_fichier, bool verbose); int8_t send_signal (int32_t pid, int32_t signal); int32_t get_pid_from_name (char * nom, char * parametres); int32_t get_pid_numbers_from_name (char * nom, char * parametres); int8_t version_compute_module(void); void affichage_ligne_version_compute_module(char * tmp, char * titre, char * valeur); // Variables globales : struct Struct_download download; struct Struct_systeme systeme; struct Struct_chargement_code chargement_code; struct Struct_upload upload; struct Struct_supervision_boucle_principale supervision_boucle_principale; //================================================================================================================================================================== // Fonction : Fonction d'init des fonctions de plus haut niveau. // Reçoit : Rien // Renvoit : 0 si OK, -1 si erreur //================================================================================================================================================================== int8_t init_systeme(void) { DIR *repertoire; char commande[MAX_TAILLE_COMMANDE_SHELL]; //------------------------------------ // Initialisation dépendant de la génération de ShipBase : if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1) { systeme.entree_gpio_cm_di_from_uc = CM3P_DI_FROM_UC; systeme.sortie_gpio_cm_do_to_uc = CM3P_DO_TO_UC; } else { systeme.entree_gpio_cm_di_from_uc = CM4_DI_FROM_UC; systeme.sortie_gpio_cm_do_to_uc = CM4_DO_TO_UC; } //------------------------------------ // Préparation du système de fichier : // Important : Il faut tester les répertoires dans l'ordre descendant. On ne pourra PAS créer un répertoire 2 niveaux plus bas. // Exemple : si /tmp et /tmp/bdd n'existent pas, on ne pourra pas créer /tmp/bdd directement (erreur de shell). repertoire = opendir(REPERTOIRE_SERVER); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_SERVER, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_SERVER_UPLOAD); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_SERVER_UPLOAD, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_SERVER_DOWNLOAD); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_SERVER_DOWNLOAD, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_VERSIONS); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_VERSIONS, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_VERSIONS_A_VALIDER); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_VERSIONS_A_VALIDER, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_VERSIONS_A_CHARGER); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_VERSIONS_A_CHARGER, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_CONFIG); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_CONFIG, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_CONFIG_IMAGES_ACCUEIL); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_CONFIG_IMAGES_ACCUEIL, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_CONFIG_IMAGES_SILHOUETTE); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_CONFIG_IMAGES_SILHOUETTE, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_CONFIG_RAPPORTS); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_CONFIG_RAPPORTS, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_CONFIG_SAUVEGARDES); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_CONFIG_SAUVEGARDES, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_TMP); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_TMP, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_TMP_BDD); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_TMP_BDD, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_TMP_CORE); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_TMP_CORE, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_TMP_SAUVEGARDE); // Tentative d'ouverture du répertoire... // SDIR #162 if (repertoire == NULL) mkdir(REPERTOIRE_TMP_SAUVEGARDE, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_TMP_USB); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_TMP_USB, 0777); // ...et création s'il n'existe pas else closedir(repertoire); repertoire = opendir(REPERTOIRE_TMP_WIFI); // Tentative d'ouverture du répertoire... if (repertoire == NULL) mkdir(REPERTOIRE_TMP_WIFI, 0777); // ...et création s'il n'existe pas else closedir(repertoire); sprintf(commande, "sudo chown -R koriolan:koriolan %s", REPERTOIRE_SHIPHEART); // Affecte le propriétaire des répertoires (et sous-répertoires) de shipheart. commande_shell(commande); //------------------------------------ // Init de l'état du Compagnon : if (lecture_entree(TYPE_ENTREES_GPIO, 0, systeme.entree_gpio_cm_di_from_uc, TRUE) == 0) // 0 est l'adresse de ShipBase { systeme.flag_compagnon_ready = FALSE; affichage_debug(__FILE__, __LINE__, "L'entrée Compagnon_Ready est actuellement à FALSE", TYPE_MESSAGE_DEBUG_WARNING); } else { systeme.flag_compagnon_ready = TRUE; affichage_debug(__FILE__, __LINE__, "L'entrée Compagnon_Ready est détectée à TRUE", TYPE_MESSAGE_DEBUG_OK); } //------------------------------------ // Init des variables générales : systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_INIT; systeme.sequenceur.compteur = SYSTEME_TEMPO_INIT; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_INIT; chargement_code.sequenceur.compteur = CHARGEMENT_CODE_TEMPO_INIT; systeme.compteur_sauvegarde_bdd = systeme.periode_sauvegarde_bdd; // SDIR #301 : /* //------------------------------------ // Sauvegarde de la base de données : affichage_debug(__FILE__, __LINE__, "Lancement sauvegarde BDD\t\t: OK", TYPE_MESSAGE_DEBUG_OK); ret = sauvegarde_bdd(); if (ret != 0) { sprintf(tmp, "\tSauvegarde de la base de données : NOK (retour = %i)", ret); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } else affichage_debug(__FILE__, __LINE__, "Fin de sauvegarde BDD\t\t: OK", TYPE_MESSAGE_DEBUG_OK); */ // Fin de SDIR #301 //------------------------------------ // Affichage du message de débug : affichage_debug(__FILE__, __LINE__, "Initialisation système\t\t: OK", TYPE_MESSAGE_DEBUG_OK); return(0); } //================================================================================================================================================================== // Fonction : Fonction de plus haut niveau du système. // Reçoit : Rien // Renvoit : Rien //================================================================================================================================================================== void gestion_systeme(void) { uint16_t i; int32_t ret; bool flag_id_complete; char commande[MAX_TAILLE_COMMANDE_SHELL]; struct dirent *dir; // Les types 'dirent' ou 'DIR' sont déclarés dans le header DIR *repertoire; char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; switch(systeme.sequenceur.etat) { //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_SYSTEME_INIT : { if (systeme.sequenceur.compteur == 0) { //-------------------------------------------------------------------- // RAZ du séquenceur de chargement de code (utile lorsqu'une reconnaissance réseau est lancée au milieu d'un téléchargement) : if (chargement_code.id_message_user != 0) { maj_message_users(chargement_code.id_message_user, "", MESSAGE_USERS_ETAT_SUPPRESSION); // Suppression du message s'il y en avait encore un d'actif (cas d'un redémarrage de procédure en cours) chargement_code.id_message_user = 0; } chargement_code.sequenceur.compteur = 0; chargement_code.sequenceur.compteur_time_out = 0; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS; //-------------------------------------------------------------------- // Lancement de la reconnaissance du réseau K-Bus dès qu'il est prêt : if (c_bus.sequenceur.etat == ETAT_SEQUENCEUR_C_BUS_INIT) { affichage_debug(__FILE__, __LINE__, "C-Bus pas encore démarré. Attente...", TYPE_MESSAGE_DEBUG_PAR_DEFAUT); systeme.sequenceur.compteur = SYSTEME_TEMPO_ATTENTE_DISPO_C_BUS; } else { c_bus_down_commande_lecture_date_heure(); // Lecture de la date/heure depuis le Compagnon qui est le seul à être sauvegardé c_bus_down_commande_annuaire_k_bus(); // Lecture de l'annuaire des cartes présentes dans le système affichage_debug(__FILE__, __LINE__, "Demande annuaire K-Bus envoyée\t: Ok", TYPE_MESSAGE_DEBUG_OK); systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_ATTENTE_ANNUAIRE_K_BUS; } } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_SYSTEME_ATTENTE_ANNUAIRE_K_BUS : { if (systeme.modules_physiques[0].flag_presence) // Le flag de présence du Compagnon a dû être positionné par le retour de la commande 'c_bus_down_commande_annuaire()' { for (i = 0; i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; c_bus_down_commande_lecture_id_carte(i); // Envoi d'une commande de lecture_ID à chaque carte présente } affichage_debug(__FILE__, __LINE__, "Lecture ID des modules\t\t: Ok", TYPE_MESSAGE_DEBUG_OK); systeme.sequenceur.compteur = SYSTEME_TEMPO_LECTURE_ID_CARTES; systeme.sequenceur.compteur_time_out = SYSTEME_TIME_OUT_LECTURE_ID_CARTES; // SDIR #304 systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_LECTURE_ID_CARTES; } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_SYSTEME_LECTURE_ID_CARTES : { if (systeme.sequenceur.compteur == 0) { flag_id_complete = TRUE; for (i = 0; i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes if (systeme.modules_physiques[i].type == -1) // Si l'ID de la carte a été reçu, son type a forcément été mise à jour (>0) { flag_id_complete = FALSE; // S'il n'a pas été mis à jour, il faut attendre encore un peu... break; // Inutile de continuer... } } if (flag_id_complete == TRUE) { enregistrement_annuaire_k_bus(); // A partir de la réponse à la commande 'annuaire_k_bus()' ci-dessus puis des 'lecture_id_carte()', on défini les cartes présentes ou pas et donc les circuits disponibles ou pas. affichage_debug(__FILE__, __LINE__, "Enregistrement annuaire K-Bus\t: Ok", TYPE_MESSAGE_DEBUG_OK); entrees.ow.flag_maj_annuaire_en_cours = TRUE; c_bus_down_commande_annuaire_ow(); // Lecture de l'annuaire des devices OW présents dans le système systeme.sequenceur.compteur_time_out = SYSTEME_TIME_OUT_ANNUAIRE_ONE_WIRE; systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_ATTENTE_ANNUAIRE_ONE_WIRE; } else systeme.sequenceur.compteur = SYSTEME_TEMPO_LECTURE_ID_CARTES; // Si les ID de toutes les cartes n'ont pas été reçus, on lance une petite tempo supplémentaire... } // SDIR #304 : Début if (systeme.sequenceur.compteur_time_out == 0) { systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_INIT; // On relance le séquenceur au départ pour effectuer une configuration complète de l'application en fonction du résultat de la reconnaissance réseau faite par le Compagnon sur K-Bus systeme.sequenceur.compteur = 0; // Pas la peine d'attendre... } // SDIR #304 : Fin break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_SYSTEME_ATTENTE_ANNUAIRE_ONE_WIRE : { if (!entrees.ow.flag_maj_annuaire_en_cours) { systeme.sequenceur.compteur_time_out = 0; // Arrêt du time-out affichage_debug(__FILE__, __LINE__, "Mise à jour annuaire One-Wire\t: Ok", TYPE_MESSAGE_DEBUG_OK); systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_CHARGEMENT_CONFIG_CARTES; break; } if (systeme.sequenceur.compteur_time_out == 0) { affichage_debug(__FILE__, __LINE__, "Mise à jour annuaire One-Wire\t: Erreur de time-out", TYPE_MESSAGE_DEBUG_ERREUR); systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_CHARGEMENT_CONFIG_CARTES; break; } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_SYSTEME_CHARGEMENT_CONFIG_CARTES : { for (i = 0; i < MAX_NOMBRE_MODULES; i ++) // Envoi des commandes de config de chaque carte : { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes switch(systeme.modules_physiques[i].type) { case TYPE_CARTE_SHIPBASE : { c_bus_down_commande_config_carte(i, C_BUS_CONFIG_LECTURE_SEULE); break; } case TYPE_CARTE_SP812 : case TYPE_CARTE_SP4AC : case TYPE_CARTE_SP8DC : { c_bus_down_commande_config_carte(i, C_BUS_CONFIG_LECTURE_SEULE); c_bus_down_commande_config_circuits(i); c_bus_down_commande_cde_circuits(i); // NB : le flag 'flag_changement_consigne_en_cours' de chaque circuit de la carte n'est PAS positionné à TRUE. Cela ne doit pas poser de soucis au démarrage... (Cf SDIR #179) break; } case TYPE_CARTE_SBS : { c_bus_down_commande_config_carte(i, C_BUS_CONFIG_LECTURE_SEULE); c_bus_down_commande_config_batteries(i); break; } default : ; } } affichage_debug(__FILE__, __LINE__, "Configuration des modules\t\t: Ok", TYPE_MESSAGE_DEBUG_OK); systeme.sequenceur.compteur = SYSTEME_TEMPO_ATTENTE_CONFIG_CARTES; // Cette tempo retarde la remonté de la sortie CM3P_READY et "bloque" donc au niveau du Compagnon la remontée de certaines commandes qui ne serviraient à rien. systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_ATTENTE_CONFIG_CARTES; break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_SYSTEME_ATTENTE_CONFIG_CARTES : { if (systeme.sequenceur.compteur == 0) { check_mise_a_jour(); // Vérification de la cohérence des versions de chaque module. Si besoin, la fonction lancera le séquenceur de chargement_code. maj_etat_cm3p(ON); // Maj du flag, de la BDD et de la sortie physique affichage_debug(__FILE__, __LINE__, "La configuration est terminée. La sortie CM3P_Ready est activée vers le Compagnon", TYPE_MESSAGE_DEBUG_OK); printf("\n----------------- Fin d'initialisation --------------------\n\n"); // SDIR #301 : //------------------------------------ // Sauvegarde de la base de données : affichage_debug(__FILE__, __LINE__, "Lancement sauvegarde BDD\t\t: OK", TYPE_MESSAGE_DEBUG_OK); //ret = sauvegarde_bdd(); ret=0; if (ret != 0) { sprintf(tmp, "\tSauvegarde de la base de données : NOK (retour = %i)", ret); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } else affichage_debug(__FILE__, __LINE__, "Fin de sauvegarde BDD\t\t: OK", TYPE_MESSAGE_DEBUG_OK); // Fin de SDIR #301 systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_REPOS; } break; } //----------------------------------------------------------------------------------------------------------------------------------------- // Cet état repos est balayé à chaque boucle principale, // sans temporisation. Il est donc important de la garder // la plus rapide possible dans son cas le plus général. case ETAT_SEQUENCEUR_SYSTEME_REPOS : { //============================= // Surveillance du Compagnon : if (systeme.flag_compagnon_ready == FALSE) { if (lecture_entree(TYPE_ENTREES_GPIO, 0, systeme.entree_gpio_cm_di_from_uc, TRUE) != 0) // 0 est l'adresse de ShipBase { systeme.flag_compagnon_ready = TRUE; affichage_debug(__FILE__, __LINE__, "L'entrée Compagnon_Ready est passée à ON", TYPE_MESSAGE_DEBUG_OK); re_configuration_systeme(); // Génère les commandes nécessaires sur C-Bus pour reconfigurer le Compagnon et le K-Bus } } else { if (lecture_entree(TYPE_ENTREES_GPIO, 0, systeme.entree_gpio_cm_di_from_uc, TRUE) == 0) // 0 est l'adresse de ShipBase { systeme.flag_compagnon_ready = FALSE; affichage_debug(__FILE__, __LINE__, "L'entrée Compagnon_Ready est passée à OFF", TYPE_MESSAGE_DEBUG_ERREUR); } } //================================== // Sauvegarde régulière de la BDD : if (systeme.compteur_sauvegarde_bdd == 0) { systeme.compteur_sauvegarde_bdd = systeme.periode_sauvegarde_bdd; // Provenance = 'Periode_sauvegarde_bdd' de TB_Configuration // sauvegarde_bdd(); } //====================================================== // Recherche de nouveaux fichiers downloadés à traiter : if (systeme.compteur_check_new_download == 0) // SDIR #196 (Début) { systeme.compteur_check_new_download = SYSTEME_TEMPO_PERIODE_CHECK_NEW_DOWNLOAD; systeme.flag_new_download = TRUE; } // SDIR #196 (Fin) if ((systeme.flag_new_download == TRUE) && (chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS)) // Si un chargement de code est en cours, on attend avant de traiter d'autre fichiers à downloader { // NB : le flag n'est remis à FALSE qu'après avoir traité tous les fichiers actuellement présents dans le répertoire download. // Sinon, dans le cas de fréquence de Download "élevée", comme pendant les tests, on relançait un download en plein chargement de code // => plantage car on partage les fichiers et les répertoires... // Listing des fichiers locaux : repertoire = opendir(REPERTOIRE_SERVER_DOWNLOAD); // 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 '..' //-------------------------------------------------------- // Recherche des fichiers bash exécutables immédiatement : // Ce sont les fichiers 'now*.sh' qui sont exécutés (en parallèle de l'application via l'utilisation d'un '&' au lancement). // Il est important que le fichier bash se renomme lui-même avec le suffixe DONE afin de ne pas être traité à nouveau. if ((strstr(dir->d_name, MARQUEUR_FICHIER_BASH) != NULL) && (strstr(dir->d_name, "now_") != NULL) && // On ne traite que les fichiers qui contiennent (en pratique, commencent par) "now_"... (strstr(dir->d_name, MARQUEUR_FICHIER_DONE) == NULL)) // ... MAIS qui ne contiennent pas le texte ".DONE" qui indique qu'ils ont été traités. { #ifdef __DEBUG_SYSTEME sprintf(tmp, "Le fichier bash [%s] a été trouvé dans le répertoire download", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif // Affectation des droits d'exécution au fichier bash : sprintf(commande, "sudo chmod +x %s/%s", REPERTOIRE_SERVER_DOWNLOAD, dir->d_name); // Sans '&' de terminaison car il faut que la commande soit terminée avant de poursuivre commande_shell(commande); // Exécution du fichier bash : sprintf(commande, "%s/%s &", REPERTOIRE_SERVER_DOWNLOAD, dir->d_name); // /!\ Ne pas oublier le '&' à la fin pour ne pas bloquer l'application !!!! if (commande_shell(commande) == 0) { // Enregistrement dans l'historique : enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_EXECUTION_BASH_DEBUT_OK, 0, 0, dir->d_name); sprintf(tmp, "Le fichier bash [%s] a été exécuté avec succès.", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK); } else { // Enregistrement dans l'historique : enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_EXECUTION_BASH_DEBUT_NOK, 0, 0, dir->d_name); sprintf(tmp, "Le fichier bash [%s] n'a pas ou être exécuté correctement.", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } //-------------------------------------------------------- // Recherche des fichiers encodés (a priori, des fichiers de version) : if ((strstr(dir->d_name, MARQUEUR_FICHIER_TAR_GZIP_ENC) != NULL) && (strstr(dir->d_name, MARQUEUR_FICHIER_DONE) == NULL)) // On ne traite que les fichiers qui ne contiennent pas le texte ".DONE" qui indique qu'ils ont été traités. { sprintf(tmp, "Le fichier archive [%s] a été trouvé dans le répertoire download", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); // Vérification du type de MAJ à appliquer en fonction du fichier reçu : uint8_t mode_validation = systeme.mode_validation_maj; // La variable locale sera modifié au cours de l'analyse donc on récupère une copie au départ pour ne pas altérer l'image de la BDD if ((mode_validation == MODE_VALIDATION_MAJ_MANUELLE) || // Si le mode de MAJ est AUCUNE, il est inutile dde vérifier si la nouvelle version est valide (mode_validation == MODE_VALIDATION_MAJ_AUTOMATIQUE)) { // Vérification que le fichier reçu est utilisable : char *ptr_new[MAX_NOMBRE_PARAMETRES_LISTE_DOWNLOAD]; // NB : le define utilisé pour la taille n'est pas directement lié au sujet mais pratique... char *ptr_now[MAX_NOMBRE_PARAMETRES_LISTE_DOWNLOAD]; char version_new[MAX_LONGUEUR_NOM_FICHIER]; char version_now[MAX_LONGUEUR_NOM_FICHIER]; strcpy(version_new, dir->d_name); // Copie dans une chaine locale car on va la modifier. Nom de la forme : 'ShipHeart_v_3_2_1_uf.tar.gz.enc' ptr_new[0] = strstr(version_new, "."); // Recherche du premier '.' if (ptr_new[0] != NULL) // Si on a trouvé un premier '.' : { *ptr_new[0] = 0; // Fin de chaine au premier point. Version maintenant de la forme : 'ShipHeart_v_3_2_1_uf' i = 0; ptr_new[i] = strtok (version_new, "_"); // Extraction du premier segment avant le premier '_'. ATTENTION : si aucun délimiteur trouvé, la fonction renvoit la chaine entière (et pas NULL...) while ((ptr_new[i] != NULL) && (i < MAX_NOMBRE_PARAMETRES_LISTE_DOWNLOAD)) { i ++; ptr_new[i] = strtok (NULL, "_"); // Extraction du segment suivant le prochain '_' } // Check du nombre de champs trouvés : if (i == 6) // Valeur correcte = 6 segments autour des '_' dans 'ShipHeart_v_3_2_1_uf' { if ((ptr_new[5][1] != 't') && (ptr_new[5][1] != 'T')) // Si le flag 'Version_back_enable' n'est PAS 'true' (probablement 'false' donc), alors il faut vérifier l'antériorité de la version actuelle : { strcpy(version_now, systeme.package_no_version); // Copie dans une chaine locale car on va la modifier. Version de la forme : '3.2.1' i = 0; ptr_now[i] = strtok (version_now, "."); // Extraction du premier segment avant le premier '.'. ATTENTION : si aucun délimiteur trouvé, la fonction renvoit la chaine entière (et pas NULL...) while ((ptr_now[i] != NULL) && (i < MAX_NOMBRE_PARAMETRES_LISTE_DOWNLOAD)) { i ++; ptr_now[i] = strtok (NULL, "."); // Extraction du segment suivant le prochain '.' } if (i == 3) // Valeur correcte = 3 segments autour des '.' dans '3.2.1' { do // Fake loop : { // Premier chiffre : if (atoi(ptr_new[2]) < atoi(ptr_now[0])) // 1.y.z < 3.y.z { mode_validation = MODE_VALIDATION_MAJ_AUCUNE; break; } if (atoi(ptr_new[2]) > atoi(ptr_now[0])) break; // 3.y.z > 1.y.z // x = x // Deucième chiffre : if (atoi(ptr_new[3]) < atoi(ptr_now[1])) // 1.2.z < 1.3.z { mode_validation = MODE_VALIDATION_MAJ_AUCUNE; break; } if (atoi(ptr_new[3]) > atoi(ptr_now[1])) break; // 1.3.z > 1.2.z // x.y = x.y // Troisème chiffre : if (atoi(ptr_new[4]) < atoi(ptr_now[2])) // 1.2.3 < 1.2.4 { mode_validation = MODE_VALIDATION_MAJ_AUCUNE; break; } if (atoi(ptr_new[4]) > atoi(ptr_now[2])) break; // 1.2.4 > 1.2.3 // Egalité des versions : mode_validation = MODE_VALIDATION_MAJ_AUCUNE; // 1.2.3 = 1.2.3 } while(0); if (mode_validation == MODE_VALIDATION_MAJ_AUCUNE) { sprintf(tmp, "Le fichier archive [%s] ne peut pas être traité car sa version n'est pas strictement postérieure à la version en cours [%s] et son flag [Version_back_enable] est False.", dir->d_name, systeme.package_no_version); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } } else // Si la structure de version n'est pas de la forme "x.y.z', on rejette le fichier car on aun problème de structure générale : { mode_validation = MODE_VALIDATION_MAJ_AUCUNE; sprintf(tmp, "Le fichier archive [%s] ne peut pas être traité car la version actuelle [%s] a un format non valide.", dir->d_name, systeme.package_no_version); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } else // Si le flag 'Version_back_enable' est 'true', alors il est inutile de vérifier l'antériorité de la version actuelle... { sprintf(tmp, "Le fichier archive [%s] est considéré comme valide puisque son flag [Version_back_enable] est True.", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); } } else // Si la structure de nom de fichier n'a pas 6 segments autour des '_', on le rejette : { mode_validation = MODE_VALIDATION_MAJ_AUCUNE; sprintf(tmp, "Le fichier archive [%s] ne peut pas être traité car son format est non valide (attendu [ShipHeart_v_3_2_1_uf.*]).", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } else // Si la structure de nom de fichier n'a pas de '.' dans le nom, on ne le traite pas : // NB : ce cas ne devrait pas arriver car on a détecté MARQUEUR_FICHIER_TAR_GZIP_ENC (qui contient 3 x '.' !) dans le nom pour arriver ici... Donc pas de message de debug. { mode_validation = MODE_VALIDATION_MAJ_AUCUNE; } } else { sprintf(tmp, "Le mode de validation des mises à jour étant dévalidé [%i], le fichier [%s] n'est pas traité.", mode_validation, dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } // Le traitement dépend du mode de validation en cours : char nom_repertoire_destination[MAX_LONGUEUR_NOM_REPERTOIRE_LOCAL]; uint16_t code_ok = 0, code_erreur = 0; // L'init sert juste à éviter un warning... //------------------------------------------------------------ // Attente validation manuelle => Transfert vers A_VALIDER : if (mode_validation == MODE_VALIDATION_MAJ_MANUELLE) { strcpy(nom_repertoire_destination, REPERTOIRE_VERSIONS_A_VALIDER); code_ok = SYSTEME_COPIE_ARCHIVE_A_VALIDER_OK; code_erreur = SYSTEME_COPIE_ARCHIVE_A_VALIDER_NOK; } //------------------------------------------------------------------ // Validation automatique -> Transfert directement dans A_CHARGER : else if (mode_validation == MODE_VALIDATION_MAJ_AUTOMATIQUE) { strcpy(nom_repertoire_destination, REPERTOIRE_VERSIONS_A_CHARGER); code_ok = SYSTEME_COPIE_ARCHIVE_A_CHARGER_OK; code_erreur = SYSTEME_COPIE_ARCHIVE_A_CHARGER_NOK; } //----------------------------- // Aucune mise à jour : else ; // Vidage des répertoires A_VALIDER et A_CHARGER (la méthode choisie est un peu violente mais efficace...) : // NB : ce vidage est fait dans les 3 cas de 'Mode_validation maj'. En effet, même dans le cas de MAJ_AUCUNE, // on considère que si on vient de recevoir un fichier et qu'on le jette, il faut s'assurer qu'il ne reste pas // un "vieux" fichier dans A_CHARGER ou A_VALIDER... sprintf(commande, "sudo rm -f %s/*", REPERTOIRE_VERSIONS_A_VALIDER); commande_shell(commande); sprintf(commande, "sudo rm -f %s/*", REPERTOIRE_VERSIONS_A_CHARGER); commande_shell(commande); sprintf(tmp, "Les répertoires A_CHARGER et A_VALIDER viennent d'être vidés suite à la réception d'une nouvelle version."); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); // Copie du fichier reçu dans le répertoire ad'hoc : if ((mode_validation == MODE_VALIDATION_MAJ_MANUELLE) || (mode_validation == MODE_VALIDATION_MAJ_AUTOMATIQUE)) { // Copie du fichier reçu : sprintf(commande, "sudo cp -f %s/%s %s/%s", REPERTOIRE_SERVER_DOWNLOAD, dir->d_name, nom_repertoire_destination, dir->d_name); // NB : l'utilisation de '&' en fin de commande pose pb (la copie ne doit pas être terminée quand on tente de renommer ensuite le fichier ?) if (commande_shell(commande) == 0) { // Enregistrement dans l'historique : enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, code_ok, 0, 0, dir->d_name); sprintf(tmp, "Le fichier archive [%s] a été copié avec succès dans le répertoire [%s].", dir->d_name, nom_repertoire_destination); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK); } else { // Enregistrement dans l'historique : enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, code_erreur, 0, 0, dir->d_name); sprintf(tmp, "Le fichier archive [%s] n'a pas ou être copié correctement dans le répertoire [%s].", dir->d_name, nom_repertoire_destination); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } // Renommage du fichier reçu avec le marqueur DONE (dans tous les cas) : sprintf(commande, "mv %s/%s %s/%s%s", REPERTOIRE_SERVER_DOWNLOAD, dir->d_name, REPERTOIRE_SERVER_DOWNLOAD, dir->d_name, MARQUEUR_FICHIER_DONE); commande_shell(commande); // Commande de synchro afin de s'assurer que les modifications de fichier seront bien prises en compte par le système : sprintf(commande, "sudo sync"); commande_shell(commande); } } closedir(repertoire); // Fermeture du répertoire } systeme.flag_new_download = FALSE; // Il faut RAZ le flag pour autoriser les downloads à venir. } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_SYSTEME_DEMARRAGE_IMPOSSIBLE : { break; } //----------------------------------------------------------------------------------------------------------------------------------------- default : { sprintf(tmp, "L'état du séquenceur Système est inconnu [%i]. Il est repositionné au REPOS", systeme.sequenceur.etat); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_REPOS; break; } } //==================================== // Séquenceur de chargement du code : gestion_chargement_code(); } //================================================================================================================================================================== // Fonction : Lecture du fichier JSON de la version courante puis comparaison entre les n° de version présents dans ce fichier, les fichiers présents dans CURRENT // et, surtout, entre le fichier présent dans CURRENT et la version en cours d'éxécution sur les modules sur K-Bus. S'il y a écart, activation du // séquenceur de chargement afin que les fichiers de current soient chargés dans les modules concernés sur K-Bus. // Reçoit : Rien // Renvoit : Rien //================================================================================================================================================================== void check_mise_a_jour(void) { struct dirent *dir; // Les types 'dirent' ou 'DIR' sont déclarés dans le header DIR *repertoire; char nom_fichier[MAX_LONGUEUR_NOM_REPERTOIRE_LOCAL + MAX_LONGUEUR_NOM_FICHIER]; uint16_t i; int16_t comp; struct Struct_json_version json_version; char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; // Parse du fichier de version : sprintf(nom_fichier, "%s/%s%s", REPERTOIRE_VERSIONS_CURRENT, systeme.package_version, MARQUEUR_FICHIER_JSON); #ifdef __DEBUG_SYSTEME_FICHIER_JSON json_version = parse_json_version(nom_fichier, true); #else json_version = parse_json_version(nom_fichier, false); #endif // Traitement des infos du fichier de version : if (strstr(json_version.no_version, "ERREUR") == NULL) // Si la lecture du fichier de version s'est passée normalement { repertoire = opendir(REPERTOIRE_VERSIONS_CURRENT); // Ouverture du répertoire CURRENT 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 '..' //------------------------------------------------------ // Application : if (strstr(dir->d_name, MARQUEUR_FICHIER_APPLICATION) != NULL) { comp = strcmp(dir->d_name, json_version.application); if (comp == 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier Application [%s] trouvé dans le répertoire CURRENT correspond bien au package en cours", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif } else if (comp > 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier Application [%s] trouvé dans le répertoire CURRENT est postérieur au package en cours [%s]. Une mise à jour correcte serait nécessaire...", dir->d_name, json_version.application); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); #endif } else { sprintf(tmp, "Le fichier Application [%s] trouvé dans le répertoire CURRENT est antérieur au package en cours [%s]. Une mise à jour est impérative !!", dir->d_name, json_version.application); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } //------------------------------------------------------ // Application QT : if (strstr(dir->d_name, MARQUEUR_FICHIER_QT) != NULL) { comp = strcmp(dir->d_name, json_version.qt); if (comp == 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier QT [%s] trouvé dans le répertoire CURRENT correspond bien au package en cours", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif } else if (comp > 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier QT [%s] trouvé dans le répertoire CURRENT est postérieur au package en cours [%s]. Une mise à jour correcte serait nécessaire...", dir->d_name, json_version.qt); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); #endif } else { sprintf(tmp, "Le fichier QT [%s] trouvé dans le répertoire CURRENT est antérieur au package en cours [%s]. Une mise à jour est impérative !!", dir->d_name, json_version.qt); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } //------------------------------------------------------ // Firmware Compagnon : if ( ((systeme.generation_shipbase == GENERATION_SHIPBASE_V1) && (strstr(dir->d_name, MARQUEUR_FICHIER_COMPAGNON_V1) != NULL)) || // SDIR #162 (((systeme.generation_shipbase == GENERATION_SHIPBASE_V2) || (systeme.generation_shipbase == GENERATION_SHIPBASE_V3)) && (strstr(dir->d_name, MARQUEUR_FICHIER_COMPAGNON_V2) != NULL)) ) // if (strstr(dir->d_name, MARQUEUR_FICHIER_COMPAGNON) != NULL) // SDIR #162 { comp = strcmp(dir->d_name, json_version.compagnon); // Comparaison entre le fichier réellement présent dans CURRENT et la version de firmware indiquée dans le fichier de version : if (comp == 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier Compagnon [%s] trouvé dans le répertoire CURRENT correspond bien au package en cours", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif } else if (comp > 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier Compagnon [%s] trouvé dans le répertoire CURRENT est postérieur au package en cours [%s]. Une mise à jour correcte serait nécessaire...", dir->d_name, json_version.compagnon); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); #endif } else { sprintf(tmp, "Le fichier Compagnon [%s] trouvé dans le répertoire CURRENT est antérieur au package en cours [%s]. Une mise à jour est impérative !!", dir->d_name, json_version.compagnon); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } // Comparaison entre le fichier présent dans CURRENT et la version en cours d'éxécution sur le Compagnon : if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1) sprintf(nom_fichier, "%s_%s.bin", MARQUEUR_FICHIER_COMPAGNON_V1, systeme.modules_physiques[0].soft_version); else sprintf(nom_fichier, "%s_%s.bin", MARQUEUR_FICHIER_COMPAGNON_V2, systeme.modules_physiques[0].soft_version); // SDIR #137 : if (((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_NORMAL) && (strcmp(dir->d_name, nom_fichier) > 0)) || // Si le fichier dans CURRRENT est plus récent que le firmware en cours d'excéution (flag de MAJ des firmwares = 0 = Normal) ((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_SI_DIFFERENTS) && (strcmp(dir->d_name, nom_fichier) != 0)) || // ... OU si le fichier est juste différent mais le flag de MAJ des firmwares est à 1 (systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_TOUJOURS) ) // ... OU le flag de MAJ des firmwares est à 2 // Fin de SDIR #137 { if ((chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS) || (chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT)) { strcpy(chargement_code.nom_fichier[0], dir->d_name); // Stockage du nom de fichier à utiliser pour le chargement de code chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT; sprintf(tmp, "Le fichier Compagnon [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution [%s]. Le fichier va être chargé sur le Compagnon", dir->d_name, nom_fichier); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } else { sprintf(tmp, "Le fichier Compagnon [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution [%s]. Mais le séquenceur de chargement de code est occupé (état = %i) et le code ne peut donc pas être chargé sur le Compagnon.", dir->d_name, systeme.modules_physiques[0].soft_version, chargement_code.sequenceur.etat); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } } //------------------------------------------------------ // Firmware SP812 : if (strstr(dir->d_name, MARQUEUR_FICHIER_SP812) != NULL) { comp = strcmp(dir->d_name, json_version.sp812); // Comparaison entre le fichier réellement présent dans CURRENT et la version de firmware indiquée dans le fichier de version : if (comp == 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier SP812 [%s] trouvé dans le répertoire CURRENT correspond bien au package en cours", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif } else if (comp > 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier SP812 [%s] trouvé dans le répertoire CURRENT est postérieur au package en cours [%s]. Une mise à jour correcte serait nécessaire...", dir->d_name, json_version.sp812); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); #endif } else { sprintf(tmp, "Le fichier SP812 [%s] trouvé dans le répertoire CURRENT est antérieur au package en cours [%s]. Une mise à jour est impérative !!", dir->d_name, json_version.sp812); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } // Comparaison entre le fichier présent dans CURRENT et la version en cours d'éxécution sur chaque SP812 : for (i = 0; i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes if (systeme.modules_physiques[i].type != TYPE_CARTE_SP812) continue; // On ne traite que les cartes de type SP812 pour ce type de fichier de code sprintf(nom_fichier, "%s_%s.bin", MARQUEUR_FICHIER_SP812, systeme.modules_physiques[i].soft_version); // SDIR #137 : if (((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_NORMAL) && (strcmp(dir->d_name, nom_fichier) > 0)) || // Si le fichier dans CURRRENT est plus récent que le firmware en cours d'excéution (flag de MAJ des firmwares = 0 = Normal) ((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_SI_DIFFERENTS) && (strcmp(dir->d_name, nom_fichier) != 0)) || // ... OU si le fichier est juste différent mais le flag de MAJ des firmwares est à 1 (systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_TOUJOURS) ) // ... OU le flag de MAJ des firmwares est à 2 // Fin de SDIR #137 { if ((chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS) || (chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT)) { strcpy(chargement_code.nom_fichier[i], dir->d_name); // Stockage du nom de fichier à utiliser pour le chargement de code chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT; sprintf(tmp, "Le fichier SP812 [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution sur la carte n° %i [%s]. Le fichier va être chargé sur le SP812", dir->d_name, i, systeme.modules_physiques[i].soft_version); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } else { sprintf(tmp, "Le fichier SP812 [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution sur la carte n° %i [%s]. Mais le séquenceur de chargementd e code est occupé (état = %i) et le code ne peut donc pas être chargé sur le SP812.", dir->d_name, i, systeme.modules_physiques[0].soft_version, chargement_code.sequenceur.etat); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } } } //------------------------------------------------------ // Firmware ShipBS : if (strstr(dir->d_name, MARQUEUR_FICHIER_SBS) != NULL) { comp = strcmp(dir->d_name, json_version.sbs); // Comparaison entre le fichier réellement présent dans CURRENT et la version de firmware indiquée dans le fichier de version : if (comp == 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier ShipBS [%s] trouvé dans le répertoire CURRENT correspond bien au package en cours", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif } else if (comp > 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier ShipBS [%s] trouvé dans le répertoire CURRENT est postérieur au package en cours [%s]. Une mise à jour correcte serait nécessaire...", dir->d_name, json_version.sbs); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); #endif } else { sprintf(tmp, "Le fichier ShipBS [%s] trouvé dans le répertoire CURRENT est antérieur au package en cours [%s]. Une mise à jour est impérative !!", dir->d_name, json_version.sbs); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } // Comparaison entre le fichier présent dans CURRENT et la version en cours d'éxécution sur chaque ShipBS : for (i = 0; i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes if (systeme.modules_physiques[i].type != TYPE_CARTE_SBS) continue; // On ne traite que les cartes de type ShipBS pour ce type de fichier de code sprintf(nom_fichier, "%s_%s.bin", MARQUEUR_FICHIER_SBS, systeme.modules_physiques[i].soft_version); // SDIR #137 : // if (strcmp(dir->d_name, nom_fichier) > 0) // Si le fichier dans CURRRENT est plus récent que le firmware en cours d'exécution, le fichier va être chargé if (((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_NORMAL) && (strcmp(dir->d_name, nom_fichier) > 0)) || // Si le fichier dans CURRRENT est plus récent que le firmware en cours d'excéution (flag de MAJ des firmwares = 0 = Normal) ((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_SI_DIFFERENTS) && (strcmp(dir->d_name, nom_fichier) != 0)) || // ... OU si le fichier est juste différent mais le flag de MAJ des firmwares est à 1 (systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_TOUJOURS) ) // ... OU le flag de MAJ des firmwares est à 2 // Fin de SDIR #137 { if ((chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS) || (chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT)) { strcpy(chargement_code.nom_fichier[i], dir->d_name); // Stockage du nom de fichier à utiliser pour le chargement de code chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT; sprintf(tmp, "Le fichier ShipBS [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution sur la carte n° %i [%s]. Le fichier va être chargé sur le ShipBS", dir->d_name, i, systeme.modules_physiques[i].soft_version); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } else { sprintf(tmp, "Le fichier ShipBS [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution sur la carte n° %i [%s]. Mais le séquenceur de chargementd e code est occupé (état = %i) et le code ne peut donc pas être chargé sur le ShipBS.", dir->d_name, i, systeme.modules_physiques[0].soft_version, chargement_code.sequenceur.etat); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } } } //------------------------------------------------------ // Firmware SP4AC : if (strstr(dir->d_name, MARQUEUR_FICHIER_SP4AC) != NULL) { comp = strcmp(dir->d_name, json_version.sp4ac); // Comparaison entre le fichier réellement présent dans CURRENT et la version de firmware indiquée dans le fichier de version : if (comp == 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier SP4AC [%s] trouvé dans le répertoire CURRENT correspond bien au package en cours", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif } else if (comp > 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier SP4AC [%s] trouvé dans le répertoire CURRENT est postérieur au package en cours [%s]. Une mise à jour correcte serait nécessaire...", dir->d_name, json_version.sp4ac); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); #endif } else { sprintf(tmp, "Le fichier SP4AC [%s] trouvé dans le répertoire CURRENT est antérieur au package en cours [%s]. Une mise à jour est impérative !!", dir->d_name, json_version.sp4ac); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } // Comparaison entre le fichier présent dans CURRENT et la version en cours d'éxécution sur chaque SP4AC : for (i = 0; i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes if (systeme.modules_physiques[i].type != TYPE_CARTE_SP4AC) continue; // On ne traite que les cartes de type SP4AC pour ce type de fichier de code sprintf(nom_fichier, "%s_%s.bin", MARQUEUR_FICHIER_SP4AC, systeme.modules_physiques[i].soft_version); // SDIR #137 : // if (strcmp(dir->d_name, nom_fichier) > 0) // Si le fichier dans CURRRENT est plus récent que le firmware en cours d'exécution, le fichier va être chargé if (((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_NORMAL) && (strcmp(dir->d_name, nom_fichier) > 0)) || // Si le fichier dans CURRRENT est plus récent que le firmware en cours d'excéution (flag de MAJ des firmwares = 0 = Normal) ((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_SI_DIFFERENTS) && (strcmp(dir->d_name, nom_fichier) != 0)) || // ... OU si le fichier est juste différent mais le flag de MAJ des firmwares est à 1 (systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_TOUJOURS) ) // ... OU le flag de MAJ des firmwares est à 2 // Fin de SDIR #137 { if ((chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS) || (chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT)) { strcpy(chargement_code.nom_fichier[i], dir->d_name); // Stockage du nom de fichier à utiliser pour le chargement de code chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT; sprintf(tmp, "Le fichier SP4AC [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution sur la carte n° %i [%s]. Le fichier va être chargé sur le SP4AC", dir->d_name, i, systeme.modules_physiques[i].soft_version); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } else { sprintf(tmp, "Le fichier SP4AC [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution sur la carte n° %i [%s]. Mais le séquenceur de chargementd e code est occupé (état = %i) et le code ne peut donc pas être chargé sur le SP4AC.", dir->d_name, i, systeme.modules_physiques[0].soft_version, chargement_code.sequenceur.etat); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } } } //------------------------------------------------------ // Firmware SP8DC : if (strstr(dir->d_name, MARQUEUR_FICHIER_SP8DC) != NULL) { comp = strcmp(dir->d_name, json_version.sp8dc); // Comparaison entre le fichier réellement présent dans CURRENT et la version de firmware indiquée dans le fichier de version : if (comp == 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier SP8DC [%s] trouvé dans le répertoire CURRENT correspond bien au package en cours", dir->d_name); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif } else if (comp > 0) { #ifdef __DEBUG_SYSTEME_MISE_A_JOUR sprintf(tmp, "Le fichier SP8DC [%s] trouvé dans le répertoire CURRENT est postérieur au package en cours [%s]. Une mise à jour correcte serait nécessaire...", dir->d_name, json_version.sp8dc); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); #endif } else { sprintf(tmp, "Le fichier SP8DC [%s] trouvé dans le répertoire CURRENT est antérieur au package en cours [%s]. Une mise à jour est impérative !!", dir->d_name, json_version.sp8dc); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } // Comparaison entre le fichier présent dans CURRENT et la version en cours d'éxécution sur chaque SP8DC : for (i = 0; i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes if (systeme.modules_physiques[i].type != TYPE_CARTE_SP8DC) continue; // On ne traite que les cartes de type SP8DC pour ce type de fichier de code sprintf(nom_fichier, "%s_%s.bin", MARQUEUR_FICHIER_SP8DC, systeme.modules_physiques[i].soft_version); // SDIR #137 : // if (strcmp(dir->d_name, nom_fichier) > 0) // Si le fichier dans CURRRENT est plus récent que le firmware en cours d'exécution, le fichier va être chargé if (((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_NORMAL) && (strcmp(dir->d_name, nom_fichier) > 0)) || // Si le fichier dans CURRRENT est plus récent que le firmware en cours d'excéution (flag de MAJ des firmwares = 0 = Normal) ((systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_SI_DIFFERENTS) && (strcmp(dir->d_name, nom_fichier) != 0)) || // ... OU si le fichier est juste différent mais le flag de MAJ des firmwares est à 1 (systeme.mode_maj_firmwares == MODE_MAJ_FIRMWARES_TOUJOURS) ) // ... OU le flag de MAJ des firmwares est à 2 // Fin de SDIR #137 { if ((chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS) || (chargement_code.sequenceur.etat == ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT)) { strcpy(chargement_code.nom_fichier[i], dir->d_name); // Stockage du nom de fichier à utiliser pour le chargement de code chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT; sprintf(tmp, "Le fichier SP8DC [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution sur la carte n° %i [%s]. Le fichier va être chargé sur le SP8DC", dir->d_name, i, systeme.modules_physiques[i].soft_version); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } else { sprintf(tmp, "Le fichier SP8DC [%s] trouvé dans le répertoire CURRENT est postérieur à la version en cours d'exécution sur la carte n° %i [%s]. Mais le séquenceur de chargement de code est occupé (état = %i) et le code ne peut donc pas être chargé sur le SP8DC.", dir->d_name, i, systeme.modules_physiques[0].soft_version, chargement_code.sequenceur.etat); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } } } } } closedir(repertoire); // Fermeture du répertoire } } else ; // Si la lecture du fichier de version n'a pas pu être faite, on ne fait rien... } //================================================================================================================================================================== // Fonction : Activé par la fonction 'check_mise_a_jour()' si un fichier présent dans CURRENT doit être chargé dans 1 ou plusieurs modules sur K-Bus. // Dans ce cas, le séquenceur prend en charge pour toutes les cartes sur K-Bus concerné les phases de : // - effacement de la flash, // - chargement du fichier en gérant les multi-blocs // - calcul du CRC du fichier et celui sur la cible // - lancement procédure de reset lorsque tous les modules devant être chargés l'ont été. // Reçoit : Rien // Renvoit : Rien //================================================================================================================================================================== void gestion_chargement_code(void) { FILE * ptr_fic; uint8_t llsb, lsb, msb, mmsb; uint16_t i; // char commande[MAX_TAILLE_COMMANDE_SHELL]; char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; switch(chargement_code.sequenceur.etat) { //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_INIT : { if (chargement_code.sequenceur.compteur == 0) { chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS; } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS : { break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT : { chargement_code.nb_repetitions = 0; sprintf(tmp, "-1;0"); // Paramètres = 'no_module';'avancement_en_%' (no_module: -1=démarrage, 0-N=No_module en cours, -2=fin) chargement_code.id_message_user = enregistrement_message_users(MESSAGE_USERS_CODE_MAJ_EN_COURS, tmp, MESSAGE_USERS_ETAT_ALERTE); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT_CARTE; break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT_CARTE : { // Recherche de la prochaine carte à charger : for (i = 0; i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes // sprintf(tmp, "\tNom de fichier pour la carte %i = %s", i, chargement_code.nom_fichier[i]); // affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); if (chargement_code.nom_fichier[i][0] != 0) // Si le nom de fichier est nul, c'est qu'il n'y a rien à charger pour cette carte { chargement_code.adresse_module = i; // Dès qu'on trouve une carte à charger, on mémorise son numéro ... break; // ... et on passe au chargement proprement dit } } if (i == MAX_NOMBRE_MODULES) { #ifdef __DEBUG_SYSTEME_CHARGEMENT_CODE sprintf(tmp, "Plus aucune carte n'a besoin d'un chargement"); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_CHARGEMENT; break; } // Ouverture du fichier pour extraire les informations générales : sprintf(tmp, "%s/%s", REPERTOIRE_VERSIONS_CURRENT, chargement_code.nom_fichier[chargement_code.adresse_module]); ptr_fic = fopen(tmp, "rb"); // Ouverture du fichier en "lecture"... if (ptr_fic == NULL) // Si l'ouverture du fichier est impossible : { sprintf(tmp, "L'ouverture du fichier à charger '%s' n'est pas possible. Le chargement du code est abandonné...", chargement_code.nom_fichier[chargement_code.adresse_module]); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_DEBUT_NOK, chargement_code.adresse_module, 0, chargement_code.nom_fichier[chargement_code.adresse_module]); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_ERREUR; break; } // Préparation du chargement de code : fseek (ptr_fic, 0, SEEK_END); // Place le curseur à la fin du fichier chargement_code.taille_fichier = ftell(ptr_fic); // Lit la position du curseur, donc la taille... fseek (ptr_fic, -4, SEEK_END); // Place le curseur à 4 octets de la fin du fichier llsb = (uint8_t)fgetc(ptr_fic); lsb = (uint8_t)fgetc(ptr_fic); msb = (uint8_t)fgetc(ptr_fic); mmsb = (uint8_t)fgetc(ptr_fic); chargement_code.crc_fichier = (uint32_t)(mmsb << 24) | (uint32_t)(msb << 16) | (uint32_t)(lsb << 8) | (uint32_t)llsb; #ifdef __DEBUG_SYSTEME_CHARGEMENT_CODE sprintf(tmp, "Fichier à charger : [%s] - %i octets - CRC = %08Xh", chargement_code.nom_fichier[chargement_code.adresse_module], chargement_code.taille_fichier, chargement_code.crc_fichier); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif chargement_code.no_bloc = 0; chargement_code.nb_transmis = 0; fclose(ptr_fic); // Fermeture du fichier #ifdef __DEBUG_SYSTEME_CHARGEMENT_CODE sprintf(tmp, "Envoi de la commande d'effacement de la flash sur carte n° %i", chargement_code.adresse_module); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif // Mise à jour du message User pour l'informer de l'avancement : sprintf(tmp, "%i;0", chargement_code.adresse_module); // Paramètres = 'no_module';'avancement_en_%' (no_module: -1=démarrage, 0-N=No_module en cours, -2=fin) maj_message_users(chargement_code.id_message_user, tmp, MESSAGE_USERS_ETAT_ALERTE); enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_DEBUT_OK, chargement_code.adresse_module, 0, chargement_code.nom_fichier[chargement_code.adresse_module]); c_bus_down_commande_chargement_code(CHARGEMENT_CODE_MODE_EFFACEMENT_FLASH, chargement_code.adresse_module); // Commande d'effacement de la flash chargement_code.sequenceur.compteur = CHARGEMENT_CODE_TEMPO_ATTENTE_EFFACEMENT_FLASH; // De l'ordre de 2-3 secondes chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_EFFACEMENT_FLASH; break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_EFFACEMENT_FLASH : { if (chargement_code.sequenceur.compteur == 0) { if (chargement_code.status_reponse == 0) { c_bus_down_commande_chargement_code(CHARGEMENT_CODE_MODE_CHARGEMENT_BLOC, chargement_code.adresse_module); // Envoi du prochain bloc #ifdef __DEBUG_SYSTEME_CHARGEMENT_CODE sprintf(tmp, "\tChargement bloc n° %3i Ok (taille bloc = %3i octets, taille totale = %7i octets, soit %i%%)", chargement_code.no_bloc, chargement_code.taille_bloc, chargement_code.nb_transmis, ((chargement_code.nb_transmis * 100) / chargement_code.taille_fichier)); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif chargement_code.sequenceur.compteur_time_out = CHARGEMENT_CODE_TIME_OUT_ATTENTE_ECRITURE_BLOC; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_CHARGEMENT_BLOC; } else { sprintf(tmp, "Retour d'effacement de flash en erreur sur la carte n° %i (erreur [%i])", chargement_code.adresse_module, chargement_code.status_reponse); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_ERASE_FLASH_NOK, chargement_code.adresse_module, 0, chargement_code.nom_fichier[chargement_code.adresse_module]); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_ERREUR; } } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_CHARGEMENT_BLOC : { if (chargement_code.sequenceur.compteur_time_out == 0) { sprintf(tmp, "Déclenchement de time-out lors du chargement du bloc n° %i sur la carte n° %i", chargement_code.no_bloc, chargement_code.adresse_module); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_ECRITURE_FLASH_NOK, chargement_code.adresse_module, 0, chargement_code.nom_fichier[chargement_code.adresse_module]); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_ERREUR; } if (chargement_code.flag_reponse == TRUE) { if (chargement_code.status_reponse == 0) { if (chargement_code.nb_transmis < chargement_code.taille_fichier) // Il reste des données à transmettre { chargement_code.no_bloc ++; if (chargement_code.adresse_module == 0) chargement_code.sequenceur.compteur = CHARGEMENT_CODE_TEMPO_ATTENTE_INTER_BLOCS_COMPAGNON; // Petite attente si le chargement concerne le Compagnon... else chargement_code.sequenceur.compteur = CHARGEMENT_CODE_TEMPO_ATTENTE_INTER_BLOCS_K_BUS; // ... mais attente plus importante s'il est destiné à une carte sur K-Bus (cette tempo permet au Compagnon d'écouler sur K-Bus les commandes consécutives) chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_ATTENTE_INTER_BLOCS; } else { #ifdef __DEBUG_SYSTEME_CHARGEMENT_CODE sprintf(tmp, "Demande de vérification du CRC sur la carte n° %i", chargement_code.adresse_module); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif c_bus_down_commande_chargement_code(CHARGEMENT_CODE_MODE_CHECK_CRC, chargement_code.adresse_module); // Demande de vérification du CRC chargement_code.sequenceur.compteur_time_out = CHARGEMENT_CODE_TIME_OUT_ATTENTE_ECRITURE_BLOC; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_VERIFICATION_CRC; } } else { sprintf(tmp, "La dernière commande de chargement de code est revenue en erreur (code [%i]). Le séquenceur de chargement de code est repositionné au repos.", chargement_code.status_reponse); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_ECRITURE_FLASH_NOK, chargement_code.adresse_module, 0, chargement_code.nom_fichier[chargement_code.adresse_module]); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_ERREUR; } } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_ATTENTE_INTER_BLOCS : { if (chargement_code.sequenceur.compteur == 0) { c_bus_down_commande_chargement_code(CHARGEMENT_CODE_MODE_CHARGEMENT_BLOC, chargement_code.adresse_module); // Envoi du prochain bloc #ifdef __DEBUG_SYSTEME_CHARGEMENT_CODE sprintf(tmp, "\tChargement bloc n° %3i Ok (taille bloc = %3i octets, taille totale = %7i octets, soit %i%%)", chargement_code.no_bloc, chargement_code.taille_bloc, chargement_code.nb_transmis, ((chargement_code.nb_transmis * 100) / chargement_code.taille_fichier)); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif // Mise à jour du message User pour l'informer de l'avancement : sprintf(tmp, "%i;%i", chargement_code.adresse_module, (chargement_code.nb_transmis * 100) / chargement_code.taille_fichier); // Paramètres = 'no_module';'avancement_en_%' (no_module: -1=démarrage, 0-N=No_module en cours, -2=fin) maj_message_users(chargement_code.id_message_user, tmp, MESSAGE_USERS_ETAT_ALERTE); chargement_code.sequenceur.compteur_time_out = CHARGEMENT_CODE_TIME_OUT_ATTENTE_ECRITURE_BLOC; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_CHARGEMENT_BLOC; } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_VERIFICATION_CRC : { if (chargement_code.sequenceur.compteur_time_out == 0) { sprintf(tmp, "Déclenchement de time-out lors de la vérification du CRC sur la carte n° %i", chargement_code.adresse_module); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_CRC_FLASH_NOK, chargement_code.adresse_module, 0, chargement_code.nom_fichier[chargement_code.adresse_module]); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_ERREUR; } if (chargement_code.flag_reponse == TRUE) { if (chargement_code.status_reponse == 0) { #ifdef __DEBUG_SYSTEME_CHARGEMENT_CODE sprintf(tmp, "Le CRC de la nouvelle version de logiciel chargé sur la carte n° %i est valide", chargement_code.adresse_module); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_CARTE; } else { sprintf(tmp, "Retour de vérification de CRC en erreur sur la carte n° %i. Le séquenceur de chargement est repositionné au repos. ", chargement_code.adresse_module); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_ECRITURE_FLASH_NOK, chargement_code.adresse_module, 0, chargement_code.nom_fichier[chargement_code.adresse_module]); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_ERREUR; } } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_CARTE : { for (i = (chargement_code.adresse_module + 1); i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes if (strcmp(chargement_code.nom_fichier[i], chargement_code.nom_fichier[chargement_code.adresse_module]) == 0) break; // Si une carte à venir doit recevoir le même fichier } systeme.modules_physiques[chargement_code.adresse_module].maj_soft_disponible = 1; // Mise à jour du flag de disponibilité d'une nouvelle version pour la carte chargement_code.nom_fichier[chargement_code.adresse_module][0] = 0; // Suppression du besoin pour cette carte #ifdef __DEBUG_SYSTEME_CHARGEMENT_CODE sprintf(tmp, "Le chargement de la nouvelle version de logiciel pour la carte n° %i est terminé", chargement_code.adresse_module); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); #endif chargement_code.nb_repetitions = 0; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT_CARTE; break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_CHARGEMENT: { // RAZ de tous les noms de fichier de chargements (dans le doute) : for (i = 0; i < MAX_NOMBRE_MODULES; i ++) chargement_code.nom_fichier[i][0] = 0; // Activation de la nouvelle version sur toutes les cartes ayant reçu une nouvelle version de firmware : bool flag_carte_chargee = false; for (i = 0; i < MAX_NOMBRE_MODULES; i ++) { if (systeme.modules_physiques[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes if (systeme.modules_physiques[i].maj_soft_disponible != 0) { flag_carte_chargee = TRUE; c_bus_down_commande_chargement_code(CHARGEMENT_CODE_MODE_VALIDATION_VERSION, i); // Demande d'activation de la nouvelle version chargée systeme.modules_physiques[i].maj_soft_disponible = 0; // RAZ du flag enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_FIN_OK, 0, 0, chargement_code.nom_fichier[i]); sprintf(tmp, "Activation de la nouvelle version de firmware adressée à la carte n° %i", i); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); } } if (flag_carte_chargee) { sprintf(tmp, "Une ou plusieurs cartes ont été chargées avec une nouvelle version de firmware => réinitialisation du système pour prise en compte par leur bootloader"); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); sprintf(tmp, "-2;0"); // Paramètres = 'id_module';'avancement_en_%' (id_module: -1=démarrage, 0-N=Id_module en cours, -2=fin) maj_message_users(chargement_code.id_message_user, tmp, MESSAGE_USERS_ETAT_ALERTE); chargement_code.sequenceur.compteur = CHARGEMENT_CODE_TEMPO_ATTENTE_FIN_ACTIVATION; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_ACTIVATION; } else { sprintf(tmp, "Aucune carte n'a été chargée avec une nouvelle version de firmware => la mise à jour est terminée"); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); maj_message_users(chargement_code.id_message_user, "", MESSAGE_USERS_ETAT_SUPPRESSION); // Suppression du message devenu inutile chargement_code.id_message_user = 0; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS; // Probablement inutile } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_ACTIVATION: { if (chargement_code.sequenceur.compteur == 0) { maj_message_users(chargement_code.id_message_user, "", MESSAGE_USERS_ETAT_SUPPRESSION); // Suppression du message juste avant la réinit... chargement_code.id_message_user = 0; lancement_reinit(0); // La valeur 0 indique d'utiliser la valeur par défaut chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS; // Probablement inutile } break; } //----------------------------------------------------------------------------------------------------------------------------------------- case ETAT_SEQUENCEUR_CHARGEMENT_CODE_ERREUR: { if ((++ chargement_code.nb_repetitions) >= MAX_REPETITIONS_CHARGEMENT_CODE) { sprintf(tmp, "Le nombre de répétitions maximal a été atteint (%i). Le chargement de code est abandonné.", MAX_REPETITIONS_CHARGEMENT_CODE); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CHARGEMENT_CODE_FIN_NOK, chargement_code.adresse_module, 0, chargement_code.nom_fichier[chargement_code.adresse_module]); maj_message_users(chargement_code.id_message_user, "", MESSAGE_USERS_ETAT_SUPPRESSION); // Suppression du message de mise à jour chargement_code.id_message_user = 0; chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS; } else { sprintf(tmp, "Le chargement de code est relancé pour le %i ème fois sur cette carte", chargement_code.nb_repetitions); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT_CARTE; } break; } //----------------------------------------------------------------------------------------------------------------------------------------- default : { sprintf(tmp, "L'état du séquenceur de Chargement de Code est inconnu [%i]. Il est repositionné au REPOS", chargement_code.sequenceur.etat); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); chargement_code.sequenceur.etat = ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS; break; } } } //================================================================================================================================================================== // Fonction : Fonction appelée à la fin de chaque boucle principale. Elle commence par faire une courte attente pour éviter que l'application de consomme 100% // de temps CPU ! // Reçoit : Rien // Renvoit : Rien //================================================================================================================================================================== void supervision(void) { struct timespec gettime_now; // Attente pour ralentir la boucle principale : delai_nano_sec(SYSTEME_ATTENTE_BOUCLE_PRINCIPALE_TEMPO); // Supervision de la vitesse de boucle principale : clock_gettime(CLOCK_REALTIME, &gettime_now); if (supervision_boucle_principale.last_second == gettime_now.tv_sec) supervision_boucle_principale.nb_en_cours ++; else { supervision_boucle_principale.last_second = gettime_now.tv_sec; if (supervision_boucle_principale.attente_premieres_mesures == 0) // Si on n'est plus dans la phase d'attente initiale : { supervision_boucle_principale.nb_boucles += supervision_boucle_principale.nb_en_cours; supervision_boucle_principale.nb_secondes ++; //printf("Compteur de boucles principales = %i\n", supervision_boucle_principale.nb_en_cours); } else supervision_boucle_principale.attente_premieres_mesures --; // En phase d'attente initiale, on décrémente le compteur d'attente... supervision_boucle_principale.nb_en_cours = 0; } } //================================================================================================================================================================== // Fonction : Fonction appelée suite à la sortie de la boucle principale (suite à réception d'un signal d'arrêt - de la part d'un utilisateur ou par une erreur // majeure). Elle enregistre l'arrêt dans le fichier de log et l'historique (autant que possbible). Puis elle libère au maximum les ressources matérielles // utilisées par l'application. // Reçoit : Rien // Renvoit : Rien //================================================================================================================================================================== void arret_programme(void) { char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; // Enregistrement dans le fichier de debug : sprintf(tmp, "Arrêt du programme demandé. Fermeture en cours..."); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); // Enregistrement dans l'historique : enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_ARRET, 0, 0, NULL); // Info au Compagnon et MAJ dans la BDD avant fermeture : maj_etat_cm3p(OFF); // Maj du flag, de la BDD et de la sortie physique //Fermeture de MySQL : mysql_close(bdd.pointeur); // Désactivation des sorties de commandes d'alimentations : // ecriture_sortie(TYPE_SORTIE_GPIO, 0, CM3P_DO_USBPWR_EN, OFF); // Coupure de l'alim des USB /!\ Il ne faut PAS couper en mode debuug ous peine de ne plus avoir accès au réseau Ethernet via le routeur USB/Ethernet....! // ecriture_sortie(TYPE_SORTIE_GPIO, 0, audio.cle_primaire_sortie_cm_do_audio_sd, OFF); // Coupure du circuit audio // ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.cle_primaire_sortie_cm_pdown_hdmi_cmd_n, OFF); // Coupure de la sortie du flux HDMI // ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.cle_primaire_sortie_cm_do_lcd_en_vgx, OFF); // Coupure de l'alim VGx // ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.cle_primaire_sortie_cm_do_lcd_en_vdd, OFF); // Coupure de l'alim VDD (après VGx !) // Libération des ports série : if ((config_serial0.validite == 1) && (config_serial0.filestream != -1)) close(config_serial0.filestream); if ((config_serial1.validite == 1) && (config_serial1.filestream != -1)) close(config_serial1.filestream); // Libération des projections dans l'espace virtuel d'adressage (normalement fait automatiquement à la fermeture du processus mais on ne sait jamais...) : munmap((uint32_t *)hardware.gpio_base, BLOCK_SIZE); } //================================================================================================================================================================== // Fonction : Fonction générant toutes les commandes lorsqu'une mise à jour de la confguration est nécessaire. // Elle est notamment appelée lorsqu'une modif de configuration a été faite dans la BDD ou que le K-Bus a été réinitialisé // Reçoit : Rien // Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée //================================================================================================================================================================== int8_t re_configuration_systeme(void) { // Forçage d'un enregistrement des mesures avant la reconfiguration (qui va RAZ tous les cumuls) (SDIR #174) : bdd.compteur_enregistrement_mesures = 0; enregistrement_mesures(BDD_ENREGISTREMENT_MESURE_NORMAL); // NB : le timer de mesure est rechargé à l'occasion avec la période normale // Rechargement (presque) complet de la BDD : init_bdd(BDD_MODE_INIT_RELOAD); // Appelle 'maj_etat_cm3p()' puis réinitialise les fonctions CARTES et CIRCUITS. // Relance du séquenceur d'init : systeme.sequenceur.etat = ETAT_SEQUENCEUR_SYSTEME_INIT; // On relance le séquenceur au départ pour effectuer une configuration complète de l'application en fonction du résultat de la reconnaissance réseau faite par le Compagnon sur K-Bus systeme.sequenceur.compteur = 0; // Pas la peine d'attendre... // Mise à jour des fonctions audio : set_volume(audio.consigne_volume, AUDIO_SET_VOLUME_ECHO_OFF); // Mise à jour du volume au niveau matériel. NB : l'alimentation de l'ampli est faite en fin de 'set_volume()' et tient compte de l'état de 'Fonction_jack' // Commandes spécifiques Compagnon : c_bus_down_commande_config_level_sensors(); // Utile dans la cas où la configuration des Level Sensors aurait changé (par exempe de via QT et la BDD) return(0); } //================================================================================================================================================================== // Fonction : Lance l'exécution de la commande reçue en paramètre et vérifie son exécution. // Reçoit : La chaine de la commande // Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée //================================================================================================================================================================== int32_t commande_shell(char * commande) { int32_t retour; char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; retour = system(commande); if (retour != 0) { sprintf(tmp, "Le retour de la commande shell [%s] est en erreur (code = %i)", commande, retour); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); } /* else { sprintf(tmp, "La commande shell [%s] a été lancée sans erreur.", commande); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT); } */ return (retour); } //================================================================================================================================================================== // Fonction : Lit le fichier dont le nom est reçu en paramètre et récupère les champs d'un fichier de version. // Reçoit : Le nom du fichier JSON à parser + un flag de verbose // Renvoit : Une structure contenant les champs d'un fichier de version. NB : si erreur, le champ 'no_version' contient la chaine "ERREUR" //================================================================================================================================================================== struct Struct_json_version parse_json_version(char * nom_fichier, bool verbose) { FILE *fp; char buffer[MAX_TAILLE_FICHIER_JSON]; struct json_object *parsed_json; struct json_object *obj_no_version; struct json_object *obj_updater; struct json_object *obj_application; struct json_object *obj_qt; struct json_object *obj_compagnon; struct json_object *obj_sp812; struct json_object *obj_sbs; struct json_object *obj_sp4ac; struct json_object *obj_sp8dc; struct json_object *obj_sql; struct json_object *obj_force; struct json_object *obj_description; struct Struct_json_version json_version; char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; fp = fopen(nom_fichier,"r"); if (fp == NULL) { sprintf(tmp, "Erreur d'ouverture du fichier [%s]\n", nom_fichier); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); strcpy(json_version.no_version, "ERREUR"); // Marqueur d'erreur return (json_version); } fread(&buffer, 1, MAX_TAILLE_FICHIER_JSON, fp); // Lecture du fichier dans Buffer. fclose(fp); parsed_json = json_tokener_parse(buffer); if (parsed_json == NULL) { sprintf(tmp, "Erreur de parse du fichier [%s].\n", nom_fichier); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); strcpy(json_version.no_version, "ERREUR"); // Marqueur d'erreur return (json_version); } json_object_object_get_ex(parsed_json, "NoVersion", &obj_no_version); json_object_object_get_ex(parsed_json, "Updater", &obj_updater); json_object_object_get_ex(parsed_json, "Application", &obj_application); json_object_object_get_ex(parsed_json, "QT", &obj_qt); if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1) json_object_object_get_ex(parsed_json, "Compagnon_v1", &obj_compagnon); else json_object_object_get_ex(parsed_json, "Compagnon_v2", &obj_compagnon); json_object_object_get_ex(parsed_json, "SP812", &obj_sp812); json_object_object_get_ex(parsed_json, "SBS", &obj_sbs); json_object_object_get_ex(parsed_json, "SP4AC", &obj_sp4ac); json_object_object_get_ex(parsed_json, "SP8DC", &obj_sp8dc); json_object_object_get_ex(parsed_json, "SQL", &obj_sql); json_object_object_get_ex(parsed_json, "Force", &obj_force); json_object_object_get_ex(parsed_json, "Description", &obj_description); if (obj_no_version != NULL) strcpy(json_version.no_version, json_object_get_string(obj_no_version)); else strcpy(json_version.no_version, "...inconnue..."); if (obj_updater != NULL) strcpy(json_version.updater, json_object_get_string(obj_updater)); else strcpy(json_version.updater, "...inconnue..."); if (obj_application != NULL) strcpy(json_version.application, json_object_get_string(obj_application)); else strcpy(json_version.application, "...inconnue..."); if (obj_qt != NULL) strcpy(json_version.qt, json_object_get_string(obj_qt)); else strcpy(json_version.qt, "...inconnue..."); if (obj_compagnon != NULL) strcpy(json_version.compagnon, json_object_get_string(obj_compagnon)); else strcpy(json_version.compagnon, "...inconnue..."); if (obj_sp812 != NULL) strcpy(json_version.sp812, json_object_get_string(obj_sp812)); else strcpy(json_version.sp812, "...inconnue..."); if (obj_sbs != NULL) strcpy(json_version.sbs, json_object_get_string(obj_sbs)); else strcpy(json_version.sbs, "...inconnue..."); if (obj_sp4ac != NULL) strcpy(json_version.sp4ac, json_object_get_string(obj_sp4ac)); else strcpy(json_version.sp4ac, "...inconnue..."); if (obj_sp8dc != NULL) strcpy(json_version.sp8dc, json_object_get_string(obj_sp8dc)); else strcpy(json_version.sp8dc, "...inconnue..."); if (obj_sql != NULL) strcpy(json_version.sql, json_object_get_string(obj_sql)); else strcpy(json_version.sql, "...inconnue..."); if (obj_force != NULL) json_version.force = json_object_get_boolean(obj_force); else json_version.force = FALSE; if (obj_description != NULL) strcpy(json_version.description, json_object_get_string(obj_description)); else strcpy(json_version.description, "...inconnue..."); if (verbose) { printf("Fichier de version\t\t: [%s]\n", nom_fichier); printf("\tNo de version\t\t: [%s]\n", json_version.no_version); printf("\tUpdater\t\t\t: [%s]\n", json_version.updater); printf("\tApplication\t\t: [%s]\n", json_version.application); printf("\tQT\t\t\t: [%s]\n", json_version.qt); printf("\tCompagnon\t\t: [%s]\n", json_version.compagnon); printf("\tSP812\t\t\t: [%s]\n", json_version.sp812); printf("\tSBS\t\t\t: [%s]\n", json_version.sbs); printf("\tSP4AC\t\t\t: [%s]\n", json_version.sp4ac); printf("\tSP8DC\t\t\t: [%s]\n", json_version.sp8dc); printf("\tSQL\t\t\t: [%s]\n", json_version.sql); printf("\tFlag force\t\t: [%s]\n", json_version.force ? "true" : "false"); printf("\tDescription\t\t: [%s]\n", json_version.description); printf("\n"); } return(json_version); } //================================================================================================================================================================== // Fonction : Envoi le signal reçu au PID reçu (NB : àa peut être SIGKILL ou SIGTERM pour tuer le processus mais ça peut aussi être SIGHUP pour lui demander // de recharger sa config (comme 'hostapd' par exemple). // Reçoit : Le PID du processus à qui envoyer le signal et le signal à envoyer // Renvoit : -1 si erreur, >=0 si Ok (si >0, cela doit représenter le nombre de processus à qui le signel a été envoyé - utilisable si PID est < 0. Pas testé...) //================================================================================================================================================================== int8_t send_signal (int32_t pid, int32_t signal) { int32_t ret; ret = kill(pid, signal); // printf("ret : %d",ret); if ((ret < 0) || (ret > 127)) return(-1); // Ret contient -1 si erreur ou >=0 si Ok else return(ret); } //================================================================================================================================================================== // Fonction : Recherche le PID du processus dont le nom est passé en paramètre // de recharger sa config (comme 'hostapd' par exemple). // Reçoit : Le nom du processus à rechercher, les paramètres éventuels à rechercher // Renvoit : -1 si erreur, >0=PID du processus trouvé //================================================================================================================================================================== int32_t get_pid_from_name (char * nom, char * parametres) { #define MAX_LONGUEUR_NOM_PROCESSUS 50 #define MAX_LONGUEUR_PARAMETRES_PROCESSUS 200 #define MAX_BUFFER 1500 char buf[MAX_BUFFER]; char cde[MAX_LONGUEUR_NOM_PROCESSUS + MAX_LONGUEUR_PARAMETRES_PROCESSUS + 50]; if (strlen(nom) > MAX_LONGUEUR_NOM_PROCESSUS) return(-1); if (strlen(parametres) > MAX_LONGUEUR_PARAMETRES_PROCESSUS) return(-1); // sprintf(cde, "pidof -s %s", nom); sprintf(cde, "pgrep -f '%s.*%s' ", nom, parametres); // Le '.' indique n'importe quel caractère et le '*' s'applique au '.' pou rindiquer "peu importe ne nombre". // char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; // sprintf(tmp, "\tCommande de 'get_pid_from_name' = [ %s ]", cde); // affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); FILE *cmd_pipe = popen(cde, "r"); fgets(buf, MAX_BUFFER, cmd_pipe); int32_t pid = strtoul(buf, NULL, 10); pclose(cmd_pipe); return(pid); } //================================================================================================================================================================== // Fonction : Recherche le nombre de PID actifs dont le nom est passé en paramètre // Reçoit : Le nom du processus à rechercher, les paramètres éventuels à rechercher // Renvoit : -1 si erreur, >0=nombre de PID incluant le nom recherché //================================================================================================================================================================== int32_t get_pid_numbers_from_name (char * nom, char * parametres) { #define MAX_LONGUEUR_NOM_PROCESSUS 50 #define MAX_LONGUEUR_PARAMETRES_PROCESSUS 200 #define MAX_BUFFER 1500 char buf[MAX_BUFFER]; char cde[MAX_LONGUEUR_NOM_PROCESSUS + MAX_LONGUEUR_PARAMETRES_PROCESSUS + 50]; if (strlen(nom) > MAX_LONGUEUR_NOM_PROCESSUS) return(-1); if (strlen(parametres) > MAX_LONGUEUR_PARAMETRES_PROCESSUS) return(-1); sprintf(cde, "ps aux | grep %s | grep ' %s' | grep -cv grep", nom, parametres); // Le '-c' permet d'obtenir uniquement le nombre d'occurences, le '-v' permet d'éliminer les lignes contenant GREP. FILE *cmd_pipe = popen(cde, "r"); fgets(buf, MAX_BUFFER, cmd_pipe); int32_t pid_nb = strtoul(buf, NULL, 10); pclose(cmd_pipe); return(pid_nb); } //================================================================================================================================================================== // Fonction : Recherche la révision du module sur lequel on est en cours d'exécution et en déduit le type et la version de module. // Cf https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#new-style-revision-codes pour plus de précisions (ou des updates...) // Reçoit : Rien // Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée //================================================================================================================================================================== int8_t version_compute_module(void) { FILE *fp; char revcode[32]; uint32_t code; char chaine_valeur[300]; char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; fp = popen("cat /proc/cpuinfo | awk '/Revision/ {print $3}'", "r"); // récupération du code de Révision via la commande "cat /proc/cpuinfo | awk '/Revision/ {print $3}'". Exemple de retour : "c03141" if (fp == NULL) return(-1); // Cas où la commande n'a pas pu être exécutée correctement fgets(revcode, sizeof(revcode), fp); // Lecture de la ligne pclose(fp); // Fermeturre du fichier code = strtol(revcode, NULL, 16); // Conversion en entier long depuis la chaine en hexa systeme.cm.overvoltage_allowed = (code >> 31) & 0x1; systeme.cm.otp_programming_allowed = (code >> 30) & 0x1; systeme.cm.otp_reading_allowed = (code >> 29) & 0x1; systeme.cm.warranty_bit = (code >> 25) & 0x1; systeme.cm.new_style_revision = (code >> 23) & 0x1; systeme.cm.memory_size = (code >> 20) & 0x7; systeme.cm.manufacturer = (code >> 16) & 0x0F; systeme.cm.processor = (code >> 12) & 0x0F; systeme.cm.type = (code >> 4) & 0xFF; systeme.cm.revision = (code >> 0) & 0x0F; if (systeme.cm.new_style_revision == 0) // Ce bit indique le format du code de révision. Le 'new' type est actif depuis le RaspberryPi2 donc on devrait toujours être dans ce cas... { sprintf(tmp, "/!\\ Le bit de style de révision indique un ancien style de révision qui ne peut pas être lu...!"); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return (-1); } else { systeme.cm.chaine_version[0] = 0; // Chaine vide. sprintf(tmp, "Caractéristiques du module :"); //--------------------------------------------------------------- switch (systeme.cm.type) { case 0x00 : { strcpy(chaine_valeur, "A"); break; } case 0x01 : { strcpy(chaine_valeur, "B"); break; } case 0x02 : { strcpy(chaine_valeur, "A+"); break; } case 0x03 : { strcpy(chaine_valeur, "B+"); break; } case 0x04 : { strcpy(chaine_valeur, "2B"); break; } case 0x05 : { strcpy(chaine_valeur, "Alpha"); break; } case 0x06 : { strcpy(chaine_valeur, "CM1"); break; } case 0x08 : { strcpy(chaine_valeur, "3B"); break; } case 0x09 : { strcpy(chaine_valeur, "Zero"); break; } case 0x0A : { strcpy(chaine_valeur, "CM3"); break; } case 0x0C : { strcpy(chaine_valeur, "Zero W"); break; } case 0x0D : { strcpy(chaine_valeur, "3B+"); break; } case 0x0E : { strcpy(chaine_valeur, "3A+"); break; } case 0x0F : { strcpy(chaine_valeur, "Internal Use only"); break; } case 0x10 : { strcpy(chaine_valeur, "CM3+"); break; } case 0x11 : { strcpy(chaine_valeur, "4B"); break; } case 0x12 : { strcpy(chaine_valeur, "Zero 2W"); break; } case 0x13 : { strcpy(chaine_valeur, "400"); break; } case 0x14 : { strcpy(chaine_valeur, "CM4"); break; } case 0x15 : { strcpy(chaine_valeur, "CM4S"); break; } case 0x18 : { strcpy(chaine_valeur, "CM5"); break; } case 0x07 : case 0x0B : default : { sprintf(chaine_valeur, "Inconnu [code = %i]", systeme.cm.type); break; } } affichage_ligne_version_compute_module(tmp, "Type de module", chaine_valeur); strcat(systeme.cm.chaine_version, chaine_valeur); //--------------------------------------------------------------- switch (systeme.cm.memory_size) { case 0 : { strcpy(chaine_valeur, "256Mo"); break; } case 1 : { strcpy(chaine_valeur, "512Mo"); break; } case 2 : { strcpy(chaine_valeur, "1Go"); break; } case 3 : { strcpy(chaine_valeur, "2Go"); break; } case 4 : { strcpy(chaine_valeur, "4Go"); break; } case 5 : { strcpy(chaine_valeur, "8Go"); break; } default : { sprintf(chaine_valeur, "Inconnue [code = %i]", systeme.cm.memory_size); break; } } affichage_ligne_version_compute_module(tmp, "Taille RAM", chaine_valeur); strcat(systeme.cm.chaine_version, "-"); strcat(systeme.cm.chaine_version, chaine_valeur); //--------------------------------------------------------------- switch (systeme.cm.manufacturer) { case 0 : { strcpy(chaine_valeur, "SonyUK"); break; } // Eviter les espaces car moins ces chaines sont utilisées pour remonter la version de Compute Module dans TB_Systeme... case 1 : { strcpy(chaine_valeur, "Egoman"); break; } case 2 : { strcpy(chaine_valeur, "Embest"); break; } case 3 : { strcpy(chaine_valeur, "SonyJapan"); break; } case 4 : { strcpy(chaine_valeur, "Embest"); break; } case 5 : { strcpy(chaine_valeur, "Stadium"); break; } default : { sprintf(chaine_valeur, "Inconnu [code = %i]", systeme.cm.manufacturer); break; } } affichage_ligne_version_compute_module(tmp, "Fabricant", chaine_valeur); strcat(systeme.cm.chaine_version, "-"); strcat(systeme.cm.chaine_version, chaine_valeur); //--------------------------------------------------------------- sprintf(chaine_valeur, "%i", systeme.cm.revision); affichage_ligne_version_compute_module(tmp, "Revision", chaine_valeur); strcat(systeme.cm.chaine_version, "-Rev"); strcat(systeme.cm.chaine_version, chaine_valeur); //--------------------------------------------------------------- if (systeme.cm.overvoltage_allowed == 0) strcpy(chaine_valeur, "Allowed"); else strcpy(chaine_valeur, "Forbidden"); affichage_ligne_version_compute_module(tmp, "Overvoltage", chaine_valeur); strcat(systeme.cm.chaine_version, "-"); if (systeme.cm.overvoltage_allowed == 0) strcat(systeme.cm.chaine_version, "A"); else strcat(systeme.cm.chaine_version, "F"); //--------------------------------------------------------------- if (systeme.cm.otp_programming_allowed == 0) strcpy(chaine_valeur, "Allowed"); else strcpy(chaine_valeur, "Forbidden"); affichage_ligne_version_compute_module(tmp, "OTP Programming", chaine_valeur); if (systeme.cm.otp_programming_allowed == 0) strcat(systeme.cm.chaine_version, "A"); else strcat(systeme.cm.chaine_version, "F"); //--------------------------------------------------------------- if (systeme.cm.otp_reading_allowed == 0) strcpy(chaine_valeur, "Allowed"); else strcpy(chaine_valeur, "Forbidden"); affichage_ligne_version_compute_module(tmp, "OTP Reading", chaine_valeur); if (systeme.cm.otp_reading_allowed == 0) strcat(systeme.cm.chaine_version, "A"); else strcat(systeme.cm.chaine_version, "F"); //--------------------------------------------------------------- if (systeme.cm.warranty_bit == 0) strcpy(chaine_valeur, "Intact"); else strcpy(chaine_valeur, "Warranty has been voided by overclocking"); affichage_ligne_version_compute_module(tmp, "Warranty bit", chaine_valeur); if (systeme.cm.warranty_bit == 0) strcat(systeme.cm.chaine_version, "I"); else strcat(systeme.cm.chaine_version, "V"); //--------------------------------------------------------------- switch (systeme.cm.processor) { case 0 : { strcpy(chaine_valeur, "BCM2835"); break; } case 1 : { strcpy(chaine_valeur, "BCM2836"); break; } case 2 : { strcpy(chaine_valeur, "BCM2837"); break; } case 3 : { strcpy(chaine_valeur, "BCM2711"); break; } case 4 : { strcpy(chaine_valeur, "BCM2712"); break; } default : { sprintf(chaine_valeur, "Inconnu [code = %i]", systeme.cm.processor); break; } } affichage_ligne_version_compute_module(tmp, "Processeur", chaine_valeur); //--------------------------------------------------------------- affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK); //--------------------------------------------------------------- // Détermination de la génération de ShipBase utilisée : if (systeme.cm.type == 0x10) { systeme.generation_shipbase = GENERATION_SHIPBASE_V1; affichage_debug(__FILE__, __LINE__, "Génération de ShipBase\t\t\t\t\t\t\t: Première génération", TYPE_MESSAGE_DEBUG_OK); return 0; } else if (systeme.cm.type == 0x14) { systeme.generation_shipbase = GENERATION_SHIPBASE_V2; affichage_debug(__FILE__, __LINE__, "Génération de ShipBase\t\t\t\t\t\t\t: Seconde génération", TYPE_MESSAGE_DEBUG_OK); return 0; } else if (systeme.cm.type == 0x18) { systeme.generation_shipbase = GENERATION_SHIPBASE_V3; affichage_debug(__FILE__, __LINE__, "Génération de ShipBase\t\t\t\t\t\t\t: Troisième génération", TYPE_MESSAGE_DEBUG_OK); return 0; } else { systeme.generation_shipbase = GENERATION_SHIPBASE_INCONNUE; sprintf(tmp, "Génération de ShipBase inconnue [type de Compute Module = %02Xh]. L'initialisation est arrêtée...", systeme.cm.type); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } } //================================================================================================================================================================== // Fonction : Met en forme et affiche une ligne de version de comupte module // Reçoit : Rien // Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée //================================================================================================================================================================== void affichage_ligne_version_compute_module(char * tmp, char * titre, char * valeur) { char chaine[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; sprintf(chaine, "\n\t\t\t\t\t\t\t%-20s %s", titre, valeur); strcat(tmp, chaine); }