Import initial du projet shipheart_appli
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier _VERSION.C
|
||||
//
|
||||
// Contient le minimum pour effectuer le lien entre le '#define VERSION_LOGICIEL' situé dans le fichier '_version.txt' et l'application.
|
||||
// Pour cela, le fichier '_version.txt' est mis à jour par le fichier 'mak.sh' avant de lancer le make proprement dit. Ainsi, ce fichier txt dispose, avant tout make,
|
||||
// d'un define mis à jour avec le date-code du moment.
|
||||
// Le choix d'un fichier '.txt' plutôt qu'un '.h' traditionnel est uniquement pour que sa mise à jour ne génère pas une recompilation de tous les fichiers '.c' comme cela est
|
||||
// (fort justement) demandé dans le makefile. Donc tous les '.c' (yc _version.c même si ça n'a pas beaucoup d'intérêt) sont mis à jour lors de la modif de n'importe quel '.h'.
|
||||
// Et seul 'version.c' est mis en jour, en plus, à chaque changement de '_version.txt' ; soit à chaque lancement si le fichier bash fait bien son boulot...
|
||||
//
|
||||
// La fonction se contente de renvoyer le pointeur sur la chaine définie dans '_version.txt' afin d'avoir le minimum de lien vec le reste de l'application.
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
#include "_version.txt" // Attention : ce fichier n'est inclus qu'ici (pour ne pas tout recompiler à chaque fois...!). Et il est mis à jour automatiquement par le fichier 'mak.sh'.
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Retourne la chaine de caractère correspondant au date-code actuel mis à jour dans le fichier '_version.txt' par un fichier bash.
|
||||
// Reçoit : Rien
|
||||
// Renvoit : Le pointeur sur la chaine de version
|
||||
//==================================================================================================================================================================
|
||||
char * maj_version_logiciel(void)
|
||||
{
|
||||
|
||||
return (VERSION_LOGICIEL);
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
// **********************************************************************************************************************************************************************************
|
||||
// Fichier AUDIO.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à l'audio.
|
||||
// **********************************************************************************************************************************************************************************
|
||||
|
||||
#define __DEBUG_AUDIO //Décommenter cette ligne pour avoir les messages de debug concernant l'audio
|
||||
|
||||
|
||||
// Include :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
void gestion_audio(void);
|
||||
int8_t init_audio(void);
|
||||
int8_t emission_bip(char * nom_fichier, uint16_t nb_repetitions, uint16_t periode_boucles, uint16_t nb_boucles);
|
||||
int8_t lecture_mp3(char * nom_fichier, uint16_t nb_repetitions);
|
||||
int8_t mise_a_jour_etat_jack();
|
||||
int8_t set_volume(float volume, bool echo);
|
||||
int8_t alimentation_ampli_audio(void);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_audio audio;
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Gestion de l'audio en tâche de fond
|
||||
// Reçoit : Rien
|
||||
// Retourne : Rien
|
||||
//**********************************************************************************************************************************************************************************
|
||||
void gestion_audio(void)
|
||||
{
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
switch(audio.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_AUDIO_INIT :
|
||||
{
|
||||
if (audio.sequenceur.compteur == 0)
|
||||
{
|
||||
audio.sequenceur.etat = ETAT_SEQUENCEUR_AUDIO_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_AUDIO_REPOS :
|
||||
{
|
||||
if (audio.sequenceur.compteur == 0)
|
||||
{
|
||||
audio.sequenceur.compteur = AUDIO_PERIODE_SURVEILLANCE;
|
||||
mise_a_jour_etat_jack();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_AUDIO_DEBUT_BOUCLE :
|
||||
{
|
||||
mise_a_jour_etat_jack(); // Pour que la mise à jour se fasse quand même de temps en temps...
|
||||
|
||||
lecture_mp3(audio.boucle.nom_fichier, audio.boucle.nb_repetitions);
|
||||
audio.sequenceur.compteur = audio.boucle.periode_boucles;
|
||||
audio.sequenceur.etat = ETAT_SEQUENCEUR_AUDIO_TEMPO_BOUCLE;
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_AUDIO_TEMPO_BOUCLE :
|
||||
{
|
||||
if (audio.sequenceur.compteur == 0)
|
||||
{
|
||||
if (audio.boucle.compteur_boucles > 0)
|
||||
{
|
||||
audio.boucle.compteur_boucles --;
|
||||
audio.sequenceur.etat = ETAT_SEQUENCEUR_AUDIO_DEBUT_BOUCLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
audio.boucle.nom_fichier[0] = 0;
|
||||
audio.boucle.nb_repetitions = 0;
|
||||
audio.boucle.periode_boucles = 0;
|
||||
audio.boucle.nb_boucles = 0;
|
||||
audio.sequenceur.etat = ETAT_SEQUENCEUR_AUDIO_REPOS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur Audio est inconnu [%i]. Il est repositionné au REPOS", audio.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
audio.sequenceur.etat = ETAT_SEQUENCEUR_AUDIO_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Initialise les fonctions audio
|
||||
// Reçoit : Rien
|
||||
// Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée
|
||||
//==================================================================================================================================================================
|
||||
int8_t init_audio(void)
|
||||
{
|
||||
|
||||
// Ajustement des variables selon la génération de ShipBase en cours :
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1)
|
||||
{
|
||||
audio.sortie_gpio_cm_do_audio_sd = CM3P_DO_AUDIO_SD;
|
||||
audio.entree_gpio_cm_di_jack_detect = 0; // Non disponible sur V1
|
||||
}
|
||||
else
|
||||
{
|
||||
audio.sortie_gpio_cm_do_audio_sd = CM4_DO_AUDIO_SD;
|
||||
audio.entree_gpio_cm_di_jack_detect = CM4_DI_JACK_DETECT;
|
||||
}
|
||||
|
||||
// Mise à jour du niveau de son (sans émission de bip) :
|
||||
// if (set_volume(audio.consigne_volume, AUDIO_SET_VOLUME_ECHO_OFF) == -1) return(-1); // La valeur a été récupérée dans la BDD par 'init_bdd()'
|
||||
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'
|
||||
|
||||
// Lancement musique d'accueil :
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1) lecture_mp3("netflix.mp3", 0);
|
||||
else lecture_mp3("battement_coeur.mp3", 0);
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation audio\t\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Demande l'émission d'un bip qui peut être complexe (un ou plusieurs bips, répétés un certain nombre de fois à un intervalle défini). A noter que cette
|
||||
// fonction permet aussi d'arrêter la séquence par anticipation si besoin.
|
||||
// Reçoit : Le nom du fichier MP3 à utiliser comme son de base (ou "Off" pour stopper), le nombre de répétitions du son de base (joués à la suite les uns des autres),
|
||||
// la tempo d'attente entre chaque boucles et le nombre de boucles.
|
||||
// Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée
|
||||
//==================================================================================================================================================================
|
||||
int8_t emission_bip(char * nom_fichier, uint16_t nb_repetitions, uint16_t periode_boucles, uint16_t nb_boucles)
|
||||
{
|
||||
FILE *file;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
// Détection d'une commande d'arrêt de lecture :
|
||||
// Nb : le nom spécifique "Off" est traité de façon insensible à la casse (donc "OFF", "Off", "off" et tous les autres intermédiaires fonctionnent)
|
||||
if ( (strlen(nom_fichier) == 3)
|
||||
&& (tolower(nom_fichier[0]) == 'o')
|
||||
&& (tolower(nom_fichier[1]) == 'f')
|
||||
&& (tolower(nom_fichier[2]) == 'f') )
|
||||
{
|
||||
audio.boucle.nom_fichier[0] = 0;
|
||||
audio.boucle.nb_repetitions = 0;
|
||||
audio.boucle.periode_boucles = 0;
|
||||
audio.boucle.nb_boucles = 0;
|
||||
audio.boucle.compteur_boucles = 0;
|
||||
audio.sequenceur.etat = ETAT_SEQUENCEUR_AUDIO_REPOS;
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Test du fichier :
|
||||
sprintf(tmp, "%s/%s", REPERTOIRE_CONFIG_SONS, nom_fichier); // Chemin complet du fichier dont le nom a été reçu
|
||||
file = fopen(tmp, "r"); // Tentative d'ouverture en lecture du fichier
|
||||
if (file == NULL)
|
||||
{
|
||||
sprintf(tmp, "Le fichier audio à lire [%s] n'existe pas dans le répertoire SONS [%s]. La lecture n'est pas lancée...", nom_fichier, REPERTOIRE_CONFIG_SONS);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
return(-1); // Si erreur d'ouverture, sortie en erreur (et, surtout, pas de lancementd e lecture)
|
||||
}
|
||||
else fclose(file); // Si pas d'erreur, on referme immédiatement le fichier avantd e continuer...
|
||||
|
||||
// Cas où le fichier existe bien :
|
||||
strcpy(audio.boucle.nom_fichier, nom_fichier);
|
||||
audio.boucle.nb_repetitions = nb_repetitions;
|
||||
audio.boucle.periode_boucles = periode_boucles;
|
||||
audio.boucle.nb_boucles = nb_boucles;
|
||||
audio.boucle.compteur_boucles = nb_boucles;
|
||||
audio.sequenceur.etat = ETAT_SEQUENCEUR_AUDIO_DEBUT_BOUCLE;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Lance le son correspondant au fichier MP3 passé en paramètre.
|
||||
// NB : la fonction lance un appel système non bloquant. Le fichier doit être dans REPERTOIRE_CONFIG_SONS.
|
||||
// Reçoit : Nom complet du fichier (depuis REPERTOIRE_CONFIG_SONS)
|
||||
// Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée
|
||||
//==================================================================================================================================================================
|
||||
int8_t lecture_mp3(char * nom_fichier, uint16_t nb_repetitions)
|
||||
{
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
char loop[15];
|
||||
|
||||
if (nb_repetitions > 0) sprintf(loop, "--loop %i", nb_repetitions);
|
||||
else loop[0] = 0;
|
||||
|
||||
sprintf(tmp, "sudo mpg123 %s %s/'%s' > /dev/null 2>&1 &", loop , REPERTOIRE_CONFIG_SONS, nom_fichier); // Attention : le '&' en fin de commande est nécessaire pour que l'appli n'attende pas la fin de la commande, donc de la lecture du morceau...!
|
||||
system(tmp);
|
||||
//printf("\tLancement lecture du fichier MP3 via la commande : [%s]\n", tmp);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Effectue une lecture matérielle pour définir si une prise jack est connectée ou pas sur la sortie audio de ShipBase
|
||||
// NB : valable uniquement sur V2.
|
||||
// NB 2 : cd SDIR #232
|
||||
// Reçoit : Rien
|
||||
// Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée
|
||||
//==================================================================================================================================================================
|
||||
int8_t mise_a_jour_etat_jack()
|
||||
{
|
||||
bool flag;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
if (audio.entree_gpio_cm_di_jack_detect != 0) // Les V1 ne sont pas concernées...
|
||||
{
|
||||
// flag = (bool) lecture_entree(TYPE_ENTREES_GPIO, 0, audio.entree_gpio_cm_di_jack_detect, FALSE); // 0 = adresse ShipBase
|
||||
flag = TRUE; // SDIR #232
|
||||
|
||||
if (flag != audio.etat_presence_jack)
|
||||
{
|
||||
audio.etat_presence_jack = flag;
|
||||
alimentation_ampli_audio();
|
||||
#ifdef __DEBUG_AUDIO
|
||||
sprintf(tmp, "La présence d'une prise jack sur la sortie audio a changé d'état. Elle est maintenant : %s. NB : Fonction jack = %i", audio.etat_presence_jack ? "Présente" : "Absente", audio.fonction_jack);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Met à jour le niveau de volume du son de la carte. La consigne est celle reçue en paramètre et la fonction met à jour les paramètres de AlsaMixer.
|
||||
// Dans le cas où la consigne est à 0, la sortie de commande de l'ampli est carrément coupée.
|
||||
// Reçoit : Le niveau de volume attendu (de 0 à 100%), en centièmes de pourcent.
|
||||
// Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée
|
||||
//==================================================================================================================================================================
|
||||
int8_t set_volume(float volume, bool echo)
|
||||
{
|
||||
long min, max;
|
||||
snd_mixer_t *handle;
|
||||
snd_mixer_selem_id_t *sid;
|
||||
const char *card = "default";
|
||||
const char *selem_name = "PCM";
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
// Vérification de la nouvelle valeur de consigne :
|
||||
if ((volume < AUDIO_CONSIGNE_MIN) || (volume > AUDIO_CONSIGNE_MAX))
|
||||
{
|
||||
sprintf(tmp, "La nouvelle consigne de volume audio n'est pas dans la plage autorisée : %.2f pour [%i ; %i%%]. La commande est ignorée...", volume, AUDIO_CONSIGNE_MIN, AUDIO_CONSIGNE_MAX);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
// Mise à jour de la nouvelle valeur :
|
||||
audio.consigne_volume = volume;
|
||||
|
||||
// Envoi vers le driver :
|
||||
snd_mixer_open(&handle, 0);
|
||||
snd_mixer_attach(handle, card);
|
||||
snd_mixer_selem_register(handle, NULL, NULL);
|
||||
snd_mixer_load(handle);
|
||||
snd_mixer_selem_id_alloca(&sid);
|
||||
snd_mixer_selem_id_set_index(sid, 0);
|
||||
snd_mixer_selem_id_set_name(sid, selem_name);
|
||||
snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);
|
||||
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
|
||||
snd_mixer_selem_set_playback_volume_all(elem, volume * max / 100);
|
||||
snd_mixer_close(handle);
|
||||
|
||||
// Activation ampli audio :
|
||||
alimentation_ampli_audio();
|
||||
|
||||
// Enregistrement dans l'historique :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_VOLUME_CHANGEMENT_CONSIGNE, 0, audio.consigne_volume, NULL);
|
||||
|
||||
#ifdef __DEBUG_AUDIO
|
||||
sprintf(tmp, "Nouvelle consigne de volume = %.2f %%", audio.consigne_volume);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
|
||||
// Bip de mise à jour s'il est demandé :
|
||||
// if (echo) lecture_mp3("button-8.mp3", 0);
|
||||
if (echo) lecture_mp3("beep-07.mp3", 0);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Active ou désactive l'alimentation de l'ampli audio (alimentant le HP intégré) selon la présence ou non d'une prise jack sur la sortie AUDIO
|
||||
// et selon le paramètre de configuration 'Fonction_jack'
|
||||
// Reçoit : Rien
|
||||
// Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée
|
||||
//==================================================================================================================================================================
|
||||
int8_t alimentation_ampli_audio(void)
|
||||
{
|
||||
#ifdef __DEBUG_AUDIO
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
#endif
|
||||
|
||||
if ( ((audio.etat_presence_jack == TRUE) && (audio.fonction_jack == AUDIO_FONCTION_JACK_HP_OFF)) || // Si une fiche jack est présente sur la sortie Audio ET que le mode de fonctionnement est de couper le HP dans ce cas...
|
||||
(audio.consigne_volume == 0) ) // ... OU le volume est à 0
|
||||
{
|
||||
// Coupure de l'alimentation de la sortie audio :
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, audio.sortie_gpio_cm_do_audio_sd, OFF); // 0 est l'adresse de ShipBase
|
||||
#ifdef __DEBUG_AUDIO
|
||||
sprintf(tmp, "L'alimentation de l'ampli audio est passée à OFF car Présence Jack = %s et Fonction Jack = %i", (audio.etat_presence_jack ? "Présente" : "Absente"), audio.fonction_jack);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
}
|
||||
else // Dans tous les autres cas, l'ampli est alimenté.
|
||||
{
|
||||
// Alimentation de la sortie audio :
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, audio.sortie_gpio_cm_do_audio_sd, ON); // 0 est l'adresse de ShipBase
|
||||
#ifdef __DEBUG_AUDIO
|
||||
sprintf(tmp, "L'alimentation de l'ampli audio est passée à ON car Présence Jack = %s et Fonction Jack = %i", (audio.etat_presence_jack ? "Présente" : "Absente"), audio.fonction_jack);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier AUDIO.H
|
||||
//
|
||||
// Contient tous les define liés à l'audio...
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
|
||||
// Maximums :
|
||||
#define AUDIO_CONSIGNE_MAX 100
|
||||
#define AUDIO_CONSIGNE_MIN 0
|
||||
|
||||
|
||||
// Timings :
|
||||
#define AUDIO_PERIODE_SURVEILLANCE 5 // En x 100ms
|
||||
|
||||
// Définitions :
|
||||
#define AUDIO_SET_VOLUME_ECHO_OFF 0 // Indique que le changement de niveau se fera sans émettre de son
|
||||
#define AUDIO_SET_VOLUME_ECHO_ON 1 // Indique que le changement de niveau se fera en émettant un son après la mise à jour
|
||||
|
||||
// Fonctions Jack :
|
||||
#define AUDIO_FONCTION_JACK_HP_OFF 0 // le HP est coupé quand une prise jack est présente
|
||||
#define AUDIO_FONCTION_JACK_HP_ON 1 // Le HP est maintenu On quand une prise jack est présente
|
||||
|
||||
// Etat séquenceur Audio :
|
||||
#define ETAT_SEQUENCEUR_AUDIO_INIT 0
|
||||
#define ETAT_SEQUENCEUR_AUDIO_REPOS 1
|
||||
#define ETAT_SEQUENCEUR_AUDIO_DEBUT_BOUCLE 2
|
||||
#define ETAT_SEQUENCEUR_AUDIO_TEMPO_BOUCLE 3
|
||||
@@ -0,0 +1,706 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier BATTERIES.C
|
||||
//
|
||||
// Contient toutes les fonctions liées aux batteries de ShipHeart
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
//#define __DEBUG_BATTERIES
|
||||
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t init_batteries(void);
|
||||
void gestion_batteries(void);
|
||||
int16_t batterie_cle_primaire(uint16_t cle_primaire);
|
||||
int16_t variable_batterie_cle_primaire(uint16_t cle_primaire);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_batteries batteries;
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction : Initialise les différents paramètres des batteries au démarrage de l'application
|
||||
Reçoit : Rien
|
||||
Retour : -1 si erreur, 0 sinon.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_batteries(void)
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------------
|
||||
// Init des variables générales :
|
||||
|
||||
batteries.sequenceur.etat = ETAT_SEQUENCEUR_BATTERIES_INIT;
|
||||
batteries.sequenceur.compteur = BATTERIES_TEMPO_INIT;
|
||||
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation des batteries\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction : Fonction de plus haut niveau de gestion batteries
|
||||
Reçoit : Rien
|
||||
Retour : Rien
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_batteries(void)
|
||||
{
|
||||
uint16_t i, j;
|
||||
float soc;
|
||||
float tension_a_vide;
|
||||
float resistance_interne;
|
||||
float efficacite;
|
||||
float delta_energie;
|
||||
float capacite_reelle;
|
||||
float duree_decharge_corrigee;
|
||||
float courant_differentiel_corrige;
|
||||
bool flag_erreur;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
if (!systeme.flag_cm3p_ready) return; // Evite que le traitement soit fait au milieu d'une reconfiguration...
|
||||
|
||||
switch(batteries.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_BATTERIES_INIT :
|
||||
{
|
||||
if ((systeme.flag_cm3p_ready) && // Permet de s'assurer que le cycle d'init système est terminé. En particulier, on est sûr que 'init_bdd()' puis 'annuaire_k_bus()' ont été traités.
|
||||
(batteries.sequenceur.compteur == 0))
|
||||
{
|
||||
|
||||
affichage_debug(__FILE__, __LINE__, "------------------BATTEREIES INIT", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
batteries.sequenceur.etat = ETAT_SEQUENCEUR_BATTERIES_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_BATTERIES_REPOS :
|
||||
{
|
||||
if (batteries.sequenceur.compteur == 0)
|
||||
{
|
||||
batteries.sequenceur.compteur = BATTERIES_PERIODE_MESURES;
|
||||
#ifdef __DEBUG_BATTERIES
|
||||
batteries.sequenceur.compteur = 10;
|
||||
// Valeur passée de 300ms à 1s pour les tests (cf batteries.h)
|
||||
#endif
|
||||
for (i = 0; i < batteries.nb; i ++)
|
||||
{
|
||||
if (batteries.batteries[i].flag_validite == FALSE) continue;
|
||||
|
||||
flag_erreur = FALSE;
|
||||
|
||||
// Acquisition des dernières valeurs et mémorisation du nouveau niveau :
|
||||
switch(batteries.batteries[i].type_entrees)
|
||||
{
|
||||
//--------------------------------------------------------------------------
|
||||
case TYPE_ENTREES_VOLTAGE :
|
||||
{
|
||||
// Récupération de l'état de l'entrées Voltage configurée sur cette batterie et calcul de la nouvelle moyenne de tension à partir de l'ancienne et de la valeur lue :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante = (((batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante * (batteries.batteries[i].tension_coeff_filtrage - 1))) + entrees.volt.entrees[batteries.batteries[i].no_entrees].valeur) / batteries.batteries[i].tension_coeff_filtrage;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
case TYPE_ENTREES_PREDEFINIES :
|
||||
{
|
||||
// Récupération de l'état de l'entrées Prédéfinie configurée sur cette batterie et calcul de la nouvelle moyenne de tension à partir de l'ancienne et de la valeur lue :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante = (((batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante * (batteries.batteries[i].tension_coeff_filtrage - 1))) + entrees.predefinies.entrees[batteries.batteries[i].no_entrees].valeur) / batteries.batteries[i].tension_coeff_filtrage;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
case TYPE_ENTREES_IBS :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "Le 'Type_entrées' de la batterie #%i est invalide [%i]. La batterie est dévalidée", (i+1), batteries.batteries[i].type_entrees);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
batteries.batteries[i].flag_validite = FALSE;
|
||||
flag_erreur = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Traitement :
|
||||
if (flag_erreur == FALSE)
|
||||
{
|
||||
|
||||
//-------------------------------------
|
||||
// Tension :
|
||||
//-------------------------------------
|
||||
// Calcul de l'impact de Gain_tension sur la tension courante :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante *= batteries.batteries[i].tension_gain;
|
||||
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante;
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
// Courant de décharge :
|
||||
//-------------------------------------
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante = 0;
|
||||
|
||||
for (j = 0; j < circuits.nb; j ++)
|
||||
{
|
||||
if (! circuits.circuits[j].flag_validite) continue;
|
||||
if (circuits.circuits[j].id_batterie != batteries.batteries[i].cle_primaire) continue;
|
||||
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante -= circuits.circuits[j].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante; // Cumul du courant dans chaque circuit. En négatif car le courant de chaque circuit est comptabilisé de façon positive alors que le courant de décharge est forcément négatif.
|
||||
}
|
||||
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante;
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
// Puissance :
|
||||
//-------------------------------------
|
||||
// SDIR #199 : suppression du (-1) dans le produit (tension x courant) afin de laisser la puissance consommée toujours négative :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante = batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante * batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante;
|
||||
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante;
|
||||
|
||||
|
||||
|
||||
//================================================
|
||||
// Entrée de type Entrée Prédéfinie ou Voltage :
|
||||
//================================================
|
||||
if (batteries.batteries[i].type_entrees != TYPE_ENTREES_IBS)
|
||||
{
|
||||
//-------------------------------------
|
||||
// SOC :
|
||||
//-------------------------------------
|
||||
// Calcul du SOC :
|
||||
soc = calcul_niveau(batteries.batteries[i].points_tension_soc, MAX_NOMBRE_POINTS_TENSION_SOC_BATTERIE, batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante);
|
||||
if (soc >= 0) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = soc;
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "Erreur de calcul de SOC de la batterie #%i avec tension=%.3fV. La valeur lue n'est pas exploitée.\n", i, batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante;
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
// Mise à jour BDD :
|
||||
//-------------------------------------
|
||||
// Mise à jour dans la BDD si les valeurs ont suffisemment évolué :
|
||||
// if ((fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_TENSION].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_COURANT_DECHARGE].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_SOC].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_PUISSANCE].marge))
|
||||
if ((fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante) > 0))
|
||||
{
|
||||
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
}
|
||||
|
||||
/*#ifdef __DEBUG_BATTERIES
|
||||
sprintf(tmp, "Batterie #%i : Tension = %.3fV, courant de décharge = %.3fA (donc puissance = %.3fW) et SOC = %.2f%% (coeff filtrage tension = %i)",
|
||||
i, batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante,
|
||||
(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante * (-1) * batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante),
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante,
|
||||
batteries.batteries[i].tension_coeff_filtrage);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
//================================================
|
||||
// Entrée de type IBS :
|
||||
//================================================
|
||||
else
|
||||
{
|
||||
//-------------------------------------
|
||||
// Température :
|
||||
//-------------------------------------
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante;
|
||||
|
||||
//-------------------------------------
|
||||
// Courant différentiel :
|
||||
//-------------------------------------
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante;
|
||||
|
||||
//-------------------------------------
|
||||
// Calcul du courant de charge :
|
||||
//-------------------------------------
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante = batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante;
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante < 0) // Normalement, impossible car cela induirait un courantd e charge négatif...
|
||||
{
|
||||
#ifdef __DEBUG_BATTERIES
|
||||
// sprintf(tmp, "Batterie #%i : Le courant de charge est calculé avec une valeur négative [%.3f A], ce qui n'est pas possible. Il est ramené à 0 mA", i, batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante = 0; // Par défaut, on écrête...
|
||||
}
|
||||
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante;
|
||||
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
// Calcul du SOC :
|
||||
//-------------------------------------
|
||||
|
||||
// Calcul de la résistance interne en fonction de la température :
|
||||
resistance_interne = calcul_niveau(batteries.batteries[i].points_temperature_resistance_interne, MAX_NOMBRE_POINTS_TEMPERATURE_RESISTANCE_INTERNE_BATTERIE, batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante);
|
||||
if (resistance_interne != -1) resistance_interne = resistance_interne * batteries.batteries[i].resistance_interne / 1000; // Le '/1000' permet de passer de valeurs de résistance interne en mOhms à Ohms.
|
||||
else resistance_interne = batteries.batteries[i].resistance_interne / 1000; // Le '/1000' permet de passer de valeurs de résistance interne en mOhms à Ohms.
|
||||
#ifdef __DEBUG_BATTERIES
|
||||
// sprintf(tmp, "Valeur brute de résistance interne = %.2f mOhms, température batterie = %.2f °C, soit résistance interne corrigée = %.2f mOhms", batteries.batteries[i].resistance_interne, batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante, (resistance_interne * 1000));
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
// Estimation de la tension à vide (en tenant compte de la chute de tension due à la résistance interne de la batterie) :
|
||||
tension_a_vide = batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante - (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante * resistance_interne);
|
||||
|
||||
if ((batteries.batteries[i].sequenceur.etat != ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE) && // Le calcul de l'EOD, et, in fine, du SOC n'est pas effectué tant qu'on est à l'état de charge nulle...
|
||||
(batteries.batteries[i].sequenceur.etat != ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE)) // ... ou de pleine charge.
|
||||
{
|
||||
// Calcul de l'EOD :
|
||||
// Calculs fonction d'une charge ou d'une décharge :
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante < 0) // Il est important de ne PAS prendre la valeur 0 (sinon le calcul de 'duree_decharge_corrigee' va planter via division par 0)
|
||||
{
|
||||
efficacite = 1 / batteries.batteries[i].efficacite_decharge;
|
||||
|
||||
// Effet Peukert :
|
||||
duree_decharge_corrigee = batteries.batteries[i].heures_capacite * powf(((batteries.batteries[i].capacite / batteries.batteries[i].heures_capacite) / (-batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante)), batteries.batteries[i].coeff_peukert); // Le signe - devant le courant permet d'avoir une valeur positive (sinon POWF va générer une erreur)
|
||||
courant_differentiel_corrige = -(float)batteries.batteries[i].capacite / duree_decharge_corrigee; // Le signe '-' permet de revenir à un courant négatif en cas de décharge
|
||||
}
|
||||
else
|
||||
{
|
||||
efficacite = batteries.batteries[i].efficacite_charge;
|
||||
courant_differentiel_corrige = batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante; // Pas de correction de Peukert en charge...
|
||||
}
|
||||
|
||||
// Calculs intermédiaires (facilite la lecture et le debug) :
|
||||
delta_energie = courant_differentiel_corrige * efficacite * (BATTERIES_PERIODE_MESURES * 0.1 / 3600); // La dernière () permet de passer en heures.
|
||||
// SDIR #337 : capacite_reelle = batteries.batteries[i].capacite * batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante / 100; // Le '100' permet de tenir compte du fait que le SOH est en pourcents
|
||||
capacite_reelle = batteries.batteries[i].capacite; // SDIR #337
|
||||
|
||||
// Calcul de l'EOD proprement dit :
|
||||
batteries.batteries[i].eod += delta_energie;
|
||||
if (batteries.batteries[i].eod > 0) batteries.batteries[i].eod = 0; // SDIR #337
|
||||
//printf("Courant diff = %.3f, efficacité = %.3f, Delta T = %.6f secondes donc Delta Energie = %.6fAh => energie_dechargee = %.6fAh. Capacite_reelle = %.2fAh\n", batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante, efficacite, (BATTERIES_PERIODE_MESURES * 0.1 / 3600), delta_energie, batteries.batteries[i].eod, capacite_reelle);
|
||||
|
||||
// Mise à jour du SOC à partir de l'EOD :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = (1 + (batteries.batteries[i].eod / capacite_reelle)) * 100; // EOD est négative par nature. Le 'x100' permet de revenir d'une fraction en pourcents
|
||||
}
|
||||
else
|
||||
{
|
||||
efficacite = 0; // Permet d'éviter un warning losqu'il n'est pas calculé (état de pleine charge ou de charge nulle) mais utilisé par le message de debug
|
||||
courant_differentiel_corrige = 0; // Idem
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
// Mode repos :
|
||||
//--------------------------------
|
||||
/* if (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante) < batteries.batteries[i].courant_repos)
|
||||
{
|
||||
soc = calcul_niveau(batteries.batteries[i].points_tension_soc, MAX_NOMBRE_POINTS_TENSION_SOC_BATTERIE, tension_a_vide);
|
||||
if (soc >= 0)
|
||||
{
|
||||
// batteries.batteries[i].soc_coeff_filtrage = 50;
|
||||
// float old = batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante;
|
||||
// float new;
|
||||
// new = moyenne_mobile(old, soc, batteries.batteries[i].soc_coeff_filtrage);
|
||||
// sprintf(tmp, "Old = %.3f%%, Add=%.3f%%, New = %.3f%% et le coeff %i. ", old, soc, new, batteries.batteries[i].soc_coeff_filtrage);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
|
||||
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = moyenne_mobile(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante, soc, batteries.batteries[i].soc_coeff_filtrage);
|
||||
sprintf(tmp, "La batterie #%i est en mode REPOS. Son nouveau SOC = %.1f%%, il a été mis à jour via moyenne mobile avec la nouvelle valeur %.1f%% et le coeff %i. ", i, batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante, soc, batteries.batteries[i].soc_coeff_filtrage);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
}
|
||||
// Sinon, on n'utilise pas la valeur calculée car il ne sert à rien de corriger avec une valeur erronée...
|
||||
}
|
||||
*/
|
||||
//--------------------------------
|
||||
// Mode Décharge :
|
||||
//--------------------------------
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante < 0)
|
||||
{
|
||||
// Vérification du passage en "charge nulle" :
|
||||
switch(batteries.batteries[i].sequenceur.etat)
|
||||
{
|
||||
//......................................
|
||||
case ETAT_SEQUENCEUR_BATTERIE_NORMAL:
|
||||
{
|
||||
if (tension_a_vide <= batteries.batteries[i].tension_charge_nulle)
|
||||
{
|
||||
batteries.batteries[i].sequenceur.compteur = batteries.batteries[i].temporisation_charge_nulle;
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_CHARGE_NULLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//......................................
|
||||
case ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_CHARGE_NULLE:
|
||||
{
|
||||
if (tension_a_vide > batteries.batteries[i].tension_charge_nulle) // Cas où on n'a pas eu le temps d'attendre la tempo de confirmation avant remontée de la tension.
|
||||
{
|
||||
batteries.batteries[i].sequenceur.compteur = 0;
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (batteries.batteries[i].sequenceur.compteur == 0) // Cas où le passage à charge nulle est confirmé :
|
||||
{
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 0;
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante = -(batteries.batteries[i].eod * 100) / batteries.batteries[i].capacite;
|
||||
sprintf(tmp, "La Batterie [%i] est confirmée en CHARGE NULLE. EOD = %.3fAh et Capacité = %.2fAh donc SOH = %.3f%%", (i+1), batteries.batteries[i].eod, batteries.batteries[i].capacite, batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//......................................
|
||||
case ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE:
|
||||
{
|
||||
if (tension_a_vide > (batteries.batteries[i].tension_charge_nulle + BATTERIES_HYSTERESIS_CHARGE_NULLE))
|
||||
{
|
||||
batteries.batteries[i].sequenceur.compteur = 0;
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
//......................................
|
||||
default :
|
||||
{
|
||||
#ifdef __DEBUG_BATTERIES
|
||||
sprintf(tmp, "L'état du séquenceur de la Batterie [%i] est inconnu pour ce mode [%i]. Il est repositionné à NORMAL", (i+1), batteries.batteries[i].sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
batteries.batteries[i].sequenceur.compteur = 0;
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
// Mode Charge :
|
||||
//--------------------------------
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante > 0)
|
||||
{
|
||||
switch(batteries.batteries[i].sequenceur.etat)
|
||||
{
|
||||
//......................................
|
||||
case ETAT_SEQUENCEUR_BATTERIE_NORMAL:
|
||||
{
|
||||
// Détection d'un passage à l'état "Pleine charge" :
|
||||
if ((tension_a_vide >= batteries.batteries[i].tension_pleine_charge) &&
|
||||
(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante <= batteries.batteries[i].courant_pleine_charge))
|
||||
{
|
||||
#ifdef __DEBUG_BATTERIES
|
||||
sprintf(tmp, "Les conditions du mode PLEINE CHARGE ont été détectées sur la Batterie [%i]. La temporisation de vérification (%is) est lancée ", (i+1), batteries.batteries[i].temporisation_pleine_charge);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
batteries.batteries[i].sequenceur.compteur = batteries.batteries[i].temporisation_pleine_charge;
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_PLEINE_CHARGE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//......................................
|
||||
case ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_PLEINE_CHARGE:
|
||||
{
|
||||
// Détection de sortie de l'état "Pleine charge" avant d'avoir été confirmé :
|
||||
if ((tension_a_vide < batteries.batteries[i].tension_pleine_charge) || // Si la tension est redescendue...
|
||||
(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante > batteries.batteries[i].courant_pleine_charge)) // ... ou le courant remonté avant l'expiration de la tempo :
|
||||
{
|
||||
sprintf(tmp, "Les conditions du mode PLEINE CHARGE ont disparu sur la Batterie [%i]. La batterie est repositionnée en mode NORMAL ", (i+1));
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
batteries.batteries[i].sequenceur.compteur = 0;
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
// Confirmation du passage à l'état "Pleine charge" :
|
||||
if (batteries.batteries[i].sequenceur.compteur == 0) // Cas où le passage à pleine charge est confirmé :
|
||||
{
|
||||
sprintf(tmp, "La Batterie [%i] est confirmée en PLEINE CHARGE ", (i+1));
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 100;
|
||||
batteries.batteries[i].eod = 0;
|
||||
// batteries.batteries[i].tension_pleine_charge = tension_a_vide - BATTERIES_DELTA_TENSION_PLEINE_CHARGE_AUTO; // Ajustement auto de la tension pleine charge
|
||||
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//......................................
|
||||
case ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE:
|
||||
{
|
||||
// Détection de sortie de l'état "Pleine charge" :
|
||||
if ((tension_a_vide < batteries.batteries[i].tension_pleine_charge) || // Si la tension est redescendue...
|
||||
(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante > batteries.batteries[i].courant_pleine_charge)) // ... ou le courant remonté :
|
||||
{
|
||||
batteries.batteries[i].sequenceur.compteur = 0;
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
// Etat "pleine charge" :
|
||||
// batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 100;
|
||||
// batteries.batteries[i].eod = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
//......................................
|
||||
default :
|
||||
{
|
||||
#ifdef __DEBUG_BATTERIES
|
||||
sprintf(tmp, "L'état du séquenceur de la Batterie [%i] est inconnu pour ce mode [%i]. Il est repositionné à NORMAL", (i+1), batteries.batteries[i].sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
batteries.batteries[i].sequenceur.compteur = 0;
|
||||
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vérification du SOC :
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante > 100) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 100;
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante < 0) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 0;
|
||||
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante;
|
||||
|
||||
|
||||
//--------------------------------------------
|
||||
// Calcul des nombres de cycles :
|
||||
//--------------------------------------------
|
||||
if (batteries.batteries[i].flag_increment_cycles == 0) // Le compteur est armé et n'a pas encore été incrémenté :
|
||||
{
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante <= BATTERIES_SEUIL_SOC_BAS_NOMBRE_CYCLES)
|
||||
{
|
||||
batteries.batteries[i].flag_increment_cycles = 1; // Blocage du flag jusqu'au prochain passage par 100%
|
||||
batteries.batteries[i].nombre_cycles ++; // Incrémentation du compteur
|
||||
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
}
|
||||
}
|
||||
else // Le compteur "Nombre_cylces" a été incrémenté, on attend maintenant de revenir à 100% pour le réarmer :
|
||||
{
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante == 100)
|
||||
{
|
||||
batteries.batteries[i].flag_increment_cycles = 0; // Réarmement du flag pour le prochain cycle
|
||||
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------
|
||||
// Calcul du nombre de décharges complètes :
|
||||
//--------------------------------------------
|
||||
if (batteries.batteries[i].flag_increment_decharges_completes == 0) // Le compteur est armé et n'a pas encore été incrémenté :
|
||||
{
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante == 0)
|
||||
{
|
||||
batteries.batteries[i].flag_increment_decharges_completes = 1; // Blocage du flag jusqu'au prochain passage par 100%
|
||||
batteries.batteries[i].nombre_decharges_completes ++; // Incrémentation du compteur
|
||||
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
}
|
||||
}
|
||||
else // Le compteur "Nombre_cylces" a été incrémenté, on attend maintenant de revenir à 100% pour le réarmer :
|
||||
{
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante == 100)
|
||||
{
|
||||
batteries.batteries[i].flag_increment_decharges_completes = 0; // Réarmement du flag pour le prochain cycle
|
||||
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
// Calcul du SOH :
|
||||
//-------------------------------------
|
||||
// Vérification du SOH :
|
||||
// if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante > 100) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante = 100;
|
||||
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante < BATTERIES_SEUIL_MINI_SOH) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante = BATTERIES_SEUIL_MINI_SOH;
|
||||
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
// Calcul de l'autonomie :
|
||||
//-------------------------------------
|
||||
|
||||
// Mise à jour du cumul :
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_courante;
|
||||
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
// Mise à jour BDD :
|
||||
//-------------------------------------
|
||||
// Mise à jour dans la BDD si les valeurs ont suffisemment évolué :
|
||||
// if ((fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_TEMPERATURE].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_TENSION].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_COURANT_CHARGE].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_COURANT_DECHARGE].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_SOH].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_SOC].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_AUTONOMIE].marge) ||
|
||||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_PUISSANCE].marge))
|
||||
if ((fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_courante) > 0) ||
|
||||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante) > 0))
|
||||
{
|
||||
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
}
|
||||
|
||||
#ifdef __DEBUG_BATTERIES
|
||||
char texte_etat[200];
|
||||
|
||||
if (++ batteries.compteur_affichage_debug == 6) // Comme BATTERIES_PERIODE_MESURES = 300ms, cela donne un affichage toutes les 1.8s
|
||||
{
|
||||
batteries.compteur_affichage_debug = 0;
|
||||
|
||||
switch(batteries.batteries[i].sequenceur.etat)
|
||||
{
|
||||
case ETAT_SEQUENCEUR_BATTERIE_NORMAL: { strcpy(texte_etat, "NORMAL"); break; }
|
||||
case ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_CHARGE_NULLE: { strcpy(texte_etat, "ATTENTE_CONFIRMATION_CHARGE_NULLE"); break; }
|
||||
case ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE: { strcpy(texte_etat, "CHARGE_NULLE"); break; }
|
||||
case ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_PLEINE_CHARGE: { strcpy(texte_etat, "ATTENTE_CONFIRMATION_PLEINE_CHARGE"); break; }
|
||||
case ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE: { strcpy(texte_etat, "PLEINE_CHARGE"); break; }
|
||||
default: { strcpy(texte_etat, "Inconnu"); break; }
|
||||
}
|
||||
|
||||
sprintf(tmp, "Batterie #%i : Etat = %s, Température = %.2f°C, Tension = %.3fV, Courant diff = %.3fA, courant charge = %.3fA, Courant décharge = %.3fA, SOH = %.2f%%, SOC = %.2f%%, Autonomie = %.2fh et puissance = %.3fW. Tension à vide = %.3fV, résistance interne corrigée = %.2fmOhms, efficacité = %.3f, courant_differentiel_corrigé = %.3fA, capacité = %.2fAh, EOD (énergie déchargée depuis démarrage) = %.5fAh", i,
|
||||
texte_etat,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante,
|
||||
tension_a_vide,
|
||||
(resistance_interne * 1000), // Pour passer de Ohms à mOhms
|
||||
efficacite,
|
||||
courant_differentiel_corrige,
|
||||
batteries.batteries[i].capacite,
|
||||
batteries.batteries[i].eod
|
||||
);
|
||||
|
||||
/*sprintf(tmp, "Batterie #%i : Etat = %s, Tension = %.3fV, Courant diff = %.3fA. Tension à vide = %.3fV, efficacité = %.3f, courant_differentiel_corrigé = %.3fA, capacité = %.2fAh, duree_decharge_corrigee = %.2fh, EOD = %.5fAh", i,
|
||||
texte_etat,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante,
|
||||
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante,
|
||||
tension_a_vide,
|
||||
efficacite,
|
||||
courant_differentiel_corrige,
|
||||
batteries.batteries[i].capacite,
|
||||
duree_decharge_corrigee,
|
||||
batteries.batteries[i].eod
|
||||
);
|
||||
*/
|
||||
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
}
|
||||
#endif
|
||||
} // Fin du traitement pour batterie sur IBS
|
||||
|
||||
batteries.batteries[i].cumuls_nb_val ++; // MàJ du nombre d'échantillons dans le cumul
|
||||
|
||||
|
||||
// Mise à jour des valeurs BDD des variables :
|
||||
if (batteries.batteries[i].flag_dde_maj_bdd)
|
||||
{
|
||||
for (j = 0; j < MAX_NOMBRE_VARIABLES_BATTERIES; j ++) batteries.batteries[i].variables[j].valeur_bdd = batteries.batteries[i].variables[j].valeur_courante;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur Batteries est inconnu [%i]. Il est repositionné au REPOS", batteries.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
batteries.sequenceur.etat = ETAT_SEQUENCEUR_BATTERIES_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Recherche la batterie dont la Clé_primaire est reçue en paramètre
|
||||
// Reçoit : La Cle_primaire de la batterie à rechercher
|
||||
// Retourne : le numéro de batterie correspondant (ou -1 si aucun circuit valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_BATTERIES - 1.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int16_t batterie_cle_primaire(uint16_t cle_primaire)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
|
||||
if (cle_primaire == 0) return (-1); // Inutile de chercher si le n° à chercher est nul...
|
||||
|
||||
for (i = 0; i < batteries.nb; i ++)
|
||||
{
|
||||
if (batteries.batteries[i].flag_validite == FALSE) continue;
|
||||
if (batteries.batteries[i].cle_primaire == cle_primaire) return(i);
|
||||
}
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction VARIABLE_BATTERIE_CLE_PRIMAIRE
|
||||
// Reçoit en paramètre :
|
||||
// - La Cle_primaire de la variable à rechercher
|
||||
// Retourne :
|
||||
// - le numéro de variable correspondant (ou -1 si aucune variable valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_VARIABLES_BATTERIES-1.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int16_t variable_batterie_cle_primaire(uint16_t cle_primaire)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_VARIABLES_BATTERIES; i++)
|
||||
{
|
||||
if (batteries.variables[i].cle_primaire == cle_primaire) return(i);
|
||||
|
||||
}
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
|
||||
Fichier BATTERIES.H
|
||||
|
||||
Contient tous les define liés aux BATTERIES
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MAX_NOMBRE_BATTERIES 12
|
||||
#define MAX_NOMBRE_POINTS_TENSION_SOC_BATTERIE 100
|
||||
#define MAX_NOMBRE_POINTS_TEMPERATURE_RESISTANCE_INTERNE_BATTERIE 20
|
||||
#define MAX_NOMBRE_ENTREES_PAR_BATTERIE 1
|
||||
#define MAX_NOMBRE_VARIABLES_BATTERIES 10
|
||||
|
||||
// Tempos :
|
||||
#define BATTERIES_TEMPO_INIT 10 // En x 100ms
|
||||
#define BATTERIES_PERIODE_MESURES 3 // En x 100ms
|
||||
|
||||
// Mesures :
|
||||
#define BATTERIES_HYSTERESIS_CHARGE_NULLE 1.0 // En V. Permet d'éviter que la coupure des charges au moment du passage à CHARGE_NULLE ne redéclenche le mode NORMAL par juste remontée de la tension batterie. NB : ce cas ne se présente que si cpurant_diff reste négatif (s'il passe positif, on repassera par le mode NORMAL quoi qu'il arrive)
|
||||
#define BATTERIES_NTC_TEMPERATURE_ERREUR -50 // Valeur provenant de NTC_TEMPERATURE_ERREUR dans le soft des ShipBS1224
|
||||
#define BATTERIES_DELTA_TENSION_PLEINE_CHARGE_AUTO 0.2 // En V. A chaque passage à Pleine Charge, la 'tension_pleine_charge' est automatiquement ajustée à 'tension_a_vide' en cours MOINS cette valeur.
|
||||
#define BATTERIES_SEUIL_MINI_SOH 1.00 // En %. Attention, doit toujours être (STRICTEMENT) > 0 car sinon la capacité réelle sera nulle ou négative et plantera le calcul.
|
||||
#define BATTERIES_SEUIL_SOC_BAS_NOMBRE_CYCLES 60 // En %. Défini la valeur en-dessous de laquelle le compteur 'Nombre_cycles' est incrémenté (NB : il faut ensuite repasser par un SOC=100% avant de compter un nouveau cycle)
|
||||
|
||||
|
||||
// Variables de la batterie :
|
||||
#define BATTERIE_VARIABLE_TEMPERATURE 0
|
||||
#define BATTERIE_VARIABLE_TENSION 1
|
||||
#define BATTERIE_VARIABLE_COURANT_DIFFERENTIEL 2
|
||||
#define BATTERIE_VARIABLE_COURANT_CHARGE 3
|
||||
#define BATTERIE_VARIABLE_COURANT_DECHARGE 4
|
||||
#define BATTERIE_VARIABLE_SOH 5
|
||||
#define BATTERIE_VARIABLE_SOC 6
|
||||
#define BATTERIE_VARIABLE_AUTONOMIE 7
|
||||
#define BATTERIE_VARIABLE_PUISSANCE 8
|
||||
#define BATTERIE_VARIABLE_ENERGIE 9
|
||||
// NB : ces valeurs doivent rester strictement inférieures à MAX_NOMBRE_VARIABLES_BATTERIES
|
||||
|
||||
|
||||
// Commandes de la batterie :
|
||||
#define BATTERIE_COMMMANDE_FORCAGE_PLEINE_CHARGE 1
|
||||
#define BATTERIE_COMMMANDE_RESET_SOH 2
|
||||
#define BATTERIE_COMMMANDE_RESET_COMPTEURS 3
|
||||
|
||||
|
||||
// Etats du séquenceur d'une batterie :
|
||||
#define ETAT_SEQUENCEUR_BATTERIE_NORMAL 0
|
||||
#define ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_CHARGE_NULLE 1
|
||||
#define ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE 2
|
||||
|
||||
#define ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_PLEINE_CHARGE 10
|
||||
#define ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE 11
|
||||
|
||||
|
||||
// Etats du séquenceur Batteries :
|
||||
#define ETAT_SEQUENCEUR_BATTERIES_INIT 0
|
||||
#define ETAT_SEQUENCEUR_BATTERIES_REPOS 1
|
||||
+249
@@ -0,0 +1,249 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fichier GESTION_BDD.H
|
||||
Contient toutes les définitions liées à la gestion de la BDD
|
||||
**********************************************************************************************************************************************************************************/
|
||||
// Maximums :
|
||||
#define MAX_LONGUEUR_REQUETE_MYSQL 3500
|
||||
#define MAX_LONGUEUR_SOUS_REQUETE_MYSQL 1000
|
||||
#define MAX_NOMBRE_CHAMPS_INTERNES 300 // Utilisé pour dimensionner les tableaux de pointeurs de décodage (exemple : champs 'Entrees' des Réservoirs, Batteries ou Capteurs)
|
||||
#define MAX_LONGUEUR_NOM_FICHIER_SAUVEGARDE_BDD 150
|
||||
#define MAX_LONGUEUR_OPTION_COMMANDE_SAUVEGARDE_BDD 300
|
||||
#define MAX_LONGUEUR_NOM_TABLE 50
|
||||
#define MAX_NOMBRE_TABLES_FRAGMENTEES 20
|
||||
#define MAX_LONGUEUR_NOM_CHAMP_BDD 80
|
||||
|
||||
// Valeurs fonctionnelles :
|
||||
#define MAX_TENTATIVES_CONNEXION_BDD 30 // Au démarrage, la connexion à la BDD sera tentée autant de fois, avec une attente de 1s entre chaque essais (permet à tous les services d'être prêts au démarrage)
|
||||
#define PERIODE_CHECK_SYNCHRO_WEB 10 // x 10ms
|
||||
#define PERIODE_MAJ_BDD 10 // x 100ms
|
||||
#define PERIODE_ENREGISTREMENT_MESURES 150 // x 100ms
|
||||
|
||||
|
||||
|
||||
// Types d'init de la BDD :
|
||||
#define BDD_MODE_INIT_RESET 0 // Au démarrage après reset
|
||||
#define BDD_MODE_INIT_RELOAD 1 // Uniquement un rechargement des paramètres de config sur un système déjà démarré
|
||||
|
||||
// Types d'enrehistrement de mesures :
|
||||
#define BDD_ENREGISTREMENT_MESURE_INIT 0 // Au démarrage après reset. Les valeurs enregistrées sont toutes à NULL avec date de dernier Heart-Beat connu
|
||||
#define BDD_ENREGISTREMENT_MESURE_NORMAL 1 // Enregistrement normal (date en cours et valeur courante)
|
||||
#define BDD_ENREGISTREMENT_MESURE_PONCTUEL 2 // Enregistrement d'une valeur poctuelle (notamment capteur configuré en mode MODE_ENREGISTREMENT_MESURES_CHANGEMENT_ETAT)
|
||||
|
||||
// Types de demandes de mise à jour dans la BDD :
|
||||
#define BDD_TYPE_MAJ_AUCUNE 0
|
||||
#define BDD_TYPE_MAJ_COURANTE 1
|
||||
#define BDD_TYPE_MAJ_CONFIG 2
|
||||
|
||||
// Typde d'erreur K-Bus :
|
||||
#define DEFAUT_K_BUS_AUCUN 0
|
||||
#define DEFAUT_K_BUS_MINEUR 1
|
||||
#define DEFAUT_K_BUS_MAJEUR 2
|
||||
|
||||
// Types d'archivage :
|
||||
// Nb : les valeurs 0 et 1 étaient historiqueemnt utilisées et on n'a pas tout redécalé pour des raisons de simplicité...
|
||||
// D'autant que la valeur 0 est particulière pour les enregistrments de TB_Mesures_circuits...
|
||||
#define BDD_TYPE_ARCHIVAGE_1_HEURE 2 // L'archivage exécutera d'abord un Type 3 (5 minutes) puis un Type 2 (1h) dans la foulée
|
||||
#define BDD_TYPE_ARCHIVAGE_5_MINUTES 3 // Uniquement un Type 3
|
||||
#define BDD_TYPE_ARCHIVAGE_PURGE_SEULE 10
|
||||
#define BDD_TYPE_ARCHIVAGE_1_HEURE_ET_PURGE 12 // L'archivage exécutera d'abord un Type 3 (5 minutes) puis un Type 2 (1h) dans la foulée puis une purge [ce type d'appel est déconseillé car il cumule les 3 traitements !]
|
||||
#define BDD_TYPE_ARCHIVAGE_5_MINUTES_ET_PURGE 13 // L'archivage exécutera d'abord un Type 3 (5 minutes) puis une purge dans la foulée
|
||||
|
||||
|
||||
// Modes enregistrement des mesures
|
||||
#define MODE_ENREGISTREMENT_MESURES_AUCUN 0 // Aucun enregistrement de mesures
|
||||
#define MODE_ENREGISTREMENT_MESURES_PERIODIQUE 1 // Enregistrement des mesures périodique avec intégration sur la période et création de nouvelles mesures uniquement lorsque le seuil de marge est dépassé
|
||||
#define MODE_ENREGISTREMENT_MESURES_CHANGEMENT_ETAT 2 // Enregistrement d'une mesure sans cumul, chaque fois que le seuil de marge est dépassé
|
||||
|
||||
|
||||
// Modes enregistrement de l'historique
|
||||
#define MODE_ENREGISTREMENT_HISTORIQUE_AUCUN 0 // Les changements d'état ne sont pas enregistrés dans l'historique
|
||||
#define MODE_ENREGISTREMENT_HISTORIQUE_NORMAL 1 // Les changements d'état dont enregistrés dans l'historique
|
||||
|
||||
|
||||
// Type mesure :
|
||||
#define SOURCE_MESURE_CIRCUIT 1
|
||||
#define SOURCE_MESURE_CAPTEUR 2
|
||||
#define SOURCE_MESURE_RESERVOIR 3
|
||||
#define SOURCE_MESURE_BATTERIE 4
|
||||
|
||||
// Etat fichier download:
|
||||
#define ETAT_FICHIER_DOWNLOAD_LISTE 0
|
||||
#define ETAT_FICHIER_DOWNLOAD_TELECHARGE 1
|
||||
#define ETAT_FICHIER_DOWNLOAD_VERIFIE 2
|
||||
#define ETAT_FICHIER_DOWNLOAD_UPLOADE_COMPAGNON 3
|
||||
#define ETAT_FICHIER_DOWNLOAD_UPLOADE_EXTENSION 4
|
||||
#define ETAT_FICHIER_DOWNLOAD_INSTALLE_EXECUTE 5
|
||||
#define ETAT_FICHIER_DOWNLOAD_ARCHIVE 6
|
||||
#define ETAT_FICHIER_DOWNLOAD_EFFACE 7
|
||||
|
||||
|
||||
// Codes prédéfinis de messages aux users :
|
||||
#define MESSAGE_USERS_CODE_AUCUN 0
|
||||
#define MESSAGE_USERS_CODE_FIN_MINUTEUR 1 // Paramètres = 'compteur_initial' au format 'hh:mm:ss'
|
||||
#define MESSAGE_USERS_CODE_REVEIL 2 // Paramètres = 'condition_horaire' au format '[jour_semaine] @ [hh:mm]'
|
||||
#define MESSAGE_USERS_CODE_MAJ_EN_COURS 3 // Paramètres = 'id_module';'avancement_en_%' (id_module: -1=démarrage, 0-N=Id_module en cours, -2=fin)
|
||||
#define MESSAGE_USERS_CODE_REDEMARRAGE 4 // Paramètres = 'temps_restant' en ms ou rien
|
||||
#define MESSAGE_USERS_CODE_NOUVELLE_VERSION_DETECTEE 5 // Paramètres = 'ancienne version';'nouvelle version'
|
||||
#define MESSAGE_USERS_CODE_DEFAUT_CONFIG_K_BUS 6 // Paramètres = 'adresse_k_bus du premier module Nok';'Type_module_physique à cette adresse (yc -1 pour type inconnu)';'Type module configuré'.
|
||||
// Il peut donc y avoir : - Physique inconnu (pas de module physique à cette adresse) + config d'un type connu => vérifier K-bus entre module (@Adr-1) et module (@Adr)
|
||||
// - Physique connu + config d'un autre type ==> Il est probable qu'un/des modules aient été ajoutés/enlevés/déplacés ==> Aller dans config-K-Bus
|
||||
#define MESSAGE_USERS_CODE_DECLENCHEMENT_EVENT 7 // Paramètres = 'id_event'
|
||||
|
||||
|
||||
// Etat du message users :
|
||||
#define MESSAGE_USERS_ETAT_SUPPRESSION -1
|
||||
#define MESSAGE_USERS_ETAT_INFO 0
|
||||
#define MESSAGE_USERS_ETAT_ALERTE 1
|
||||
#define MESSAGE_USERS_ETAT_URGENT 2
|
||||
|
||||
|
||||
|
||||
// Historique :
|
||||
// Valeur principale (Système, Circuits, Capteurs, ... ne sert qu'à router sur la bonne table : TB_Historique_systeme, TB_Historique_circuits, etc...)
|
||||
// Event en uint8_t (valeur par défaut = 0)
|
||||
// ID en int (cle primaire de l'élément concerné)
|
||||
// Valeur en int (valeur par défaut = 0)
|
||||
// Complément en texte
|
||||
|
||||
//-------------------------------------------------------------
|
||||
#define TYPE_SOURCE_HISTORIQUE_SYSTEME 0
|
||||
#define SYSTEME_REINIT 1 // Réinitialisation de l'application
|
||||
#define SYSTEME_ERREUR_MYSQL 2
|
||||
#define SYSTEME_CONNEXION_USER 3
|
||||
#define SYSTEME_REBOOT 4 // Reboot du système
|
||||
#define SYSTEME_ARRET 5
|
||||
#define SYSTEME_TIME_OUT_CONNEXION 6
|
||||
#define SYSTEME_DECONNEXION_USER 7
|
||||
#define SYSTEME_CONFIGURATION_INVALIDE_DEMARRAGE_IMPOSSIBLE 8
|
||||
#define SYSTEME_SIGNAL_RECU 9 // La valeur du signal reçu est stocké dans Valeur
|
||||
#define SYSTEME_DEMANDE_REINIT 10
|
||||
#define SYSTEME_CHANGEMENT_VEILLE 11 // La nouvelle valeur de 'veille' est stockée dans Valeur
|
||||
#define SYSTEME_ERREUR_SAUVEGARDE_BDD 12 // Le message d'info sur l'erreur est stocké dans le complément.
|
||||
|
||||
#define SYSTEME_MODEM_DEMANDE_ACTIVATION 20 // La Valeur indique dans quel sens (On ou Off)
|
||||
#define SYSTEME_MODEM_CHANGEMENT_ETAT 21 // La Valeur indique dans quel sens (On ou Off)
|
||||
#define SYSTEME_MODEM_ERREUR_CHANGEMENT_ETAT 22 // La Valeur indique dans quel sens (On ou Off) le changement était demandé et a échoué
|
||||
#define SYSTEME_MODEM_ERREUR_ETABLISSEMENT_LIAISON 23
|
||||
#define SYSTEME_MODEM_CHANGEMENT_ETAT_NON_SOLLICITE 24 // La Valeur indique dans quel sens (On ou Off) le modem se trouve alors qu'il ne devrait pas
|
||||
#define SYSTEME_MODEM_CHANGEMENT_REVISION_FIRMWARE 25 // La valeur de révision est stockée dans Complément
|
||||
#define SYSTEME_MODEM_CHANGEMENT_IMEI 26 // Le n° est stocké dans Complément
|
||||
#define SYSTEME_MODEM_CHANGEMENT_IMSI 27 // Le n° est stocké dans Complément
|
||||
#define SYSTEME_MODEM_CHANGEMENT_ICCID 28 // Le n° est stocké dans Complément
|
||||
#define SYSTEME_MODEM_CHANGEMENT_NO_TELEPHONE 29 // Le n° est stocké dans Complément
|
||||
#define SYSTEME_MODEM_CHANGEMENT_APN 30 // Le n° est stocké dans Complément
|
||||
#define SYSTEME_MODEM_ERREUR_FTP 31 // Le code d'erreur reçu du modem est stocké dans Valeur et la réponse complète du modem dans Complement
|
||||
#define SYSTEME_MODEM_ERREUR_GNSS 32 // Le cycle d'acquisition n'a pas pu être réalisé complètement. Le nombre de cycles valides est indiqué dans Valeur.
|
||||
#define SYSTEME_MODEM_ERREUR_M_BUS_PLEIN 33 // Le nombre de refus de nouvelle commande dans le buffer de commandes est trop important. Le nb de refus consécutifs est dans Valeur
|
||||
#define SYSTEME_MODEM_PERTE_LIAISON_4G_LTE 34
|
||||
#define SYSTEME_MODEM_ETABLISSEMENT_LIAISON_4G_LTE 35
|
||||
|
||||
#define SYSTEME_MODULES_NOUVEAU_MODULE 40 // L'adresse K-Bus où est apparu le module est dans 'id'. Le Type de module est dans Valeur. L'adresse MAC est dans Complément
|
||||
#define SYSTEME_MODULES_SUPPRESSION_MODULE 41 // L'adresse K-Bus où était le module est dans 'id'. Le Type de module est dans Valeur. L'adresse MAC est dans Complément
|
||||
|
||||
#define SYSTEME_FTP_UPLOAD_FICHIER_DEBUT_OK 50 // Le nom du fichier source et du fichier destination sont stockés dans complément. La taille dans valeur
|
||||
#define SYSTEME_FTP_UPLOAD_FICHIER_DEBUT_NOK 51 // Le nom du fichier source et du fichier destination sont stockés dans complément. La taille dans valeur
|
||||
#define SYSTEME_FTP_UPLOAD_FICHIER_FIN_OK 52 // Le nom du fichier source et du fichier destination sont stockés dans complément. La taille dans valeur
|
||||
#define SYSTEME_FTP_UPLOAD_FICHIER_FIN_NOK 53 // Le nom du fichier source et du fichier destination sont stockés dans complément
|
||||
|
||||
#define SYSTEME_FTP_DOWNLOAD_FICHIER_DEBUT_OK 60 // Le nom du fichier source et du fichier destination sont stockés dans complément.
|
||||
#define SYSTEME_FTP_DOWNLOAD_FICHIER_DEBUT_NOK 61 // Le nom du fichier source et du fichier destination sont stockés dans complément. La taille dans valeur
|
||||
#define SYSTEME_FTP_DOWNLOAD_FICHIER_FIN_OK 62 // Le nom du fichier source et du fichier destination sont stockés dans complément.
|
||||
#define SYSTEME_FTP_DOWNLOAD_FICHIER_FIN_NOK 63 // Le nom du fichier source et du fichier destination sont stockés dans complément. La taille dans valeur
|
||||
#define SYSTEME_FTP_DOWNLOAD_LIST_NOK 64 // Le nom du fichier de LIST est stocké dans complément.
|
||||
#define SYSTEME_FTP_DOWNLOAD_NOMBRE_FICHIERS_LOCAUX_TROP_ELEVE 65 // Le nombre maxi admissible est stocké dans Valeur
|
||||
#define SYSTEME_FTP_DOWNLOAD_NOMBRE_FICHIERS_SERVEUR_TROP_ELEVE 66 // Le nombre maxi admissible est stocké dans Valeur
|
||||
|
||||
#define SYSTEME_EXECUTION_BASH_DEBUT_OK 70 // Le nom du fichier utilisé pour l'upload est dans le complément.
|
||||
#define SYSTEME_EXECUTION_BASH_DEBUT_NOK 71 // Le nom du fichier utilisé pour l'upload est dans le complément.
|
||||
#define SYSTEME_EXECUTION_BASH_FIN_OK 72 // Le nom du fichier utilisé pour l'upload est dans le complément.
|
||||
#define SYSTEME_EXECUTION_BASH_FIN_NOK 73 // Le nom du fichier utilisé pour l'upload est dans le complément.
|
||||
#define SYSTEME_COPIE_ARCHIVE_A_VALIDER_OK 74 // Le nom du fichier est dans le complément.
|
||||
#define SYSTEME_COPIE_ARCHIVE_A_VALIDER_NOK 75 // Le nom du fichier est dans le complément.
|
||||
#define SYSTEME_COPIE_ARCHIVE_A_CHARGER_OK 76 // Le nom du fichier est dans le complément.
|
||||
#define SYSTEME_COPIE_ARCHIVE_A_CHARGER_NOK 77 // Le nom du fichier est dans le complément.
|
||||
|
||||
#define SYSTEME_CHARGEMENT_CODE_DEBUT_OK 80 // Le nom du fichier utilisé pour l'upload est dans le complément. Le n° de la carte dans ID
|
||||
#define SYSTEME_CHARGEMENT_CODE_DEBUT_NOK 81 // Le nom du fichier utilisé pour l'upload est dans le complément. Le n° de la carte dans ID
|
||||
#define SYSTEME_CHARGEMENT_CODE_ERASE_FLASH_NOK 82 // Le nom du fichier utilisé pour l'upload est dans le complément. Le n° de la carte dans ID
|
||||
#define SYSTEME_CHARGEMENT_CODE_ECRITURE_FLASH_NOK 83 // Le nom du fichier utilisé pour l'upload est dans le complément. Le n° de la carte dans ID
|
||||
#define SYSTEME_CHARGEMENT_CODE_CRC_FLASH_NOK 84 // Le nom du fichier utilisé pour l'upload est dans le complément. Le n° de la carte dans ID
|
||||
#define SYSTEME_CHARGEMENT_CODE_FIN_OK 85 // Le nom du fichier utilisé pour l'upload est dans le complément. Le n° de la carte dans ID
|
||||
#define SYSTEME_CHARGEMENT_CODE_FIN_NOK 86 // Le nom du fichier utilisé pour l'upload est dans le complément. Le n° de la carte dans ID
|
||||
|
||||
|
||||
|
||||
#define SYSTEME_UART_BUFFER_RX_PLEIN 100 // Valeur précise quel UART
|
||||
#define SYSTEME_BUS_BUFFER_COMMANDES_PLEIN 101 // Valeur précise quel bus ('M' ou 'C')
|
||||
|
||||
#define SYSTEME_BACKLIGHT_CHANGEMENT_CONSIGNE 110 // La valeur indique la nouvelle consigne
|
||||
#define SYSTEME_VOLUME_CHANGEMENT_CONSIGNE 111 // La valeur indique la nouvelle consigne
|
||||
#define SYSTEME_LEDS_CHANGEMENT_CONSIGNE 112 // La valeur indique la nouvelle consigne
|
||||
|
||||
#define SYSTEME_WIFI_MISE_A_JOUR_CONFIG 130 // Les informations sur la nouvelle config sont stockées dans Complément
|
||||
|
||||
|
||||
//-------------------------------------------------------------
|
||||
#define TYPE_SOURCE_HISTORIQUE_CIRCUITS 1
|
||||
#define CIRCUIT_CHANGEMENT_CONSIGNE 1 // La nouvelle valeur de consigne est stockée dans Valeur. De plus, Complément comprend 'origine_consigne/id_origine_consigne'.
|
||||
|
||||
#define CIRCUIT_OK 10 // La valeur de limitation (en mA) est stockée dans Valeur
|
||||
#define CIRCUIT_LIMITATION 11 // La valeur de limitation (en mA) est stockée dans Valeur
|
||||
#define CIRCUIT_PROTECTION 12 // La valeur de limitation (en mA) est stockée dans Valeur
|
||||
#define CIRCUIT_DISJONCTE 13 // La valeur de limitation (en mA) est stockée dans Valeur
|
||||
#define CIRCUIT_CC_BATTERIE 14 // La valeur de limitation (en mA) est stockée dans Valeur
|
||||
#define CIRCUIT_DELESTAGE 15 // La valeur de limitation (en mA) est stockée dans Valeur
|
||||
|
||||
#define CIRCUIT_CREATION 20
|
||||
#define CIRCUIT_MODIFICATION 21
|
||||
#define CIRCUIT_SUPPRESSION 22
|
||||
|
||||
#define CIRCUIT_CONFIGURATION_INVALIDE 30 // L'ID précise la clé primaire. Valeur contient l'ID_Carte actuellement configuré
|
||||
|
||||
#define CIRCUIT_EXPIRATION_TIME_OUT 40 // La valeur initiale du time-out est stockée dans Valeur
|
||||
|
||||
#define CIRCUIT_ACTION_EVENT 50 // L'ID précise la clé primaire. Valeur contient la clé_primaire de l'event qui a déclenché l'action sur le circuit
|
||||
|
||||
//-------------------------------------------------------------
|
||||
#define TYPE_SOURCE_HISTORIQUE_CAPTEURS 2
|
||||
#define CAPTEUR_PASSAGE_OK 1 // L'ID précise la clé primaire. VAleur contient la valeur du capteur au moment du changement
|
||||
#define CAPTEUR_PASSAGE_ALERTE 2 // L'ID précise la clé primaire. VAleur contient la valeur du capteur au moment du changement
|
||||
#define CAPTEUR_PASSAGE_ALARME 3 // L'ID précise la clé primaire. VAleur contient la valeur du capteur au moment du changement
|
||||
|
||||
#define CAPTEUR_OW_DEVICE_OK 40 // L'ID précise la clé primaire. Complément contient le Rom_code du device One_wire
|
||||
#define CAPTEUR_OW_DEVICE_NOK 41 // L'ID précise la clé primaire. Complément contient le Rom_code du device One_wire
|
||||
#define CAPTEUR_OW_BUS_NOK 42 // L'ID précise la clé primaire. Complément contient le Rom_code du device One_wire
|
||||
|
||||
//-------------------------------------------------------------
|
||||
#define TYPE_SOURCE_HISTORIQUE_RESERVOIRS 3
|
||||
#define RESERVOIR_PASSAGE_NIVEAU_NORMAL 1 // L'ID précise le Réservoir. La valeur indique l'ancien état
|
||||
#define RESERVOIR_PASSAGE_NIVEAU_ALERTE 2 // L'ID précise le Réservoir. La valeur indique l'ancien état
|
||||
#define RESERVOIR_PASSAGE_NIVEAU_ALARME 3 // L'ID précise le Réservoir. La valeur indique l'ancien état
|
||||
|
||||
//-------------------------------------------------------------
|
||||
#define TYPE_SOURCE_HISTORIQUE_BATTERIES 4
|
||||
#define BATTERIE_ALARME_TEMPERATURE (BATTERIE_VARIABLE_TEMPERATURE + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
#define BATTERIE_ALARME_TENSION (BATTERIE_VARIABLE_TENSION + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
#define BATTERIE_ALARME_COURANT_DIFFERENTIEL (BATTERIE_VARIABLE_COURANT_DIFFERENTIEL + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
#define BATTERIE_ALARME_COURANT_CHARGE (BATTERIE_VARIABLE_COURANT_CHARGE + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
#define BATTERIE_ALARME_COURANT_DECHARGE (BATTERIE_VARIABLE_COURANT_DECHARGE + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
#define BATTERIE_ALARME_SOH (BATTERIE_VARIABLE_SOH + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
#define BATTERIE_ALARME_SOC (BATTERIE_VARIABLE_SOC + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
#define BATTERIE_ALARME_AUTONOMIE (BATTERIE_VARIABLE_AUTONOMIE + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
#define BATTERIE_ALARME_PUISSANCE (BATTERIE_VARIABLE_PUISSANCE + 1) // L'ID précise la batterie. La valeur indique l'état : 0=Ok, 1=Défaut seuil bas, 2=Défaut seuil haut, 3=Défaut seuil haut ET seuil bas, 99=Défaut calcul ou capteur (état inconnu)
|
||||
|
||||
|
||||
#define BATTERIE_RX_CDE_FORCAGE_PLEINE_CHARGE 11 // L'ID précise la batterie.
|
||||
#define BATTERIE_RX_CDE_RESET_SOH 12 // L'ID précise la batterie.
|
||||
#define BATTERIE_RX_CDE_RESET_COMPTEURS 13 // L'ID précise la batterie.
|
||||
|
||||
//-------------------------------------------------------------
|
||||
#define TYPE_SOURCE_HISTORIQUE_USB 5
|
||||
#define USB_CHANGEMENT_CONSIGNE 1 // La valeur indique le nouvel état. L'ID contient le n° du port (1 pour ports Avant ou 4 pour port Arrière)
|
||||
|
||||
#define USB_PASSAGE_OK 10 // L'ID contient le n° du port (1 à 3 ou 4 pour arrière)
|
||||
#define USB_PASSAGE_DEFAUT 11 // L'ID contient le n° du port (1 à 3 ou 4 pour arrière)
|
||||
|
||||
//-------------------------------------------------------------
|
||||
#define TYPE_SOURCE_HISTORIQUE_EVENTS 6
|
||||
#define EVENT_DECLENCHEMENT 1 // L'ID contient la cle_primaire de l'event
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier BDD_ADMIN.C
|
||||
//
|
||||
// Contient les fonctions de supervision de la BDD (archivage, sauvegard,...)
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************
|
||||
|
||||
// #define __DEBUG_ARCHIVAGE //Décommenter cette ligne pour avoir les messages de debug concernant les fonctions d'archivage
|
||||
|
||||
// Include :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int32_t sauvegarde_bdd(void);
|
||||
int8_t archivage_bdd(char * chaine_date_fin, uint8_t type);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Cette fonction génère un fichier de sauvegarde de la base de données.
|
||||
// Le fichier est stocké dans le répertoire d'upload pour pouvoir être remonté au serveur Koriolan via FTP ensuite (cette remontée ne fait pas partie de la présente fonction)
|
||||
// La base de données est sauvegardée en totalité (tous les enregistrements de toutes les tables) SAUF :
|
||||
// - les tables TB_Mesures_xxx : seuls les enregistrements dont le champ No_paquet est identique au No_paquet de TB_Systeme sont remontés.
|
||||
// - la table TB_Historique : seuls les enregistrements dont le champ No_paquet est identique au No_paquet de TB_Systeme sont remontés.
|
||||
// Le champ No_paquet de TB_Systeme est incrémenté dès la fin de l'archive (afin que les nouveaux enregistrements soient tagués avec ce nouveau n°)
|
||||
// Reçoit : Rien
|
||||
// Renvoit : 0 si pas d'erreur. Valeur de retour du premier appel 'system()' qui est différent de 0.
|
||||
//==================================================================================================================================================================
|
||||
int32_t sauvegarde_bdd(void)
|
||||
{
|
||||
int32_t retour_commande;
|
||||
char str_date[MAX_LONGUEUR_DATE_COURANTE];
|
||||
char nom_fichier_sauvegarde[MAX_LONGUEUR_NOM_FICHIER_SAUVEGARDE_BDD];
|
||||
FILE * ptr_fichier_sauvegarde;
|
||||
char requete[MAX_LONGUEUR_REQUETE_MYSQL];
|
||||
char commande[MAX_TAILLE_COMMANDE_SHELL];
|
||||
char options[MAX_LONGUEUR_OPTION_COMMANDE_SAUVEGARDE_BDD];
|
||||
char filtre_table[MAX_LONGUEUR_OPTION_COMMANDE_SAUVEGARDE_BDD];
|
||||
char param[MAX_LONGUEUR_OPTION_COMMANDE_SAUVEGARDE_BDD];
|
||||
struct {
|
||||
char nom[MAX_LONGUEUR_NOM_TABLE]; // Nom de la table (par exemple, TB_Mesures_capteurs')
|
||||
} tables_fragmentees[MAX_NOMBRE_TABLES_FRAGMENTEES];
|
||||
uint8_t nb_tables_fragmentees;
|
||||
MYSQL_RES *result = NULL;
|
||||
MYSQL_ROW row = NULL;
|
||||
uint16_t i;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
sprintf(tmp, "Début de sauvegarde de la BDD avec n° de paquet = %i", systeme.no_paquet);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
|
||||
// SDIR # 202 (début) :
|
||||
// Vérification qu'une phase d'archivage n'est pas en cours (si c'est le cas, on va décaler la sauvagarde pour éviter de surcharger inutilement le système) :
|
||||
if (get_pid_numbers_from_name(NOM_FICHIER_ARCHIVAGE, "") > 0) // Il y a au moins 1 processus d'archivage en cours...
|
||||
{
|
||||
systeme.compteur_sauvegarde_bdd = SYSTEME_TEMPO_REPORT_SAUVEGARDE; // Dans ce cas, on relance une tempo courte (5s typique) avant de refaire une tentative.
|
||||
|
||||
sprintf(tmp, "Un processus [%s] a été détecté en cours d'exécution. La sauvegarde est temporisée pour %i secondes", NOM_FICHIER_ARCHIVAGE, systeme.compteur_sauvegarde_bdd);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
// SDIR # 202 (fin)
|
||||
|
||||
|
||||
|
||||
retour_commande = 0;
|
||||
|
||||
// Calcul de la date et de l'heure, au bon format :
|
||||
date_courante(str_date, DATE_COURANTE_SANS_MS, FORMAT_DATE_COURANTE_FICHIER);
|
||||
|
||||
// Nom du fichier de sauvegarde :
|
||||
// sprintf(nom_fichier_sauvegarde, "%s/%s_%s.sql", REPERTOIRE_SERVER_UPLOAD, NOM_FICHIER_SAUVEGARDE_BDD, str_date); // SDIR #298
|
||||
sprintf(nom_fichier_sauvegarde, // SDIR #298
|
||||
"%s/%02X%02X%02X%02X%02X%02X_%08i_%s.sql", // Le '%08i' permet de forcer le n° de paquet avec 8 chiffres commençant par 0. Sinon, '10' est trié avant '9' par exemple. 8 chiffres = 1 fichier par minutes pendant 190 ans...
|
||||
REPERTOIRE_SERVER_UPLOAD,
|
||||
systeme.modules_physiques[0].adresse_mac[0], systeme.modules_physiques[0].adresse_mac[1], systeme.modules_physiques[0].adresse_mac[2],
|
||||
systeme.modules_physiques[0].adresse_mac[3], systeme.modules_physiques[0].adresse_mac[4], systeme.modules_physiques[0].adresse_mac[5],
|
||||
systeme.no_paquet, str_date); // SDIR #298
|
||||
|
||||
// Options de la commande de sauvegarde (utilisée sur la commande 'mysqldump' :
|
||||
sprintf(options, "--single-transaction --no-create-info --compact --complete-insert");
|
||||
// sprintf(options, "--single-transaction --skip-lock-tables --no-create-info --compact --complete-insert"); // SDIR # 202
|
||||
|
||||
|
||||
do // Fake loop...
|
||||
{
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// Remplissage de l'entête du fichier de sauvegarde (SDIR #292) :
|
||||
//-------------------------------------------------------------------------------------------
|
||||
ptr_fichier_sauvegarde = fopen(nom_fichier_sauvegarde, "w+"); // Ouverture du flux en lecture/écriture. Si le fichier existe, il sera alors écrasé et la position courante est fixée au début du fichier. Sinon le fichier sera créé.
|
||||
if (ptr_fichier_sauvegarde == NULL)
|
||||
{
|
||||
printf("Ouverture du fichier de sauvegarde [ %s ] impossible. La sauvegarde est arrêtée !\n", nom_fichier_sauvegarde);
|
||||
retour_commande = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Attention : le format '# [nom_de_champ=valeur_du_champ]' est utilisé par la fonction 'upload_code.php' sur le serveur...
|
||||
// Il est donc fortement conseillé de ne PAS modifier le format de ces trames d'entête !!!
|
||||
fprintf(ptr_fichier_sauvegarde,
|
||||
"# [Adresse_mac=%02X:%02X:%02X:%02X:%02X:%02X]\n",
|
||||
systeme.modules_physiques[0].adresse_mac[0], systeme.modules_physiques[0].adresse_mac[1], systeme.modules_physiques[0].adresse_mac[2],
|
||||
systeme.modules_physiques[0].adresse_mac[3], systeme.modules_physiques[0].adresse_mac[4], systeme.modules_physiques[0].adresse_mac[5]);
|
||||
fprintf(ptr_fichier_sauvegarde, "# [Nom_du_bateau=%s]\n", systeme.nom_bateau);
|
||||
fprintf(ptr_fichier_sauvegarde, "# [No_paquet=%i]\n", systeme.no_paquet);
|
||||
fprintf(ptr_fichier_sauvegarde, "# [Date_fichier=%s]\n", str_date);
|
||||
fprintf(ptr_fichier_sauvegarde, "# [Version_soft_no_package=%s]\n", systeme.package_no_version);
|
||||
|
||||
fclose(ptr_fichier_sauvegarde);
|
||||
|
||||
// Fin de SDIR #292
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// Recherche des tables fragmentées : TB_Mesures* et TB_Historique
|
||||
//-------------------------------------------------------------------------------------------
|
||||
nb_tables_fragmentees = 0;
|
||||
|
||||
// Tables de mesures :
|
||||
sprintf(requete, "SHOW TABLES FROM shipheart LIKE 'TB_Mesures%%'");
|
||||
mysql_query(bdd.pointeur, requete);
|
||||
result = mysql_store_result(bdd.pointeur);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
strcpy(tables_fragmentees[nb_tables_fragmentees ++].nom, row[0]);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
// Table historique :
|
||||
strcpy(tables_fragmentees[nb_tables_fragmentees ++].nom, "TB_Historique");
|
||||
|
||||
// Vérification du nombre de tables max :
|
||||
if (nb_tables_fragmentees > MAX_NOMBRE_TABLES_FRAGMENTEES)
|
||||
{
|
||||
sprintf(tmp, "Le nombre de tables fragmentées (qui sont sauvegardées par fragment) est supérieur au nombre maxi (%i tables trouvées pour maxi = %i). La sauvegarde de la BDD est arrêté.", nb_tables_fragmentees, MAX_NOMBRE_TABLES_FRAGMENTEES);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
retour_commande = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("Le nombre de tables fragmentées trouvé est : %i \n", nb_tables_fragmentees);
|
||||
//for (i = 0; i < nb_tables_fragmentees; i ++) printf("\tTable #%i: [%s]\n", i, tables_fragmentees[i].nom);
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// Sauvegarde de toutes les tables, sauf TB_Mesures* et TB_Historique :
|
||||
//-------------------------------------------------------------------------------------------
|
||||
|
||||
// Début de la commande de dump:
|
||||
sprintf(commande, "mysqldump %s -u %s --password=%s %s ", options, BDD_USER, BDD_PASSWORD, BDD_DATABASE);
|
||||
|
||||
// Suppression des tables fragmentées du dump :
|
||||
for (i = 0; i < nb_tables_fragmentees; i ++)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-overflow"
|
||||
sprintf(param, "--ignore-table=%s.%s ", BDD_DATABASE, tables_fragmentees[i].nom); // Warning connu mais non justifié : tables_fragmentees[].nom : 50 car et param : 300 car
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
strcat(commande, param);
|
||||
}
|
||||
|
||||
// Fin de la commande :
|
||||
sprintf(param, ">> %s ", nom_fichier_sauvegarde);
|
||||
strcat(commande, param);
|
||||
|
||||
// printf("Commande shell = [%s]\n", commande);
|
||||
|
||||
retour_commande = commande_shell(commande);
|
||||
if (retour_commande != 0)
|
||||
{
|
||||
sprintf(tmp, "La commande de sauvegarde de toutes les tables non fragmentées [%s] a échoué avec le code %i", commande, retour_commande);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Sauvegarde des derniers enregistrements des tables fragmentées :
|
||||
//---------------------------------------------------------------------
|
||||
for (i = 0; i < nb_tables_fragmentees; i ++)
|
||||
{
|
||||
// Ajout au fichier de sauvegarde des enregistrements de la table dont le No_paquet est égal à celui de TB_Systeme.No_paquet :
|
||||
// NB : la requête pourrait être complétée d'un 'ORDER BY Date' mais cela risque de prendre du temps et ne semble pas nécessaire...
|
||||
|
||||
// Suppression des 'Type>0' pour TB_Mesures_circuits :
|
||||
if (strstr(tables_fragmentees[i].nom, "TB_Mesures_circuits") != NULL) strcpy(filtre_table, " AND Type=0");
|
||||
else strcpy(filtre_table, "");
|
||||
sprintf(commande, "mysqldump %s -u %s --password=%s %s %s --where=\"No_paquet=%i %s \" >> %s", options, BDD_USER, BDD_PASSWORD, BDD_DATABASE, tables_fragmentees[i].nom, systeme.no_paquet, filtre_table, nom_fichier_sauvegarde);
|
||||
//printf("Commande shell = [%s]\n", commande);
|
||||
retour_commande = commande_shell(commande);
|
||||
if (retour_commande != 0)
|
||||
{
|
||||
sprintf(tmp, "La commande de sauvegarde de la table fragmentée %s [%s] a échoué avec le code %i", tables_fragmentees[i].nom, commande, retour_commande);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
break; // Sortie de la boucle FOR
|
||||
}
|
||||
}
|
||||
if (retour_commande != 0) break;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Compression du fichier de sauvegarde :
|
||||
//---------------------------------------------------------------------
|
||||
// SDIR #170 : ajout du paramètre '-k' dans la commande de compresion afin de conserver le fichier SQL initial (sinon, il n'est pas conservé par GZIP)
|
||||
sprintf(commande, "gzip %s -k -S .%s", nom_fichier_sauvegarde, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD);
|
||||
// sprintf(tmp, "Commande de compression = [%s]\n", commande);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
retour_commande = commande_shell(commande);
|
||||
if (retour_commande != 0)
|
||||
{
|
||||
sprintf(tmp, "La commande de compression du fichier de sauvegarde [%s] a échoué avec le code %i", commande, retour_commande);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
break;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Encryption du fichier de sauvegarde :
|
||||
//---------------------------------------------------------------------
|
||||
sprintf(commande, "openssl enc -aes-256-cbc -pbkdf2 -iter 10000 -md sha256 -in %s.%s -out %s.%s.%s -pass pass:%s", nom_fichier_sauvegarde, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD, nom_fichier_sauvegarde, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD, SUFFIXE_NOM_FICHIER_ENCRYPTE_SAUVEGARDE_BDD, BDD_PASSWORD);
|
||||
// sprintf(tmp, "Commande d'encryptage = [%s]\n", commande);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
retour_commande = commande_shell(commande);
|
||||
if (retour_commande != 0)
|
||||
{
|
||||
sprintf(tmp, "La commande d'encryption du fichier de sauvegarde [%s] a échoué avec le code %i", commande, retour_commande);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
break;
|
||||
}
|
||||
|
||||
// SDIR #170 : cf jusqu'à la fin de la fake loop...
|
||||
//---------------------------------------------------------------------
|
||||
// Décryptage du fichier final :
|
||||
//---------------------------------------------------------------------
|
||||
sprintf(commande, "openssl enc -aes-256-cbc -pbkdf2 -iter 10000 -md sha256 -d -in %s.%s.%s -out %s/%s.sql.%s -pass pass:Mp7Hgf12bV9zm", nom_fichier_sauvegarde, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD, SUFFIXE_NOM_FICHIER_ENCRYPTE_SAUVEGARDE_BDD, REPERTOIRE_TMP_BDD, NOM_FICHIER_CHECK_SAUVEGARDE, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD);
|
||||
// sprintf(tmp, "Commande de décryptage temporaire = [%s]\n", commande);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
retour_commande = commande_shell(commande);
|
||||
if (retour_commande != 0)
|
||||
{
|
||||
sprintf(tmp, "La commande de décrytage temporaire du fichier de sauvegarde [%s] a échoué avec le code %i", commande, retour_commande);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
break;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Décompression du fichier temporaire :
|
||||
//---------------------------------------------------------------------
|
||||
sprintf(commande, "gzip -d -f %s/%s.sql.%s", REPERTOIRE_TMP_BDD, NOM_FICHIER_CHECK_SAUVEGARDE, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD);
|
||||
// sprintf(tmp, "Commande de décompression temporaire = [%s]\n", commande);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
retour_commande = commande_shell(commande);
|
||||
if (retour_commande != 0)
|
||||
{
|
||||
sprintf(tmp, "La commande de décompression temporaire [%s] a échoué avec le code %i", commande, retour_commande);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
break;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Comparaison du fichier temporaire avec le fichier inital :
|
||||
//---------------------------------------------------------------------
|
||||
sprintf(commande, "diff -q %s %s/%s.sql", nom_fichier_sauvegarde, REPERTOIRE_TMP_BDD, NOM_FICHIER_CHECK_SAUVEGARDE);
|
||||
//sprintf(commande, "diff -q %s %s/%s_test.sql", nom_fichier_sauvegarde, REPERTOIRE_TMP_BDD, NOM_FICHIER_CHECK_SAUVEGARDE);
|
||||
|
||||
// sprintf(tmp, "Commande de comparaison du fichier temporaire avec le fchier inital = [%s]\n", commande);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
retour_commande = commande_shell(commande);
|
||||
if (retour_commande != 0)
|
||||
{
|
||||
sprintf(tmp, "La comparaison du fichier temporaire avec le fichier inital [%s] indique deux fichiers différents [%i]", commande, retour_commande);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
break;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Vérification que la sauvegarde s'est bien passée et retour :
|
||||
//---------------------------------------------------------------------
|
||||
if (retour_commande != 0) // Cas où au moins l'une des opérations de sauvegarde ne s'est pas bien passée
|
||||
{
|
||||
// Enregistrement dans l'historique :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_ERREUR_SAUVEGARDE_BDD, 0, 0, tmp);
|
||||
|
||||
// Suppression du fichier qui est incomplet, mais aussi du fichier compressé et du fichier encrypté car on ne sait pas où on s'est arrêté) :
|
||||
sprintf(commande, "%s", nom_fichier_sauvegarde);
|
||||
remove(commande);
|
||||
sprintf(commande, "%s.%s", nom_fichier_sauvegarde, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD);
|
||||
remove(commande);
|
||||
sprintf(commande, "%s.%s.%s", nom_fichier_sauvegarde, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD, SUFFIXE_NOM_FICHIER_ENCRYPTE_SAUVEGARDE_BDD);
|
||||
remove(commande);
|
||||
|
||||
sprintf(tmp, "La sauvegarde de la BDD est abandonnée. Les fichiers créés ont été supprimés et les indicateurs de sauvegarde dans TB_Systeme ont été remis à leur valeur d'origine.");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
// NB : en pratique, c'est le fait de ne PAS incrémenter le n° de paquet dans TB_Systeme qui permettra de reprendre les enregistrements qui étaient prévus dans cet archive dans la prochaine.
|
||||
|
||||
return(retour_commande);
|
||||
}
|
||||
else // Cas normal, sans erreur :
|
||||
{
|
||||
// Incrémentation du No_paquet :
|
||||
systeme.no_paquet ++;
|
||||
sprintf(requete, "UPDATE TB_Systeme SET Valeur='%i' WHERE Nom='No_paquet' ", systeme.no_paquet);
|
||||
// printf("requête = [%s]\n", requete);
|
||||
mysql_query(bdd.pointeur, requete);
|
||||
|
||||
// Supression du fichier SQL (qui a été volontairement conservé via le paramètre '-k' de GZIP)...
|
||||
// ... et du fichier compressé (openssl ne peut pas "écraser" la source si elle est dans le même répertoire ; on le fait donc manuellement)...
|
||||
// ... si tout s'est bien passé :
|
||||
sprintf(commande, "%s", nom_fichier_sauvegarde);
|
||||
remove(commande);
|
||||
sprintf(commande, "%s.%s", nom_fichier_sauvegarde, SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD);
|
||||
remove(commande);
|
||||
}
|
||||
|
||||
affichage_debug(__FILE__, __LINE__, "Fin de sauvegarde de la BDD", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction ARCHIVAGE_BDD
|
||||
//
|
||||
// Fonction : Lance l'utilitaire 'archivage.php' situé dans '/utils'
|
||||
// Reçoit : la chaine de date de fin de période à utiliser et le Type d'archivage à réaliser (de 0 à 3 ou 10 - cf bdd.h : BDD_TYPE_ARCHIVAGE_xxxx)
|
||||
// Retour : -1 en cas d'erreur, 0 si Ok
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int8_t archivage_bdd(char * chaine_date_fin, uint8_t type)
|
||||
{
|
||||
char commande[MAX_TAILLE_COMMANDE_SHELL];
|
||||
time_t now;
|
||||
struct tm maintenant;
|
||||
int32_t pid_nb;
|
||||
char suffixe_fichier_log[MAX_LONGUEUR_NOM_FICHIER];
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
// Calcul de la date courante pour nommer le fichier de logs :
|
||||
time(&now);
|
||||
maintenant = *localtime(&now);
|
||||
|
||||
// Vérification des paramètres & préparation du suffixe de fichier de logs :
|
||||
switch(type)
|
||||
{
|
||||
case BDD_TYPE_ARCHIVAGE_1_HEURE :
|
||||
{
|
||||
sprintf(suffixe_fichier_log, "_h%02i", maintenant.tm_hour);
|
||||
break;
|
||||
}
|
||||
case BDD_TYPE_ARCHIVAGE_5_MINUTES :
|
||||
{
|
||||
sprintf(suffixe_fichier_log, "_min%02i", maintenant.tm_min);
|
||||
break;
|
||||
}
|
||||
case BDD_TYPE_ARCHIVAGE_PURGE_SEULE :
|
||||
{
|
||||
sprintf(suffixe_fichier_log, "_purge_demarrage"); // Cet appel n'étant fait qu'au démarrage (et donc à des heures/min non définies, on prend un nom générique qui sera donc écrasé à chaque démarrage)
|
||||
break;
|
||||
}
|
||||
case BDD_TYPE_ARCHIVAGE_1_HEURE_ET_PURGE :
|
||||
case BDD_TYPE_ARCHIVAGE_5_MINUTES_ET_PURGE :
|
||||
{
|
||||
sprintf(suffixe_fichier_log, "_purge_%02i_%02i", maintenant.tm_hour, maintenant.tm_min);
|
||||
break;
|
||||
}
|
||||
default : return (-1);
|
||||
}
|
||||
|
||||
// Récupération du nombre de process incluant 'archivage.php' :
|
||||
pid_nb = get_pid_numbers_from_name(NOM_FICHIER_ARCHIVAGE, "");
|
||||
|
||||
// Archivage si aucun processus équivalent n'est déjà en cours :
|
||||
if (pid_nb <= 0) // Il ny a aucun processus d'archivage en cours...
|
||||
{
|
||||
sprintf(commande, "sudo nice -n 18 php %s/%s \"%s\" %i >%s/%s%s.txt &", REPERTOIRE_UTILS, NOM_FICHIER_ARCHIVAGE, chaine_date_fin, type, REPERTOIRE_LOGS, PREFIXE_NOM_FICHIER_ARCHIVAGE_LOG, suffixe_fichier_log); // AVEC '&' de terminaison car c'était bien l'objectif, de faire exécuter cette tâche en tâche de fond...!
|
||||
commande_shell(commande);
|
||||
|
||||
if (pid_nb == 0)
|
||||
{
|
||||
sprintf(tmp, "La commande d'archivage [%s] vient d'être lancée en tâche de fond car aucun processus d'archivage n'a été détecté en cours d'exécution", commande);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "Le retour de recherche de processus d'archivage en cours a détecté une erreur (%i). L'archivage demandé est exécuté quand même...", pid_nb);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
}
|
||||
else // Il y a déjà un processus en cours :
|
||||
{
|
||||
sprintf(tmp, "Au moins un processus d'archivage a été détecté en cours d'exécution (nb = %i). L'archivage demandé n'est donc pas exécuté...", pid_nb);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
// NB : dans ce cas, on ne met pas à jour 'systeme.jour_dernier_archivage' afin qu'une nouvelle tentative soit effectuée dans 5 minutes...
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------- RETOUR ------------------------------------
|
||||
return(0);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+3605
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+548
@@ -0,0 +1,548 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier C_BUS.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à la gestion du C_Bus
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
|
||||
#define __DEBUG_C_BUS 0 // Passer cette ligne à 0: aucun message de debug de C_bus, 1: les messages de debug de C_Bus sur l'écran, 2: sur fichier (cf NOM_FICHIER_DEBUG_BUS dans 'debug.h') ou 3: sur l'écran et fichier.
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t init_c_bus(void);
|
||||
void gestion_c_bus(void);
|
||||
int8_t gestion_protocole_rx_c_bus(void);
|
||||
void gestion_protocole_tx_c_bus(void);
|
||||
int8_t c_bus_next_write_buffer_cdes(uint8_t priorite);
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_c_bus c_bus;
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_C_BUS
|
||||
|
||||
Fonction d'initialisation du C-Bus
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_c_bus(void)
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------------
|
||||
// Init des variables générales :
|
||||
|
||||
c_bus.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_INIT;
|
||||
c_bus.sequenceur.compteur = C_BUS_TEMPO_INIT;
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_INIT;
|
||||
c_bus.protocole_rx.sequenceur.compteur = C_BUS_PROTOCOLE_RX_TEMPO_INIT;
|
||||
c_bus.protocole_rx.flag_dle = FALSE;
|
||||
|
||||
c_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_TX_INIT;
|
||||
c_bus.protocole_tx.sequenceur.compteur = C_BUS_PROTOCOLE_TX_TEMPO_INIT;
|
||||
|
||||
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation du C-BUS\t\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction GESTION_C_BUS
|
||||
|
||||
Fonction de plus haut niveau de gestion du C-Bus
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_c_bus(void)
|
||||
{
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
switch(c_bus.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_INIT :
|
||||
{
|
||||
if (c_bus.sequenceur.compteur == 0)
|
||||
{
|
||||
//.........................................................
|
||||
// Vidage du buffer de réception de tous les caractères reçus pendant la phase d'init :
|
||||
serial1.ptr_debut_buffer_rx = 0;
|
||||
serial1.ptr_fin_buffer_rx = 0;
|
||||
|
||||
//.........................................................
|
||||
// Mise à jour des séquenceurs pour démarrage des envois :
|
||||
c_bus.protocole_rx.sequenceur.compteur = 0;
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_REPOS;
|
||||
c_bus.protocole_tx.sequenceur.compteur = 0;
|
||||
c_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_TX_REPOS;
|
||||
c_bus.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_REPOS;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_REPOS :
|
||||
{
|
||||
//=================================
|
||||
// Gestion du C-Bus en émission :
|
||||
|
||||
gestion_protocole_tx_c_bus(); // Vérifie si une réponse (Up) ou une commande (Down) est en attente. Si oui, elle la traite et l'émet.
|
||||
|
||||
|
||||
//=================================
|
||||
// Gestion du C-Bus en réception :
|
||||
|
||||
if (gestion_protocole_rx_c_bus() == 1) // Vérifie si une commande (Up) ou une réponse (Down) a été reçue.
|
||||
{
|
||||
|
||||
#ifdef __DEBUG_C_BUS
|
||||
c_bus.down.reponse.reponse[c_bus.down.reponse.lg_reponse] = 0; // On ajoute un /0 à la fin mais on ne change surtout pas la longueur qui est utilisée pour les transferts binaires.
|
||||
affichage_debug_bus(TYPE_BUS_DEBUG_C_BUS, "Rx", (char *) c_bus.down.reponse.reponse, __DEBUG_C_BUS);
|
||||
#endif
|
||||
if (c_bus.protocole_rx.sens == 'U') // Réception d'une commande (Up) :
|
||||
{
|
||||
c_bus_up_recherche_commande(); // Recherche et traitement de la commande reçue. La réponse est préparée et son 'flag_ready' est positionné afin d'être traité par gestion_protocole_tx_c_bus() lors de la prochaine boucle.
|
||||
}
|
||||
else // Réception d'une réponse (Down) :
|
||||
{
|
||||
if (c_bus_down_recherche_reponse() != -1) // Comme la réponse a été reçue sans erreur, on libère le Protocole_Tx :
|
||||
{
|
||||
c_bus.down.flag_attente_reponse = FALSE;
|
||||
c_bus.protocole_tx.repetitions = 0;
|
||||
c_bus.protocole_tx.sequenceur.compteur_time_out = 0;
|
||||
}
|
||||
else c_bus.protocole_tx.sequenceur.compteur_time_out = 0; // En cas de réponse reçue avec erreur, on simule un déclenchement de time-out pour faire de suite le test du nombre de répétitions (cela permet juste de ne pas attandre l'expiration du time-out)
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur C_bus est inconnu [%i]. Il est repositionné au REPOS", c_bus.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
c_bus.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Appelée en tâche de fond, cette fonction lit le buffer de réception de l'UART 1 et traite les trames reçues.
|
||||
Soit une commande du Compagnon (Up), soit une réponse à une commande du CM3+ (Down)
|
||||
Reçoit : Rien
|
||||
Renvoit : 0 si RAS, 1 si une nouvelle commande complète a été reçue
|
||||
******************************************************************************************************************************************************************/
|
||||
int8_t gestion_protocole_rx_c_bus(void)
|
||||
{
|
||||
uint8_t c;
|
||||
bool flag_controle;
|
||||
bool flag_cde_recue;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
flag_cde_recue = FALSE;
|
||||
|
||||
// Traitement de chaque caractère reçu :
|
||||
while (serial1.ptr_debut_buffer_rx != serial1.ptr_fin_buffer_rx)
|
||||
{
|
||||
// Calcul de la prochaine position à lire (avec bouclage en fin de buffer tournant) :
|
||||
if (++ serial1.ptr_debut_buffer_rx == MAX_TAILLE_RX_BUFFER_UART) serial1.ptr_debut_buffer_rx = 0;
|
||||
|
||||
// Lecture du caractère dans le buffer :
|
||||
flag_controle = FALSE; // Permettra de marquer le caractère en cours de lecture
|
||||
c = serial1.buffer_rx[serial1.ptr_debut_buffer_rx]; // Lecture du caractère à traiter
|
||||
|
||||
|
||||
// Traitement des caractères DLE :
|
||||
if (c_bus.protocole_rx.flag_dle == TRUE) // Si le caractère précédent était un DLE
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case ASCII_DLE : break; // C'est un DLE qui a fort justement été doublé, on va donc traiter le second comme un octet de data.
|
||||
|
||||
case ASCII_SOH : // Caractères de contrôle échappés
|
||||
case ASCII_STX :
|
||||
case ASCII_ETX :
|
||||
{
|
||||
flag_controle = TRUE; // On marque donc 'x' comme un caractère de contrôle et non une data
|
||||
break;
|
||||
}
|
||||
|
||||
default: // erreur de "DLE isolé"
|
||||
{
|
||||
flag_controle = TRUE; // On marque donc 'x' comme un caractère de contrôle et non une data
|
||||
c = ASCII_NULL; // On change volontairement la valeur à NULL afin que la trame soit rejetée et qu'en fonction de l'état du séquenceur, un NACK soit retourné ou non...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c_bus.protocole_rx.flag_dle = FALSE; // Dans tous les cas précédent, le premier DLE a été traité (y compris dans le cas d'un double DLE)
|
||||
}
|
||||
else // Si le caractère précédent n'était PAS un DLE :
|
||||
{
|
||||
if (c == ASCII_DLE) c_bus.protocole_rx.flag_dle = TRUE; // On positionne le flag si c'est un DLE
|
||||
}
|
||||
|
||||
|
||||
// Traitement du caractère reçu :
|
||||
if (c_bus.protocole_rx.flag_dle == FALSE) // Sauf si on est sur le "premier" DLE...
|
||||
{
|
||||
switch(c_bus.protocole_rx.sequenceur.etat)
|
||||
{
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_INIT :
|
||||
{
|
||||
// NB : Le caractère lu est jeté tant que la phase d'init n'est pas terminée...
|
||||
// NB 2 : le passage à l'état REPOS se fait par le séquenceur C-Bus, indépendemment de la réception ou non de caractères.
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_REPOS :
|
||||
{
|
||||
if ((flag_controle == TRUE) && (c == ASCII_SOH)) // Attente de réception du SOH de début de trame
|
||||
{
|
||||
c_bus.protocole_rx.cs = (uint16_t) c; // Premier chargement du CS
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_SENS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_SENS :
|
||||
{
|
||||
c_bus.protocole_rx.cs += (uint16_t) c; // Rechargement du CS
|
||||
|
||||
if ((c == 'D') || (c =='U'))
|
||||
{
|
||||
c_bus.protocole_rx.sens = c;
|
||||
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_STX;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __DEBUG_C_BUS
|
||||
affichage_debug(__FILE__, __LINE__, "Etat séquenceur C-Bus = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_SENS", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_ERREUR; // Erreur de CS
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_STX :
|
||||
{
|
||||
c_bus.protocole_rx.cs += (uint16_t) c; // Rechargement du CS
|
||||
|
||||
if ((flag_controle == TRUE) && (c == ASCII_STX))
|
||||
{
|
||||
if (c_bus.protocole_rx.sens == 'U') c_bus.up.cde.lg_cde = 0; // On reçoit une commande Up...
|
||||
else c_bus.down.reponse.lg_reponse = 0; // ... ou une réponse à une commande Down
|
||||
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_DATA;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __DEBUG_C_BUS
|
||||
affichage_debug(__FILE__, __LINE__, "Etat séquenceur C-Bus = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_STX", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_ERREUR; // Erreur de CS
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_DATA :
|
||||
{
|
||||
c_bus.protocole_rx.cs += (uint16_t) c; // Rechargement du CS
|
||||
|
||||
if (flag_controle == FALSE)
|
||||
{
|
||||
if (c_bus.protocole_rx.sens == 'U') c_bus.up.cde.cde[c_bus.up.cde.lg_cde ++] = c;
|
||||
else c_bus.down.reponse.reponse[c_bus.down.reponse.lg_reponse ++] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == ASCII_ETX)
|
||||
{
|
||||
c_bus.protocole_rx.cs_recu = 0;
|
||||
c_bus.protocole_rx.ptr_cs_recu = 0;
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_CS;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __DEBUG_C_BUS
|
||||
affichage_debug(__FILE__, __LINE__, "Etat séquenceur C-Bus = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_DATA", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_ERREUR; // Erreur de CS
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_CS :
|
||||
{
|
||||
if (c_bus.protocole_rx.ptr_cs_recu == 0) // Premier caractère de CS reçu, à archviver en LSB :
|
||||
{
|
||||
c_bus.protocole_rx.cs_recu = ((uint16_t) c) & 0x00FF;
|
||||
c_bus.protocole_rx.ptr_cs_recu ++;
|
||||
}
|
||||
else // Second caractère de CS reçu, à archiver en MSB puis comparer avec la valeur calculée :
|
||||
{
|
||||
c_bus.protocole_rx.cs_recu |= (((uint16_t) c) & 0x00FF) << 8;
|
||||
if (c_bus.protocole_rx.cs == c_bus.protocole_rx.cs_recu)
|
||||
{
|
||||
flag_cde_recue = TRUE; // Flag pour remonter qu'une commande a été reçue et sans erreur
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_REPOS; // Retour du séquenceur au repos
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __DEBUG_C_BUS
|
||||
affichage_debug(__FILE__, __LINE__, "Etat séquenceur C-Bus = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_CS", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_ERREUR; // Erreur de CS
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_ERREUR :
|
||||
{
|
||||
|
||||
// !!!! Voir si retour d'un NACK.... !!!!
|
||||
|
||||
affichage_debug(__FILE__, __LINE__, "Erreur de protocole Rx sur C-Bus", TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_REPOS;
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur C-Bus.Protocole_Rx est inconnu [%i]. Il est repositionné au REPOS", c_bus.protocole_rx.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
c_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flag_cde_recue) break;
|
||||
|
||||
}
|
||||
|
||||
if (flag_cde_recue) return(1);
|
||||
else return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Appelée en tâche de fond, cette fonction vérifie si une réponse est à émettre vers le Compagnon (Up) ou si une commande est prête à être émise
|
||||
dans le buffer de commandes Down. Si oui, elle gère via son séquenceur le formattage de la trame à émettre.
|
||||
Reçoit : Rien
|
||||
Renvoit : Rien
|
||||
*****************************************************************************************************************************************************************/
|
||||
void gestion_protocole_tx_c_bus(void)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t c;
|
||||
uint8_t sens;
|
||||
uint16_t cs;
|
||||
uint8_t tx_buffer[C_BUS_MAX_TAILLE_BUFFER_TX];
|
||||
uint16_t lg_tx_buffer;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
switch(c_bus.protocole_tx.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_TX_INIT :
|
||||
{
|
||||
// NB : le passage à l'état REPOS se fait par le séquenceur C-Bus, indépendemment de la présence de commande à émettre
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_TX_REPOS :
|
||||
{
|
||||
//..................................
|
||||
// Recherche d'une trame à émettre :
|
||||
if (c_bus.up.reponse.flag_ready) // Si une réponse est à émettre (en mode Up donc), elle est émise en priorité :
|
||||
{
|
||||
c_bus.up.reponse.flag_ready = FALSE; // RAZ du flag
|
||||
sens = 'U'; // Mise à jour du sens avant préparation de la trame et envoi
|
||||
}
|
||||
else // Sinon, on regarde si une action est à faire en mode Down :
|
||||
{
|
||||
sens = 'D'; // Pour ne pas l'oublier....
|
||||
|
||||
if (c_bus.down.flag_attente_reponse) // Cas où une commande Down a déjà été émise et qu'on est en attente de réponse :
|
||||
{
|
||||
if (c_bus.protocole_tx.sequenceur.compteur_time_out == 0) // On vérifie alors si le time-out a expiré :
|
||||
{
|
||||
c_bus.down.flag_attente_reponse = FALSE; // RAZ du flag (qui sera éventuellement remis à 1 si la répétition a lieu)
|
||||
c_bus.protocole_tx.repetitions ++; // Incrémentation du nombre de répétitions
|
||||
if (c_bus.protocole_tx.repetitions > C_BUS_PROTOCOLE_TX_MAX_REPETITIONS) // Si le nombre maxi de répétitions a été dépassé, on laisse tomber la commande
|
||||
{
|
||||
c_bus.protocole_tx.repetitions = 0; // RAZ du compteur pour utilisation ultérieure
|
||||
break; // Sortie du séquenceur
|
||||
}
|
||||
}
|
||||
else break; // Tant qu'on est en attente d'une réponse et que le time-out n'est pas expiré, on ne traite aucun envoi en mode Down
|
||||
}
|
||||
else // Sinon, recherche d'une nouvelle commande à émettre en mode Down :
|
||||
{
|
||||
if (c_bus.down.ptr_debut_buffer_cdes != c_bus.down.ptr_fin_buffer_cdes) // Cas où il y a une commande en attente d'émission...
|
||||
{
|
||||
// ATTENTION : gérer les priorités ...!
|
||||
|
||||
if (++ c_bus.down.ptr_debut_buffer_cdes == C_BUS_MAX_TAILLE_BUFFER_CDES) c_bus.down.ptr_debut_buffer_cdes = 0;
|
||||
#ifdef __DEBUG_C_BUS
|
||||
c_bus.down.buffer_cdes[c_bus.down.ptr_debut_buffer_cdes].cde[c_bus.down.buffer_cdes[c_bus.down.ptr_debut_buffer_cdes].lg_cde] = 0; // On ajoute un /0 à la fin mais on ne change surtout pas la longueur qui est utilisée pour les transferts binaires.
|
||||
affichage_debug_bus(TYPE_BUS_DEBUG_C_BUS, "Tx", (char *) c_bus.down.buffer_cdes[c_bus.down.ptr_debut_buffer_cdes].cde, __DEBUG_C_BUS);
|
||||
#endif
|
||||
}
|
||||
else break; // Il n'y a pas de nouvelle commande en attente d'émission
|
||||
}
|
||||
}
|
||||
|
||||
//.....................................
|
||||
// Préparation de la trame d'émission :
|
||||
lg_tx_buffer = 0;
|
||||
|
||||
tx_buffer[lg_tx_buffer ++] = ASCII_DLE;
|
||||
tx_buffer[lg_tx_buffer ++] = ASCII_SOH;
|
||||
cs = ASCII_SOH; // Initialisation du CS calculé
|
||||
tx_buffer[lg_tx_buffer ++] = sens;
|
||||
cs += sens; // Rechargement du CS
|
||||
tx_buffer[lg_tx_buffer ++] = ASCII_DLE;
|
||||
tx_buffer[lg_tx_buffer ++] = ASCII_STX;
|
||||
cs += ASCII_STX; // Rechargement du CS
|
||||
|
||||
if (sens == 'D')
|
||||
{
|
||||
for (i=0; (i < c_bus.down.buffer_cdes[c_bus.down.ptr_debut_buffer_cdes].lg_cde) && (lg_tx_buffer < C_BUS_MAX_TAILLE_BUFFER_TX); i++)
|
||||
{
|
||||
c = c_bus.down.buffer_cdes[c_bus.down.ptr_debut_buffer_cdes].cde[i];
|
||||
if (c == ASCII_DLE) tx_buffer[lg_tx_buffer ++] = ASCII_DLE;
|
||||
tx_buffer[lg_tx_buffer ++] = c;
|
||||
cs += c; // Rechargement du CS
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; (i < c_bus.up.reponse.lg_reponse) && (lg_tx_buffer < C_BUS_MAX_TAILLE_BUFFER_TX); i++)
|
||||
{
|
||||
c = c_bus.up.reponse.reponse[i];
|
||||
if (c == ASCII_DLE) tx_buffer[lg_tx_buffer ++] = ASCII_DLE;
|
||||
tx_buffer[lg_tx_buffer ++] = c;
|
||||
cs += c; // Rechargement du CS
|
||||
}
|
||||
}
|
||||
|
||||
tx_buffer[lg_tx_buffer ++] = ASCII_DLE;
|
||||
tx_buffer[lg_tx_buffer ++] = ASCII_ETX;
|
||||
cs += ASCII_ETX; // Rechargement du CS
|
||||
|
||||
c = (uint8_t)(cs & 0x00FF); // LSB du CS
|
||||
if (c == ASCII_DLE) tx_buffer[lg_tx_buffer ++] = ASCII_DLE;
|
||||
tx_buffer[lg_tx_buffer ++] = c;
|
||||
|
||||
c = (uint8_t)(cs >> 8); // MSB du CS
|
||||
if (c == ASCII_DLE) tx_buffer[lg_tx_buffer ++] = ASCII_DLE;
|
||||
tx_buffer[lg_tx_buffer ++] = c;
|
||||
|
||||
//.............................
|
||||
// Envoi au driver d'émission :
|
||||
write(config_serial1.filestream, tx_buffer, lg_tx_buffer);
|
||||
|
||||
//..........................................................
|
||||
// Mise à jour des paramètres après l'émission de la trame :
|
||||
if (sens == 'D') // S'il s'agissait d'une commande émise en mode Down, on lance un time-out et on indique qu'on attend la réponse :
|
||||
{
|
||||
c_bus.down.flag_attente_reponse = TRUE;
|
||||
c_bus.protocole_tx.sequenceur.compteur_time_out = C_BUS_TIME_OUT_REPONSE_TX;
|
||||
}
|
||||
else ; // S'il s'agissait d'une réponse à une commande reçue en mode Up, on revient immédiatement au repos (la gestion des répétitions des commandes est de la responsabilité du maitre)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur C-Bus.Protocole_Tx est inconnu [%i]. Il est repositionné au REPOS", c_bus.protocole_tx.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
c_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_TX_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Incrémente le pointeur du buffer de commandes en attente d'émission vers C-Bus
|
||||
La fonction gère :
|
||||
- le rebouclage en fin de buffer (buffer circulaire)
|
||||
- le dépassement (quand la fin rattrape le début) en émettant un message de debug et en choissant :
|
||||
. soit d'écraser la commande la plus ancienne si elle est de priorité inférieure (strictement)
|
||||
. soit refuser l'ajout en laissant le pointeur de fin du buffer à sa position et en renvoyant une erreur.
|
||||
Reçoit : La priorité de la commande à ajouter (permet d'arbitrer dans la cas où le buffer est plein)
|
||||
Renvoit : 0 si une position disponible a été trouvée, -1 si aucune position n'est disponible.
|
||||
******************************************************************************************************************************************************************/
|
||||
int8_t c_bus_next_write_buffer_cdes(uint8_t priorite)
|
||||
{
|
||||
int8_t retour = 0;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
// Incrémentation :
|
||||
if (++ c_bus.down.ptr_fin_buffer_cdes == C_BUS_MAX_TAILLE_BUFFER_CDES) c_bus.down.ptr_fin_buffer_cdes = 0;
|
||||
|
||||
// Vérification si buffer plein :
|
||||
if (c_bus.down.ptr_fin_buffer_cdes == c_bus.down.ptr_debut_buffer_cdes)
|
||||
{
|
||||
if (c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes].priorite >= priorite)
|
||||
{
|
||||
// Décrémentation du pointeur puisqu'on ne va pas accepter la nouvelle commande qui n'a pas une priorité suffisante :
|
||||
if (c_bus.down.ptr_fin_buffer_cdes == 0) c_bus.down.ptr_fin_buffer_cdes = (C_BUS_MAX_TAILLE_BUFFER_CDES - 1);
|
||||
else c_bus.down.ptr_fin_buffer_cdes --;
|
||||
|
||||
// Message de débug :
|
||||
sprintf(tmp, "Buffer de commandes C-Bus plein. La demande de stockage d'une nouvelle commande a été rejetée...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
// Enregistrement dans l'historique :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_BUS_BUFFER_COMMANDES_PLEIN, (uint32_t) 'C', 0, NULL);
|
||||
|
||||
retour = -1;
|
||||
}
|
||||
else // Dans ce cas, la nouvelle commande est plus prioritaire (strictement) à la commande existante dans le buffer et elle va la remplacer.
|
||||
{
|
||||
// Message de débug :
|
||||
sprintf(tmp, "Buffer de commandes C-Bus plein. La demande de stockage d'une nouvelle commande a écrasée la commande la plus ancienne qui était de priorité inférieure...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
return (retour);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
|
||||
Fichier C_BUS.H
|
||||
|
||||
Contient tous les define liés au C_BUS
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define C_BUS_MAX_TAILLE_BUFFER_CDES 100 // Taille du buffer de commandes (donc on stocke plusieurs commandes entières !) C-bus en mode UP
|
||||
#define C_BUS_PROTOCOLE_TX_MAX_REPETITIONS 3 // Nombre de répétitions des commandes émises sur C_Bus
|
||||
#define C_BUS_MAX_TAILLE_BUFFER_TX 550
|
||||
#define C_BUS_MAX_TAILLE_CDE 500
|
||||
#define C_BUS_MAX_TAILLE_REPONSE 500
|
||||
|
||||
|
||||
// Tempos :
|
||||
#define C_BUS_TEMPO_INIT 2 // En x 100ms
|
||||
#define C_BUS_PROTOCOLE_RX_TEMPO_INIT 10 // en x 100ms
|
||||
#define C_BUS_PROTOCOLE_TX_TEMPO_INIT 10 // en x 100ms
|
||||
#define C_BUS_TIME_OUT_REPONSE_TX 2 // En x 100ms
|
||||
|
||||
// Priorité des commandes :
|
||||
#define PRIORITE_CDE_C_BUS_FAIBLE 0
|
||||
#define PRIORITE_CDE_C_BUS_HAUTE 1
|
||||
|
||||
|
||||
// Etats du séquenceur C-Bus :
|
||||
#define ETAT_SEQUENCEUR_C_BUS_INIT 0
|
||||
#define ETAT_SEQUENCEUR_C_BUS_REPOS 1
|
||||
|
||||
// Etats séquenceur du Protocole_Rx C-bus :
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_INIT 0
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_REPOS 1
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_SENS 2
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_STX 3
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_DATA 4
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_ETX 5
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_CS 6
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_NACK 7
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_RX_ERREUR 10
|
||||
|
||||
// Etats séquenceur du Protocole_Tx C-bus :
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_TX_INIT 0
|
||||
#define ETAT_SEQUENCEUR_C_BUS_PROTOCOLE_TX_REPOS 1
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier C_COMMANDES_.H
|
||||
//
|
||||
// Contient toutes définitions de constantes liées au commandes sur C_Bus
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
|
||||
// Codes commande Down :
|
||||
#define C_BUS_DOWN_COMMANDE_CONFIG_DATE_HEURE 0x01
|
||||
#define C_BUS_DOWN_COMMANDE_CONFIG_CARTE 0x02
|
||||
#define C_BUS_DOWN_COMMANDE_CONFIG_CIRCUITS 0x03
|
||||
#define C_BUS_DOWN_COMMANDE_CONFIG_LEVEL_SENSORS 0x04
|
||||
#define C_BUS_DOWN_COMMANDE_CONFIG_OW 0x05
|
||||
#define C_BUS_DOWN_COMMANDE_CONFIG_BATTERIES 0x06
|
||||
#define C_BUS_DOWN_COMMANDE_CONFIG_PGN_NMEA 0x07
|
||||
|
||||
#define C_BUS_DOWN_COMMANDE_RESET 0x10
|
||||
#define C_BUS_DOWN_COMMANDE_CDE_BACKLIGHT 0x11
|
||||
#define C_BUS_DOWN_COMMANDE_CDE_CIRCUITS 0x12
|
||||
// C_BUS_DOWN_COMMANDE_CDE_SORTIES_AUX 0x13 Plus utilisé depuis la suppression des sorties Aux de ShipBase
|
||||
#define C_BUS_DOWN_COMMANDE_CDE_CARTE 0x14
|
||||
|
||||
#define C_BUS_DOWN_COMMANDE_LECTURE_DATE_HEURE 0x20
|
||||
#define C_BUS_DOWN_COMMANDE_LECTURE_ID_CARTE 0x21
|
||||
|
||||
#define C_BUS_DOWN_COMMANDE_ANNUAIRE_K_BUS 0x32
|
||||
#define C_BUS_DOWN_COMMANDE_CHARGEMENT_CODE 0x33
|
||||
#define C_BUS_DOWN_COMMANDE_ANNUAIRE_OW 0x34
|
||||
|
||||
|
||||
// Codes commande Up :
|
||||
#define C_BUS_UP_COMMANDE_ETAT_CARTE 0x80
|
||||
#define C_BUS_UP_COMMANDE_ETAT_CIRCUITS 0x81
|
||||
#define C_BUS_UP_COMMANDE_ETAT_ENTREES_AUX 0x82
|
||||
#define C_BUS_UP_COMMANDE_ETAT_LEVEL_SENSORS 0x83
|
||||
#define C_BUS_UP_COMMANDE_ETAT_ENTREES_VOLT 0x84
|
||||
#define C_BUS_UP_COMMANDE_ETAT_ENTREES_OW 0x85
|
||||
#define C_BUS_UP_COMMANDE_ETAT_ENTREES_BATTERIES 0x86
|
||||
#define C_BUS_UP_COMMANDE_ETAT_PGN_NMEA 0x87
|
||||
|
||||
#define C_BUS_UP_COMMANDE_CONFIG_CARTE 0x90
|
||||
|
||||
// Cdes cartes :
|
||||
#define C_BUS_COMMANDE_CDE_CARTE_LOCALISATION 1
|
||||
#define C_BUS_COMMANDE_CDE_CARTE_ETAT_SYSTEME 2 // Uniquement destiné à ShipBase. La consigne porte la valeur de l'état (0=Normal, 1=Alerte, 2=Alarme)
|
||||
|
||||
#define C_BUS_COMMANDE_CDE_CARTE_ETAT_SYSTEME_NORMAL 0
|
||||
#define C_BUS_COMMANDE_CDE_CARTE_ETAT_SYSTEME_ALERTE 1
|
||||
#define C_BUS_COMMANDE_CDE_CARTE_ETAT_SYSTEME_ALARME 2
|
||||
#define C_BUS_COMMANDE_CDE_CARTE_MAX_CONSIGNE C_BUS_COMMANDE_CDE_CARTE_ETAT_SYSTEME_ALARME // Valeur maximale de la consigne d'une commande carte (2=ALARME)
|
||||
|
||||
// Commandes de config :
|
||||
#define C_BUS_CONFIG_AUCUNE -1
|
||||
#define C_BUS_CONFIG_LECTURE_SEULE 0
|
||||
#define C_BUS_CONFIG_WRITE_COURANTE 1
|
||||
#define C_BUS_CONFIG_WRITE_USINE 2
|
||||
|
||||
// Codes d'erreur :
|
||||
#define C_BUS_ERREUR_AUCUNE 0
|
||||
#define C_BUS_ERREUR_COMMANDE_INCONNUE 1
|
||||
#define C_BUS_ERREUR_FORMAT_COMMANDE 2
|
||||
#define C_BUS_ERREUR_PARAMETRE_INCONNU 3
|
||||
#define C_BUS_ERREUR_LONGUEUR_PARAMETRE 4
|
||||
#define C_BUS_ERREUR_ADRESSE_MAC 5
|
||||
#define C_BUS_ERREUR_ADRESSE_BUS 6
|
||||
#define C_BUS_ERREUR_FORMAT_DATE 7
|
||||
#define C_BUS_ERREUR_FORMAT_HEURE 8
|
||||
#define C_BUS_ERREUR 9
|
||||
#define C_BUS_ERREUR_NUMERO_CIRCUIT 10
|
||||
#define C_BUS_ERREUR_VALEUR_CONSIGNE 11
|
||||
#define C_BUS_ERREUR_MODE_COMMANDE 12
|
||||
#define C_BUS_ERREUR_TYPE_CIRCUIT 13
|
||||
#define C_BUS_ERREUR_COMPATIBILITE_MODE_TYPE 14
|
||||
#define C_BUS_ERREUR_VALEUR_VALIDITE 15
|
||||
#define C_BUS_ERREUR_VALEUR_SEUIL 16
|
||||
#define C_BUS_ERREUR_VALEUR_FILTRAGE 17
|
||||
#define C_BUS_ERREUR_RTC 18
|
||||
#define C_BUS_ERREUR_NO_CARTE 19
|
||||
#define C_BUS_ERREUR_CONSIGNE_BACKLIGHT 20
|
||||
#define C_BUS_VALEUR_HORS_DOMAINE 21
|
||||
#define C_BUS_ERREUR_BLOCS 22
|
||||
#define C_BUS_ERREUR_VALEUR_TAILLE 23
|
||||
#define C_BUS_ERREUR_FLASH 24
|
||||
#define C_BUS_ERREUR_CRC 25
|
||||
#define C_BUS_ERREUR_PRIORITE 26
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,747 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier CAPTEURS.C
|
||||
//
|
||||
// Contient toutes les fonctions liées aux capteurs, associé à la table TB_Capteurs de la BDD (créé en janvier 2017)
|
||||
//**********************************************************************************************************************************************************************************
|
||||
|
||||
//#define __DEBUG_CAPTEURS // Décommenter cette ligne pour que les infos de debug soient affichées
|
||||
//#define __DEBUG_CAPTEURS_CALCULES // Décommenter cette ligne pour que les infos de debug soient affichées
|
||||
//#define __DEBUG_CAPTEURS_ALERTES_ALARMES // Décommenter cette ligne pour que les infos de debug soient affichées
|
||||
|
||||
// Include :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
void gestion_capteurs(void);
|
||||
int8_t init_capteurs(void);
|
||||
bool test_condition_capteur_booleen(uint16_t no_capteur, uint16_t no_condition);
|
||||
bool valeur_neutre_operation_booleene(uint8_t operation);
|
||||
int16_t capteur_cle_primaire(uint16_t cle_primaire);
|
||||
int16_t variable_capteur_cle_primaire(uint16_t cle_primaire);
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_capteurs capteurs;
|
||||
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction INIT_CAPTEURS
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int8_t init_capteurs(void)
|
||||
{
|
||||
|
||||
capteurs.sequenceur.etat = ETAT_SEQUENCEUR_CAPTEURS_INIT;
|
||||
capteurs.sequenceur.compteur = CAPTEURS_TEMPO_INIT;
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation des capteurs\t\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction GESTION_CAPTEURS
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************
|
||||
void gestion_capteurs(void)
|
||||
{
|
||||
uint16_t i, j;
|
||||
float val;
|
||||
int16_t no;
|
||||
bool flag_erreur;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
if (!systeme.flag_cm3p_ready) return; // Evite que le traitement soit fait au milieu d'une reconfiguration...
|
||||
|
||||
switch(capteurs.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_CAPTEURS_INIT :
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
if ((systeme.flag_cm3p_ready) && // Permet de s'assurer que le cycle d'init système est terminé. En particulier, on est sûr que 'init_bdd()' puis 'annuaire_k_bus()' ont été traités.
|
||||
(capteurs.sequenceur.compteur == 0))
|
||||
{
|
||||
|
||||
affichage_debug(__FILE__, __LINE__, "------------------CAPTEURS INIT", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
for (i=0; i<capteurs.nb; i++)
|
||||
{
|
||||
if (capteurs.capteurs[i].flag_validite == FALSE) continue;
|
||||
|
||||
// Mise à jour de valeurs de démarrage des entrées prédéfinies à partir des valeurs de capteurs stockés dans la BDD.
|
||||
|
||||
// Correction de l'offset et du gain :
|
||||
if (capteurs.capteurs[i].gain != 0) // Le cas d'un gain=0 ne doit pas arriver car cela est vérifié au chargement, dans bdd_init.c. Mais on ne sait jamais...
|
||||
{
|
||||
val = (capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante - capteurs.capteurs[i].offset) / capteurs.capteurs[i].gain;
|
||||
}
|
||||
else val = capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante - capteurs.capteurs[i].offset;
|
||||
|
||||
|
||||
no = capteurs.capteurs[i].no_entrees[0]; // Facilite le traitement et la lecture ensuite. ATTENTION : Uniquement pour les types n'ayant qu'UNE entrée par capteur !!!!
|
||||
|
||||
switch(capteurs.capteurs[i].type_entrees)
|
||||
{
|
||||
//==================================
|
||||
case TYPE_ENTREES_AUXILIAIRES :
|
||||
{
|
||||
uint32_t val_u32 = (uint32_t) val;
|
||||
for (j = 0; j < capteurs.capteurs[i].nb_entrees; j ++)
|
||||
{
|
||||
entrees.aux.entrees[capteurs.capteurs[i].no_entrees[j]].valeur = (uint8_t) (val_u32 & 0x00000001);
|
||||
val_u32 >>= 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
case TYPE_ENTREES_LEVEL_SENSOR :
|
||||
{
|
||||
entrees.level_sensor.entrees[no].valeur = val; // NB : si le capteur est valide, l'entrée correspondante l'est aussi (traité dans 'enregistrement_annuaire_k_bus()')
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
case TYPE_ENTREES_VOLTAGE :
|
||||
{
|
||||
entrees.volt.entrees[no].valeur = val; // NB : si le capteur est valide, l'entrée correspondante l'est aussi (traité dans 'enregistrement_annuaire_k_bus()')
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
case TYPE_ENTREES_OW :
|
||||
{
|
||||
// L'init se fait dans 'c_bus_down_reponse_annuaire_ow()' car on n'est pas sûr d'avoir l'annuaire OW disponible à ce stade.
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
case TYPE_ENTREES_PREDEFINIES :
|
||||
{
|
||||
entrees.predefinies.entrees[no].valeur = val; // NB : si le capteur est valide, l'entrée correspondante l'est aussi (traité dans 'enregistrement_annuaire_k_bus()')
|
||||
break;
|
||||
}
|
||||
|
||||
/* //==================================
|
||||
case TYPE_ENTREES_IBS :
|
||||
{
|
||||
break;
|
||||
}
|
||||
*/
|
||||
//==================================
|
||||
case TYPE_ENTREES_NMEA :
|
||||
{
|
||||
entrees.nmea.entrees[no].valeur = val; // NB : si le capteur est valide, l'entrée correspondante l'est aussi (traité dans 'enregistrement_annuaire_k_bus()')
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
/* case TYPE_ENTREES_CAN :
|
||||
{
|
||||
break;
|
||||
}
|
||||
*/
|
||||
//==================================
|
||||
case TYPE_ENTREES_CALCULEE_BOOLEEN :
|
||||
{
|
||||
for (j = 0; j < capteurs.capteurs[i].nb_entrees; j ++)
|
||||
{
|
||||
if (capteurs.capteurs[i].conditions.conditions[j].type_condition == CAPTEUR_CONDITION_GROUPE_NORMAL)
|
||||
{
|
||||
// Mise à jour du n° de source à partir de l'ID_Source :
|
||||
// Mise à jour du n° de variable à partir de l'ID_Variable :
|
||||
int16_t no_source;
|
||||
int16_t no_variable;
|
||||
switch(capteurs.capteurs[i].conditions.conditions[j].type_source)
|
||||
{
|
||||
case SOURCE_MESURE_CIRCUIT:
|
||||
{
|
||||
no_source = circuit_cle_primaire(capteurs.capteurs[i].conditions.conditions[j].id_source);
|
||||
no_variable = variable_circuit_cle_primaire(capteurs.capteurs[i].conditions.conditions[j].id_variable);
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_CAPTEUR:
|
||||
{
|
||||
no_source = capteur_cle_primaire(capteurs.capteurs[i].conditions.conditions[j].id_source);
|
||||
no_variable = 0; // Un capteur n'a qu'un n° de variable...
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_RESERVOIR:
|
||||
{
|
||||
no_source = reservoir_cle_primaire(capteurs.capteurs[i].conditions.conditions[j].id_source);
|
||||
no_variable = variable_reservoir_cle_primaire(capteurs.capteurs[i].conditions.conditions[j].id_variable);
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_BATTERIE:
|
||||
{
|
||||
no_source = batterie_cle_primaire(capteurs.capteurs[i].conditions.conditions[j].id_source);
|
||||
no_variable = variable_batterie_cle_primaire(capteurs.capteurs[i].conditions.conditions[j].id_variable);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
no_source = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (no_source < 0) // Si on n'a pas trouvé d'équipement valide correspondant à l'ID reçu, on est obligé de dévalider complètement de capteur car l'équation peut ne plus rien vouloir dire...
|
||||
{
|
||||
sprintf(tmp, "L'ID_Source de la condition #%i du capteur #%i (clé primaire = %i) est invalide [%i]. Le capteur est dévalidé complètement car l'équation pourrait devenir instable", j, i, capteurs.capteurs[i].cle_primaire, capteurs.capteurs[i].conditions.conditions[j].id_source);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
capteurs.capteurs[i].flag_validite = FALSE;
|
||||
break;
|
||||
}
|
||||
else capteurs.capteurs[i].conditions.conditions[j].no_source = no_source;
|
||||
|
||||
if (no_variable < 0) // Si on n'a pas trouvé de variable valide correspondant à l'ID reçu, on est obligé de dévalider complètement de capteur car l'équation peut ne plus rien vouloir dire...
|
||||
{
|
||||
sprintf(tmp, "L'ID_Variable de la condition #%i du capteur #%i (clé primaire = %i) est invalide [%i]. Le capteur est dévalidé complètement car l'équation pourrait devenir instable", j, i, capteurs.capteurs[i].cle_primaire, capteurs.capteurs[i].conditions.conditions[j].id_variable);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
capteurs.capteurs[i].flag_validite = FALSE;
|
||||
break;
|
||||
}
|
||||
else capteurs.capteurs[i].conditions.conditions[j].no_variable = no_variable;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* //==================================
|
||||
case TYPE_ENTREES_CALCULEE_NUMERIQUE :
|
||||
{
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
//==================================
|
||||
default:
|
||||
{
|
||||
sprintf(tmp, "Le 'Type_entrées' du capteur #%i est invalide [%i]. Le capteur est dévalidé", i, capteurs.capteurs[i].type_entrees);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
capteurs.capteurs[i].flag_validite = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
capteurs.sequenceur.etat = ETAT_SEQUENCEUR_CAPTEURS_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_CAPTEURS_REPOS :
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (capteurs.sequenceur.compteur == 0)
|
||||
{
|
||||
capteurs.sequenceur.compteur = CAPTEURS_PERIODE_INTEGRATION_VALEUR;
|
||||
|
||||
for (i = 0; i < capteurs.nb; i ++)
|
||||
{
|
||||
if (capteurs.capteurs[i].flag_validite == FALSE) continue;
|
||||
|
||||
flag_erreur = FALSE;
|
||||
val = 0;
|
||||
|
||||
//-------------------------------------
|
||||
// Recherche de la valeur du capteur :
|
||||
//-------------------------------------
|
||||
|
||||
// ATTENTION : ne doit pas fonctionner si le nb d'entrées est > 1 !!!!
|
||||
no = capteurs.capteurs[i].no_entrees[0]; // Facilite le traitement et la lecture ensuite.
|
||||
|
||||
switch(capteurs.capteurs[i].type_entrees)
|
||||
{
|
||||
//==================================
|
||||
case TYPE_ENTREES_AUXILIAIRES :
|
||||
{
|
||||
uint32_t val_u32 = 0;
|
||||
for (j = 0; j < capteurs.capteurs[i].nb_entrees; j ++)
|
||||
{
|
||||
val_u32 |= ((uint32_t)(entrees.aux.entrees[capteurs.capteurs[i].no_entrees[j]].valeur) ) << j;
|
||||
}
|
||||
|
||||
val = (float) val_u32;
|
||||
capteurs.capteurs[i].valeur_brute = val; // SDIR #135
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
case TYPE_ENTREES_LEVEL_SENSOR :
|
||||
{
|
||||
switch(entrees.level_sensor.entrees[no].mode)
|
||||
{
|
||||
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_MASSE :
|
||||
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_PLUS :
|
||||
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_FULL :
|
||||
{
|
||||
val = entrees.level_sensor.entrees[no].valeur;
|
||||
if (fabs(val) < 0.8) val = 0; // Seuil (en valeur absolue), en-dessous duquel on considère la valeur comme non significative donc nulle. Evite les questions...!
|
||||
// if (val < -99.9) val = -99.9; // Il est inutile d'afficher des valeurs supérieures qui risquent d'affoler pour rien puisque c'est une projection qui est faite et pas un courant réel.
|
||||
//printf("Valeur lue sur détection de courant de défaut = %.3f\n", val);
|
||||
break;
|
||||
}
|
||||
|
||||
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_NON_DEFINI :
|
||||
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_0_10V :
|
||||
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_500R :
|
||||
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_4_20MA :
|
||||
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_AUTO_TEST :
|
||||
default :
|
||||
{
|
||||
val = entrees.level_sensor.entrees[no].valeur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
capteurs.capteurs[i].valeur_brute = val; // SDIR #135
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
case TYPE_ENTREES_VOLTAGE :
|
||||
{
|
||||
val = entrees.volt.entrees[no].valeur;
|
||||
capteurs.capteurs[i].valeur_brute = val; // SDIR #135
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
case TYPE_ENTREES_OW :
|
||||
{
|
||||
// NB : on sait que l'entrée est valide car le test a été fait dans 'enregistrement_annuaire_ow()'... Inutile de retester à chaque boucle.
|
||||
|
||||
// Vérification qu'on a déjà reçu des valeurs OW depuis le Companon :
|
||||
if (!entrees.ow.flag_premieres_valeurs_recues)
|
||||
{
|
||||
flag_erreur = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// SDIR # 176 :
|
||||
val = entrees.ow.entrees[no].valeur;
|
||||
capteurs.capteurs[i].valeur_brute = val; // SDIR #135
|
||||
|
||||
// SDIR #178 [début] :
|
||||
if (entrees.ow.entrees[no].etat != OW_ETAT_DEVICE_OK) // Si le capteur OW est NOK :
|
||||
{
|
||||
flag_erreur = TRUE; // Il est inutile de traiter de nouvelles valeurs de capteurs si le capteur est défaillant.
|
||||
|
||||
if (capteurs.capteurs[i].etat != CAPTEUR_ETAT_ALARME) // Détection d'un changement d'état.
|
||||
{
|
||||
capteurs.capteurs[i].etat = CAPTEUR_ETAT_ALARME; // Mise à jour du nouvel état du capteur
|
||||
capteurs.capteurs[i].flag_dde_maj_bdd = TRUE;
|
||||
|
||||
if (entrees.ow.entrees[no].etat == OW_ETAT_BUS_NOK) // Différentiation entre erreur globale du bus OW :
|
||||
{
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CAPTEURS, CAPTEUR_OW_BUS_NOK, capteurs.capteurs[i].cle_primaire, 0, entrees.ow.entrees[no].rom_code);
|
||||
}
|
||||
else // ... et erreur du capteur seulement :
|
||||
{
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CAPTEURS, CAPTEUR_OW_DEVICE_NOK, capteurs.capteurs[i].cle_primaire, 0, entrees.ow.entrees[no].rom_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Si le capteur OW est Ok :
|
||||
{
|
||||
if (capteurs.capteurs[i].etat != CAPTEUR_ETAT_NORMAL) // Détection d'un changement d'état
|
||||
{
|
||||
capteurs.capteurs[i].etat = CAPTEUR_ETAT_NORMAL; // Mise à jour du nouvel état du capteur (il sera peut-être modifié ensuite si une alerte ou une alarme est détectée)
|
||||
capteurs.capteurs[i].flag_dde_maj_bdd = TRUE;
|
||||
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CAPTEURS, CAPTEUR_OW_DEVICE_OK, capteurs.capteurs[i].cle_primaire, 0, entrees.ow.entrees[no].rom_code);
|
||||
}
|
||||
}
|
||||
// SDIR #178 [fin]
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
case TYPE_ENTREES_PREDEFINIES :
|
||||
{
|
||||
val = entrees.predefinies.entrees[no].valeur;
|
||||
capteurs.capteurs[i].valeur_brute = val; // SDIR #135
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* //==================================
|
||||
case TYPE_ENTREES_IBS :
|
||||
{
|
||||
break;
|
||||
}
|
||||
*/
|
||||
//==================================
|
||||
case TYPE_ENTREES_NMEA :
|
||||
{
|
||||
val = entrees.nmea.entrees[no].valeur;
|
||||
capteurs.capteurs[i].valeur_brute = val; // SDIR #135
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//==================================
|
||||
/* case TYPE_ENTREES_CAN :
|
||||
{
|
||||
break;
|
||||
}
|
||||
*/
|
||||
//==================================
|
||||
case TYPE_ENTREES_CALCULEE_BOOLEEN :
|
||||
{
|
||||
struct Struct_calcul_capteur_booleen calcul_booleen;
|
||||
calcul_booleen.niveau = -1;
|
||||
|
||||
|
||||
#ifdef __DEBUG_CAPTEURS_CALCULES
|
||||
sprintf(tmp, "Capteur calculé #%i : ---------------------------------", i);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
|
||||
for (j = 0; j < capteurs.capteurs[i].nb_entrees; j ++)
|
||||
{
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Condition de début de groupe '[' :
|
||||
if (capteurs.capteurs[i].conditions.conditions[j].type_condition > CAPTEUR_CONDITION_GROUPE_NORMAL)
|
||||
{
|
||||
calcul_booleen.niveau ++;
|
||||
|
||||
calcul_booleen.parentheses[calcul_booleen.niveau].operation = capteurs.capteurs[i].conditions.conditions[j].type_condition;
|
||||
calcul_booleen.parentheses[calcul_booleen.niveau].resultat = valeur_neutre_operation_booleene(calcul_booleen.parentheses[calcul_booleen.niveau].operation);
|
||||
#ifdef __DEBUG_CAPTEURS_CALCULES
|
||||
char ch[100] = "";
|
||||
uint8_t k;
|
||||
|
||||
for (k=0; k<calcul_booleen.niveau; k++) strcat(ch, "\t");
|
||||
sprintf(tmp, "#%i : %s[",
|
||||
j, ch );
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Condition normale :
|
||||
if (capteurs.capteurs[i].conditions.conditions[j].type_condition == CAPTEUR_CONDITION_GROUPE_NORMAL)
|
||||
{
|
||||
bool val_bool;
|
||||
|
||||
if (capteurs.capteurs[i].conditions.conditions[j].flag_validite) val_bool = test_condition_capteur_booleen(i, j);
|
||||
else val_bool = valeur_neutre_operation_booleene(calcul_booleen.parentheses[calcul_booleen.niveau].operation);
|
||||
|
||||
if (calcul_booleen.parentheses[calcul_booleen.niveau].operation == CAPTEUR_CONDITION_GROUPE_OU)
|
||||
{
|
||||
calcul_booleen.parentheses[calcul_booleen.niveau].resultat |= val_bool;
|
||||
}
|
||||
else
|
||||
{
|
||||
calcul_booleen.parentheses[calcul_booleen.niveau].resultat &= val_bool;
|
||||
}
|
||||
#ifdef __DEBUG_CAPTEURS_CALCULES
|
||||
char ch[100] = "";
|
||||
uint8_t k;
|
||||
|
||||
for (k=0; k<(calcul_booleen.niveau+1); k++) strcat(ch, "\t");
|
||||
sprintf(tmp, "#%i : %s%s (%s) %s",
|
||||
j, ch,
|
||||
(calcul_booleen.parentheses[calcul_booleen.niveau].operation == CAPTEUR_CONDITION_GROUPE_OU) ? "OU" : "ET",
|
||||
(val_bool) ? "TRUE" : "FALSE",
|
||||
(capteurs.capteurs[i].conditions.conditions[j].flag_validite) ? "" : "[condition dévalidée]" );
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Condition de fin de groupe ']' :
|
||||
if (capteurs.capteurs[i].conditions.conditions[j].type_condition < CAPTEUR_CONDITION_GROUPE_NORMAL)
|
||||
{
|
||||
if (calcul_booleen.niveau > 0)
|
||||
{
|
||||
calcul_booleen.niveau --;
|
||||
|
||||
if (calcul_booleen.parentheses[calcul_booleen.niveau].operation == CAPTEUR_CONDITION_GROUPE_OU)
|
||||
{
|
||||
calcul_booleen.parentheses[calcul_booleen.niveau].resultat |= calcul_booleen.parentheses[calcul_booleen.niveau + 1].resultat;
|
||||
}
|
||||
else
|
||||
{
|
||||
calcul_booleen.parentheses[calcul_booleen.niveau].resultat &= calcul_booleen.parentheses[calcul_booleen.niveau + 1].resultat;
|
||||
}
|
||||
#ifdef __DEBUG_CAPTEURS_CALCULES
|
||||
char ch[100] = "";
|
||||
uint8_t k;
|
||||
|
||||
for (k=0; k<(calcul_booleen.niveau+1); k++) strcat(ch, "\t");
|
||||
sprintf(tmp, "#%i : %s] %s (%s)",
|
||||
j, ch,
|
||||
(calcul_booleen.parentheses[calcul_booleen.niveau].operation == CAPTEUR_CONDITION_GROUPE_OU) ? "OU" : "ET",
|
||||
(calcul_booleen.parentheses[calcul_booleen.niveau + 1].resultat) ? "TRUE" : "FALSE");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (float) calcul_booleen.parentheses[calcul_booleen.niveau].resultat;
|
||||
capteurs.capteurs[i].valeur_brute = val; // SDIR #135
|
||||
#ifdef __DEBUG_CAPTEURS_CALCULES
|
||||
sprintf(tmp, "#%i : ] Résultat = %s", j, (val == 0) ? "FALSE" : "TRUE");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* //==================================
|
||||
case TYPE_ENTREES_CALCULEE_NUMERIQUE :
|
||||
{
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
//==================================
|
||||
default: flag_erreur = TRUE; // A priori, pas possible car testé au moment de l'init...
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------
|
||||
// Traitement de la valeur récupérée :
|
||||
//------------------------------------
|
||||
if (flag_erreur == FALSE)
|
||||
{
|
||||
// Correction :
|
||||
val = (val * capteurs.capteurs[i].gain) + capteurs.capteurs[i].offset ;
|
||||
|
||||
// Calcul de la nouvelle moyenne de valeur courante à partir de l'ancienne et de la valeur lue :
|
||||
capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante = (((capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante * (capteurs.capteurs[i].valeur_coeff_filtrage - 1))) + val) / capteurs.capteurs[i].valeur_coeff_filtrage;
|
||||
|
||||
// Mise à jour du cumul :
|
||||
capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].cumul += capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante;
|
||||
capteurs.capteurs[i].cumuls_nb_val ++; // MàJ du nombre d'échantillons dans le cumul
|
||||
|
||||
// Traitement si la valeur a suffisemment évolué :
|
||||
// if (fabs(capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_bdd - capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante) >= capteurs.variables[capteurs.capteurs[i].no_variable].marge)
|
||||
if (fabs(capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_bdd - capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante) > 0)
|
||||
{
|
||||
#ifdef __DEBUG_CAPTEURS
|
||||
sprintf(tmp, "Capteur #%i (cle primaire = %i) : changement détecté avec valeur_courante=%.3f et valeur_bdd=%.3f - Marge=%.3f ", i, capteurs.capteurs[i].cle_primaire, capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante, capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_bdd, capteurs.variables[capteurs.capteurs[i].no_variable].marge);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
capteurs.capteurs[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
|
||||
|
||||
// Enregistrement de la mesure si le capteur est configuré en mode MODE_ENREGISTREMENT_MESURES_CHANGEMENT_ETAT :
|
||||
if (capteurs.capteurs[i].mode_enregistrement_mesures == MODE_ENREGISTREMENT_MESURES_CHANGEMENT_ETAT)
|
||||
{
|
||||
char date_vide[MAX_LONGUEUR_DATE_COURANTE] = ""; // Evite un warning depuis GCC14
|
||||
enregistrement_mesure(SOURCE_MESURE_CAPTEUR, i, capteurs.capteurs[i].no_variable, date_vide, BDD_ENREGISTREMENT_MESURE_PONCTUEL);
|
||||
}
|
||||
|
||||
} // Fin de traitement si la valeur a évolué.
|
||||
|
||||
#ifdef __DEBUG_CAPTEURS
|
||||
sprintf(tmp, "Capteur #%i : Valeur=%.3f ", i, capteurs.capteurs[i].variables[CAPTEUR_VARIABLE_VALEUR].valeur_courante);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
// Mise à jour des valeurs BDD des variables :
|
||||
if (capteurs.capteurs[i].flag_dde_maj_bdd)
|
||||
{
|
||||
for (j = 0; j < MAX_NOMBRE_VARIABLES_PAR_CAPTEUR; j ++) capteurs.capteurs[i].variables[j].valeur_bdd = capteurs.capteurs[i].variables[j].valeur_courante;
|
||||
}
|
||||
} // Fin du traitement sans erreur.
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
default :
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur Capteurs est inconnu [%i]. Il est repositionné au REPOS", capteurs.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
capteurs.sequenceur.etat = ETAT_SEQUENCEUR_CAPTEURS_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Teste si la condition d'un capteur calculé booléen est vraie ou fausse
|
||||
// Reçoit : Le numéro du capteur et le numéro de la condition du capteur
|
||||
// Retourne : Vrai ou Faux
|
||||
//**********************************************************************************************************************************************************************************
|
||||
bool test_condition_capteur_booleen(uint16_t no_capteur, uint16_t no_condition)
|
||||
{
|
||||
float valeur;
|
||||
|
||||
|
||||
// Si la condition n'est pas une condition normale, on retourne directement FALSE :
|
||||
if (capteurs.capteurs[no_capteur].conditions.conditions[no_condition].type_condition != CAPTEUR_CONDITION_GROUPE_NORMAL) return(false);
|
||||
|
||||
//==================================================
|
||||
// Recherche de la valeur en cours de la source :
|
||||
switch(capteurs.capteurs[no_capteur].conditions.conditions[no_condition].type_source)
|
||||
{
|
||||
case SOURCE_MESURE_CIRCUIT:
|
||||
{
|
||||
valeur = circuits.circuits[capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_source].variables[capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_variable].valeur_courante;
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_CAPTEUR:
|
||||
{
|
||||
valeur = capteurs.capteurs[capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_source].variables[capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_variable].valeur_courante;
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_RESERVOIR:
|
||||
{
|
||||
valeur = reservoirs.reservoirs[capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_source].variables[capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_variable].valeur_courante;
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_BATTERIE:
|
||||
{
|
||||
valeur = batteries.batteries[capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_source].variables[capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_variable].valeur_courante;
|
||||
break;
|
||||
}
|
||||
default: return(false); // Ne devrait pas arriver puisque testé à l'init...
|
||||
}
|
||||
#ifdef __DEBUG_CAPTEURS_CALCULES
|
||||
/*char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
sprintf(tmp, "Test de la condition #%i du capteur #%i : Type_source=%i, N° source=%i, N° de variable=%i, Valeur= %.2f, Condition de test=%i",
|
||||
no_condition, no_capteur,
|
||||
capteurs.capteurs[no_capteur].conditions.conditions[no_condition].type_source,
|
||||
capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_source,
|
||||
capteurs.capteurs[no_capteur].conditions.conditions[no_condition].no_variable,
|
||||
valeur,
|
||||
capteurs.capteurs[no_capteur].conditions.conditions[no_condition].test);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
*/
|
||||
#endif
|
||||
|
||||
//==================================================
|
||||
// Test selon le type de test de l'évènement :
|
||||
switch(capteurs.capteurs[no_capteur].conditions.conditions[no_condition].test)
|
||||
{
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_STRICT_INFERIEUR:
|
||||
{
|
||||
return (valeur < capteurs.capteurs[no_capteur].conditions.conditions[no_condition].seuil);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_INFERIEUR_OU_EGAL:
|
||||
{
|
||||
return (valeur <= capteurs.capteurs[no_capteur].conditions.conditions[no_condition].seuil);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_EGAL:
|
||||
{
|
||||
return (fabs(valeur - capteurs.capteurs[no_capteur].conditions.conditions[no_condition].seuil) < FLT_MIN);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_SUPERIEUR_OU_EGAL:
|
||||
{
|
||||
return (valeur >= capteurs.capteurs[no_capteur].conditions.conditions[no_condition].seuil);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_STRICT_SUPERIEUR:
|
||||
{
|
||||
return (valeur > capteurs.capteurs[no_capteur].conditions.conditions[no_condition].seuil);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
default:
|
||||
case EVENTS_TYPE_TEST_NON_DEFINI :
|
||||
{
|
||||
return (false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Renvoit une valeur booléenne neutre par rapport à une opération (0 si OU , 1 si ET)
|
||||
// Reçoit : l'opération concernée
|
||||
// Retourne : Vrai ou Faux
|
||||
//**********************************************************************************************************************************************************************************
|
||||
bool valeur_neutre_operation_booleene(uint8_t operation)
|
||||
{
|
||||
|
||||
if (operation == CAPTEUR_CONDITION_GROUPE_ET) return(true);
|
||||
else return(false);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction CAPTEUR_CLE_PRIMAIRE
|
||||
// Reçoit en paramètre :
|
||||
// - La Cle_primaire du capteur à rechercher
|
||||
// Retourne :
|
||||
// - le numéro de capteur correspondant (ou -1 si aucun capteur valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_CAPTEURS-1.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int16_t capteur_cle_primaire(uint16_t cle_primaire)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i=0; i<capteurs.nb; i++)
|
||||
{
|
||||
if ((capteurs.capteurs[i].cle_primaire == cle_primaire) && (capteurs.capteurs[i].flag_validite)) return(i);
|
||||
|
||||
}
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction VARIABLE_CAPTEUR_CLE_PRIMAIRE
|
||||
// Reçoit en paramètre :
|
||||
// - La Cle_primaire de la variable à rechercher
|
||||
// Retourne :
|
||||
// - le numéro de variable correspondant (ou -1 si aucune variable valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_VARIABLES_CAPTEURS-1.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int16_t variable_capteur_cle_primaire(uint16_t cle_primaire)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_VARIABLES_CAPTEURS; i++)
|
||||
{
|
||||
if (capteurs.variables[i].cle_primaire == cle_primaire) return(i);
|
||||
|
||||
}
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier CAPTEURS.H
|
||||
//
|
||||
// Contient tous les define liés aux capteurs
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MAX_NOMBRE_CAPTEURS 100 // Ne concerne que les capteurs valides de la BDD (la table peut en contenir autant qu'on veut mais pas plus que ce MAX valides simultanément => sinon une erreur est levée à l'init de l'appli et le démarrage est arrêté)
|
||||
#define MAX_NOMBRE_ENTREES_PAR_CAPTEUR 4 // Indique le nombre max d'entrées physiques pour un même capteur. A priori, Ok jusqu'à 32 car utilisation d'uint32_t pour l'analyse dans 'capteurs.c'.
|
||||
#define MAX_NOMBRE_VARIABLES_CAPTEURS 25
|
||||
#define MAX_NOMBRE_VARIABLES_PAR_CAPTEUR 1
|
||||
#define MAX_NOMBRE_CONDITIONS_PAR_CAPTEUR 50 // Nombre maxi de conditions pour un capteur de type calculé. Cf équivalent dans 'main.qml'. Note : les conditions de début et de fin de groupe compte dans ce total
|
||||
|
||||
|
||||
// Valeurs extrêmes (NB : ces valeurs sont dupliquées dans 'archivage.php'... Penser à les mettre à jour si modification ici).
|
||||
#define TEMPERATURE_VALEUR_MINI (-40.00) // En °C Plage mini du DS18B20 = -55°C mais jugé trop faible pour l'application
|
||||
#define TEMPERATURE_VALEUR_MAXI 125.00 // En °C Plage maxi du DS18B20
|
||||
#define TEMPERATURE_DELTA_ZERO_MAXI 2.00 // En °C Delta maxi (en valeur absolue) avec la valeur précédente pour qu'une nouvelle valeur = 0 soit prise en compte
|
||||
#define PRESSION_ATM_VALEUR_MINI 900.00 // En hPa Pression Niveau de la Mer minimale (mondiale, toute période) : 870 hPa, au large des Philippines, près du centre du typhon Tip, le 12 octobre 1979. =
|
||||
#define PRESSION_ATM_VALEUR_MAXI 1080.00 // En hPa Pression Niveau de la Mer maximum (mondiale, toute période) : 1086,8 hPa, à Tosontsengel (Mongolie), le 20 janvier 2010.
|
||||
#define HUMIDITE_VALEUR_MINI 0.00 // En %HR
|
||||
#define HUMIDITE_VALEUR_MAXI 100.00 // En %HR
|
||||
#define ACCELERATION_VALEUR_MINI -16.00 // En 'g'
|
||||
#define ACCELERATION_VALEUR_MAXI +16.00 // En 'g'
|
||||
|
||||
|
||||
// Valeurs d'erreur :
|
||||
#define POSITION_VALEUR_ERRONNEE 200000000 // Valeur hors limite de latitude (-90 000 000 à +90 000 000) et longitude (-180 000 000 à +180 000 000)
|
||||
#define TEMPERATURE_VALEUR_ERRONEE 20000 // Soit 200°C qui hors du domaine possible
|
||||
|
||||
|
||||
// Timings :
|
||||
#define CAPTEURS_TEMPO_INIT 100 // En x 10ms
|
||||
#define CAPTEURS_PERIODE_INTEGRATION_VALEUR 10 // En x 10ms
|
||||
|
||||
|
||||
// Variables du capteur :
|
||||
#define CAPTEUR_VARIABLE_VALEUR 0
|
||||
// NB : ces valeurs doivent rester strictement inférieures à MAX_NOMBRE_VARIABLES_PAR_RESERVOIR
|
||||
|
||||
|
||||
// Conditions d'un capteur calculé booléen :
|
||||
#define CAPTEUR_CONDITION_GROUPE_NORMAL 0
|
||||
#define CAPTEUR_CONDITION_GROUPE_OU 1
|
||||
#define CAPTEUR_CONDITION_GROUPE_ET 2
|
||||
#define CAPTEUR_CONDITION_GROUPE_OU_EXCLUSIF 3
|
||||
#define CAPTEUR_CONDITION_GROUPE_PLUS 10
|
||||
#define CAPTEUR_CONDITION_GROUPE_MOINS 11
|
||||
#define CAPTEUR_CONDITION_GROUPE_MULTIPLIE 12
|
||||
#define CAPTEUR_CONDITION_GROUPE_DIVISE 13
|
||||
|
||||
|
||||
// Etat d'un capteur
|
||||
#define CAPTEUR_ETAT_NORMAL 0
|
||||
#define CAPTEUR_ETAT_ALERTE 1
|
||||
#define CAPTEUR_ETAT_ALARME 2
|
||||
|
||||
|
||||
|
||||
// Variables du capteur :
|
||||
#define CAPTEUR_VARIABLE_SANS_UNITE 0
|
||||
#define CAPTEUR_VARIABLE_TENSION_V 1
|
||||
#define CAPTEUR_VARIABLE_TENSION_MV 2
|
||||
#define CAPTEUR_VARIABLE_COURANT_A 3
|
||||
#define CAPTEUR_VARIABLE_COURANT_MA 4
|
||||
#define CAPTEUR_VARIABLE_PUISSANCE_W 5
|
||||
#define CAPTEUR_VARIABLE_PUISSANCE_VA 6
|
||||
#define CAPTEUR_VARIABLE_PUISSANCE_DB 7
|
||||
#define CAPTEUR_VARIABLE_FREQUENCE 8
|
||||
#define CAPTEUR_VARIABLE_RESISTANCE 9
|
||||
#define CAPTEUR_VARIABLE_TEMPERATURE 10
|
||||
#define CAPTEUR_VARIABLE_PRESSION_ATM 11
|
||||
#define CAPTEUR_VARIABLE_HUMIDITE 12
|
||||
#define CAPTEUR_VARIABLE_ACCELERATION 13
|
||||
#define CAPTEUR_VARIABLE_POSITION 14
|
||||
#define CAPTEUR_VARIABLE_POURCENTAGE 15
|
||||
#define CAPTEUR_VARIABLE_DISTANCE_M 16
|
||||
#define CAPTEUR_VARIABLE_DISTANCE_KM 17
|
||||
#define CAPTEUR_VARIABLE_DISTANCE_NQ 18
|
||||
#define CAPTEUR_VARIABLE_VITESSE_KTS 19
|
||||
#define CAPTEUR_VARIABLE_VITESSE_KMH 20
|
||||
#define CAPTEUR_VARIABLE_ANGLE_DEGRES 21
|
||||
#define CAPTEUR_VARIABLE_LATITUDE 22
|
||||
#define CAPTEUR_VARIABLE_LONGITUDE 23
|
||||
#define CAPTEUR_VARIABLE_VOLUME 24
|
||||
// ATTENTION : ces valeurs doivent rester strictement inférieures à MAX_NOMBRE_VARIABLES_CAPTEURS (augmenter la valeur en haut de ce fichier ci besoin...)
|
||||
|
||||
|
||||
|
||||
// Etats des séquenceur :
|
||||
#define ETAT_SEQUENCEUR_CAPTEURS_INIT 0
|
||||
#define ETAT_SEQUENCEUR_CAPTEURS_REPOS 1
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,479 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier CIRCUITS.C
|
||||
//
|
||||
// Contient toutes les fonctions liées aux circuits
|
||||
//**********************************************************************************************************************************************************************************
|
||||
|
||||
// #define __DEBUG_CIRCUITS // Décommenter cette ligne pour que les infos de debug soient affichées
|
||||
|
||||
// Include :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
void gestion_circuits(void);
|
||||
void gestion_circuit(uint16_t no_circuit);
|
||||
int8_t changement_consigne_circuit(uint16_t no_circuit, uint8_t consigne, uint8_t origine_consigne, uint16_t id_origine_consigne);
|
||||
int8_t init_circuits(void);
|
||||
int16_t circuit_cle_primaire(uint16_t cle_primaire);
|
||||
int16_t variable_circuit_cle_primaire(uint16_t cle_primaire);
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_circuits circuits;
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction GESTION_CIRCUITS
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************
|
||||
void gestion_circuits(void)
|
||||
{
|
||||
uint16_t i, j;
|
||||
float courant_total;
|
||||
uint16_t circuit_maxi;
|
||||
float courant_maxi;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
if (!systeme.flag_cm3p_ready) return; // Evite que le traitement soit fait au milieu d'une reconfiguration...
|
||||
|
||||
switch(circuits.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_CIRCUITS_INIT :
|
||||
{
|
||||
if ((systeme.flag_cm3p_ready) && // Permet de s'assurer que le cycle d'init système est terminé. En particulier, on est sûr que 'init_bdd()' puis 'annuaire_k_bus()' ont été traités.
|
||||
(circuits.sequenceur.compteur == 0))
|
||||
{
|
||||
|
||||
affichage_debug(__FILE__, __LINE__, "------------------CIRCUITS INIT", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
circuits.sequenceur.etat = ETAT_SEQUENCEUR_CIRCUITS_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_CIRCUITS_REPOS :
|
||||
{
|
||||
if (circuits.sequenceur.compteur == 0)
|
||||
{
|
||||
circuits.sequenceur.compteur = CIRCUITS_PERIODE_MISE_A_JOUR;
|
||||
|
||||
//------------------------------------------------
|
||||
// Appel de Gestion_circuit pour chaque circuit :
|
||||
for (i = 0; i < circuits.nb; i ++)
|
||||
{
|
||||
if (! circuits.circuits[i].flag_validite) continue;
|
||||
|
||||
// sprintf(tmp, "Circuit #%i : Consigne = %.2f ", i, circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
|
||||
gestion_circuit(i);
|
||||
circuits.circuits[i].flag_dde_maj_bdd = TRUE; // On ne vérifie pas s'il y a eu évolution car ce serait un peu compliqué
|
||||
}
|
||||
|
||||
//-----------------------------------------
|
||||
// Supervision du courant total par carte :
|
||||
for (i = 0; i < MAX_NOMBRE_MODULES; i ++)
|
||||
{
|
||||
if (systeme.modules_config[i].flag_presence == FALSE) continue; // On ne taite que les cartes présentes
|
||||
if (systeme.modules_config[i].courant_maxi == 0) continue; // SI le seuil = 0, c'est que la fonction est dévalidée.
|
||||
|
||||
switch(systeme.modules_config[i].type)
|
||||
{
|
||||
case TYPE_CARTE_SP812 :
|
||||
case TYPE_CARTE_SP8DC :
|
||||
{
|
||||
circuit_maxi = MAX_NOMBRE_CIRCUITS; // Valeur 'impossible' par défaut
|
||||
courant_maxi = 0;
|
||||
courant_total = 0;
|
||||
|
||||
// Recherche de tous les circuits de la carte :
|
||||
for (j=0; j<circuits.nb; j++)
|
||||
{
|
||||
if (circuits.circuits[j].flag_validite == FALSE) continue; // On ne traite que les circuits valides... NB : On teste le flag de Validité (plutôt que Disponible) car on est sûr que la carte est présente (donc si le circuit est valide, il est disponible)
|
||||
if (circuits.circuits[j].adresse_module != i ) continue; // ... et ceux piloté par cette carte...
|
||||
if (circuits.circuits[j].no_circuit >= SP8XX_NOMBRE_CIRCUITS) continue; // ... et dont le n° de circuit est valide pour cette carte
|
||||
|
||||
// Calcul du courant total de la carte :
|
||||
courant_total += circuits.circuits[j].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante;
|
||||
|
||||
// Recehrche du circuit consommant le plus sur la carte (utile si on déclenche) :
|
||||
if (circuits.circuits[j].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante > courant_maxi)
|
||||
{
|
||||
courant_maxi = circuits.circuits[j].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante;
|
||||
circuit_maxi = j;
|
||||
}
|
||||
}
|
||||
|
||||
// Action selon le dépassement ou non du seuil :
|
||||
if (courant_total <= systeme.modules_config[i].courant_maxi) systeme.modules_config[i].courant_maxi_compteur = systeme.modules_config[i].courant_maxi_tempo; // Réarmement du compteur dès qu'on passe en dessous du seuil
|
||||
else if (systeme.modules_config[i].courant_maxi_compteur == 0) // On dép&sse le seuil ET la tempo est expirée sans qu'on soit repassés sous le seuil :
|
||||
{
|
||||
if (circuit_maxi < MAX_NOMBRE_CIRCUITS) // Cas normal où on a trouvé le circuit qui consomme le plus sur la carte :
|
||||
{
|
||||
circuits.circuits[circuit_maxi].etat = ETAT_CIRCUIT_DELESTE;
|
||||
|
||||
changement_consigne_circuit(circuit_maxi, OFF, CIRCUITS_ORIGINE_CONSIGNE_DEFAUT, 0);
|
||||
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CIRCUITS, CIRCUIT_DELESTAGE, circuits.circuits[circuit_maxi].cle_primaire, systeme.modules_config[i].courant_maxi, NULL); // Enregistrement dans l'historique
|
||||
|
||||
sprintf(tmp, "/!\\ Carte %i : Le courant total (%.3fA) est resté supérieur au seuil MAXI (%.3fA) pendant %i secondes consécutives. Le circuit %i est délesté car sa consommation est la plus élevée de la carte (%.3fA soit %.2f%% de la carte)", i, courant_total, systeme.modules_config[i].courant_maxi, systeme.modules_config[i].courant_maxi_tempo, circuit_maxi, courant_maxi, (courant_total != 0) ? ((courant_maxi*100)/courant_total) : 0);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
systeme.modules_config[i].courant_maxi_compteur = systeme.modules_config[i].courant_maxi_tempo; // Permet notamment d'attendre que la prise en compte du délestage du circuit le plus consommateur soit effective...
|
||||
}
|
||||
else // A priori, ne doit pas arriver car cela voudriat dire que'on a trouvé aucun circuit > 0A alors que le courant total dépasse 50A (par exemple)...
|
||||
{
|
||||
sprintf(tmp, "La détection de courant total a rencontér une erreur... La détection est dévalidée");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur Circuits est inconnu [%i]. Il est repositionné au REPOS", circuits.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
circuits.sequenceur.etat = ETAT_SEQUENCEUR_CIRCUITS_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction GESTION_CIRCUIT
|
||||
// Séquenceur dédié à chaque circuit
|
||||
// Reçoit : le n° du circuit
|
||||
// Retour : Rien
|
||||
//**********************************************************************************************************************************************************************************
|
||||
void gestion_circuit(uint16_t no_circuit)
|
||||
{
|
||||
int16_t no_entree_in_i;
|
||||
int16_t no_entree_usb_i;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
//==============================================================================================
|
||||
// Mise à jour des valeurs obtenues par un autre biais que 'c_bus_up_commande_etat_circuits()' :
|
||||
//==============================================================================================
|
||||
switch(systeme.modules_config[circuits.circuits[no_circuit].adresse_module].type)
|
||||
{
|
||||
//------------------------
|
||||
case TYPE_CARTE_SHIPBASE:
|
||||
//------------------------
|
||||
{
|
||||
// Courant USB :
|
||||
// NB : la notion de valeur plancher du courant USB est traitée dans 'commandes.c', vers la ligne 1800...
|
||||
float courant_usb;
|
||||
float in_i;
|
||||
float usb_i;
|
||||
|
||||
no_entree_in_i = entree_no(TYPE_ENTREES_PREDEFINIES, 0, ENTREE_PREDEFINIE_IN_I);
|
||||
if ((no_entree_in_i >=0) && (no_entree_in_i < MAX_NOMBRE_ENTREES_PREDEFINIES)) in_i = entrees.predefinies.entrees[no_entree_in_i].valeur;
|
||||
else in_i = 0;
|
||||
|
||||
no_entree_usb_i = entree_no(TYPE_ENTREES_PREDEFINIES, 0, ENTREE_PREDEFINIE_USB_I);
|
||||
if ((no_entree_usb_i >=0) && (no_entree_usb_i < MAX_NOMBRE_ENTREES_PREDEFINIES)) usb_i = entrees.predefinies.entrees[no_entree_usb_i].valeur;
|
||||
else usb_i = 0;
|
||||
|
||||
if (systeme.modules_config[circuits.circuits[no_circuit].adresse_module].alim_valeur != 0) courant_usb = (usb_i * 5) / systeme.modules_config[circuits.circuits[no_circuit].adresse_module].alim_valeur; // Il est important de ramner le courant USB mesuré sur 5V sur la tension d'alimentation de ShipBase afin de l'extraire du courant de ShipBase.
|
||||
else courant_usb = 0;
|
||||
|
||||
if (in_i <= courant_usb)
|
||||
{
|
||||
courant_usb = 0;
|
||||
#ifdef __DEBUG_CIRCUITS
|
||||
sprintf(tmp, "/!\\ Le courant USB (compensé en tension) [%.2f A] est supérieur ou égal au courant de ShipBase [%.2f A]. Le courant USB n'est pas pris en compte du tout (ramené à 0A)...", courant_usb, in_i);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Calculs spécifiques en fonction du "circuit" de Shipbase :
|
||||
switch(circuits.circuits[no_circuit].no_circuit)
|
||||
{
|
||||
//----------------------------
|
||||
case SB_CIRCUIT_NO_SHIPHEART : // Circuit correspondant à ShipBase sans les ports USB (appelé 'ShipHeart' dans la BDD)
|
||||
{
|
||||
// Tension :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION].valeur_courante = systeme.modules_config[circuits.circuits[no_circuit].adresse_module].alim_valeur;
|
||||
|
||||
// Courant :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante = in_i - courant_usb;
|
||||
#ifdef __DEBUG_CIRCUITS
|
||||
sprintf(tmp, "Courant total ShipBase = [%.2f A], courant de ShipBase uniquement [%.2f A], courant USB (compensé en tension) = [%.2f A]", in_i, circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante, courant_usb);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
// Puissance :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_PUISSANCE].valeur_courante = circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION].valeur_courante * circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
case SB_CIRCUIT_NO_USB_AVANT : // Circuit correspondant aux ports USB seulement (appelé 'ShipHeart - USB' dans la BDD)
|
||||
{
|
||||
// Tension :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION].valeur_courante = 5; // Attention : on applique la règle mais c'est une valeur théorique...
|
||||
|
||||
// Courant :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante = usb_i; // Attention : c'est un courant "réel" sur 5V (non compensé en tension)
|
||||
|
||||
// Puissance :
|
||||
if (courant_usb == 0) circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_PUISSANCE].valeur_courante = 0;
|
||||
else circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_PUISSANCE].valeur_courante = usb_i * 5; // Calculé directemenr depuis le courant mesuré sur 5V.
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
case SB_CIRCUIT_NO_USB_ARRIERE : // Circuit correspondant aux ports USB seulement (appelé 'ShipHeart - USB arrière' dans la BDD)
|
||||
{
|
||||
// Tension :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION].valeur_courante = 5; // Attention : on applique la règle mais c'est une valeur théorique...
|
||||
|
||||
break;
|
||||
}
|
||||
default : break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------
|
||||
case TYPE_CARTE_SP812:
|
||||
case TYPE_CARTE_SP8DC:
|
||||
//------------------------
|
||||
{
|
||||
// Tension :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION].valeur_courante = systeme.modules_config[circuits.circuits[no_circuit].adresse_module].alim_valeur;
|
||||
|
||||
// Puissance :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_PUISSANCE].valeur_courante = circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION].valeur_courante * circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------
|
||||
case TYPE_CARTE_SP4AC:
|
||||
//------------------------
|
||||
{
|
||||
// Puissance :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_PUISSANCE].valeur_courante = circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION_SECTEUR].valeur_courante * circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------
|
||||
default: ;
|
||||
//------------------------
|
||||
}
|
||||
|
||||
//====================================
|
||||
// Intégration des cumuls du circuit :
|
||||
//====================================
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION].cumul += circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION].valeur_courante;
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].cumul += circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante;
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_FREQUENCE].cumul += circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_FREQUENCE].valeur_courante;
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_PUISSANCE].cumul += circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_PUISSANCE].valeur_courante;
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION_SECTEUR].cumul += circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_TENSION_SECTEUR].valeur_courante;
|
||||
circuits.circuits[no_circuit].cumuls_nb_val ++; // MàJ du nombre d'échantillons dans le cumul
|
||||
|
||||
|
||||
//===========================================
|
||||
// Vérification de l'expiration du time-out :
|
||||
//===========================================
|
||||
if ((circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante > 0) &&
|
||||
(circuits.circuits[no_circuit].time_out > 0) &&
|
||||
(circuits.circuits[no_circuit].compteur_time_out == 0))
|
||||
{
|
||||
changement_consigne_circuit(no_circuit, OFF, CIRCUITS_ORIGINE_CONSIGNE_TIME_OUT, 0);
|
||||
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CIRCUITS, CIRCUIT_EXPIRATION_TIME_OUT, circuits.circuits[no_circuit].cle_primaire, circuits.circuits[no_circuit].time_out, NULL); // Enregistrement dans l'historique
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Surveillance du seuil haut de courant :
|
||||
//========================================
|
||||
switch(circuits.circuits[no_circuit].sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_CIRCUIT_INIT :
|
||||
{
|
||||
circuits.circuits[no_circuit].sequenceur.etat = ETAT_SEQUENCEUR_CIRCUITS_REPOS;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_CIRCUIT_REPOS :
|
||||
{
|
||||
// Recherche d'un dépassement de seuil de courant :
|
||||
if ((circuits.circuits[no_circuit].intensite_seuil_haut > 0) &&
|
||||
(circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante > circuits.circuits[no_circuit].intensite_seuil_haut))
|
||||
{
|
||||
circuits.circuits[no_circuit].sequenceur.compteur = circuits.circuits[no_circuit].intensite_seuil_haut_tempo / 10; // Le compteur est décrémenté toutes les 100ms.
|
||||
circuits.circuits[no_circuit].sequenceur.etat = ETAT_SEQUENCEUR_CIRCUIT_CHECK_LIMITATION;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_CIRCUIT_CHECK_LIMITATION :
|
||||
{
|
||||
// Test de disparition du défaut avant expiration de la tempo :
|
||||
if (circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante <= circuits.circuits[no_circuit].intensite_seuil_haut)
|
||||
{
|
||||
circuits.circuits[no_circuit].sequenceur.compteur = 0; // RAZ pour usage ultérieur
|
||||
circuits.circuits[no_circuit].sequenceur.etat = ETAT_SEQUENCEUR_CIRCUIT_REPOS;
|
||||
break;
|
||||
}
|
||||
|
||||
// Expiration de la tempo de filtrage :
|
||||
if (circuits.circuits[no_circuit].sequenceur.compteur == 0)
|
||||
{
|
||||
changement_consigne_circuit(no_circuit, OFF, CIRCUITS_ORIGINE_CONSIGNE_DEFAUT, 0);
|
||||
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CIRCUITS, CIRCUIT_LIMITATION, circuits.circuits[no_circuit].cle_primaire, circuits.circuits[no_circuit].intensite_seuil_haut, NULL); // Enregistrement dans l'historique
|
||||
|
||||
circuits.circuits[no_circuit].etat = ETAT_CIRCUIT_LIMITATION;
|
||||
circuits.circuits[no_circuit].sequenceur.etat = ETAT_SEQUENCEUR_CIRCUIT_REPOS;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur du circuit %i est inconnu [%i]. Il est repositionné au REPOS", no_circuit+1, circuits.circuits[no_circuit].sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
circuits.circuits[no_circuit].sequenceur.etat = ETAT_SEQUENCEUR_CIRCUIT_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Effectue toutes les actions nécessaires lors d'un changement de consigne du circuit
|
||||
// Reçoit : Le n° de circuit, la valeur de consigne, l'origine de la consigne et l'ID de cette origine
|
||||
// Retourne : 0 si aucune erreur. -1 si erreur
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int8_t changement_consigne_circuit(uint16_t no_circuit, uint8_t consigne, uint8_t origine_consigne, uint16_t id_origine_consigne)
|
||||
{
|
||||
if (no_circuit > MAX_NOMBRE_CIRCUITS) return (-1);
|
||||
if (consigne > MAX_CONSIGNE_CIRCUIT) return(-1);
|
||||
|
||||
// Mise à jour des variables du circuit :
|
||||
circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante = consigne;
|
||||
circuits.circuits[no_circuit].origine_consigne = origine_consigne;
|
||||
circuits.circuits[no_circuit].id_origine_consigne = id_origine_consigne;
|
||||
|
||||
// Emission d'une commande vers le Compagnon que si le circuit n'est pas sur ShipBase :
|
||||
if (circuits.circuits[no_circuit].adresse_module != 0)
|
||||
{
|
||||
circuits.circuits[no_circuit].flag_changement_consigne_en_cours = true; // SDIR #179
|
||||
c_bus_down_commande_cde_circuits(circuits.circuits[no_circuit].adresse_module); // Consigne du circuit envoyée au Compagnon
|
||||
}
|
||||
|
||||
if (consigne > 0)
|
||||
{
|
||||
// RAZ du flag d'état du circuit à chaque fois qu'on l'active avec une consigne > 0 :
|
||||
circuits.circuits[no_circuit].etat = ETAT_CIRCUIT_OK;
|
||||
|
||||
// Armement du time-out, si le circuit est ON et qu'un time-out est configuré dessus :
|
||||
if (circuits.circuits[no_circuit].time_out > 0)
|
||||
{
|
||||
circuits.circuits[no_circuit].compteur_time_out = (circuits.circuits[no_circuit].time_out * 10); // Réarmement du time-out si le circuit est ON. NB : le time-out est exprimé en secondes mais, pour gagner en précision sur les petites durées, on a passé le décomptage en 100ms dans 'hardware.c' d'où le x10...
|
||||
}
|
||||
}
|
||||
|
||||
// Enregistrement du changement de consigne dans les mesures (qui ne sont faites que sur changement d'état pour les consignes) :
|
||||
char date_vide[MAX_LONGUEUR_DATE_COURANTE] = ""; // Evite un warning depuis GCC14
|
||||
enregistrement_mesure(SOURCE_MESURE_CIRCUIT, no_circuit, CIRCUIT_VARIABLE_CONSIGNE, date_vide, BDD_ENREGISTREMENT_MESURE_PONCTUEL);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction INIT_CIRCUITS
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int8_t init_circuits(void)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
circuits.sequenceur.etat = ETAT_SEQUENCEUR_CIRCUITS_INIT;
|
||||
circuits.sequenceur.compteur = CIRCUITS_TEMPO_INIT;
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_CIRCUITS; i++)
|
||||
{
|
||||
circuits.circuits[i].sequenceur.etat = ETAT_SEQUENCEUR_CIRCUIT_INIT;
|
||||
circuits.circuits[i].flag_dde_maj_bdd = FALSE;
|
||||
}
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation des circuits\t\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Recherche le circuit dont la Clé_primaire est reçue en paramètre
|
||||
// Reçoit : La Cle_primaire du circuit à rechercher
|
||||
// Retourne : le numéro de circuit correspondant (ou -1 si aucun circuit valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_CIRCUITS - 1.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int16_t circuit_cle_primaire(uint16_t cle_primaire)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < circuits.nb; i ++)
|
||||
{
|
||||
if ((circuits.circuits[i].cle_primaire == cle_primaire) && (circuits.circuits[i].flag_validite)) return(i);
|
||||
}
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction VARIABLE_CIRCUIT_CLE_PRIMAIRE
|
||||
// Reçoit en paramètre :
|
||||
// - La Cle_primaire de la variable à rechercher
|
||||
// Retourne :
|
||||
// - le numéro de variable correspondant (ou -1 si aucune variable valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_VARIABLES_CIRCUITS-1.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int16_t variable_circuit_cle_primaire(uint16_t cle_primaire)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_VARIABLES_CIRCUITS; i++)
|
||||
{
|
||||
if (circuits.variables[i].cle_primaire == cle_primaire) return(i);
|
||||
|
||||
}
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier CIRCUITS.H
|
||||
//
|
||||
// Contient tous les define liés aux circuits
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MAX_NOMBRE_CIRCUITS 256 // Nombre maximal de circuits commandés par ShipHeart, quelle que soit la carte sur laquelle ils sont.
|
||||
#define MAX_CONSIGNE_CIRCUIT 100
|
||||
#define MAX_NOMBRE_VARIABLES_CIRCUITS 7
|
||||
#define MAX_TAILLE_NOM_CIRCUITS 80 // Lié à dimension du champs 'Nom' dans TB_Circuits
|
||||
#define MAX_CIRCUITS_PAR_MODULE_SHIPBASE_V1 2 // ShipBase proprement-dit et ports USB en face avant
|
||||
#define MAX_CIRCUITS_PAR_MODULE_SHIPBASE_V2 3 // ShipBase proprement-dit, ports USB en face avant et port USB à l'arrière
|
||||
#define MAX_CIRCUITS_PAR_MODULE_SP8XX 8 // Valable pour les SP812 et SP8DC
|
||||
#define MAX_CIRCUITS_PAR_MODULE_SP4AC 4
|
||||
#define MAX_CIRCUITS_PAR_MODULE MAX_CIRCUITS_PAR_MODULE_SP8XX
|
||||
#define MAX_COURANT_MASSES_SP8DC 25.4 // En A (la limite vient du fait que la valeur est ensuite transmise aux SP8DC sous forme de uint_8).
|
||||
|
||||
|
||||
// Timings :
|
||||
#define CIRCUITS_TEMPO_INIT 100 // En x 10ms
|
||||
#define CIRCUITS_PERIODE_MISE_A_JOUR 10 // En x 10ms
|
||||
#define CIRCUIT_TEMPO_INIT 20 // En x 10ms
|
||||
|
||||
|
||||
// Général :
|
||||
#define CIRCUITS_TENSION_CARTE_OK 0
|
||||
#define CIRCUITS_TENSION_CARTE_UNDERVOLTAGE 1
|
||||
|
||||
|
||||
// Etat de commande carte :
|
||||
#define CIRCUITS_ETAT_COMMANDE_CARTE_OK 0
|
||||
#define CIRCUITS_ETAT_COMMANDE_CARTE_UNDERVOLTAGE 1
|
||||
#define CIRCUITS_ETAT_COMMANDE_CARTE_TEST 2
|
||||
|
||||
|
||||
// Modes de commande circuits :
|
||||
#define CIRCUITS_MODE_COMMANDE_ON_OFF 0 // Ne peut prendre que deux états ON/OFF
|
||||
#define CIRCUITS_MODE_COMMANDE_ON_OFF_SOFT 1 // Ne peut prendre que deux états ON/OFF mais la transition de l'un à l'autre se fait de façon douce
|
||||
#define CIRCUITS_MODE_COMMANDE_VARIABLE_SOFT 2 // Peut prendre toute valeur entre 0 et 100 et start/stop soft
|
||||
#define CIRCUITS_MODE_COMMANDE_CADENCE 3
|
||||
|
||||
|
||||
// Origine consigne :
|
||||
#define CIRCUITS_ORIGINE_CONSIGNE_SHIPBASE 0
|
||||
#define CIRCUITS_ORIGINE_CONSIGNE_TIME_OUT 1
|
||||
#define CIRCUITS_ORIGINE_CONSIGNE_EVENT 2
|
||||
#define CIRCUITS_ORIGINE_CONSIGNE_DEFAUT 3
|
||||
|
||||
|
||||
// SHIPBASE :
|
||||
#define SB_CIRCUIT_NO_SHIPHEART 0
|
||||
#define SB_CIRCUIT_NO_USB_AVANT 1
|
||||
#define SB_CIRCUIT_NO_USB_ARRIERE 2
|
||||
|
||||
// SP4AC :
|
||||
#define SP4AC_NOMBRE_CIRCUITS 4
|
||||
|
||||
// SP8XX = SP812 ou SP8DC indifféremment
|
||||
// ATTENTION : il est important de s'assurer que tous les defines ci-dessous s'appliquent indifféremment à SP812 et SP8DC !!!!
|
||||
#define SP8XX_NOMBRE_CIRCUITS 8
|
||||
#define SP8XX_MAX_COURANT_TOTAL_CIRCUITS 50.00 // En A. Si 0, aucune surveillance du courant maxi
|
||||
|
||||
#define SP8XX_TEMPO_COURANT_TOTAL_CIRCUITS_CHECK 10 // En secondes.
|
||||
|
||||
#define SP8XX_TYPE_CIRCUIT_ON_OFF 0 // Ne peut prendre que deux états ON/OFF
|
||||
#define SP8XX_TYPE_CIRCUIT_ON_OFF_SOFT 1 // Ne peut prendre que deux états ON/OFF mais la transition de l'un à l'autre se fait de façon douce
|
||||
#define SP8XX_TYPE_CIRCUIT_VARIABLE_SOFT 2 // Peut prendre toute valeur entre 0 et 100 et start/stop soft
|
||||
|
||||
#define SP8XX_MODE_CDE_CIRCUIT_ON_OFF 0 // Ne peut prendre que deux états ON/OFF
|
||||
#define SP8XX_MODE_CDE_CIRCUIT_ON_OFF_SOFT 1 // Ne peut prendre que deux états ON/OFF mais la transition de l'un à l'autre se fait de façon douce
|
||||
#define SP8XX_MODE_CDE_CIRCUIT_VARIABLE_SOFT 2 // Peut prendre toute valeur entre 0 et 100 et start/stop soft
|
||||
#define SP8XX_MODE_CDE_CIRCUIT_AUTO 3 // Mode de commande hérité du type
|
||||
|
||||
|
||||
|
||||
|
||||
// Etats d'un circuit :
|
||||
#define ETAT_CIRCUIT_OK 0 // Tout va bien...
|
||||
#define ETAT_CIRCUIT_LIMITATION 1
|
||||
#define ETAT_CIRCUIT_PROTECTION 2
|
||||
#define ETAT_CIRCUIT_DISJONCTE 3
|
||||
#define ETAT_CIRCUIT_CC_BATTERIE 4
|
||||
#define ETAT_CIRCUIT_DELESTE 5
|
||||
#define ETAT_CIRCUIT_UNDERVOLTAGE 6
|
||||
#define ETAT_CIRCUIT_INVERSION_PHASE_NEUTRE 7 // Sur SP4AC uniquement
|
||||
#define ETAT_CIRCUIT_ABSENCE_TERRE 8 // Sur SP4AC uniquement
|
||||
#define ETAT_CIRCUIT_ABSENCE_MASSE 9 // Sur SP8DC uniquement
|
||||
#define ETAT_CIRCUIT_INCONNU 99
|
||||
|
||||
|
||||
// Variables du circuit :
|
||||
#define CIRCUIT_VARIABLE_CONSIGNE 0
|
||||
#define CIRCUIT_VARIABLE_TENSION 1
|
||||
#define CIRCUIT_VARIABLE_COURANT 2
|
||||
#define CIRCUIT_VARIABLE_FREQUENCE 3
|
||||
#define CIRCUIT_VARIABLE_PUISSANCE 4
|
||||
#define CIRCUIT_VARIABLE_ENERGIE 5
|
||||
#define CIRCUIT_VARIABLE_TENSION_SECTEUR 6
|
||||
// NB : ces valeurs doivent rester strictement inférieures à MAX_NOMBRE_VARIABLES_PAR_CIRCUIT
|
||||
|
||||
|
||||
// Validation des commandes par des évènements du circuit :
|
||||
#define CIRCUIT_VALIDATION_COMMANDES_EVENTS_OFF 0
|
||||
#define CIRCUIT_VALIDATION_COMMANDES_EVENTS_ON 1
|
||||
|
||||
|
||||
// Etat séquenceur Circuits :
|
||||
#define ETAT_SEQUENCEUR_CIRCUITS_INIT 0
|
||||
#define ETAT_SEQUENCEUR_CIRCUITS_REPOS 1
|
||||
|
||||
// Etat séquenceur circuit :
|
||||
#define ETAT_SEQUENCEUR_CIRCUIT_INIT 0
|
||||
#define ETAT_SEQUENCEUR_CIRCUIT_REPOS 1
|
||||
#define ETAT_SEQUENCEUR_CIRCUIT_CHECK_LIMITATION 2
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
//**********************************************************************************************************************************************************************************␍// Fichier DEBUG.H␍//␍// Contient tous les define liés aux fontions de debug et de logs...␍//**********************************************************************************************************************************************************************************/␍␍ // Maximums :␍#define MAX_LONGUEUR_NOM_FICHIER_DEBUG 100␍#define MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG (MAX_LONGUEUR_REQUETE_MYSQL - 100) // Utilisé dans chaque fonction ayant besoin d'un buffer temporaire pour cosntruire le message de debug␍#define MAX_LONGUEUR_LIGNE_FICHIER_LOG MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG␍#define MAX_NOMBRE_LIGNES_FICHIER_LOG 100000 //2500␍// En pratique, la taille du fichier de log n'est pas limitée (on fait des 'append' au fil de l'eau et la seule limite sera l'espace libre du disque).␍// Par contre, à chaque init (dans fonctions.c, 'init_affichage_debug()'), on purge toutes les lignes dépassant MAX_NOMBRE_LIGNES_FICHIER_LOG.␍␍␍␍ // Mode d'affichage des messages de debug␍#define AFFICHAGE_DEBUG_AUCUN 0␍#define AFFICHAGE_DEBUG_ECRAN 1␍#define AFFICHAGE_DEBUG_FICHIER 2␍#define AFFICHAGE_DEBUG_ECRAN_ET_FICHIER 3␍␍␍ // Types de messages de débug :␍#define TYPE_MESSAGE_DEBUG_PAR_DEFAUT 0␍#define TYPE_MESSAGE_DEBUG_OK 1␍#define TYPE_MESSAGE_DEBUG_WARNING 2␍#define TYPE_MESSAGE_DEBUG_ERREUR 3␍#define TYPE_MESSAGE_DEBUG_FICHIER_SEULEMENT 4␍#define TYPE_MESSAGE_DEBUG_DEBUG 5␍␍␍ // Type de bus dont le debug est possible :␍#define TYPE_BUS_DEBUG_C_BUS 0␍#define TYPE_BUS_DEBUG_M_BUS 1␍#define TYPE_BUS_DEBUG_G_BUS 1␍␍ // Codes des couleurs d'affichage sur la console :␍#define DEBUG_TEXT_COLOR_RESET "\033[0m" // Reset la couleur précémment demandée␍#define DEBUG_TEXT_COLOR_BLACK "\033[0;30m"␍#define DEBUG_TEXT_COLOR_RED "\033[0;31m"␍#define DEBUG_TEXT_COLOR_GREEN "\033[0;32m"␍#define DEBUG_TEXT_COLOR_YELLOW "\033[0;33m"␍#define DEBUG_TEXT_COLOR_BLUE "\033[0;34m"␍#define DEBUG_TEXT_COLOR_PURPLE "\033[0;35m"␍#define DEBUG_TEXT_COLOR_CYAN "\033[0;36m"␍#define DEBUG_TEXT_COLOR_WHITE "\033[0;37m"␍␍␍␍
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
// **********************************************************************************************************************************************************************************
|
||||
// Fichier ECRAN.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à l'écran tactile.
|
||||
// **********************************************************************************************************************************************************************************
|
||||
|
||||
// Include :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t set_luminosite_ecran(uint16_t luminosite);
|
||||
void gestion_ecran(void);
|
||||
int8_t init_ecran(void);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_ecran ecran;
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Met à jour le niveau de luminosité de l'écran
|
||||
// Reçoit : Le niveau de luminosité attendu (de 0 à 100%), en centièmes de pourcent.
|
||||
// Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée
|
||||
//==================================================================================================================================================================
|
||||
int8_t set_luminosite_ecran(uint16_t luminosite)
|
||||
{
|
||||
|
||||
if (luminosite > ECRAN_CONSIGNE_MAX) return(-1);
|
||||
|
||||
if (luminosite == 0)
|
||||
{
|
||||
if (ecran.sequenceur.etat != ETAT_SEQUENCEUR_ECRAN_REPOS_ETEINT) ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_DEMANDE_EXTINCTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ecran.sequenceur.etat != ETAT_SEQUENCEUR_ECRAN_REPOS_ALLUME) ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_DEMANDE_ALLUMAGE;
|
||||
else // Si on est déjà allumé, uniquement envoi de la consigne au Compagnon pour mise à jour de la consigne de backlight (reste allumé mais à une autre consigne)
|
||||
{
|
||||
if (ecran.validation_leds == 0) c_bus_down_commande_cde_backlight(ecran.consigne_backlight, 0);
|
||||
else c_bus_down_commande_cde_backlight(ecran.consigne_backlight, ecran.consigne_leds);
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Fonction de plus haut niveau de gestion de l'écran
|
||||
// Reçoit : Rien
|
||||
// Renvoit : Rien
|
||||
//==================================================================================================================================================================
|
||||
void gestion_ecran(void)
|
||||
{
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
switch(ecran.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_INIT :
|
||||
{
|
||||
if ((ecran.sequenceur.compteur == 0) && (c_bus.sequenceur.etat != ETAT_SEQUENCEUR_C_BUS_INIT))
|
||||
{
|
||||
if (ecran.consigne_backlight == 0) ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_DEMANDE_EXTINCTION;
|
||||
else ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_DEMANDE_ALLUMAGE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_DEMANDE_EXTINCTION :
|
||||
{
|
||||
if (ecran.validation_leds == 0) c_bus_down_commande_cde_backlight(0, 0);
|
||||
else c_bus_down_commande_cde_backlight(0, ecran.consigne_leds);
|
||||
|
||||
ecran.sequenceur.compteur = ECRAN_TEMPO_EXTINCTION_BACKLIGHT_LVDS;
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_BACKLIGHT;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_BACKLIGHT :
|
||||
{
|
||||
if (ecran.sequenceur.compteur == 0)
|
||||
{
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.sortie_gpio_cm_pdown_hdmi_cmd_n, OFF); // Coupure de la commande du HDMI et donc du LVDS. 0 est l'adresse de ShipBase
|
||||
|
||||
ecran.sequenceur.compteur = ECRAN_TEMPO_EXTINCTION_LVDS_VGX;
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_LVDS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_LVDS :
|
||||
{
|
||||
if (ecran.sequenceur.compteur == 0)
|
||||
{
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.sortie_gpio_cm_do_lcd_en_vgx, OFF); // .. puis coupure de la commande de VGx. 0 est l'adresse de ShipBAse
|
||||
|
||||
ecran.sequenceur.compteur = ECRAN_TEMPO_EXTINCTION_VGX_VDD;
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_VGX;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_VGX :
|
||||
{
|
||||
if (ecran.sequenceur.compteur == 0)
|
||||
{
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.sortie_gpio_cm_do_lcd_en_vdd, OFF); // Coupure immédiate de la commande de VDD. 0 est l'adresse de ShipBase
|
||||
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_REPOS_ETEINT;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_REPOS_ETEINT :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_DEMANDE_ALLUMAGE :
|
||||
{
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.sortie_gpio_cm_do_lcd_en_vdd, ON); // Activation immédiate de la commande de VDD. 0 est l'adresse de ShipBase
|
||||
|
||||
ecran.sequenceur.compteur = ECRAN_TEMPO_ALIMENTATION_VDD_LVDS;
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_VDD;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_VDD :
|
||||
{
|
||||
if (ecran.sequenceur.compteur == 0)
|
||||
{
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.sortie_gpio_cm_pdown_hdmi_cmd_n, ON); // Activation de la commande du HDMI qui émet alors du LVDS. 0 est l'adresse de ShipBase
|
||||
|
||||
ecran.sequenceur.compteur = ECRAN_TEMPO_ALIMENTATION_LVDS_VGX;
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_LVDS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_LVDS :
|
||||
{
|
||||
if (ecran.sequenceur.compteur == 0)
|
||||
{
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, ecran.sortie_gpio_cm_do_lcd_en_vgx, ON); // Activation immédiate de la commande de VGx. 0 est l'adresse de ShipBase
|
||||
|
||||
ecran.sequenceur.compteur = ECRAN_TEMPO_ALIMENTATION_VGX_BACKLIGHT;
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_VGX;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_VGX :
|
||||
{
|
||||
if (ecran.sequenceur.compteur == 0)
|
||||
{
|
||||
if (ecran.validation_leds == 0) c_bus_down_commande_cde_backlight(ecran.consigne_backlight, 0);
|
||||
else c_bus_down_commande_cde_backlight(ecran.consigne_backlight, ecran.consigne_leds);
|
||||
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_REPOS_ALLUME;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_ECRAN_REPOS_ALLUME :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur Ecran est inconnu [%i]. Il est repositionné au REPOS", ecran.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_INIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Initialise les fonctions de l'écran
|
||||
// Reçoit : Rien
|
||||
// Renvoit : 0 si aucune erreur, -1 si une erreur a été détectée
|
||||
//==================================================================================================================================================================
|
||||
int8_t init_ecran(void)
|
||||
{
|
||||
|
||||
ecran.sequenceur.compteur = ECRAN_TEMPO_INIT;
|
||||
ecran.sequenceur.etat = ETAT_SEQUENCEUR_ECRAN_INIT;
|
||||
|
||||
// Ajustement des variables selon la génération de ShipBase en cours :
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1)
|
||||
{
|
||||
ecran.sortie_gpio_cm_pdown_hdmi_cmd_n = CM3P_Pdown_HDMI_CMD_N;
|
||||
ecran.sortie_gpio_cm_do_lcd_en_vgx = CM3P_DO_LCD_EN_VGx;
|
||||
ecran.sortie_gpio_cm_do_lcd_en_vdd = CM3P_DO_LCD_EN_VDD;
|
||||
}
|
||||
else
|
||||
{
|
||||
ecran.sortie_gpio_cm_pdown_hdmi_cmd_n = CM4_Pdown_HDMI_CMD_N;
|
||||
ecran.sortie_gpio_cm_do_lcd_en_vgx = CM4_DO_EN_LCD_VGx;
|
||||
ecran.sortie_gpio_cm_do_lcd_en_vdd = CM4_DO_EN_LCD_VDD;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier ECRAN.H
|
||||
//
|
||||
// Contient tous les define liés à l'écran...
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
//#define CM3P_Pdown_HDMI_CMD_N est renseigné dans 'sorties.h'
|
||||
//#define CM3P_DO_LCD_EN_VGx est renseigné dans 'sorties.h'
|
||||
//#define CM3P_DO_LCD_EN_VDD est renseigné dans 'sorties.h'
|
||||
|
||||
|
||||
// Maximums :
|
||||
#define ECRAN_CONSIGNE_MAX 100 // Soit 100%
|
||||
#define ECRAN_CONSIGNE_MIN 0 // Soit éteint
|
||||
#define LEDS_CONSIGNE_MAX 100 // Soit 100%
|
||||
#define LEDS_CONSIGNE_MIN 0 // Soit éteint
|
||||
|
||||
|
||||
// Timings
|
||||
#define ECRAN_TEMPO_INIT 2 // En x 10ms En pratique, on attend que le C-Bus soit prêt pour envoyer la commande de backlight...
|
||||
|
||||
#define ECRAN_TEMPO_EXTINCTION_BACKLIGHT_LVDS 120 // En x 10ms Supérieur ou égal à 0ms selon datasheet de l'écran. Le choix est donc fonctionnel et d'attendre que le backlight soit éteint doucement avant de modifier les alims.
|
||||
#define ECRAN_TEMPO_EXTINCTION_LVDS_VGX 2 // En x 10ms Supérieur à 0 selond datasheet de l'écran
|
||||
#define ECRAN_TEMPO_EXTINCTION_VGX_VDD 2 // En x 10ms Entre 0 et 50ms depuis la coupure LVDS selon datasheet de l'écran (donc [ECRAN_TEMPO_EXTINCTION_LVDS_VGX + ECRAN_TEMPO_ALIMENTATION_VGX_VDD] entre 0 et 50ms)
|
||||
|
||||
#define ECRAN_TEMPO_ALIMENTATION_VDD_LVDS 4 // En x 10ms Entre 0 et 50ms selon datasheet de l'écran
|
||||
#define ECRAN_TEMPO_ALIMENTATION_LVDS_VGX 2 // En x 10ms Juste > 0 selon datasheet de l'écran
|
||||
#define ECRAN_TEMPO_ALIMENTATION_VGX_BACKLIGHT 15 // En x 10ms Supérieur à 120ms selon datasheet de l'écran
|
||||
|
||||
|
||||
// #define ECRAN_TEMPO_ALIMENTATION_VDD_VGX 2 // En x 10ms Tempo à l'allumage de l'écran entre l'alimentation de VDD puis de VGx
|
||||
|
||||
|
||||
|
||||
#define ETAT_SEQUENCEUR_ECRAN_INIT 0
|
||||
|
||||
#define ETAT_SEQUENCEUR_ECRAN_DEMANDE_EXTINCTION 1
|
||||
#define ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_BACKLIGHT 2
|
||||
#define ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_LVDS 3
|
||||
#define ETAT_SEQUENCEUR_ECRAN_ATTENTE_EXTINCTION_VGX 4
|
||||
#define ETAT_SEQUENCEUR_ECRAN_REPOS_ETEINT 5
|
||||
|
||||
#define ETAT_SEQUENCEUR_ECRAN_DEMANDE_ALLUMAGE 6
|
||||
#define ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_VDD 7
|
||||
#define ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_LVDS 8
|
||||
#define ETAT_SEQUENCEUR_ECRAN_ALLUMAGE_ATTENTE_VGX 9
|
||||
#define ETAT_SEQUENCEUR_ECRAN_REPOS_ALLUME 10
|
||||
@@ -0,0 +1,884 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier ENTREES.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à la lecture de l'état des entrées
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
void gestion_entrees(void);
|
||||
void gestion_entrees_aux(void);
|
||||
void gestion_entrees_level_sensor(void);
|
||||
void gestion_entrees_volt(void);
|
||||
void gestion_entrees_nmea(void);
|
||||
void gestion_entrees_ow(void);
|
||||
void gestion_entrees_predefinies(void);
|
||||
void gestion_entrees_core(void);
|
||||
void gestion_entrees_gpio(void);
|
||||
int8_t init_entrees(void);
|
||||
int8_t init_entrees_aux(void);
|
||||
int8_t init_entrees_level_sensor(void);
|
||||
int8_t init_entrees_volt(void);
|
||||
int8_t init_entrees_nmea(void);
|
||||
int8_t init_entrees_ow(void);
|
||||
int8_t init_entrees_predefinies(void);
|
||||
int8_t init_entrees_core(void);
|
||||
int8_t init_entrees_gpio(void);
|
||||
float lecture_entree(uint8_t type, uint8_t module, uint8_t no, bool flag_immediat);
|
||||
int16_t entree_no(uint8_t type, uint8_t module, uint8_t no);
|
||||
uint8_t lecture_entree_gpio(uint8_t no, int8_t logique);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_entrees entrees;
|
||||
struct gpiod_chip *gpiod_chip0; // Nécessaire pour CM5
|
||||
struct gpiod_line_request *gpiod_entrees_request; // Nécessaire pour CM5
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction LECTURE_ENTREE
|
||||
|
||||
Fonction utilisée pour connaitre l'état d'une entrée, quel que soit sont type.
|
||||
Reçoit en paramètre : le Type d'entrée, le module comportant l'entrée, le n° sur le module et un flag permettant de forcer la lecture immédiate (pour GPIO)
|
||||
Retourne : l'état de l'entrée
|
||||
NB : Dans le cas où le flag est 'faux', l'appel à cette fonction remontera le dernier état connu, mis à jour par le gestionnaire correspondant au type.
|
||||
NB2 : L'utilisation du flag n'est possible que pour les entrées de type GPIO (pour les autres, il est ignoré...). Ce flag est à utiliser avec modération...
|
||||
**********************************************************************************************************************************************************************************/
|
||||
float lecture_entree(uint8_t type, uint8_t module, uint8_t no, bool flag_immediat)
|
||||
{
|
||||
int16_t x;
|
||||
|
||||
x = entree_no(type, module, no);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
//-----------------------------
|
||||
case TYPE_ENTREES_AUXILIAIRES :
|
||||
{
|
||||
return(entrees.aux.entrees[x].valeur);
|
||||
break;
|
||||
}
|
||||
//-----------------------------
|
||||
case TYPE_ENTREES_LEVEL_SENSOR :
|
||||
{
|
||||
return(entrees.level_sensor.entrees[x].valeur);
|
||||
break;
|
||||
}
|
||||
//-----------------------------
|
||||
case TYPE_ENTREES_VOLTAGE :
|
||||
{
|
||||
return(entrees.volt.entrees[x].valeur);
|
||||
break;
|
||||
}
|
||||
//-----------------------------
|
||||
case TYPE_ENTREES_NMEA :
|
||||
{
|
||||
return(entrees.nmea.entrees[x].valeur);
|
||||
break;
|
||||
}
|
||||
//-----------------------------
|
||||
case TYPE_ENTREES_OW :
|
||||
{
|
||||
return(entrees.ow.entrees[x].valeur);
|
||||
break;
|
||||
}
|
||||
//-----------------------------
|
||||
case TYPE_ENTREES_PREDEFINIES :
|
||||
{
|
||||
return(entrees.predefinies.entrees[x].valeur);
|
||||
break;
|
||||
}
|
||||
//-----------------------------
|
||||
case TYPE_ENTREES_CORE :
|
||||
{
|
||||
return(entrees.core.entrees[x].valeur);
|
||||
break;
|
||||
}
|
||||
//-----------------------------
|
||||
case TYPE_ENTREES_GPIO :
|
||||
{
|
||||
if (flag_immediat) entrees.gpio.entrees[x].valeur = lecture_entree_gpio(no, entrees.gpio.entrees[x].logique);
|
||||
return(entrees.gpio.entrees[x].valeur);
|
||||
break;
|
||||
}
|
||||
//-----------------------------
|
||||
default: ;
|
||||
}
|
||||
|
||||
return (0xFFFFFFFF); // Cas d'erreur
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES
|
||||
|
||||
Lance le traitement régulier du gestionnaire de chaque type d'entrée
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees(void)
|
||||
{
|
||||
|
||||
gestion_entrees_aux();
|
||||
gestion_entrees_level_sensor();
|
||||
gestion_entrees_volt();
|
||||
gestion_entrees_nmea();
|
||||
gestion_entrees_ow();
|
||||
gestion_entrees_predefinies();
|
||||
gestion_entrees_core();
|
||||
gestion_entrees_gpio();
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES_AUX
|
||||
|
||||
Fonction utilisée pour mettre à jour toutes les sorties GPIO de façon synchrones
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees_aux(void)
|
||||
{
|
||||
// Il n'y a rien à faire car l'état des entrées AUX est remonté automatiquement par le Compagnon via une commande UP.
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES_LEVEL_SENSOR
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees_level_sensor(void)
|
||||
{
|
||||
|
||||
switch(entrees.level_sensor.sequenceur.etat)
|
||||
{
|
||||
case ETAT_SEQUENCEUR_ENTREES_LEVEL_SENSOR_INIT:
|
||||
{
|
||||
if ((entrees.level_sensor.sequenceur.compteur == 0) && (systeme.flag_cm3p_ready))
|
||||
{
|
||||
c_bus_down_commande_config_level_sensors(); // Commande de config des entrées Level Sensor vers le Compagnon sur C-Bus
|
||||
|
||||
entrees.level_sensor.sequenceur.etat = ETAT_SEQUENCEUR_ENTREES_LEVEL_SENSOR_REPOS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ETAT_SEQUENCEUR_ENTREES_LEVEL_SENSOR_REPOS:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default : entrees.level_sensor.sequenceur.etat = ETAT_SEQUENCEUR_ENTREES_LEVEL_SENSOR_REPOS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES_VOLT
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees_volt(void)
|
||||
{
|
||||
// Il n'y a rien à faire car l'état des entrées VOLTAGE est remonté automatiquement par le Compagnon via une commande UP.
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES_NMEA
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees_nmea(void)
|
||||
{
|
||||
// Il n'y a rien à faire car l'état des entrées NMEA est remonté automatiquement par le Compagnon via une commande UP.
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES_OW
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees_ow(void)
|
||||
{
|
||||
// Il n'y a rien à faire car l'état des entrées OW est remonté automatiquement par le Compagnon via une commande UP.
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES_PREDEFINIES
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees_predefinies(void)
|
||||
{
|
||||
// Il n'y a rien à faire car l'état des entrées PREDEFINIES est remonté automatiquement par le Compagnon via les commandes UP.
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES_CORE
|
||||
|
||||
Séquenceur permettant la lecture des trames reçues sur la ligne Téléinfo du compteur EDF
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees_core(void)
|
||||
{
|
||||
int i;
|
||||
char commande[MAX_TAILLE_COMMANDE_SHELL];
|
||||
char chaine[300];
|
||||
|
||||
if (entrees.core.sequenceur.compteur == 0)
|
||||
{
|
||||
entrees.core.sequenceur.compteur = PERIODE_LECTURE_ENTREES_CORE; // Réarmement du timer périodique
|
||||
|
||||
strcpy(commande, "{ "); // Attention, l'espace après le '{' est obligatoire !
|
||||
for (i=0; i<MAX_NOMBRE_ENTREES_CORE; i++)
|
||||
{
|
||||
if (!entrees.core.entrees[i].flag_validite) continue;
|
||||
|
||||
if (strstr(entrees.core.entrees[i].nom, "TEMPERATURE_CORE") != NULL) strcat(commande, "vcgencmd measure_temp; ");
|
||||
else if (strstr(entrees.core.entrees[i].nom, "TENSION_CORE") != NULL) strcat(commande, "vcgencmd measure_volts core; ");
|
||||
else if (strstr(entrees.core.entrees[i].nom, "FREQUENCE_CORE") != NULL) strcat(commande, "vcgencmd measure_clock core; ");
|
||||
else if (strstr(entrees.core.entrees[i].nom, "FREQUENCE_UART") != NULL) strcat(commande, "vcgencmd measure_clock uart; ");
|
||||
else if (strstr(entrees.core.entrees[i].nom, "VITESSE_BOUCLE_PRINCIPALE") != NULL)
|
||||
{
|
||||
if (supervision_boucle_principale.nb_secondes > 0) // Dans le cas où on n'a pas effectué un comptage sur 1 seconde au moins, on ne traite pas la mesure de l'entrée :
|
||||
{
|
||||
// printf("Vitesse boucle principale = %i boucles/seconde\n", (supervision_boucle_principale.nb_boucles / supervision_boucle_principale.nb_secondes));
|
||||
supervision_boucle_principale.nb_boucles = 0;
|
||||
supervision_boucle_principale.nb_secondes = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
strcat(commande, " }"); // Attention, l'espace avant le '{' est obligatoire !
|
||||
sprintf(chaine, " > %s/%s &", REPERTOIRE_TMP_CORE, NOM_FICHIER_ETAT_ENTREES_CORE);
|
||||
strcat(commande, chaine);
|
||||
//printf("Commande Shell = [%s]\n", commande);
|
||||
commande_shell(commande);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ENTREES_GPIO
|
||||
|
||||
Fonction utilisée pour rendre la lecture des entrées GPIO synchrones (tous les états lus d'un coup)
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_entrees_gpio(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (entrees.gpio.sequenceur.compteur == 0)
|
||||
{
|
||||
entrees.gpio.sequenceur.compteur = PERIODE_LECTURE_ENTREES_GPIO; // Réarmement du timer périodique
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_ENTREES_GPIO; i++)
|
||||
{
|
||||
if (!entrees.gpio.entrees[i].flag_validite) continue;
|
||||
|
||||
entrees.gpio.entrees[i].valeur = lecture_entree_gpio(entrees.gpio.entrees[i].no, entrees.gpio.entrees[i].logique);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES
|
||||
|
||||
Intitialisation des entrées, quel que soit leur type.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees(void)
|
||||
{
|
||||
|
||||
|
||||
// Init des entrées AUX :
|
||||
if (init_entrees_aux() == -1) return(-1);
|
||||
|
||||
// Init des entrées Level Sensor :
|
||||
if (init_entrees_level_sensor() == -1) return(-1);
|
||||
|
||||
// Init des entrées VOLT :
|
||||
if (init_entrees_volt() == -1) return(-1);
|
||||
|
||||
// Init des entrées NMEA :
|
||||
if (init_entrees_nmea() == -1) return(-1);
|
||||
|
||||
// Init des entrées OW :
|
||||
if (init_entrees_ow() == -1) return(-1);
|
||||
|
||||
// Init des entrées PREDEFINIES :
|
||||
if (init_entrees_predefinies() == -1) return(-1);
|
||||
|
||||
// Init des entrées CORE :
|
||||
if (init_entrees_core() == -1) return(-1);
|
||||
|
||||
// Init des entrées GPIO :
|
||||
if (init_entrees_gpio() == -1) return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES_AUX
|
||||
|
||||
Configure les entrées qui sont configurées dans la table 'TB_Entrées_aux'
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees_aux(void)
|
||||
{
|
||||
// Rien à faire car la remontée de l'état des entrées AUX est faite automatiquement par le Compagnon via des commandes UP.
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES_LEVEL_SENSOR
|
||||
|
||||
Configure les entrées qui sont configurées dans la table 'TB_Entrées_level_sensor'
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees_level_sensor(void)
|
||||
{
|
||||
|
||||
entrees.level_sensor.sequenceur.etat = ETAT_SEQUENCEUR_ENTREES_LEVEL_SENSOR_INIT;
|
||||
entrees.level_sensor.sequenceur.compteur = TEMPO_INIT_ENTREES_LEVEL_SENSOR;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES_VOLT
|
||||
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees_volt(void)
|
||||
{
|
||||
// Rien à faire car la remontée de l'état des entrées VOLT est faite automatiquementpar le Compagnon via des commandes UP.
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES_NMEA
|
||||
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees_nmea(void)
|
||||
{
|
||||
// Rien à faire car la remontée de l'état des entrées NMEA est faite automatiquementpar le Compagnon via des commandes UP.
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES_OW
|
||||
|
||||
Configure les entrées qui sont configurées dans la table 'TB_One_wire'
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees_ow(void)
|
||||
{
|
||||
// Rien à faire car la remontée de l'état des entrées OW est faite automatiquementpar le Compagnon via des commandes UP.
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES_PREDEFINIES
|
||||
|
||||
Configure les entrées qui sont configurées dans la table 'TB_Entrées_predefinies'
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees_predefinies(void)
|
||||
{
|
||||
// Rien à faire car la remontée de l'état des entrées PREDEFINIES est faite automatiquementpar le Compagnon via des commandes UP.
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES_CORE
|
||||
|
||||
+--------------+----------+---------------------------+-----------------+-----------------------------------------------------------------+---------------------+
|
||||
| Cle_primaire | Validite | Nom | Unite | Description | Date_maj |
|
||||
+--------------+----------+---------------------------+-----------------+-----------------------------------------------------------------+---------------------+
|
||||
| 1 | 1 | TEMPERATURE_CORE | °C | Température interne du processeur. | 2020-01-01 00:00:00 |
|
||||
| 2 | 1 | TENSION_CORE | V | Tension d'alimentation du processeur | 2020-01-01 00:00:00 |
|
||||
| 3 | 1 | FREQUENCE_CORE | Hz | Fréquence d'horloge du Core | 2020-01-01 00:00:00 |
|
||||
| 4 | 1 | FREQUENCE_UART | HZ | Fréquence d'horloge de l'UART | 2020-01-01 00:00:00 |
|
||||
| 5 | 1 | VITESSE_BOUCLE_PRINCIPALE | Boucles/seconde | Indique le nombre de boucle principale exécutée par secondes. | 2020-01-01 00:00:00 |
|
||||
+--------------+----------+---------------------------+-----------------+-----------------------------------------------------------------+---------------------+
|
||||
|
||||
Configure les entrées 'Core'
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees_core(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
|
||||
i = 0;
|
||||
|
||||
entrees.core.entrees[i].flag_validite = TRUE;
|
||||
strcpy(entrees.core.entrees[i].nom, "TEMPERATURE_CORE"); // Température interne du processeur (en °C)
|
||||
entrees.core.entrees[i].no = i; // Définition arbitraire pour garder la comptabilité avec les autres entrées...
|
||||
i++;
|
||||
|
||||
entrees.core.entrees[i].flag_validite = TRUE;
|
||||
strcpy(entrees.core.entrees[i].nom, "TENSION_CORE"); // Tension d'alimentation du processeur (en V)
|
||||
entrees.core.entrees[i].no = i; // Définition arbitraire pour garder la comptabilité avec les autres entrées...
|
||||
i++;
|
||||
|
||||
entrees.core.entrees[i].flag_validite = TRUE;
|
||||
strcpy(entrees.core.entrees[i].nom, "FREQUENCE_CORE"); // Fréquence d'horloge du Core (en Hz)
|
||||
entrees.core.entrees[i].no = i; // Définition arbitraire pour garder la comptabilité avec les autres entrées...
|
||||
i++;
|
||||
|
||||
entrees.core.entrees[i].flag_validite = TRUE;
|
||||
strcpy(entrees.core.entrees[i].nom, "FREQUENCE_UART"); // Fréquence d'horloge de l'UART (en Hz)
|
||||
entrees.core.entrees[i].no = i; // Définition arbitraire pour garder la comptabilité avec les autres entrées...
|
||||
i++;
|
||||
|
||||
entrees.core.entrees[i].flag_validite = TRUE;
|
||||
strcpy(entrees.core.entrees[i].nom, "VITESSE_BOUCLE_PRINCIPALE"); // Indique le nombre de boucle principale exécutée par secondes (en boucles/secondes)
|
||||
entrees.core.entrees[i].no = i; // Définition arbitraire pour garder la comptabilité avec les autres entrées...
|
||||
i++;
|
||||
|
||||
|
||||
entrees.core.sequenceur.compteur = TEMPO_INIT_ENTREES_CORE;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_ENTREES_GPIO
|
||||
|
||||
Configure les I/O du GPIO
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_entrees_gpio(void)
|
||||
{
|
||||
bool flag_erreur;
|
||||
uint8_t groupe;
|
||||
uint8_t position_groupe;
|
||||
uint8_t i;
|
||||
uint8_t val;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
i = 0;
|
||||
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1)
|
||||
{
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_MOD_RI;
|
||||
entrees.gpio.entrees[i].pull = PULL_DOWN;
|
||||
entrees.gpio.entrees[i].logique = 1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_LIGHT_MOD;
|
||||
entrees.gpio.entrees[i].pull = PULL_DOWN;
|
||||
entrees.gpio.entrees[i].logique = 1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_STATUS_MOD;
|
||||
entrees.gpio.entrees[i].pull = PULL_DOWN;
|
||||
entrees.gpio.entrees[i].logique = 1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_USB1_ALERT_N;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP;
|
||||
entrees.gpio.entrees[i].logique = -1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_USB2_ALERT_N;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP;
|
||||
entrees.gpio.entrees[i].logique = -1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_USB3_ALERT_N;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP;
|
||||
entrees.gpio.entrees[i].logique = -1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_FROM_UC;
|
||||
entrees.gpio.entrees[i].pull = PULL_DOWN;
|
||||
entrees.gpio.entrees[i].logique = 1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_LOW_12V;
|
||||
entrees.gpio.entrees[i].pull = NO_PUP_PDN;
|
||||
entrees.gpio.entrees[i].logique = 1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM3P_DI_SIM_SW;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP;
|
||||
entrees.gpio.entrees[i].logique = -1;
|
||||
i++;
|
||||
}
|
||||
else // Concerne V2 & V3
|
||||
{
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM4_DI_USB_BAS_ALERT_N;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP;
|
||||
entrees.gpio.entrees[i].logique = -1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM4_DI_USB_MILIEU_ALERT_N;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP;
|
||||
entrees.gpio.entrees[i].logique = -1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM4_DI_USB_HAUT_ALERT_N;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP;
|
||||
entrees.gpio.entrees[i].logique = -1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM4_LOW_32V_INPUT;
|
||||
entrees.gpio.entrees[i].pull = NO_PUP_PDN;
|
||||
entrees.gpio.entrees[i].logique = 1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM4_DI_USB_ARRIERE_ALERT_N;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP;
|
||||
entrees.gpio.entrees[i].logique = -1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM4_DI_JACK_DETECT;
|
||||
entrees.gpio.entrees[i].pull = PULL_UP; // SDIR #232
|
||||
entrees.gpio.entrees[i].logique = 1;
|
||||
i++;
|
||||
|
||||
entrees.gpio.entrees[i].flag_validite = TRUE;
|
||||
entrees.gpio.entrees[i].no = CM4_DI_FROM_UC;
|
||||
entrees.gpio.entrees[i].pull = PULL_DOWN;
|
||||
entrees.gpio.entrees[i].logique = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
flag_erreur = FALSE;
|
||||
|
||||
//====================================================================================================
|
||||
// V3 (CM5) : réservation groupée des lignes GPIO via libgpiod.
|
||||
//====================================================================================================
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V3)
|
||||
{
|
||||
unsigned int offsets[MAX_NOMBRE_ENTREES_GPIO];
|
||||
uint8_t nb_lignes = 0;
|
||||
|
||||
struct gpiod_line_settings *settings = gpiod_line_settings_new();
|
||||
gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT);
|
||||
|
||||
struct gpiod_line_config *line_cfg = gpiod_line_config_new();
|
||||
|
||||
struct gpiod_request_config *req_cfg = gpiod_request_config_new();
|
||||
gpiod_request_config_set_consumer(req_cfg, "shipheart_entrees");
|
||||
|
||||
gpiod_chip0 = gpiod_chip_open("/dev/gpiochip0");
|
||||
if (gpiod_chip0 == NULL)
|
||||
{
|
||||
sprintf(tmp, "Ouverture de /dev/gpiochip0 impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_ENTREES_GPIO; i++)
|
||||
{
|
||||
if (!entrees.gpio.entrees[i].flag_validite) continue;
|
||||
|
||||
switch (entrees.gpio.entrees[i].pull)
|
||||
{
|
||||
case PULL_UP : gpiod_line_settings_set_bias(settings, GPIOD_LINE_BIAS_PULL_UP); break;
|
||||
case PULL_DOWN : gpiod_line_settings_set_bias(settings, GPIOD_LINE_BIAS_PULL_DOWN); break;
|
||||
default : gpiod_line_settings_set_bias(settings, GPIOD_LINE_BIAS_DISABLED); break;
|
||||
}
|
||||
|
||||
offsets[nb_lignes] = entrees.gpio.entrees[i].no;
|
||||
gpiod_line_config_add_line_settings(line_cfg, &offsets[nb_lignes], 1, settings);
|
||||
nb_lignes++;
|
||||
|
||||
sprintf(tmp, "GPIO #%2i configurée en ENTREE (via libgpiod)", entrees.gpio.entrees[i].no);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
|
||||
gpiod_entrees_request = gpiod_chip_request_lines(gpiod_chip0, req_cfg, line_cfg);
|
||||
|
||||
gpiod_request_config_free(req_cfg);
|
||||
gpiod_line_config_free(line_cfg);
|
||||
gpiod_line_settings_free(settings);
|
||||
|
||||
if (gpiod_entrees_request == NULL)
|
||||
{
|
||||
sprintf(tmp, "Réservation des lignes GPIO d'entrée impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
entrees.gpio.sequenceur.compteur = TEMPO_INIT_ENTREES_GPIO;
|
||||
return(0); // On sort ici : la boucle V1/V2 ci-dessous ne doit pas s'exécuter pour V3
|
||||
}
|
||||
|
||||
|
||||
//====================================================================================================
|
||||
// V1 et V2 :
|
||||
//====================================================================================================
|
||||
for (i=0; i<MAX_NOMBRE_ENTREES_GPIO; i++)
|
||||
{
|
||||
if (!entrees.gpio.entrees[i].flag_validite) continue;
|
||||
|
||||
groupe = entrees.gpio.entrees[i].no / 10;
|
||||
position_groupe = entrees.gpio.entrees[i].no % 10;
|
||||
|
||||
// Configuration en Entrée de l'E/S GPIO :
|
||||
*(hardware.gpio_base + groupe) &= ~(7<<(position_groupe*3)); // Mets à 0 les 3 bits correspondant à N0
|
||||
sprintf(tmp, "GPIO #%2i configurée en ENTREE", entrees.gpio.entrees[i].no);
|
||||
|
||||
// Configuration des résitances de pull-up/down :
|
||||
switch (entrees.gpio.entrees[i].pull)
|
||||
{
|
||||
case NO_PUP_PDN :
|
||||
{
|
||||
strcat(tmp, " ");
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1) val = CM3P_NO_PUP_PDN;
|
||||
else val = CM4_NO_PUP_PDN;
|
||||
break;
|
||||
}
|
||||
case PULL_UP :
|
||||
{
|
||||
strcat(tmp, " avec résistance de pull-up");
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1) val = CM3P_PULL_UP;
|
||||
else val = CM4_PULL_UP;
|
||||
break;
|
||||
}
|
||||
case PULL_DOWN :
|
||||
{
|
||||
strcat(tmp, " avec résistance de pull-down");
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1) val = CM3P_PULL_DOWN;
|
||||
else val = CM4_PULL_DOWN;
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
strcat(tmp, " avec un type de résistance de pull-up/down inconnu !!! ");
|
||||
flag_erreur = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flag_erreur)
|
||||
{
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1)
|
||||
{
|
||||
if (entrees.gpio.entrees[i].pull != NO_PUP_PDN)
|
||||
{
|
||||
// Séquence de configuration pour l'E/S en cours (cf page 101 de la doc du BCM2835-ARM-Peripherals) :
|
||||
*(hardware.gpio_base + CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE) = (uint32_t) val;
|
||||
|
||||
delai_nano_sec(200); // Wait 150 cycles – this provides the required set-up time for the control signal
|
||||
|
||||
if (entrees.gpio.entrees[i].no < 32) *(hardware.gpio_base + CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE_CLOCK_0) |= (1 << entrees.gpio.entrees[i].no); // 0 = no effect, 1 = Assert Clock on line (n)
|
||||
else *(hardware.gpio_base + CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE_CLOCK_1) |= (1 << (entrees.gpio.entrees[i].no - 32)); // 0 = no effect, 1 = Assert Clock on line (n)
|
||||
|
||||
delai_nano_sec(200); // Wait 150 cycles – this provides the required set-up time for the control signal
|
||||
|
||||
*(hardware.gpio_base + CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE) = (uint32_t) 0x00; // 00 = Off – disable pull-up/down
|
||||
if (entrees.gpio.entrees[i].no < 32) *(hardware.gpio_base + CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE_CLOCK_0) = 0; // Write to GPPUDCLK0/1 to remove the clock
|
||||
else *(hardware.gpio_base + CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE_CLOCK_1) = 0;
|
||||
}
|
||||
}
|
||||
else // CM4 (NB : dans ce cas, on met à jour les registre même si la demande est NO_PUP-DWN) :
|
||||
{
|
||||
groupe = entrees.gpio.entrees[i].no / 16;
|
||||
position_groupe = entrees.gpio.entrees[i].no % 16;
|
||||
|
||||
*(hardware.gpio_base + CM4_OFFSET_GPIO_PUP_PDN_CNTRL_REG0 + groupe) &= ~(3<<(position_groupe*2)); // Mets à 0 les 2 bits correspondant à l'entrée
|
||||
*(hardware.gpio_base + CM4_OFFSET_GPIO_PUP_PDN_CNTRL_REG0 + groupe) |= (val<<(position_groupe*2)); // Ecrit la valeur demandée dans les 2 bits correspondant à l'entrée
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Affichage du message de débug :
|
||||
if (!flag_erreur) affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
else affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
// Arrêt de l'intitialisation si erreur :
|
||||
if (flag_erreur) return(-1);
|
||||
}
|
||||
|
||||
entrees.gpio.sequenceur.compteur = TEMPO_INIT_ENTREES_GPIO;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************************************************************************************************
|
||||
Fonction ENTREE_NO
|
||||
Reçoit en paramètre :
|
||||
- le type d'entrée concerné
|
||||
- le module (adresse_k_bus) sur lequel l'entrée se situe
|
||||
- Le n° de l'entrée sur le module
|
||||
Retourne :
|
||||
- le numéro d'entrée correspondant (ou -1 si aucune entrée valide ne correspond). La numérotation allant de 0 à MAX_ENTREES_xxxx (fonction du type).
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int16_t entree_no(uint8_t type, uint8_t module, uint8_t no)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
//------------------------------------
|
||||
case TYPE_ENTREES_AUXILIAIRES:
|
||||
{
|
||||
for (i=0; i<entrees.aux.nb; i++)
|
||||
{
|
||||
if ((entrees.aux.entrees[i].flag_validite) &&
|
||||
(entrees.aux.entrees[i].module == module) &&
|
||||
(entrees.aux.entrees[i].no == no)) return(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
case TYPE_ENTREES_LEVEL_SENSOR :
|
||||
{
|
||||
for (i=0; i<entrees.level_sensor.nb; i++)
|
||||
{
|
||||
if ((entrees.level_sensor.entrees[i].flag_validite) &&
|
||||
(entrees.level_sensor.entrees[i].module == module) &&
|
||||
(entrees.level_sensor.entrees[i].no == no)) return(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
case TYPE_ENTREES_VOLTAGE:
|
||||
{
|
||||
for (i=0; i<entrees.volt.nb; i++)
|
||||
{
|
||||
if ((entrees.volt.entrees[i].flag_validite) &&
|
||||
(entrees.volt.entrees[i].module == module) &&
|
||||
(entrees.volt.entrees[i].no == no)) return(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* //------------------------------------
|
||||
case TYPE_ENTREES_NMEA:
|
||||
{
|
||||
for (i=0; i<entrees.nmea.nb; i++)
|
||||
{
|
||||
if ((entrees.nmea.entrees[i].flag_validite) &&
|
||||
(entrees.nmea.entrees[i].module == module) &&
|
||||
(entrees.nmea.entrees[i].no == no)) return(i); // ATTENTION : pour les entrées NMEA, on n'a pas de no mais pgn et field.
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
/* //------------------------------------
|
||||
case TYPE_ENTREES_OW :
|
||||
{
|
||||
for (i=0; i<MAX_NOMBRE_ENTREES_OW; i++)
|
||||
{
|
||||
if ((entrees.ow.entrees[i].flag_validite) &&
|
||||
(entrees.ow.entrees[i].cle_primaire == no)) return(i); // ATTENTION : ici, c'est la clé primaire !
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
//------------------------------------
|
||||
case TYPE_ENTREES_PREDEFINIES:
|
||||
{
|
||||
for (i=0; i<entrees.predefinies.nb; i++)
|
||||
{
|
||||
if ((entrees.predefinies.entrees[i].flag_validite) &&
|
||||
(entrees.predefinies.entrees[i].module == module) &&
|
||||
(entrees.predefinies.entrees[i].no == no)) return(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
case TYPE_ENTREES_CORE:
|
||||
{
|
||||
for (i=0; i<MAX_NOMBRE_ENTREES_CORE; i++)
|
||||
{
|
||||
if ((entrees.core.entrees[i].flag_validite) &&
|
||||
(entrees.core.entrees[i].no == no)) return(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
case TYPE_ENTREES_GPIO:
|
||||
{
|
||||
for (i=0; i<MAX_NOMBRE_ENTREES_GPIO; i++)
|
||||
{
|
||||
if ((entrees.gpio.entrees[i].flag_validite) &&
|
||||
(entrees.gpio.entrees[i].no == no)) return(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
default: ;
|
||||
}
|
||||
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction LECTURE_ENTREE_GPIO
|
||||
|
||||
Fonction utilisée pour lire l'état de l'entrée dans les registres du BCM283x en fonction du N° d'entrée GPIO (0 à 53) et de la logique (-1 = logique inversée)
|
||||
NB : cette fonction ne doit PAS être appelée en direct mais passer par la fonction 'lecture_entree' (cette fonction ne mets pas à jour l'état de l'entrée qui n'est donc pas mémorisé après la lecture)
|
||||
**********************************************************************************************************************************************************************************/
|
||||
uint8_t lecture_entree_gpio(uint8_t no, int8_t logique)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V3)
|
||||
{
|
||||
enum gpiod_line_value val = gpiod_line_request_get_value(gpiod_entrees_request, no);
|
||||
x = (val == GPIOD_LINE_VALUE_ACTIVE) ? ON : OFF;
|
||||
}
|
||||
else // Pour V1 & V2 : accès direct aux registres
|
||||
{
|
||||
// Lecture dans les registres du BCM2836 :
|
||||
if (no < 32) // Entrées 0 à 31 :
|
||||
{
|
||||
if (((*(hardware.gpio_base + hardware.offset_gpio_pin_level_0)) & (1 << no)) != 0) x = ON;
|
||||
else x = OFF;
|
||||
}
|
||||
else // Entrées 32 à 53 :
|
||||
{
|
||||
if (((*(hardware.gpio_base + hardware.offset_gpio_pin_level_1)) & (1 << (no - 32))) != 0) x = ON;
|
||||
else x = OFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Cas d'une sortie à logique inversée :
|
||||
if (logique == -1)
|
||||
{
|
||||
if (x == ON) return(0);
|
||||
else return(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x == ON) return(1);
|
||||
else return(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier ENTREES.H
|
||||
//
|
||||
// Contient tous les define liés à la lecture de l'état des entrées
|
||||
//**********************************************************************************************************************************************************************************
|
||||
|
||||
// Entrées GPIO :
|
||||
#define CM3P_DI_MOD_RI 4 // Exemple GPIO #4
|
||||
#define CM3P_DI_LIGHT_MOD 6
|
||||
#define CM3P_DI_STATUS_MOD 7
|
||||
#define CM3P_DI_USB1_ALERT_N 8
|
||||
#define CM3P_DI_USB2_ALERT_N 9
|
||||
#define CM3P_DI_USB3_ALERT_N 10
|
||||
#define CM3P_DI_FROM_UC 28
|
||||
#define CM3P_DI_LOW_12V 34
|
||||
#define CM3P_DI_SIM_SW 36
|
||||
|
||||
#define CM4_DI_USB_BAS_ALERT_N 2
|
||||
#define CM4_DI_USB_MILIEU_ALERT_N 3
|
||||
#define CM4_DI_USB_HAUT_ALERT_N 4
|
||||
#define CM4_LOW_32V_INPUT 6
|
||||
#define CM4_DI_USB_ARRIERE_ALERT_N 8
|
||||
#define CM4_DI_JACK_DETECT 26
|
||||
#define CM4_DI_FROM_UC 27
|
||||
|
||||
|
||||
// Général :
|
||||
#define MAX_LONGUEUR_NOM_ENTREE 40
|
||||
|
||||
|
||||
// Nombre max d'E/S :
|
||||
#define MAX_NOMBRE_ENTREES_AUXILIAIRES 32
|
||||
#define MAX_NOMBRE_ENTREES_LEVEL_SENSOR 8
|
||||
#define MAX_NOMBRE_ENTREES_VOLTAGE 4
|
||||
#define MAX_NOMBRE_ENTREES_NMEA 50 // A priori, doit être identique à NMEA_MAX_NOMBRE_PGN_ACTIFS du Compagnon (vers la ligne #903 de 'shared_shipheart_compagnon_defines.h').
|
||||
#define MAX_NOMBRE_ENTREES_OW 32
|
||||
#define MAX_NOMBRE_ENTREES_PREDEFINIES 100 // Estimation taille : environ 22 pour ShipBase + (32 modules x 2 entrées TEMP et IN_V))
|
||||
#define MAX_NOMBRE_ENTREES_CORE 16
|
||||
#define MAX_NOMBRE_ENTREES_GPIO 54 // Il y a 54 E/S GPIO qui peuvent être configurées en Entrée ou en Sortie mais ce nombre peut-être < 54 (vérifié au chargement de la BDD)
|
||||
|
||||
|
||||
// Timings :
|
||||
#define TEMPO_INIT_ENTREES_LEVEL_SENSOR 200 // En 10ms.
|
||||
#define TEMPO_INIT_ENTREES_CORE 200 // En 10ms.
|
||||
#define TEMPO_INIT_ENTREES_GPIO 0 // En 10ms. Défini le temps pendant lequel la gestion des entrées GPIO est bloquée en stand-bye.
|
||||
|
||||
#define PERIODE_LECTURE_ENTREES_AUX 100 // En x10ms.
|
||||
#define PERIODE_LECTURE_ENTREES_LEVEL_SENSOR 100 // En x10ms.
|
||||
#define PERIODE_LECTURE_ENTREES_VOLT 100 // En x10ms.
|
||||
#define PERIODE_LECTURE_ENTREES_OW 100 // En x10ms.
|
||||
#define PERIODE_LECTURE_ENTREES_PREDEFINIE 100 // En x10ms. // Non utilisée car mis à jour essentiellement par COmpagnon de façon asynchrone
|
||||
#define PERIODE_LECTURE_ENTREES_CORE 500 // En x10ms.
|
||||
#define PERIODE_LECTURE_ENTREES_GPIO 5 // En x10ms.
|
||||
|
||||
|
||||
// Type entrées (utilisées dans la config des Réservoirs, Capteurs ou Batteries) :
|
||||
#define TYPE_ENTREES_AUXILIAIRES 1
|
||||
#define TYPE_ENTREES_LEVEL_SENSOR 2
|
||||
#define TYPE_ENTREES_VOLTAGE 3
|
||||
#define TYPE_ENTREES_OW 4
|
||||
#define TYPE_ENTREES_PREDEFINIES 5
|
||||
#define TYPE_ENTREES_IBS 6
|
||||
#define TYPE_ENTREES_NMEA 7
|
||||
#define TYPE_ENTREES_CAN 8
|
||||
#define TYPE_ENTREES_CALCULEE_BOOLEEN 20
|
||||
#define TYPE_ENTREES_CALCULEE_NUMERIQUE 21
|
||||
#define TYPE_ENTREES_CORE 30
|
||||
#define TYPE_ENTREES_GPIO 31
|
||||
|
||||
|
||||
// Entrées OW :
|
||||
#define DEVICE_OW_VALEUR_ERREUR_ETAT_GENERAL_NOK 0x8000 // Valeur numérique indiquant une erreur de device sur le capteur correspondant (en pratique, représente -327°C)
|
||||
#define DEVICE_OW_VALEUR_ERREUR_ETAT_DEVICE_NOK 0x8001 // Valeur numérique indiquant une erreur de device sur le capteur correspondant (en pratique, représente -327°C)
|
||||
|
||||
#define OW_ETAT_DEVICE_OK 0 // Le dernier accès au device s'est bien déroulé
|
||||
#define OW_ETAT_DEVICE_NOK 1 // Le dernier accès au device a rencontré une erreur
|
||||
#define OW_ETAT_BUS_NOK 2 // L'accès au bus OW est impossible globalement (bus en CC par exemple)
|
||||
|
||||
|
||||
#define OW_DEFAUT_BUS_AUCUN 0
|
||||
#define OW_DEFAUT_BUS_COURT_CIRCUIT 1
|
||||
#define OW_DEFAUT_BUS_TROP_DEVICES 2
|
||||
|
||||
|
||||
// Codes prédéfinis :
|
||||
#define ENTREE_PREDEFINIE_AUCUNE 0
|
||||
#define ENTREE_PREDEFINIE_PAT 1
|
||||
#define ENTREE_PREDEFINIE_HUM 2
|
||||
#define ENTREE_PREDEFINIE_TEMP 3
|
||||
#define ENTREE_PREDEFINIE_LAT 4
|
||||
#define ENTREE_PREDEFINIE_LON 5
|
||||
#define ENTREE_PREDEFINIE_IN_V 6
|
||||
#define ENTREE_PREDEFINIE_IN_I 7
|
||||
#define ENTREE_PREDEFINIE_USB_I 8
|
||||
#define ENTREE_PREDEFINIE_EDM 9
|
||||
#define ENTREE_PREDEFINIE_ACC_XYZ 10
|
||||
#define ENTREE_PREDEFINIE_ACC_X 11
|
||||
#define ENTREE_PREDEFINIE_ACC_Y 12
|
||||
#define ENTREE_PREDEFINIE_ACC_Z 13
|
||||
#define ENTREE_PREDEFINIE_ALT 14
|
||||
#define ENTREE_PREDEFINIE_SOG 15
|
||||
#define ENTREE_PREDEFINIE_COG 16
|
||||
#define ENTREE_PREDEFINIE_SIV 17
|
||||
#define ENTREE_PREDEFINIE_HPA 18
|
||||
#define ENTREE_PREDEFINIE_VPA 19
|
||||
#define ENTREE_PREDEFINIE_RSRP 20
|
||||
#define ENTREE_PREDEFINIE_RSSI 21
|
||||
#define ENTREE_PREDEFINIE_SINR 22
|
||||
|
||||
|
||||
// Logique des entrées AUX :
|
||||
#define ENTREE_AUX_LOGIQUE_NORMALE 0
|
||||
#define ENTREE_AUX_LOGIQUE_INVERSEE 1
|
||||
|
||||
|
||||
// Level Sensors - modes de fonctionnement :
|
||||
#define ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_NON_DEFINI 0
|
||||
#define ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_0_10V 1
|
||||
#define ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_500R 2
|
||||
#define ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_4_20MA 3
|
||||
#define ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_AUTO_TEST 4
|
||||
#define ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_MASSE 5
|
||||
#define ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_PLUS 6
|
||||
#define ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_FULL 7
|
||||
|
||||
|
||||
// Etats séquenceur Entrées Level Sensor :
|
||||
#define ETAT_SEQUENCEUR_ENTREES_LEVEL_SENSOR_INIT 0
|
||||
#define ETAT_SEQUENCEUR_ENTREES_LEVEL_SENSOR_REPOS 1
|
||||
@@ -0,0 +1,568 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier EVENTS.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à la gestion des évènements
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
//#define __DEBUG_EVENTS //Décommenter cette ligne pour avoir les messages de debug des évènements
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t init_events(void);
|
||||
void gestion_events(void);
|
||||
void gestion_event(uint16_t no_event, uint8_t jour, uint8_t heure, uint8_t minute);
|
||||
bool test_event(uint16_t no_event);
|
||||
int8_t declenchement_event(uint16_t no_event);
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_events events;
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_EVENTS
|
||||
|
||||
Fonction d'initialisation des évènements
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_events(void)
|
||||
{
|
||||
|
||||
events.sequenceur.etat = ETAT_SEQUENCEUR_EVENTS_INIT;
|
||||
events.sequenceur.compteur = EVENTS_TEMPO_INIT;
|
||||
events.sequenceur.compteur_time_out = 0;
|
||||
|
||||
events.derniere_minute_traitee = 60; // Valeur volontairement hors limite pour forcer le premier traitement.
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation des évènements\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Appelée en tâche de fond, cette fonction gère les févènements dans leur ensemble
|
||||
// Reçoit : Rien
|
||||
// Renvoit : Rien
|
||||
//==================================================================================================================================================================
|
||||
void gestion_events(void)
|
||||
{
|
||||
uint16_t i;
|
||||
time_t now;
|
||||
struct tm tm_now;
|
||||
uint8_t jour;
|
||||
uint8_t heure;
|
||||
uint8_t minute;
|
||||
bool test_temp;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
|
||||
switch(events.sequenceur.etat)
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_EVENTS_INIT :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (events.sequenceur.compteur == 0)
|
||||
{
|
||||
events.sequenceur.etat = ETAT_SEQUENCEUR_EVENTS_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_EVENTS_REPOS :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (events.sequenceur.compteur == 0)
|
||||
{
|
||||
events.sequenceur.compteur = EVENTS_PERIODE_CHECK; // A priori, toutes les 100ms
|
||||
|
||||
//=====================================================================
|
||||
// Préparation des conditions horaires :
|
||||
jour = 0; // Permet de savoir, in fine, si les conditions horaire sont applicables (>0) ou pas (0).
|
||||
heure = 0;
|
||||
minute = 0;
|
||||
|
||||
if (++ events.compteur_diviseur_conditions_horaires >= EVENTS_DIVISEUR_CONDITIONS_HORAIRES)
|
||||
{
|
||||
events.compteur_diviseur_conditions_horaires = 0; // A priori, toutes les 1s
|
||||
|
||||
now = time (NULL); // Génère le timestamp de l'heure courante (UTC)
|
||||
now += (systeme.fuseau_horaire + systeme.heure_ete) * 60 * 60; // Passage en heure locale
|
||||
tm_now = *localtime (&now); // Convertit le timestamp en une structure lisible
|
||||
|
||||
if (events.derniere_minute_traitee != tm_now.tm_min) // A priori, toutes les minutes, à 00s
|
||||
{
|
||||
jour = tm_now.tm_wday;
|
||||
if (jour == 0) jour = 7; // de lundi (1) à dimanche (7)
|
||||
heure = tm_now.tm_hour; // de 0 à 23
|
||||
minute = tm_now.tm_min; // de 0 à 59
|
||||
|
||||
events.derniere_minute_traitee = minute; // Pour utilisation lors des boucles suivantes
|
||||
|
||||
#ifdef __DEBUG_EVENTS
|
||||
sprintf(tmp, "Traitement horaire des Events avec Jour=%i, Heure=%i et Minutes=%i", jour, heure, minute);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
// Appel du gestionnaire de chaque event valide :
|
||||
for (i = 0; i < events.nb; i ++)
|
||||
{
|
||||
if (!events.events[i].flag_validite) continue; // Si l'event n'est pas valide, on ne le traite pas
|
||||
|
||||
// Calcul du résultat du test dès lors que l'event en contient un :
|
||||
// Cela permet d'abord de mettre à jour son état dans la BDD et être utilisé par Qt.
|
||||
// Cela permet aussi de ne plus le calculer dans la suite du traitement.
|
||||
if (events.events[i].condition_test.flag_validite)
|
||||
{
|
||||
test_temp = test_event(i);
|
||||
if (events.events[i].condition_test.etat_test != test_temp)
|
||||
{
|
||||
events.events[i].condition_test.etat_test = test_temp;
|
||||
events.events[i].flag_dde_maj_bdd = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Traitement de l'event :
|
||||
gestion_event(i, jour, heure, minute); // Rappel : si les conditions horaires ne sont PAS applicables, 'jour == 0'
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
default :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur EVENTS est inconnu [%i]. Il est repositionné au REPOS", events.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
events.sequenceur.etat = ETAT_SEQUENCEUR_EVENTS_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Traite le séquenceur de test d'un évènement
|
||||
// Reçoit : le n° de l'évènement
|
||||
// Renvoit : Rien
|
||||
//==================================================================================================================================================================
|
||||
void gestion_event(uint16_t no_event, uint8_t jour, uint8_t heure, uint8_t minute)
|
||||
{
|
||||
uint16_t i;
|
||||
bool flag_repetition;
|
||||
uint8_t compteur_repetitions; // Sécurite...
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
compteur_repetitions = 0;
|
||||
|
||||
do {
|
||||
flag_repetition = false; // Par défaut. Une éventuelle répétition doit être demandée explicitement.
|
||||
|
||||
switch(events.events[no_event].sequenceur.etat)
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_EVENT_INIT :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (events.events[no_event].sequenceur.compteur == 0)
|
||||
{
|
||||
// SDIR #68 (début) :
|
||||
if (events.events[no_event].conditions_horaires.nb == 0) // S'il n'y a acune condition horaire :
|
||||
{
|
||||
// NB : la valeur de 'etat_test' a été mise à jour juste avant l'appel de 'gestion_event()' ci-dessus...
|
||||
if (events.events[no_event].condition_test.etat_test) events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_ATTENTE_DESACTIVATION; // Si la condition est déjà vraie au démarrage, on passe en phase d'attenet du retour à False avant de traiter le premier front d'apparition.
|
||||
else events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_REPOS; // Si la condition est False, on peut dès à présent attendre le premier front.
|
||||
}
|
||||
else events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_REPOS; // S'il y a une ou plusieurs conditions horaires, on passe au repos dans tous les cas, en attente de la condition horaire pour faire le premier test.
|
||||
// SDIR #68 (fin)
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_EVENT_REPOS :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
//====================================================
|
||||
// Conditions horaire :
|
||||
if (events.events[no_event].conditions_horaires.nb > 0) // Cet event a une condition horaire (au moins une)
|
||||
{
|
||||
if (jour > 0) // Dans ce cas, on sait que les conditions horaires doivent être testées
|
||||
{
|
||||
// Parcours de toutes les conditions horaires de l'évent :
|
||||
for (i = 0; i < events.events[no_event].conditions_horaires.nb; i ++)
|
||||
{
|
||||
if (!events.events[no_event].conditions_horaires.conditions[i].flag_validite) continue;
|
||||
|
||||
// Test du jour :
|
||||
if ((events.events[no_event].conditions_horaires.conditions[i].jour != JOUR_SEMAINE_TOUS_LES_JOURS) &&
|
||||
(events.events[no_event].conditions_horaires.conditions[i].jour != jour)) continue;
|
||||
|
||||
// Test de l'heure et de la minute :
|
||||
if (events.events[no_event].conditions_horaires.conditions[i].heure < 24) // La condition correspond à une heure normale :
|
||||
{
|
||||
if (events.events[no_event].conditions_horaires.conditions[i].heure != heure) continue;
|
||||
if (events.events[no_event].conditions_horaires.conditions[i].minute != minute) continue;
|
||||
}
|
||||
else // La condition correspond à une heure spéciale :
|
||||
{
|
||||
if (systeme.heures_speciales[events.events[no_event].conditions_horaires.conditions[i].heure - 24].heures != heure) continue; // Comparaison entre 'heure' de l'heure spéciale et 'heure' actuelle
|
||||
if (systeme.heures_speciales[events.events[no_event].conditions_horaires.conditions[i].heure - 24].minutes != minute) continue; // Comparaison entre 'minute' de l'heure spéciale et 'minute' actuelle
|
||||
}
|
||||
#ifdef __DEBUG_EVENTS
|
||||
sprintf(tmp, "Event #%i / condition #%i : Condition horaire validée", no_event, i);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
#endif
|
||||
// Le déclenchement horaire est validé :
|
||||
if (events.events[no_event].condition_test.flag_validite) // Si l'event comprend un test :
|
||||
{
|
||||
// Test de la condition :
|
||||
if (events.events[no_event].condition_test.etat_test)
|
||||
{
|
||||
#ifdef __DEBUG_EVENTS
|
||||
sprintf(tmp, "Event #%i / condition #%i : Résultat du test = TRUE. Lancement de la Tempo (%i sec.)", no_event, i, events.events[no_event].sequenceur.compteur = events.events[no_event].tempo);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
#endif
|
||||
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_LANCEMENT_TEMPO;
|
||||
flag_repetition = true; // Permet le traitement du déclenchement sans attendre.
|
||||
}
|
||||
#ifdef __DEBUG_EVENTS
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "Event #%i / condition #%i : Résultat du test = FALSE ", no_event, i);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else // Si l'event ne comprend pas de test :
|
||||
{
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_DECLENCHEMENT;
|
||||
flag_repetition = true; // Permet le traitement du déclenchement sans attendre.
|
||||
#ifdef __DEBUG_EVENTS
|
||||
sprintf(tmp, "Event #%i / condition #%i : L'évènement ne comprend pas de test. Il est donc considéré comme déclenché (quelle que soit la valeur de Tempo [qui est de %i sec.])", no_event, i, events.events[no_event].sequenceur.compteur = events.events[no_event].tempo);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
break; // Si une condition horaire est valide sur cet event, on ne traite pas la suite (quel que soit le résultat du test horaire lui-même)
|
||||
}
|
||||
|
||||
|
||||
//====================================================
|
||||
// Test sans condition horaire :
|
||||
if (events.events[no_event].condition_test.flag_validite)
|
||||
{
|
||||
if (events.events[no_event].compteur_diviseur_gestion > 0) events.events[no_event].compteur_diviseur_gestion --;
|
||||
if (events.events[no_event].compteur_diviseur_gestion == 0)
|
||||
{
|
||||
events.events[no_event].compteur_diviseur_gestion = events.events[no_event].diviseur_gestion; // Rechargement du diviseur (sans effet si 'diviseur' = 0 ou 1)
|
||||
|
||||
// Test de la condition :
|
||||
if (events.events[no_event].condition_test.etat_test)
|
||||
{
|
||||
#ifdef __DEBUG_EVENTS
|
||||
sprintf(tmp, "Event #%i : Résultat du test = TRUE. Lancement de la Tempo (%i sec.)", no_event, events.events[no_event].sequenceur.compteur = events.events[no_event].tempo);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
#endif
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_LANCEMENT_TEMPO;
|
||||
flag_repetition = true; // Permet le traitement du déclenchement sans attendre.
|
||||
}
|
||||
#ifdef __DEBUG_EVENTS
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "Event #%i : Résultat du test = FALSE ", no_event);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_EVENT_LANCEMENT_TEMPO :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
// Armement de la tempo si une tempo est demandée :
|
||||
if (events.events[no_event].tempo > 0)
|
||||
{
|
||||
events.events[no_event].sequenceur.compteur = events.events[no_event].tempo * 10; // Passage de secondes en x100ms du compteur
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_ATTENTE_FIN_TEMPO;
|
||||
}
|
||||
// ou déclenchement direct si aucune tempo n'est demandée :
|
||||
else
|
||||
{
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_DECLENCHEMENT;
|
||||
flag_repetition = true; // Permet le traitement du déclenchement sans attendre.
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_EVENT_ATTENTE_FIN_TEMPO :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (events.events[no_event].sequenceur.compteur == 0)
|
||||
{
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_DECLENCHEMENT;
|
||||
flag_repetition = true; // Permet de traiter le déclenchement dans la foulé, sana attendre le prochain appel au gestyionnaire d'évènements
|
||||
}
|
||||
else
|
||||
{
|
||||
// Test d'une éventuelle désactivation de l'Event avant la fin de la tempo :
|
||||
if (!events.events[no_event].condition_test.etat_test)
|
||||
{
|
||||
sprintf(tmp, "L'état de l'évènement #%i est revenu à FAUX avant l'expiration de sa temporisation [%i secondes]. Il est repositionné au REPOS sans déclenchement.", no_event, events.events[no_event].tempo);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
events.events[no_event].sequenceur.compteur = 0; // RAZ du compteur qui n'est plus utile
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_REPOS; // Retour au repos
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_EVENT_DECLENCHEMENT :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
sprintf(tmp, "Déclenchement de l'évènement # %i [clé_primaire = %i]", no_event, events.events[no_event].cle_primaire);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
|
||||
declenchement_event(no_event);
|
||||
|
||||
if (events.events[no_event].conditions_horaires.nb > 0) events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_REPOS; // S'il y a condition horaire, on revient directement au repos, en attente de la prochaine condition horaire.
|
||||
else events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_ATTENTE_DESACTIVATION; // S'il n'y a PAS de condition horaire, on est obligé d'attendre la disparition de la condition avant de revenir au repos.
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_EVENT_ATTENTE_DESACTIVATION :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
// Vérifie que la condition de l'évènement a disparue :
|
||||
if (!events.events[no_event].condition_test.etat_test)
|
||||
{
|
||||
#ifdef __DEBUG_EVENTS
|
||||
sprintf(tmp, "Event #%i : La condition de test est repassée à False. Le séquenceur repasse au repos.", no_event);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
#endif
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_REPOS; // Retour au repos
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
default :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur EVENT est inconnu [%i]. Il est repositionné au REPOS", events.events[no_event].sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
events.events[no_event].sequenceur.etat = ETAT_SEQUENCEUR_EVENT_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((flag_repetition) && (compteur_repetitions ++ < MAX_REPETITIONS_SEQUENCEUR_EVENT));
|
||||
|
||||
|
||||
// Message d'erreur si le nombre de répétitions est trop élevé :
|
||||
if (compteur_repetitions >= MAX_REPETITIONS_SEQUENCEUR_EVENT)
|
||||
{
|
||||
sprintf(tmp, "Le séquenceur EVENT a rencontré un nombre de répétitions trop élevé [%i] pour l'évènement #%i et à l'état du séquenceur %i. Les répétitions sur cet event sont arrêtées de façon forcée.", MAX_REPETITIONS_SEQUENCEUR_EVENT, no_event, events.events[no_event].sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Teste si la condition de l'évènement est vraie ou fausse
|
||||
// Reçoit : Le numéro de l'évènement
|
||||
// Retourne : Vrai ou Faux
|
||||
//**********************************************************************************************************************************************************************************
|
||||
bool test_event(uint16_t no_event)
|
||||
{
|
||||
float valeur;
|
||||
|
||||
|
||||
// Si l'event ne contient aucune condition de test, on retourne directement FALSE :
|
||||
if (!events.events[no_event].condition_test.flag_validite) return (false);
|
||||
|
||||
//==================================================
|
||||
// Recherche de la valeur en cours de la source :
|
||||
switch(events.events[no_event].condition_test.type_source)
|
||||
{
|
||||
case SOURCE_MESURE_CIRCUIT:
|
||||
{
|
||||
valeur = circuits.circuits[events.events[no_event].condition_test.no_source].variables[events.events[no_event].condition_test.no_variable].valeur_courante;
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_CAPTEUR:
|
||||
{
|
||||
valeur = capteurs.capteurs[events.events[no_event].condition_test.no_source].variables[events.events[no_event].condition_test.no_variable].valeur_courante;
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_RESERVOIR:
|
||||
{
|
||||
valeur = reservoirs.reservoirs[events.events[no_event].condition_test.no_source].variables[events.events[no_event].condition_test.no_variable].valeur_courante;
|
||||
break;
|
||||
}
|
||||
case SOURCE_MESURE_BATTERIE:
|
||||
{
|
||||
valeur = batteries.batteries[events.events[no_event].condition_test.no_source].variables[events.events[no_event].condition_test.no_variable].valeur_courante;
|
||||
break;
|
||||
}
|
||||
default: return(false); // Ne devrait pas arriver puisqu'on a renvoyé FALSE pour les Event ne contenant que des conditions horaires...
|
||||
}
|
||||
#ifdef __DEBUG_EVENTS
|
||||
/* char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
sprintf(tmp, "Test de l'évent #%i : Type_source=%i, N° source=%i, N° de variable=%i, Valeur= %.2f, Condition de test=%i",
|
||||
no_event,
|
||||
events.events[no_event].condition_test.type_source,
|
||||
events.events[no_event].condition_test.no_source,
|
||||
events.events[no_event].condition_test.no_variable,
|
||||
valeur,
|
||||
events.events[no_event].condition_test.test);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
*/
|
||||
#endif
|
||||
|
||||
//==================================================
|
||||
// Test selon le type de test de l'évènement :
|
||||
switch(events.events[no_event].condition_test.test)
|
||||
{
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_STRICT_INFERIEUR:
|
||||
{
|
||||
return (valeur < events.events[no_event].condition_test.seuil);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_INFERIEUR_OU_EGAL:
|
||||
{
|
||||
return (valeur <= events.events[no_event].condition_test.seuil);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_EGAL:
|
||||
{
|
||||
return (fabs(valeur - events.events[no_event].condition_test.seuil) < FLT_MIN);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_SUPERIEUR_OU_EGAL:
|
||||
{
|
||||
return (valeur >= events.events[no_event].condition_test.seuil);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
case EVENTS_TYPE_TEST_STRICT_SUPERIEUR:
|
||||
{
|
||||
return (valeur > events.events[no_event].condition_test.seuil);
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
default:
|
||||
case EVENTS_TYPE_TEST_NON_DEFINI :
|
||||
{
|
||||
return (false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Traite le déclenchement d'un event
|
||||
// Reçoit : Le numéro de l'évènement
|
||||
// Retourne : 0 si Ok, -1 si erreur
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int8_t declenchement_event(uint16_t no_event)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t no_circuit;
|
||||
uint8_t consigne;
|
||||
char chaine[20];
|
||||
|
||||
// Parcours de toutes les 'action_circuits' configurées sur cet event :
|
||||
for (i = 0; i < events.events[no_event].action_circuits.nb; i ++)
|
||||
{
|
||||
if (!events.events[no_event].action_circuits.action[i].flag_validite) continue; // On ne traite que les actions valides
|
||||
|
||||
no_circuit = events.events[no_event].action_circuits.action[i].no_circuit; // Facilite la lecture...
|
||||
|
||||
if (circuits.circuits[no_circuit].validation_cdes_events == CIRCUIT_VALIDATION_COMMANDES_EVENTS_OFF) continue; // Si le circuit concerné a son flag 'Validite_cdes_events' à FALSE, on ne fait aucune action dessus.
|
||||
|
||||
// Calcul de la nouvelle consigne :
|
||||
if (events.events[no_event].action_circuits.action[i].action == EVENTS_TYPE_ACTION_CIRCUIT_TOGGLE)
|
||||
{
|
||||
if (circuits.circuits[no_circuit].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante != 0) consigne = 0;
|
||||
else consigne = MAX_CONSIGNE_CIRCUIT;
|
||||
}
|
||||
else consigne = events.events[no_event].action_circuits.action[i].action;
|
||||
|
||||
// Application de la nouvelle consigne :
|
||||
changement_consigne_circuit(no_circuit, consigne, CIRCUITS_ORIGINE_CONSIGNE_EVENT, events.events[no_event].cle_primaire);
|
||||
|
||||
#ifdef __DEBUG_EVENTS
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
sprintf(tmp, "Event #%i : Consigne = %i appliquée sur circuit n° %i (clé_primaire=%i)", no_event, consigne, no_circuit, circuits.circuits[no_circuit].cle_primaire);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
#endif
|
||||
|
||||
// Enregistrement historique du changement de consigne du circuit :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CIRCUITS, CIRCUIT_ACTION_EVENT, circuits.circuits[no_circuit].cle_primaire, events.events[no_event].cle_primaire, NULL);
|
||||
}
|
||||
|
||||
// Enregistrement historique :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_EVENTS, EVENT_DECLENCHEMENT, events.events[no_event].cle_primaire, 0, NULL);
|
||||
|
||||
// Alarme message :
|
||||
if (events.events[no_event].alarme_message > 0)
|
||||
{
|
||||
sprintf(chaine, "%i", events.events[no_event].cle_primaire); // Paramètres = 'id_event'
|
||||
enregistrement_message_users(MESSAGE_USERS_CODE_DECLENCHEMENT_EVENT, chaine, MESSAGE_USERS_ETAT_ALERTE);
|
||||
}
|
||||
|
||||
// Alarme son :
|
||||
if (events.events[no_event].alarme_son > 0)
|
||||
{
|
||||
emission_bip("button-35.mp3", 5, 15, 20);
|
||||
}
|
||||
|
||||
// Alarme LED :
|
||||
if (events.events[no_event].alarme_led > 0)
|
||||
{
|
||||
c_bus_down_commande_cde_carte(0, C_BUS_COMMANDE_CDE_CARTE_ETAT_SYSTEME, C_BUS_COMMANDE_CDE_CARTE_ETAT_SYSTEME_ALARME);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier EVENTS.H
|
||||
//
|
||||
// Contient tous les define liés aux évènements
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MAX_NOMBRE_EVENTS 200 // Cf équivalent dans 'main.qml'.
|
||||
#define MAX_NOMBRE_CONDITIONS_HORAIRES_PAR_EVENT 15 // Cf équivalent dans 'main.qml'.
|
||||
#define MAX_NOMBRE_ACTION_CIRCUITS_PAR_EVENT 50 // Cf équivalent dans 'main.qml'.
|
||||
#define MAX_REPETITIONS_SEQUENCEUR_EVENT 3 // Nombre maxi de répétitions du séquenceur d'un même evenènement.
|
||||
#define MAX_HEURES_SPECIALES 9 // Selon liste ci-dessous
|
||||
|
||||
|
||||
// Tempos :
|
||||
#define EVENTS_TEMPO_INIT 500 // En x 10ms
|
||||
#define EVENTS_PERIODE_CHECK 10 // En x 10ms
|
||||
|
||||
#define EVENTS_DIVISEUR_CONDITIONS_HORAIRES 10 // Multiplie EVENTS_PERIODE_CHECK pour obtenir la période de traitement des conditions horaires.
|
||||
|
||||
|
||||
// Heures spéciales :
|
||||
#define HEURE_SPECIALE_OFFSET 24 // Les valeurs des heures spéciales telles que stockées dans des condtions horaires sont égales à [HEURE_SPECIALE_OFFSET + HEURE_SPECIALE_xxx] pour les distinguer des heures normales, de 00 à 23.
|
||||
|
||||
#define HEURE_SPECIALE_FIN_NUIT 0 // -18° de l'horizon
|
||||
#define HEURE_SPECIALE_AUBE_NAUTIQUE 1 // -12° de l'horizon
|
||||
#define HEURE_SPECIALE_AUBE 2 // -6° de l'horizon
|
||||
#define HEURE_SPECIALE_LEVER_SOLEIL 3 // -0.833° de l'horizon
|
||||
#define HEURE_SPECIALE_ZENITH 4
|
||||
#define HEURE_SPECIALE_COUCHER_SOLEIL 5 // -0.833° de l'horizon
|
||||
#define HEURE_SPECIALE_CREPUSCULE 6 // -6° de l'horizon
|
||||
#define HEURE_SPECIALE_CREPUSCULE_NAUTIQUE 7 // -12° de l'horizon
|
||||
#define HEURE_SPECIALE_DEBUT_NUIT 8 // -18° de l'horizon
|
||||
// Attention : si ajout d'heures spéciales, penser à modifier MAX_HEURES_SPECIALES en début de ce fichier...
|
||||
// NB : la valeur d'offset n'entre pas en compte dans ce MAX.
|
||||
|
||||
// Jours de la semaine :
|
||||
#define JOUR_SEMAINE_LUNDI 1
|
||||
#define JOUR_SEMAINE_MARDI 2
|
||||
#define JOUR_SEMAINE_MERCREDI 3
|
||||
#define JOUR_SEMAINE_JEUDI 4
|
||||
#define JOUR_SEMAINE_VENDREDI 5
|
||||
#define JOUR_SEMAINE_SAMEDI 6
|
||||
#define JOUR_SEMAINE_DIMANCHE 7
|
||||
#define JOUR_SEMAINE_TOUS_LES_JOURS 8
|
||||
|
||||
// Types de tests :
|
||||
#define EVENTS_TYPE_TEST_NON_DEFINI 0
|
||||
#define EVENTS_TYPE_TEST_STRICT_INFERIEUR 1
|
||||
#define EVENTS_TYPE_TEST_INFERIEUR_OU_EGAL 2
|
||||
#define EVENTS_TYPE_TEST_EGAL 3
|
||||
#define EVENTS_TYPE_TEST_SUPERIEUR_OU_EGAL 4
|
||||
#define EVENTS_TYPE_TEST_STRICT_SUPERIEUR 5
|
||||
|
||||
// Types d'action sur circuit :
|
||||
#define EVENTS_TYPE_ACTION_CIRCUIT_TOGGLE -1
|
||||
// Les autres actions sont l'application d'une consigne, entre 0 (Off) et MAX_CONSIGNE_CIRCUIT (100)
|
||||
|
||||
// Etats du séquenceur Event :
|
||||
#define ETAT_SEQUENCEUR_EVENT_INIT 0
|
||||
#define ETAT_SEQUENCEUR_EVENT_REPOS 1
|
||||
#define ETAT_SEQUENCEUR_EVENT_LANCEMENT_TEMPO 2
|
||||
#define ETAT_SEQUENCEUR_EVENT_ATTENTE_FIN_TEMPO 3
|
||||
#define ETAT_SEQUENCEUR_EVENT_DECLENCHEMENT 4
|
||||
#define ETAT_SEQUENCEUR_EVENT_ATTENTE_DESACTIVATION 5
|
||||
|
||||
// Etats du séquenceur Events :
|
||||
#define ETAT_SEQUENCEUR_EVENTS_INIT 0
|
||||
#define ETAT_SEQUENCEUR_EVENTS_REPOS 1
|
||||
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier FONCTIONS.C
|
||||
//
|
||||
// Contient toutes les fonctions générales du projet.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
|
||||
// Include :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
void date_courante(char* chaine, bool flag_ns, int format);
|
||||
int8_t set_date_heure(struct Struct_date date, struct Struct_heure heure);
|
||||
void delai_dixieme_sec(uint16_t tempo);
|
||||
void delai_nano_sec(unsigned int tempo);
|
||||
uint64_t timestamp_secondes(void);
|
||||
int8_t tri_liste_valeurs_niveaux(struct Struct_valeur_niveau * liste, uint16_t taille_liste);
|
||||
float calcul_niveau(struct Struct_valeur_niveau * liste, uint16_t taille_liste, float valeur);
|
||||
float moyenne_mobile(float old_val, float new_val, uint16_t coefficient);
|
||||
char * conversion_adresse_mac_chaine(uint8_t * adresse_mac, char * chaine, char separateur);
|
||||
uint8_t * conversion_chaine_adresse_mac(char * chaine, uint8_t * adresse_mac);
|
||||
char * conversion_rom_code_chaine(uint8_t * rom_code, char * chaine, char separateur);
|
||||
char * conversion_unique_id_chaine(uint8_t * unique_id, char * chaine);
|
||||
int32_t recherche_caractere_dans_chaine(char * chaine, char car, uint16_t debut);
|
||||
char * chaine_minuscules(char * chaine);
|
||||
|
||||
// Variables globales :
|
||||
volatile uint16_t tempo_delai_dixieme_sec;
|
||||
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction DATE_COURANTE
|
||||
//
|
||||
// Renvoie une chaine représentant la date et l'heure en cours.
|
||||
// En option (flag_ns = TRUE), on renvoie également le nombre de ns
|
||||
//**********************************************************************************************************************************************************************************
|
||||
void date_courante(char* chaine, bool flag_ms, int format)
|
||||
{
|
||||
time_t now;
|
||||
struct tm tm_now;
|
||||
struct timespec tms;
|
||||
char chaine_nb_ns[20];
|
||||
char chaine_format[50];
|
||||
|
||||
switch(format)
|
||||
{
|
||||
case FORMAT_DATE_COURANTE_USER : { strcpy(chaine_format, "%d/%m/%Y %H:%M:%S"); break; }
|
||||
case FORMAT_DATE_COURANTE_MYSQL : { strcpy(chaine_format, "%Y-%m-%d %H:%M:%S"); break; }
|
||||
case FORMAT_DATE_COURANTE_DATE_SEULE : { strcpy(chaine_format, "%d/%m/%Y"); break; }
|
||||
case FORMAT_DATE_COURANTE_HEURE_SEULE : { strcpy(chaine_format, "%H:%M:%S"); break; }
|
||||
case FORMAT_DATE_COURANTE_FICHIER : { strcpy(chaine_format, "%y%m%d_%H%M%S"); break; }
|
||||
case FORMAT_DATE_COURANTE_MODEM : { strcpy(chaine_format, "%y/%m/%d,%H:%M:%S+00"); break; } // yy/MM/dd,hh:mm:ss±zz
|
||||
case FORMAT_DATE_COURANTE_COMPRESSEE: { strcpy(chaine_format, "%y%m%d_%H%M%S"); break; } // "YYMMJJ_hhmmss"
|
||||
case FORMAT_DATE_COURANTE_SYSTEME :
|
||||
default : { strcpy(chaine_format, "%Y-%m-%d_%H:%M:%S"); break; }
|
||||
}
|
||||
|
||||
now = time (NULL); // lire l'heure courante
|
||||
tm_now = *localtime (&now); // la convertir en heure locale
|
||||
strftime (chaine, MAX_LONGUEUR_DATE_COURANTE, chaine_format, &tm_now);
|
||||
|
||||
if (flag_ms)
|
||||
{
|
||||
timespec_get(&tms, TIME_UTC); // Permet de récupérer un timestamp en secondes (tms.tv_sec, inutilisé ici) et en nanosecondes (tms.tv_nsec).
|
||||
sprintf(chaine_nb_ns, ".%03i", (int16_t) (tms.tv_nsec / 1000000)); // Formatage de la sous-chaine du nombre de ns (nb : le lien entre les secondes obtenus par DATE et les secondes obtenues par TEMESPEC_GET n'est pas garanti mais ce n'est pas génant pour l'usage)
|
||||
strcat(chaine, chaine_nb_ns); // Ajout des ns à la fin de la chaine de date.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Met à jour la date et heure système avec les valeurs reçues en paramètre
|
||||
// Reçoit : Une structure de type Date
|
||||
// Retour : 0 si la mise à jour s'est bien passée, -1 sinon
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
int8_t set_date_heure(struct Struct_date date, struct Struct_heure heure)
|
||||
{
|
||||
struct tm newdatetime;
|
||||
time_t newtime;
|
||||
struct timeval newsecus;
|
||||
int8_t result;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
newdatetime.tm_mday = date.jour; // Jour du mois
|
||||
newdatetime.tm_mon = date.mois - 1; // Mois commence à 0
|
||||
newdatetime.tm_year = date.annee - 1900; // Années depuis 1900
|
||||
|
||||
newdatetime.tm_sec = heure.secondes; // Secondes
|
||||
newdatetime.tm_min = heure.minutes; // Minutes
|
||||
newdatetime.tm_hour = heure.heures; // Heures
|
||||
|
||||
newdatetime.tm_isdst = 0; // 0=heure d'hiver, 1=heure d'été, -1=ne sait pas.
|
||||
|
||||
newtime = mktime(&newdatetime);
|
||||
newsecus.tv_sec = newtime;
|
||||
newsecus.tv_usec = 0;
|
||||
|
||||
result = settimeofday(&newsecus,NULL);
|
||||
if(result < 0)
|
||||
{
|
||||
sprintf(tmp, "Mise à jour de la date-heure impossible (demande effectuée pour %02i/%02i/%04i à %02i:%02i:%02i)", date.jour, date.mois, date.annee, heure.heures, heure.minutes, heure.secondes);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
return (-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// sprintf(tmp, "Mise à jour de la date-heure effectuée avec succès à %02i/%02i/%04i %02i:%02i:%02i", date.jour, date.mois, date.annee, heure.heures, heure.minutes, heure.secondes);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction DELAI_DIXIEME_SEC
|
||||
//
|
||||
// Met en sommeil l'exécution pendant le nombre de centaines de ms passé en paramètre.
|
||||
// NB : utilise la focntion TIMER de Linux (avec une base de temps calée dans HARDWARE.H à 100ms).
|
||||
//**********************************************************************************************************************************************************************************
|
||||
void delai_dixieme_sec(uint16_t tempo)
|
||||
{
|
||||
|
||||
tempo_delai_dixieme_sec = tempo; // NB : le type 'volatile' est absolument nécessaire. Sinon, l'optimisation du compilateur va rendre la boucle While infinie...
|
||||
while (tempo_delai_dixieme_sec != 0);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction DELAI_NANO_SEC
|
||||
//
|
||||
// Met en sommeil l'exécution pendant le nombre de ns passé en paramètre.
|
||||
// ATTENTION : le temps de latence est d'environ 65/70µs => toute valeur inféreure donnera cette valeur.
|
||||
// Au-delà, il semble que la courbe est à peu près linéaire : réel = 65/70µs + tempo
|
||||
// Par exemple : 50000 (soit 50µs) donnera environ 120µs.
|
||||
// NB : Pour débug uniquement...
|
||||
//**********************************************************************************************************************************************************************************
|
||||
void delai_nano_sec(unsigned int tempo)
|
||||
{
|
||||
struct timespec tim;
|
||||
|
||||
tim.tv_sec = 0;
|
||||
tim.tv_nsec = tempo;
|
||||
|
||||
nanosleep(&tim , (struct timespec *)NULL);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Calcule et renvoit le timestamp actuel, en secondes
|
||||
// Reçoit : Rien
|
||||
// Retourne : Le timestamp, en secondes
|
||||
//**********************************************************************************************************************************************************************************
|
||||
uint64_t timestamp_secondes(void)
|
||||
{
|
||||
struct timeval current_time;
|
||||
|
||||
gettimeofday(¤t_time, NULL);
|
||||
return (current_time.tv_sec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Traite une liste de Valeurs/Niveaux (pour un réservoir ou une batterie par exemple). La première étape est de stocker toutes les valeurs valides de la liste en début
|
||||
// de liste. Dans un second temps, c'est de stocker tous les enregistrements par ordre croissant de 'valeur'.
|
||||
// Reçoit : - le pointeur sur le début de la liste
|
||||
// - la taille de la liste
|
||||
// Retour : 0 si Ok et -1 si erreur.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int8_t tri_liste_valeurs_niveaux(struct Struct_valeur_niveau * liste, uint16_t taille_liste)
|
||||
{
|
||||
uint16_t i, j;
|
||||
float val;
|
||||
float niv;
|
||||
uint16_t max;
|
||||
|
||||
|
||||
// 1. Stockage de toutes les valeurs valides en début de liste :
|
||||
j = 0;
|
||||
for (i = 0; i < taille_liste; i ++)
|
||||
{
|
||||
if ((liste + i)->flag_validite == TRUE)
|
||||
{
|
||||
(liste + j)->valeur = (liste + i)->valeur;
|
||||
(liste + j)->niveau = (liste + i)->niveau;
|
||||
(liste + j)->flag_validite = (liste + i)->flag_validite;
|
||||
|
||||
j ++;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 (suite). Parcours la fin de la liste qui n'est plus utile et qu'il faut dévalider :
|
||||
for (; j < taille_liste; j ++)
|
||||
{
|
||||
(liste + j)->valeur = 0;
|
||||
(liste + j)->niveau = 0;
|
||||
(liste + j)->flag_validite = FALSE;
|
||||
}
|
||||
|
||||
// 2. Tri de la liste :
|
||||
j = 0; // Compteur de sécurité...
|
||||
max = taille_liste * (taille_liste + 1) / 2; // Le nombre maxi d'itération est de n(n+1)/2 boucles dans le cas où la liste initiale est totalement remplie et en sens inverse.
|
||||
for (i = 1; (i < taille_liste) && ((liste + i)->flag_validite == TRUE); i ++)
|
||||
{
|
||||
if ((liste + i)->valeur < (liste + i -1)->valeur) // Si la valeur [i] < valeur [i-1], on les inverse :
|
||||
{
|
||||
val = (liste + i)->valeur; // Stockage temporaire de la valeur [i]
|
||||
niv = (liste + i)->niveau;
|
||||
|
||||
(liste + i)->valeur = (liste + i - 1)->valeur; // Stockage de la valeur [i-1] dans [i]
|
||||
(liste + i)->niveau = (liste + i - 1)->niveau;
|
||||
|
||||
(liste + i - 1)->valeur = val; // Stockage de la valeur temporaire dans [i-1]
|
||||
(liste + i - 1)->niveau = niv;
|
||||
|
||||
i = 0; // La valeur '0' permet de tenir compte du 'i++' qui est fait juste après et donc de bien recommencer à boucle à '1'
|
||||
if ((j ++) > max) return(-1); // Sécurité car on bricole l'indice de boucle...
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Recherche dans une liste de Valeurs/Niveaux les deux points les plus proches de la 'valeur' reçue en paramètre. On effectue ensuite un calcul d'interpolation
|
||||
// entre ces deux points pour retourner une valeur de niveau entre 0.00 et 100.00%.
|
||||
// IMPORTANT : on suppose que la liste a été triée auparavant par 'valeurs' croissante ! Ce tri est fait dans bdd_init.c, en appelant 'tri_liste_valeurs_niveaux()'
|
||||
// ci-dessus après avoir chargé la liste depuis la BDD. Le tri n'est donc fait d'une seule fois à l'init.
|
||||
// Si 'valeur' < la plus petite valeur de la liste : renvoie le niveau de la plus petite valeur de la liste.
|
||||
// Si 'valeur' > la plus grande valeur de la liste : renvoie le niveau de la plus grande valeur de la liste.
|
||||
// Si 'valeur' = une valeur de la liste : renvoie le niveau de la valeur en question.
|
||||
// Si aucune valeur dans la liste, renvoie toujours 0%
|
||||
// Reçoit : - le pointeur sur le début de la liste
|
||||
// - la taille de la liste
|
||||
// - la valeur actuelle
|
||||
// Retour : la valeur de niveau (entre 0 et 100.00) si Ok et -1 si erreur.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
float calcul_niveau(struct Struct_valeur_niveau * liste, uint16_t taille_liste, float valeur)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
|
||||
for (i = 0; (i < taille_liste) && ((liste + i)->flag_validite == TRUE); i ++)
|
||||
{
|
||||
if ((liste + i)->valeur == valeur) return((liste + i)->niveau); // Si on tombe exactement sur une valeur de la table, on renvoit immédiatement le niveau.
|
||||
|
||||
if ((liste + i)->valeur > valeur) // Si on a dépassé la valeur sans tomber dessus, on s'arrête :
|
||||
{
|
||||
if (i == 0) return((liste + i)->niveau); // Si la valeur est inférieure à la plus petite entrée de la table, on renvoit immédiatement le niveau correspondant à cette première entrée.
|
||||
else
|
||||
{
|
||||
if (((liste + i)->niveau == (liste + i - 1)->niveau) || // Cas où les deux niveaux sont identiques...
|
||||
((liste + i)->valeur == (liste + i - 1)->valeur)) // ... ou les deux valeurs sont identiques (ce qui ne devrait pas arriver car dès la 1ère, on aurait dû arrêter la boucle)
|
||||
{
|
||||
return((liste + i)->niveau);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (((((liste + i)->niveau - (liste + i - 1)->niveau) * (valeur - (liste + i - 1)->valeur)) / ((liste + i)->valeur - (liste + i - 1)->valeur)) + (liste + i - 1)->niveau);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cas où on est arrivé au bout de la liste sans trouver de valeur[i] > valeur.
|
||||
// Dans ce cas, on va renvoyer le niveau correspondant à la dernière valeur valide (donc la plus grande puisque la liste est classée).
|
||||
if (i != 0) return((liste + i - 1)->niveau);
|
||||
else return(-1); // Cas où la liste ne contient aucune valeur. On ne peut pas faire d'extrapolation...
|
||||
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Fonction qui ajoute une 'new_val' à une 'old_val' par une moyenne pondérée : l'ancienne valeur est affectée du (coefficient - 1) et la nouvelle
|
||||
// d'un coefficient de 1.
|
||||
// Si le coeff de filtrage = 0 (erreur mais on traite comme si aucun filtrage) ou 1, on applique directement la nouvelle valeur comme valeur de la
|
||||
// mesure. Ces deux correspondent à "pas de filtrage".
|
||||
// Reçoit : l'ancienne valeur, la nouvelle valeur et le coefficient de filtrage à utiliser
|
||||
// Renvoit : l'ancienne valeur mise à jour
|
||||
//==================================================================================================================================================================
|
||||
float moyenne_mobile(float old_val, float new_val, uint16_t coefficient)
|
||||
{
|
||||
if (coefficient <= 1) return(new_val);
|
||||
else return(((old_val * (coefficient - 1)) + new_val) / coefficient);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Convertit le tableau de 6 octets reçu en une chaine de type adresse MAC (chaque octet étant représenté par deux caractères ASCII représentant sa valeur en
|
||||
// hexadécimal). Le séparateur utilisé entre chaque couple de caractère est reçu en paramètre (en général, soit ':', soit'-' ou '_')
|
||||
// Reçoit : - le pointeur sur le début du tableau de 6 octets
|
||||
// - le pointeur sur le début de la chaine à remplir
|
||||
// - le caractère séparateur à utiliser
|
||||
// Retour : Le pointeur sur la chaine (donc, a priori, identique à celui reçu).
|
||||
//**********************************************************************************************************************************************************************************
|
||||
char * conversion_adresse_mac_chaine(uint8_t * adresse_mac, char * chaine, char separateur)
|
||||
{
|
||||
|
||||
sprintf(chaine, "%02X%c%02X%c%02X%c%02X%c%02X%c%02X", *adresse_mac, separateur, *(adresse_mac + 1), separateur, *(adresse_mac + 2), separateur, *(adresse_mac + 3), separateur, *(adresse_mac + 4), separateur, *(adresse_mac + 5));
|
||||
return(chaine);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction CONVERSION_CHAINE_ADRESSE_MAC
|
||||
//
|
||||
// Convertit une chaine au format 'xx:xx:xx:xx:xx:xx' en un tableau d'adresse MAC
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
uint8_t * conversion_chaine_adresse_mac(char * chaine, uint8_t * adresse_mac)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t clsb, cmsb;
|
||||
uint8_t lsb, msb;
|
||||
|
||||
for (i = 0; i < TAILLE_ADRESSE_MAC; i ++)
|
||||
{
|
||||
cmsb = chaine[3*i];
|
||||
if ((cmsb >= '0') && (cmsb <= '9')) msb = cmsb - '0';
|
||||
else if ((cmsb >= 'A') && (cmsb <= 'F')) msb = cmsb - 'A' + 10;
|
||||
else if ((cmsb >= 'a') && (cmsb <= 'f')) msb = cmsb - 'a' + 10;
|
||||
else msb = 0;
|
||||
|
||||
clsb = chaine[(3*i)+1];
|
||||
if ((clsb >= '0') && (clsb <= '9')) lsb = clsb - '0';
|
||||
else if ((clsb >= 'A') && (clsb <= 'F')) lsb = clsb - 'A' + 10;
|
||||
else if ((clsb >= 'a') && (clsb <= 'f')) lsb = clsb - 'a' + 10;
|
||||
else lsb = 0;
|
||||
|
||||
*(adresse_mac + i) = (msb << 4) | lsb;
|
||||
|
||||
}
|
||||
|
||||
return(adresse_mac);
|
||||
}
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Convertit le tableau de 8 octets reçu en une chaine de type Rom Code (chaque octet étant représenté par deux caractères ASCII représentant sa valeur en
|
||||
// hexadécimal). Le séparateur utilisé entre chaque couple de caractère est reçu en paramètre (en général, soit ':', soit'-' ou '_')
|
||||
// Reçoit : - le pointeur sur le début du tableau de 8 octets
|
||||
// - le pointeur sur le début de la chaine à remplir
|
||||
// - le caractère séparateur à utiliser
|
||||
// Retour : Le pointeur sur la chaine (donc, a priori, identique à celui reçu).
|
||||
//**********************************************************************************************************************************************************************************
|
||||
char * conversion_rom_code_chaine(uint8_t * rom_code, char * chaine, char separateur)
|
||||
{
|
||||
|
||||
sprintf(chaine, "%02X%c%02X%c%02X%c%02X%c%02X%c%02X%c%02X%c%02X", *rom_code, separateur, *(rom_code + 1), separateur, *(rom_code + 2), separateur, *(rom_code + 3), separateur, *(rom_code + 4), separateur, *(rom_code + 5), separateur, *(rom_code + 6), separateur, *(rom_code + 7));
|
||||
return(chaine);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction CONVERSION_UNIQUE_ID_CHAINE
|
||||
//
|
||||
// Convertit un tableau contenant un Unique ID (au sens STM32) en une chaine au format 'xx xx xx xx xx xx xx xx xx xx xx xx'
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
char * conversion_unique_id_chaine(uint8_t * unique_id, char * chaine)
|
||||
{
|
||||
|
||||
sprintf(chaine, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
|
||||
*unique_id, *(unique_id + 1), *(unique_id + 2), *(unique_id + 3), *(unique_id + 4), *(unique_id + 5),
|
||||
*(unique_id + 6), *(unique_id + 7), *(unique_id + 8), *(unique_id + 9), *(unique_id + 10), *(unique_id + 11));
|
||||
return(chaine);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Recherche un caractère dans une chaine et retourne sa position s'il le trouve
|
||||
// Reçoit : Un pointeur sur la chaine à analyser, le caractère recherché, la posiiton du début de la recherche (par défaut, 0) et la taille de la chaine
|
||||
// Retour : La position du caractère recherché (entre 0 et taille-1), -1 si le caractère n'est pas trouvé avant le NULL de fin de chaine
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
int32_t recherche_caractere_dans_chaine(char * chaine, char car, uint16_t debut)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if (debut >= strlen(chaine)) return (-1);
|
||||
|
||||
for (i = debut; chaine[i] != 0; i ++)
|
||||
{
|
||||
if (chaine[i] == car) return(i);
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Convertit une chaine de caractères en minuscules
|
||||
// Reçoit : Un pointeur sur la chaine à convertir
|
||||
// Retour : le pointeur sur la chaine convertie
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
char * chaine_minuscules(char * chaine)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if (strlen(chaine) < 64000) // Pour éviter de déborder le 'i' de la boucle...
|
||||
{
|
||||
for (i = 0; chaine[i] != 0; i ++)
|
||||
{
|
||||
if ((chaine[i] >= 'A') && (chaine[i] <= 'Z')) chaine[i] = chaine[i] +32;
|
||||
}
|
||||
}
|
||||
|
||||
return(chaine);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier FONCTIONS.H
|
||||
//
|
||||
// Contient tous les define liés aux fontions diverses...
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MAX_LONGUEUR_DATE_COURANTE 60
|
||||
|
||||
// Timings :
|
||||
|
||||
|
||||
// Formats de date (utilisé par la fonction DATE_COURANTE) :
|
||||
#define DATE_COURANTE_SANS_MS 0 // La chaine constituée s'arrête à la seconde
|
||||
#define DATE_COURANTE_AVEC_MS 1 // La date constituée comprend, après les secondes, le nombre de ns (9 chiffres)
|
||||
|
||||
#define FORMAT_DATE_COURANTE_USER 0 // Mise en forme de façon lisible pour l'utilisateur (15/05/2018 14:12:23)
|
||||
#define FORMAT_DATE_COURANTE_MYSQL 1 // Mise ne forme pour être compris par les requêtes MySql (2018-05-15 14:12:23)
|
||||
#define FORMAT_DATE_COURANTE_SYSTEME 2 // Mise en forme pour être lue par un OS et par ordre chronologique (2018-05-15_14:12:23)
|
||||
#define FORMAT_DATE_COURANTE_DATE_SEULE 3 // Uniquement la date sous le format JJ/MM/AAAA
|
||||
#define FORMAT_DATE_COURANTE_HEURE_SEULE 4 // Uniquement l'heure sous le format hh:mm:ss
|
||||
#define FORMAT_DATE_COURANTE_FICHIER 5 // Mise en forme pour marquer un nom de fichier (2021-01-08_14-12-23)
|
||||
#define FORMAT_DATE_COURANTE_MODEM 6 // Mise en forme correspondant au format attendu par le modem : "yy/MM/dd,hh:mm:ss±zz", where characters indicate year (two last digits),month, day, hour, minutes, seconds and time zone (indicates the difference, expressed in quarters of an hour, between the local time and GMT; range -47...+48). E.g. 6th of May 2010, 00:01:52 GMT+2 hours equals to "10/05/06,00:01:52+08".
|
||||
#define FORMAT_DATE_COURANTE_COMPRESSEE 7 // Date et heure sous la forme "YYMMJJ_hhmmss"
|
||||
|
||||
|
||||
// Constantes de conversion :
|
||||
#define CONVERSION_MS_TO_KNOTS 1.9438444924406047516198704103672L // = 3600 / 1852
|
||||
#define CONVERSION_RAD_TO_DEG 57.295779513082320876798154814105L // = 360 / (2xPI) = 180 / PI
|
||||
|
||||
// Macros :
|
||||
#define carre(a) (a)*(a)
|
||||
#define cube(a) (a)*(a)*(a)
|
||||
+461
@@ -0,0 +1,461 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier G_BUS.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à la gestion du G_Bus (liaison avec le récepteur GNSS ZOE-M8Q)
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
#define __DEBUG_G_BUS // Commenter cette ligne : aucun message de debug de G_bus
|
||||
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t init_g_bus(void);
|
||||
void gestion_g_bus(void);
|
||||
int8_t gestion_protocole_rx_g_bus(void);
|
||||
void gestion_protocole_tx_g_bus(void);
|
||||
int8_t g_bus_next_write_buffer_cdes(uint8_t priorite);
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_g_bus g_bus;
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_G_BUS
|
||||
|
||||
Fonction d'initialisation du C-Bus
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_g_bus(void)
|
||||
{
|
||||
|
||||
if ((systeme.generation_shipbase == GENERATION_SHIPBASE_V2) || (systeme.generation_shipbase == GENERATION_SHIPBASE_V3))
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------------
|
||||
// Init des variables générales :
|
||||
|
||||
g_bus.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_INIT;
|
||||
g_bus.sequenceur.compteur = G_BUS_TEMPO_INIT;
|
||||
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_INIT;
|
||||
g_bus.protocole_rx.sequenceur.compteur = G_BUS_PROTOCOLE_RX_TEMPO_INIT;
|
||||
|
||||
g_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_TX_INIT;
|
||||
g_bus.protocole_tx.sequenceur.compteur = G_BUS_PROTOCOLE_TX_TEMPO_INIT;
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation du G-BUS\t\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation du G-BUS\t\t: Devalidé car non valide sur cette version de ShipBase", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction GESTION_G_BUS
|
||||
|
||||
Fonction de plus haut niveau de gestion du C-Bus
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_g_bus(void)
|
||||
{
|
||||
int8_t ret;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
if (systeme.generation_shipbase != GENERATION_SHIPBASE_V2) return;
|
||||
|
||||
switch(g_bus.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_INIT :
|
||||
{
|
||||
if (g_bus.sequenceur.compteur == 0)
|
||||
{
|
||||
//.........................................................
|
||||
// Vidage du buffer de réception de tous les caractères reçus pendant la phase d'init :
|
||||
serial0.ptr_debut_buffer_rx = 0;
|
||||
serial0.ptr_fin_buffer_rx = 0;
|
||||
|
||||
//.........................................................
|
||||
// Vidage du buffer de commandes (utile dans le cas d'un reset du modem pour overflow) :
|
||||
g_bus.down.ptr_debut_buffer_cdes = 0;
|
||||
g_bus.down.ptr_fin_buffer_cdes = 0;
|
||||
|
||||
//.........................................................
|
||||
// Mise à jour des séquenceurs pour démarrage des envois :
|
||||
g_bus.protocole_rx.sequenceur.compteur = 0;
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_REPOS;
|
||||
g_bus.protocole_tx.sequenceur.compteur = 0;
|
||||
g_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_TX_REPOS;
|
||||
|
||||
g_bus.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_REPOS :
|
||||
{
|
||||
|
||||
//=================================
|
||||
// Gestion du G-Bus en émission :
|
||||
|
||||
gestion_protocole_tx_g_bus(); // Vérifie si une commande (Down) est en attente. Si oui, elle la traite et l'émet.
|
||||
|
||||
|
||||
//=================================
|
||||
// Gestion du G-Bus en réception :
|
||||
|
||||
ret = gestion_protocole_rx_g_bus();
|
||||
if (ret != 0) // Vérifie si une réponse (à une commande Down) a été reçue.
|
||||
{
|
||||
#ifdef __DEBUG_G_BUS
|
||||
// sprintf(tmp, "Retour GNSS : Class=%02Xh, ID=%02Xh, Length=%i", g_bus.down.reponse.classe, g_bus.down.reponse.id, g_bus.down.reponse.lg_reponse);
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
|
||||
g_bus_down_analyse_reponse_commande();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur M-bus est inconnu [%i]. Il est repositionné au REPOS", g_bus.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
g_bus.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Appelée en tâche de fond, cette fonction lit le buffer de réception de l'UART 0 et traite les trames reçues en provenance du GNSS.
|
||||
Le protocole utilisé est le µBX uniquement (il est assez facile d'utiliser le protocole NMEA mais il est dévalidé au démarrage pour éviter d'avoir
|
||||
les 2 simultanés et le µBX est bien plus complet...)
|
||||
Reçoit : Rien
|
||||
Renvoit : 0 si RAS, 1 si une réponse complète a été reçue
|
||||
******************************************************************************************************************************************************************/
|
||||
int8_t gestion_protocole_rx_g_bus(void)
|
||||
{
|
||||
uint8_t c;
|
||||
int8_t reponse_recue;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
reponse_recue = 0;
|
||||
|
||||
// Traitement de chaque caractère reçu :
|
||||
while (serial0.ptr_debut_buffer_rx != serial0.ptr_fin_buffer_rx)
|
||||
{
|
||||
// Calcul de la prochaine position à lire (avec bouclage en fin de buffer tournant) :
|
||||
if (++ serial0.ptr_debut_buffer_rx == MAX_TAILLE_RX_BUFFER_UART) serial0.ptr_debut_buffer_rx = 0;
|
||||
|
||||
// Lecture du caractère dans le buffer :
|
||||
c = serial0.buffer_rx[serial0.ptr_debut_buffer_rx]; // Lecture du caractère à traiter
|
||||
|
||||
// Traitement du caractère reçu :
|
||||
switch(g_bus.protocole_rx.sequenceur.etat)
|
||||
{
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_INIT :
|
||||
{
|
||||
// NB : Le caractère lu est jeté tant que la phase d'init n'est pas terminée...
|
||||
// NB 2 : le passage à l'état REPOS se fait par le séquenceur M-Bus, indépendemment de la réception ou non de caractères.
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_REPOS :
|
||||
{
|
||||
if (c == 0xB5) // Attente de réception du 'µ' de début de trame
|
||||
{
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_SYNC_2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_SYNC_2 :
|
||||
{
|
||||
if (c == 0x62) // Attente de réception du 'b' de début de trame
|
||||
{
|
||||
g_bus.down.reponse.ck_a_attendu = 0; // Init avant de recevoir le premier octet à intégrer au calcul...
|
||||
g_bus.down.reponse.ck_b_attendu = 0;
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CLASS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CLASS :
|
||||
{
|
||||
g_bus.down.reponse.ck_a_attendu += c; // Calcul ...
|
||||
g_bus.down.reponse.ck_b_attendu += g_bus.down.reponse.ck_a_attendu; // ... du CS
|
||||
g_bus.down.reponse.classe = c;
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_ID;
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_ID :
|
||||
{
|
||||
g_bus.down.reponse.ck_a_attendu += c; // Calcul ...
|
||||
g_bus.down.reponse.ck_b_attendu += g_bus.down.reponse.ck_a_attendu; // ... du CS
|
||||
g_bus.down.reponse.id = c;
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_LENGTH_1;
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_LENGTH_1 :
|
||||
{
|
||||
g_bus.down.reponse.ck_a_attendu += c; // Calcul ...
|
||||
g_bus.down.reponse.ck_b_attendu += g_bus.down.reponse.ck_a_attendu; // ... du CS
|
||||
g_bus.down.reponse.lg_reponse_attendue = c;
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_LENGTH_2;
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_LENGTH_2 :
|
||||
{
|
||||
g_bus.down.reponse.ck_a_attendu += c; // Calcul ...
|
||||
g_bus.down.reponse.ck_b_attendu += g_bus.down.reponse.ck_a_attendu; // ... du CS
|
||||
g_bus.down.reponse.lg_reponse_attendue |= ((uint16_t) c) << 8;
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_DATA :
|
||||
{
|
||||
g_bus.down.reponse.ck_a_attendu += c; // Calcul ...
|
||||
g_bus.down.reponse.ck_b_attendu += g_bus.down.reponse.ck_a_attendu; // ... du CS
|
||||
g_bus.down.reponse.reponse[g_bus.down.reponse.lg_reponse ++] = c;
|
||||
if (g_bus.down.reponse.lg_reponse >= g_bus.down.reponse.lg_reponse_attendue)
|
||||
{
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CS_A;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CS_A :
|
||||
{
|
||||
g_bus.down.reponse.ck_a_recu = c;
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CS_B;
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CS_B :
|
||||
{
|
||||
g_bus.down.reponse.ck_b_recu = c;
|
||||
|
||||
if ((g_bus.down.reponse.ck_a_attendu == g_bus.down.reponse.ck_a_recu) && (g_bus.down.reponse.ck_b_attendu == g_bus.down.reponse.ck_b_recu))
|
||||
{
|
||||
reponse_recue = 1;
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_REPOS;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __DEBUG_G_BUS
|
||||
sprintf(tmp, "Le CS reçu [%02Xh|%02Xh] ne correspond pas au CS calculé [%02Xh|%02Xh]. Le séquenceur de réception est repositionné au REPOS", g_bus.down.reponse.ck_a_recu, g_bus.down.reponse.ck_b_recu, g_bus.down.reponse.ck_a_attendu, g_bus.down.reponse.ck_b_attendu);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
#endif
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur G-Bus.Protocole_Rx est inconnu [%i]. Il est repositionné au REPOS", g_bus.protocole_rx.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
g_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reponse_recue != 0) break;
|
||||
|
||||
}
|
||||
|
||||
return(reponse_recue);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Appelée en tâche de fond, cette fonction vérifie si une commande est prête à être émise
|
||||
dans le buffer de commandes Down. Si oui, elle gère via son séquenceur le formattage de la trame à émettre au ormat µBX
|
||||
Reçoit : Rien
|
||||
Renvoit : Rien
|
||||
*****************************************************************************************************************************************************************/
|
||||
void gestion_protocole_tx_g_bus(void)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t c;
|
||||
uint8_t ck_a, ck_b;
|
||||
uint8_t tx_buffer[G_BUS_MAX_TAILLE_BUFFER_TX];
|
||||
uint16_t lg_tx_buffer;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
switch(g_bus.protocole_tx.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_TX_INIT :
|
||||
{
|
||||
// NB : le passage à l'état REPOS se fait par le séquenceur G-Bus, indépendemment de la présence de commande à émettre
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_TX_REPOS :
|
||||
{
|
||||
//..................................
|
||||
// Recherche d'une trame à émettre :
|
||||
|
||||
if (g_bus.down.flag_attente_reponse) // Cas où une commande Down a déjà été émise et qu'on est en attente de réponse :
|
||||
{
|
||||
if (g_bus.protocole_tx.sequenceur.compteur_time_out == 0) // On vérifie alors si le time-out a expiré :
|
||||
{
|
||||
g_bus.down.flag_attente_reponse = FALSE; // RAZ du flag (qui sera éventuellement remis à 1 si la répétition a lieu)
|
||||
g_bus.protocole_tx.repetitions ++; // Incrémentation du nombre de répétitions
|
||||
if (g_bus.protocole_tx.repetitions > g_bus.down.buffer_cdes[g_bus.down.ptr_debut_buffer_cdes].max_repetitions) // Si le nombre maxi de répétitions a été dépassé, on laisse tomber la commande
|
||||
{
|
||||
|
||||
// !!! Il serait peut-être intéressant d'informer la couche supérieure que la commande est abandonnée sans avoir obtenu de réponse malgré N répétitions...
|
||||
// ==>>> Si oui, c'est ici qu'il faut le mettre....
|
||||
|
||||
g_bus.protocole_tx.repetitions = 0; // RAZ du compteur pour utilisation ultérieure
|
||||
break; // Sortie du séquenceur
|
||||
}
|
||||
}
|
||||
else break; // Tant qu'on est en attente d'une réponse et que le time-out n'est pas expiré, on ne traite aucun envoi en mode Down
|
||||
}
|
||||
else // Sinon, recherche d'une nouvelle commande à émettre en mode Down :
|
||||
{
|
||||
if (g_bus.down.ptr_debut_buffer_cdes != g_bus.down.ptr_fin_buffer_cdes) // Cas où il y a une commande en attente d'émission...
|
||||
{
|
||||
// ATTENTION : gérer les priorités ...!
|
||||
|
||||
g_bus.down.reponse.etat = G_BUS_REPONSE_ETAT_REPOS; // On prépare le traitement de la réponse à venir.
|
||||
|
||||
if (++ g_bus.down.ptr_debut_buffer_cdes == G_BUS_MAX_TAILLE_BUFFER_CDES) g_bus.down.ptr_debut_buffer_cdes = 0;
|
||||
|
||||
#ifdef __DEBUG_G_BUS
|
||||
// g_bus.down.buffer_cdes[g_bus.down.ptr_debut_buffer_cdes].cde[g_bus.down.buffer_cdes[g_bus.down.ptr_debut_buffer_cdes].lg_cde] = 0; // On ajoute un /0 à la fin mais on ne change surtout pas la longueur qui est utilisée pour les transferts binaires.
|
||||
// affichage_debug_bus(TYPE_BUS_DEBUG_G_BUS, "Tx", (char *) g_bus.down.buffer_cdes[g_bus.down.ptr_debut_buffer_cdes].cde, __DEBUG_G_BUS);
|
||||
#endif
|
||||
}
|
||||
else break; // Il n'y a pas de nouvelle commande en attente d'émission
|
||||
}
|
||||
|
||||
//.....................................
|
||||
// Préparation de la trame d'émission :
|
||||
lg_tx_buffer = 0;
|
||||
ck_a = 0;
|
||||
ck_b = 0;
|
||||
|
||||
// Ajout des caractères 'µb' en tête :
|
||||
tx_buffer[lg_tx_buffer ++] = 0xB5; // 'µ'
|
||||
tx_buffer[lg_tx_buffer ++] = 0x62; // 'b'
|
||||
|
||||
// Ajout de la commande avec calcul du CS :
|
||||
for (i=0; (i < g_bus.down.buffer_cdes[g_bus.down.ptr_debut_buffer_cdes].lg_cde) && (lg_tx_buffer < G_BUS_MAX_TAILLE_BUFFER_TX); i++)
|
||||
{
|
||||
c = g_bus.down.buffer_cdes[g_bus.down.ptr_debut_buffer_cdes].cde[i]; // Simplifie la lecture et les accès...
|
||||
ck_a += c; // Calcul du premier élément de CS
|
||||
ck_b += ck_a; // Calcul du second élément de CS
|
||||
tx_buffer[lg_tx_buffer ++] = c; // Ajout du caractère dans le buffer d'émission
|
||||
}
|
||||
|
||||
// Ajout du CS en fin de trame :
|
||||
tx_buffer[lg_tx_buffer ++] = ck_a;
|
||||
tx_buffer[lg_tx_buffer ++] = ck_b;
|
||||
|
||||
//.............................
|
||||
// Envoi au driver d'émission :
|
||||
write(config_serial0.filestream, tx_buffer, lg_tx_buffer);
|
||||
|
||||
//..........................................................
|
||||
// Mise à jour des paramètres après l'émission de la trame :
|
||||
g_bus.down.flag_attente_reponse = TRUE;
|
||||
g_bus.protocole_tx.sequenceur.compteur_time_out = g_bus.down.buffer_cdes[g_bus.down.ptr_debut_buffer_cdes].time_out;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur M-Bus.Protocole_Tx est inconnu [%i]. Il est repositionné au REPOS", g_bus.protocole_tx.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
g_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_TX_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Incrémente le pointeur du buffer de commandes en attente d'émission vers G-Bus
|
||||
La fonction gère :
|
||||
- le rebouclage en fin de buffer (buffer circulaire)
|
||||
- le dépassement (quand la fin rattrape le début) en émettant un message de debug et en choissant :
|
||||
. soit d'écraser la commande la plus ancienne si elle est de priorité inférieure (strictement)
|
||||
. soit refuser l'ajout en laissant le pointeur de fin du buffer à sa position et en renvoyant une erreur.
|
||||
Reçoit : La priorité de la commande à ajouter (permet d'arbitrer dans la cas où le buffer est plein)
|
||||
Renvoit : 0 si une position disponible a été trouvée, -1 si aucune position n'est disponible.
|
||||
******************************************************************************************************************************************************************/
|
||||
int8_t g_bus_next_write_buffer_cdes(uint8_t priorite)
|
||||
{
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
// !!! La gestion des priorités n'est pas traitée ! A vérifier mais si on écrase le début, celui-ci est probablement en cours d'utilisation...
|
||||
// Donc ATTENTION !!!!
|
||||
|
||||
|
||||
// Incrémentation :
|
||||
if (++ g_bus.down.ptr_fin_buffer_cdes == G_BUS_MAX_TAILLE_BUFFER_CDES) g_bus.down.ptr_fin_buffer_cdes = 0;
|
||||
|
||||
// Vérification si buffer plein :
|
||||
if (g_bus.down.ptr_fin_buffer_cdes == g_bus.down.ptr_debut_buffer_cdes)
|
||||
{
|
||||
// Décrémentation du pointeur puisqu'on ne va pas accepter la nouvelle commande qui n'a pas une priorité suffisante :
|
||||
if (g_bus.down.ptr_fin_buffer_cdes == 0) g_bus.down.ptr_fin_buffer_cdes = (G_BUS_MAX_TAILLE_BUFFER_CDES - 1);
|
||||
else g_bus.down.ptr_fin_buffer_cdes --;
|
||||
|
||||
// Message de débug :
|
||||
sprintf(tmp, "Buffer de commandes M-Bus plein. La demande de stockage d'une nouvelle commande a été rejetée...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
// Enregistrement dans l'historique :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_BUS_BUFFER_COMMANDES_PLEIN, (uint32_t) 'M', 0, NULL);
|
||||
|
||||
return(-1);
|
||||
}
|
||||
else return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
|
||||
Fichier G_BUS.H
|
||||
|
||||
Contient tous les define liés au G_BUS
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define G_BUS_MAX_TAILLE_BUFFER_CDES 80 // Taille du buffer de commandes (donc on stocke plusieurs commandes entières !) G-bus en mode Down
|
||||
#define G_BUS_PROTOCOLE_TX_MAX_REPETITIONS 3 // Nombre de répétitions des commandes émises sur G_Bus
|
||||
#define G_BUS_MAX_TAILLE_BUFFER_TX 3000
|
||||
#define G_BUS_MAX_REFUS_BUFFER_CDES_PLEIN 12 // Au-delà de cette valeur, si un refus supplémentaire est rencontré, le Modem sera réinitialisé
|
||||
|
||||
|
||||
// Tempos :
|
||||
#define G_BUS_TEMPO_INIT 20 // En x 100ms
|
||||
// #define G_BUS_TEMPO_IMPULSION_ACTIVATION_MODEM 12 // En x 100ms (Tmin = 1s selon datasheet du SIM7070G, page 26)
|
||||
// #define G_BUS_TEMPO_POST_IMPULSION_ACTIVATION_MODEM 5 // En x 100ms Cette tempo est à relier au MAX_REPETITIONS_TEMPO_POST_ACTIVATION_MODEM ci-dessus.
|
||||
#define G_BUS_PROTOCOLE_RX_TEMPO_INIT 10 // en x 100ms
|
||||
#define G_BUS_PROTOCOLE_TX_TEMPO_INIT 10 // en x 100ms
|
||||
#define G_BUS_TIME_OUT_REPONSE_TX 3 // En x 100ms
|
||||
|
||||
|
||||
// Priorité des commandes :
|
||||
#define PRIORITE_CDE_G_BUS_FAIBLE 0
|
||||
#define PRIORITE_CDE_G_BUS_HAUTE 1
|
||||
|
||||
// Mode de traitement de la commande par le protocole :
|
||||
#define G_BUS_PROTOCOLE_NORMAL 0
|
||||
// #define G_BUS_PROTOCOLE_DATA_BINAIRE 1 // Dans ce cas, aucun CR n'est ajouté en fin de commande
|
||||
|
||||
|
||||
// Etats du séquenceur G-Bus :
|
||||
#define ETAT_SEQUENCEUR_G_BUS_INIT 0
|
||||
#define ETAT_SEQUENCEUR_G_BUS_REPOS 1
|
||||
|
||||
// Etats séquenceur du Protocole_Rx G-bus :
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_INIT 0
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_REPOS 1
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_SYNC_2 2
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CLASS 3
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_ID 4
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_LENGTH_1 5
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_LENGTH_2 6
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_DATA 7
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CS_A 8
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_RX_ATTENTE_CS_B 9
|
||||
|
||||
|
||||
// Etats séquenceur du Protocole_Tx G-bus :
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_TX_INIT 0
|
||||
#define ETAT_SEQUENCEUR_G_BUS_PROTOCOLE_TX_REPOS 1
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,728 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier G_COMMANDES.C
|
||||
//
|
||||
// Contient toutes les fonctions liées aux commandes envoyées et reçues sur G_BUS
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
|
||||
//#define __DEBUG_G_COMMANDES_GENERALES //Décommenter cette ligne pour avoir les messages de debug concernant les commandes générales du GNSS
|
||||
//#define __DEBUG_G_COMMANDE_NAV
|
||||
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t g_bus_down_commande_libre(uint8_t classe, uint8_t id, uint8_t * ptr_cde, uint16_t lg_cde, uint8_t mode_protocole, uint16_t time_out, int8_t max_repetitions);
|
||||
int8_t g_bus_down_analyse_reponse_commande(void);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Commande libre formattée et envoyée vers le gestionnairer d'émission du protocole
|
||||
Vérifie que le buffer de commandes à émettre sur G-Bus a un emplacement de libre.
|
||||
Si oui, génère la commande correspondante dans le buffer de commandes et met à jour la longueur de la commande ainsi que
|
||||
sa priorité.
|
||||
Reçoit : La classe et l'ID de la commande, un pointeur sur le début de la commande (la chaine n'a PAS à se terminer par NULL), la longueur de la commande,
|
||||
le mode protocole, la durée du time-out s'il doit être particulier (en x100ms) et le nombre maxi de répétitions (-1 si valeur par défaut).
|
||||
Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
|
||||
******************************************************************************************************************************************************************/
|
||||
int8_t g_bus_down_commande_libre(uint8_t classe, uint8_t id, uint8_t * ptr_cde, uint16_t lg_cde, uint8_t mode_protocole, uint16_t time_out, int8_t max_repetitions)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t priorite;
|
||||
struct Struct_commande_g_bus *buffer_cde;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
// Vérification des paramètres reçus :
|
||||
if (mode_protocole != G_BUS_PROTOCOLE_NORMAL) return(-1);
|
||||
|
||||
if (lg_cde >= G_BUS_MAX_TAILLE_CDE) return(-1);
|
||||
|
||||
// Préparation de la commande :
|
||||
priorite = PRIORITE_CDE_G_BUS_FAIBLE;
|
||||
|
||||
if (g_bus_next_write_buffer_cdes(priorite) != -1) // On recherche le prochain slot de commande libre
|
||||
{
|
||||
g_bus.nb_refus_buffer = 0; // RAZ du compteur à chaque réussite
|
||||
|
||||
buffer_cde = &g_bus.down.buffer_cdes[g_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
|
||||
buffer_cde->lg_cde = 0;
|
||||
|
||||
// Chargement de la classe et de l'ID :
|
||||
buffer_cde->cde[buffer_cde->lg_cde ++] = classe;
|
||||
buffer_cde->cde[buffer_cde->lg_cde ++] = id;
|
||||
|
||||
// Chargement de la longueur :
|
||||
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(lg_cde & 0x00FF); // LSB
|
||||
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(lg_cde >> 8); // MSB
|
||||
|
||||
// Chargement de la commande proprement-dite :
|
||||
for (i = 0; i < lg_cde; i ++)
|
||||
{
|
||||
buffer_cde->cde[buffer_cde->lg_cde ++] = *(ptr_cde ++);
|
||||
}
|
||||
|
||||
// Code de la commande :
|
||||
buffer_cde->code = (classe << 8) | id; // On obtient un code unique sur 16 bits en concatenant la classe et l'ID (simplifie la recherche directe ensuite)
|
||||
|
||||
// Priorité de la commande :
|
||||
buffer_cde->priorite = priorite;
|
||||
|
||||
// Type de réponse attendue :
|
||||
buffer_cde->mode_protocole = mode_protocole;
|
||||
|
||||
// Time-out à utiliser pour la commande :
|
||||
if (time_out > 0) buffer_cde->time_out = time_out;
|
||||
else buffer_cde->time_out = G_BUS_TIME_OUT_REPONSE_TX;
|
||||
|
||||
// Nombre max de répétitions :
|
||||
if (max_repetitions >= 0) buffer_cde->max_repetitions = max_repetitions;
|
||||
else buffer_cde->max_repetitions = G_BUS_PROTOCOLE_TX_MAX_REPETITIONS;
|
||||
|
||||
return(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++ g_bus.nb_refus_buffer > G_BUS_MAX_REFUS_BUFFER_CDES_PLEIN) // Si les refus de nouvelle commandes sur M-Bus augmentent, on va réactiver le modem car il y a un sérieux problème...
|
||||
{
|
||||
sprintf(tmp, "Le nombre de refus de nouvelle commande dans le buffer de G-Bus est trop important (%i). Le récepteur GNSS va être réactivé", g_bus.nb_refus_buffer);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
// Enregistrement dans l'historique :
|
||||
// enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_MODEM_ERREUR_G_BUS_PLEIN, 0, g_bus.nb_refus_buffer, NULL);
|
||||
|
||||
// modem.sequenceur.etat = ETAT_SEQUENCEUR_MODEM_DEBUT_IMPULSION_RESET; // Déclenche une impulsion >12s de reset sur POWER_KEY
|
||||
}
|
||||
return (-1); // Si aucun slot n'est disponible, on laisse tomber la commande...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Analyse la réponse à la commande et effectue, si besoin, le traitement nécessaire.
|
||||
Le principe est de d'abord de détecter la présence d'un éventuel code d'erreur dans la réponse et de stocker son code.
|
||||
Ensuite, on saute à la fonction (en pratique, un case d'un grand switch) correspondant à la commande qui avait été émise et donc qui déclenche
|
||||
cette réponse. Là, on peut avoir les grandes tâches suivantes :
|
||||
1- cas où on vient de recevoir un code d'erreur (y compris OK qui est considéré comme l'un d'eux) : dans ce cas, on décide ce qu'on doit faire
|
||||
de ce code dans ce contexte. Souvent, il s'agit de ne pas tenir compte d'un OK intempestif (poru cela, on écrase l'erreur par G_BUS_ERREUR_AUCUNE).
|
||||
2- On effectue le traitement de la trame reçue, selon la fonction émise et le contexte.
|
||||
3- si on considère que le traitement est terminé, on écrase le code d'erreur pour le mettre à G_BUS_ERREUR_OK. Cette phase 3 est inutile pour pas
|
||||
mal de commandes simples car leur trame de retour est suivie d'une trame OK qui libère le protocole tout seul.
|
||||
En toute fin de fonction, on traite le code d'erreur subsistant. S'il est G_BUS_ERREUR_AUCUNE, on ne fait rien. S'il est G_BUS_ERREUR_OK on remet
|
||||
le protocole au repos.
|
||||
Reçoit : Rien (traite la réponse qui est stockée dans la structure g_bus.down.reponse.xxxx
|
||||
Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a rencontré une erreur.
|
||||
******************************************************************************************************************************************************************/
|
||||
int8_t g_bus_down_analyse_reponse_commande(void)
|
||||
{
|
||||
uint8_t erreur;
|
||||
uint16_t i, j;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
erreur = G_COMMANDE_ERREUR_AUCUNE;
|
||||
|
||||
switch(g_bus.down.reponse.classe)
|
||||
{
|
||||
//===============================================
|
||||
case G_COMMANDE_CLASSE_ACK :
|
||||
{
|
||||
switch(g_bus.down.reponse.id)
|
||||
{
|
||||
//-----------------------------
|
||||
case G_COMMANDE_UBX_ACK_NACK :
|
||||
{
|
||||
erreur = G_COMMANDE_ERREUR_NACK;
|
||||
break;
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
case G_COMMANDE_UBX_ACK_ACK :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
default :
|
||||
{
|
||||
erreur = G_COMMANDE_ERREUR_ID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//===============================================
|
||||
case G_COMMANDE_CLASSE_CFG :
|
||||
{
|
||||
switch(g_bus.down.reponse.id)
|
||||
{
|
||||
//-----------------------------
|
||||
case G_COMMANDE_UBX_CFG_PRT :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
case G_COMMANDE_UBX_CFG_PM2 :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
case G_COMMANDE_UBX_CFG_PMS :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
default :
|
||||
{
|
||||
erreur = G_COMMANDE_ERREUR_ID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//===============================================
|
||||
case G_COMMANDE_CLASSE_MON :
|
||||
{
|
||||
switch(g_bus.down.reponse.id)
|
||||
{
|
||||
//-----------------------------
|
||||
case G_COMMANDE_UBX_MON_VER :
|
||||
{
|
||||
if (g_bus.down.reponse.lg_reponse < 40) // Il y a normalement au minimum 40 octets en retour...
|
||||
{
|
||||
sprintf(tmp, "Retour de commande UBX_MON_VER en erreur : la longueur de la réponse [%i octets] est inférieure au minimum (40 octets)", g_bus.down.reponse.lg_reponse);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
sprintf(tmp, "Retour de commande UBX_MON_VER :");
|
||||
strcat(tmp, "\n\t"); // SwVersion (30 caractères)
|
||||
strcat(tmp, (const char * restrict)(g_bus.down.reponse.reponse + i));
|
||||
i += 30;
|
||||
strcat(tmp, "\n\t"); // HwVersion (10 caractères)
|
||||
strcat(tmp, (const char * restrict)(g_bus.down.reponse.reponse + i));
|
||||
i += 10;
|
||||
|
||||
while (i < g_bus.down.reponse.lg_reponse)
|
||||
{
|
||||
strcat(tmp, "\n\t"); // Autre groupe (toujours 30 caractères)
|
||||
strcat(tmp, (const char * restrict)(g_bus.down.reponse.reponse + i));
|
||||
i += 30;
|
||||
}
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
default :
|
||||
{
|
||||
erreur = G_COMMANDE_ERREUR_ID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//===============================================
|
||||
case G_COMMANDE_CLASSE_NAV :
|
||||
{
|
||||
switch(g_bus.down.reponse.id)
|
||||
{
|
||||
//-----------------------------
|
||||
case G_COMMANDE_UBX_NAV_PVT :
|
||||
//-----------------------------
|
||||
{
|
||||
if (g_bus.down.reponse.lg_reponse != 92) // Longueur fixe...
|
||||
{
|
||||
sprintf(tmp, "Retour de commande G_COMMANDE_UBX_NAV_PVT en erreur : la longueur de la réponse [%i octets] est différente de la longueur attendue(92 octets)", g_bus.down.reponse.lg_reponse);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
|
||||
//----------------------------------------
|
||||
// GPS time of week of the navigation epoch. :
|
||||
i +=4; // Saut de iTOW car deprecated
|
||||
|
||||
|
||||
struct Struct_date date;
|
||||
struct Struct_heure heure;
|
||||
//----------------------------------------
|
||||
// Année :
|
||||
date.annee = g_bus.down.reponse.reponse[i] + ((uint16_t)(g_bus.down.reponse.reponse[i+1]) << 8);
|
||||
i += 2;
|
||||
|
||||
//----------------------------------------
|
||||
// Mois :
|
||||
date.mois = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
|
||||
//----------------------------------------
|
||||
// Jour :
|
||||
date.jour = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
|
||||
//----------------------------------------
|
||||
// Heure :
|
||||
heure.heures = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
|
||||
//----------------------------------------
|
||||
// Minutes :
|
||||
heure.minutes = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
|
||||
//----------------------------------------
|
||||
// Secondes :
|
||||
heure.secondes = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
|
||||
//----------------------------------------
|
||||
// Validity flags :
|
||||
uint8_t validity;
|
||||
validity = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
bool flag_validity_valid_date = ((validity & 0x01) != 0) ? true : false; // 1 = valid UTC Date (see Time Validity section for details)
|
||||
bool flag_validity_valid_time = ((validity & 0x02) != 0) ? true : false; // 1 = valid UTC time of day (see Time Validity section for details)
|
||||
bool flag_validity_fully_resolved = ((validity & 0x04) != 0) ? true : false; // 1 = UTC time of day has been fully resolved (no seconds uncertainty). Cannot be used to check if time is completely solved.
|
||||
bool flag_validity_valid_magnetic_declination = ((validity & 0x08) != 0) ? true : false; // 1 = valid magnetic declination
|
||||
|
||||
//----------------------------------------
|
||||
// Time accuracy (ns) :
|
||||
uint32_t time_accuracy;
|
||||
time_accuracy = g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24);
|
||||
i += 4;
|
||||
|
||||
//----------------------------------------
|
||||
// Fraction of second (ns) :
|
||||
int32_t nano;
|
||||
nano = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
|
||||
//----------------------------------------
|
||||
// Fix type :
|
||||
uint8_t fix_type;
|
||||
fix_type = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
|
||||
//----------------------------------------
|
||||
// Fix type flags :
|
||||
uint8_t flags;
|
||||
flags = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
bool flag_flags_gnss_fix_ok = ((flags & 0x01) != 0) ? true : false; // 1 = valid fix (i.e within DOP & accuracy masks)
|
||||
bool flag_flags_differential_corrections_applied = ((flags & 0x02) != 0) ? true : false; // 1 = differential corrections were applied
|
||||
bool flag_flags_heading_of_vehicle_valid = ((flags & 0x20) != 0) ? true : false; // 1 = heading of vehicle is valid, only set if the receiver is in sensor fusion mode
|
||||
uint8_t flags_psm_state = (flags >> 2) & 0x07; // Pas de desciptif dans la doc...
|
||||
uint8_t flags_carrier_phase_range_solution = (flags >> 6) & 0x03; // Carrier phase range solution status: 0: no carrier phase range solution, 1: carrier phase range solution with floating ambiguities, 2: carrier phase range solution with fixed ambiguities
|
||||
|
||||
//----------------------------------------
|
||||
// Fix type flags 2 :
|
||||
uint8_t flags2;
|
||||
flags2 = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
bool flag_flags2_confirmed_available = ((flags2 & 0x20) != 0) ? true : false; // 1 = information about UTC Date and Time of Day validity confirmation is available (see Time Validity section for details)
|
||||
bool flag_flags2_confirmed_date = ((flags2 & 0x40) != 0) ? true : false; // 1 = UTC Date validity could be confirmed (see Time Validity section for details)
|
||||
bool flag_flags2_confirmed_time = ((flags2 & 0x80) != 0) ? true : false; // 1 = UTC Time of Day could be confirmed (see Time Validity section for details)
|
||||
|
||||
//----------------------------------------
|
||||
// Number of satellites :
|
||||
uint8_t siv;
|
||||
siv = g_bus.down.reponse.reponse[i];
|
||||
i += 1;
|
||||
|
||||
//----------------------------------------
|
||||
// Longitude (deg) :
|
||||
int32_t tmp_longitude;
|
||||
float longitude;
|
||||
tmp_longitude = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
longitude = ((float)tmp_longitude) / 10000000;
|
||||
|
||||
//----------------------------------------
|
||||
// Latitude (deg) :
|
||||
int32_t tmp_latitude;
|
||||
float latitude;
|
||||
tmp_latitude = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
latitude = ((float)tmp_latitude) / 10000000;
|
||||
|
||||
//----------------------------------------
|
||||
// Height above ellipsoid (mm) :
|
||||
int32_t tmp_height_ellipsoid;
|
||||
float height_ellipsoid;
|
||||
tmp_height_ellipsoid = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
height_ellipsoid = ((float)tmp_height_ellipsoid) / 1000;
|
||||
|
||||
//----------------------------------------
|
||||
// Height above mean sea level (mm) :
|
||||
int32_t tmp_height_sea;
|
||||
float height_sea;
|
||||
tmp_height_sea = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
height_sea = ((float)tmp_height_sea) / 1000;
|
||||
|
||||
//----------------------------------------
|
||||
// Horizontal accuracy (mm) :
|
||||
uint32_t tmp_horizontal_accuracy;
|
||||
float horizontal_accuracy;
|
||||
tmp_horizontal_accuracy = g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24);
|
||||
i += 4;
|
||||
horizontal_accuracy = ((float)tmp_horizontal_accuracy) / 1000;
|
||||
|
||||
//----------------------------------------
|
||||
// Vertical accuracy (mm) :
|
||||
uint32_t tmp_vertical_accuracy;
|
||||
float vertical_accuracy;
|
||||
tmp_vertical_accuracy = g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24);
|
||||
i += 4;
|
||||
vertical_accuracy = ((float)tmp_vertical_accuracy) / 1000;
|
||||
|
||||
//----------------------------------------
|
||||
// NED north velocity (mm/s) :
|
||||
int32_t tmp_ned_north_velocity;
|
||||
float ned_north_velocity;
|
||||
tmp_ned_north_velocity = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
// ned_north_velocity = (((float)tmp_ned_north_velocity) * 3.600) / 1000; // Conversion de 'mm/s' en 'km/h'
|
||||
ned_north_velocity = (((float)tmp_ned_north_velocity) * 3.600) / 1852; // Conversion de 'mm/s' en 'Knts = noeuds'
|
||||
|
||||
//----------------------------------------
|
||||
// NED east velocity (mm/s) :
|
||||
int32_t tmp_ned_east_velocity;
|
||||
float ned_east_velocity;
|
||||
tmp_ned_east_velocity = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
// ned_east_velocity = (((float)tmp_ned_east_velocity) * 3.600) / 1000; // Conversion de 'mm/s' en 'km/h'
|
||||
ned_east_velocity = (((float)tmp_ned_east_velocity) * 3.600) / 1852; // Conversion de 'mm/s' en 'Knts = noeuds'
|
||||
|
||||
|
||||
//----------------------------------------
|
||||
// NED down velocity (mm/s) :
|
||||
int32_t tmp_ned_down_velocity;
|
||||
float ned_down_velocity;
|
||||
tmp_ned_down_velocity = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
// ned_down_velocity = (((float)tmp_ned_down_velocity) * 3.600) / 1000; // Conversion de 'mm/s' en 'km/h'
|
||||
ned_down_velocity = (((float)tmp_ned_down_velocity) * 3.600) / 1852; // Conversion de 'mm/s' en 'Knts = noeuds'
|
||||
|
||||
//----------------------------------------
|
||||
// Ground speed (mm/s) :
|
||||
int32_t tmp_ground_speed;
|
||||
float ground_speed;
|
||||
tmp_ground_speed = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
// ground_speed = (((float)tmp_ground_speed) * 3.600) / 1000; // Conversion de 'mm/s' en 'km/h'
|
||||
ground_speed = (((float)tmp_ground_speed) * 3.600) / 1852; // Conversion de 'mm/s' en 'Knts = noeuds'
|
||||
|
||||
//----------------------------------------
|
||||
// Heading of motion (deg) :
|
||||
int32_t tmp_heading_motion;
|
||||
float heading_motion;
|
||||
tmp_heading_motion = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
heading_motion = ((float)tmp_heading_motion) / 100000;
|
||||
|
||||
//----------------------------------------
|
||||
// Speed accuracy estimate (mm/s):
|
||||
uint32_t tmp_speed_accuracy;
|
||||
float speed_accuracy;
|
||||
tmp_speed_accuracy = g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24);
|
||||
i += 4;
|
||||
// speed_accuracy = (((float)tmp_speed_accuracy) * 3.600) / 1000; // Conversion de 'mm/s' en 'km/h'
|
||||
speed_accuracy = (((float)tmp_speed_accuracy) * 3.600) / 1852; // Conversion de 'mm/s' en 'Knts = noeuds'
|
||||
|
||||
//----------------------------------------
|
||||
// Heading accuracy estimate (deg):
|
||||
uint32_t tmp_heading_accuracy;
|
||||
float heading_accuracy;
|
||||
tmp_heading_accuracy = g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24);
|
||||
i += 4;
|
||||
heading_accuracy = ((float)tmp_heading_accuracy) / 100000;
|
||||
|
||||
//----------------------------------------
|
||||
// Position DOP :
|
||||
uint16_t tmp_position_dop;
|
||||
float position_dop;
|
||||
tmp_position_dop = g_bus.down.reponse.reponse[i] + ((uint16_t)(g_bus.down.reponse.reponse[i+1]) << 8);
|
||||
i += 2;
|
||||
position_dop = ((float)tmp_position_dop) / 100;
|
||||
|
||||
//----------------------------------------
|
||||
// Fix type flags 3 :
|
||||
uint16_t flags3;
|
||||
flags3 = g_bus.down.reponse.reponse[i] + ((uint16_t)(g_bus.down.reponse.reponse[i+1]) << 8);
|
||||
i += 1;
|
||||
bool flag_flags3_invalid_llh = ((flags3 & 0x01) != 0) ? true : false; // 1 = Invalid lon, lat, height and hMSL
|
||||
uint8_t flags3_last_correction_age = (flags3 >> 1) & 0x0F; // Age of the most recently received differential correction: 0: Not available, 1: Age between 0 and 1 second, 2: Age between 1 (inclusive) and 2 seconds, 3: Age between 2 (inclusive) and 5 seconds, 4: Age between 5 (inclusive) and 10 seconds, 5: Age between 10 (inclusive) and 15 seconds, 6: Age between 15 (inclusive) and 20 seconds, 7: Age between 20 (inclusive) and 30 seconds, 8: Age between 30 (inclusive) and 45 seconds, 9: Age between 45 (inclusive) and 60 seconds, 10: Age between 60 (inclusive) and 90 seconds, 11: Age between 90 (inclusive) and 120 seconds, >=12: Age greater or equal than 120 seconds
|
||||
|
||||
//----------------------------------------
|
||||
// Reserved (U1 x 4) :
|
||||
i += 4;
|
||||
|
||||
//----------------------------------------
|
||||
// Heading of vehicule (deg) :
|
||||
int32_t tmp_heading_vehicule;
|
||||
float heading_vehicule;
|
||||
tmp_heading_vehicule = (int32_t) (g_bus.down.reponse.reponse[i] + ((uint32_t)(g_bus.down.reponse.reponse[i+1]) << 8) + ((uint32_t)(g_bus.down.reponse.reponse[i+2]) << 16) + ((uint32_t)(g_bus.down.reponse.reponse[i+3]) << 24));
|
||||
i += 4;
|
||||
heading_vehicule = ((float)tmp_heading_vehicule) / 100000;
|
||||
|
||||
//----------------------------------------
|
||||
// Magnetic declination (deg) :
|
||||
int16_t tmp_magnetic_declination;
|
||||
float magnetic_declination;
|
||||
tmp_magnetic_declination = (int16_t) (g_bus.down.reponse.reponse[i] + ((uint16_t)(g_bus.down.reponse.reponse[i+1]) << 8));
|
||||
i += 2;
|
||||
magnetic_declination = ((float)tmp_magnetic_declination) / 100;
|
||||
|
||||
//----------------------------------------
|
||||
// Magnetic declination accuracy :
|
||||
uint16_t tmp_magnetic_declination_accuracy;
|
||||
float magnetic_declination_accuracy;
|
||||
tmp_magnetic_declination_accuracy = g_bus.down.reponse.reponse[i] + ((uint16_t)(g_bus.down.reponse.reponse[i+1]) << 8);
|
||||
i += 1;
|
||||
magnetic_declination_accuracy = ((float)tmp_magnetic_declination_accuracy) / 100;
|
||||
|
||||
|
||||
//-----------------------------------------
|
||||
// TRAITEMENT :
|
||||
//-----------------------------------------
|
||||
|
||||
if (flag_validity_valid_date && flag_validity_valid_time) // Ces deux flags indiquent que l'heure et la date sont valides.
|
||||
{
|
||||
if (gnss.sequenceur.compteur_time_out == 0) // On n'utiulise la date et heure valide que périodiquement car inutils sinon.
|
||||
{
|
||||
gnss.sequenceur.compteur_time_out = GNSS_PERIODE_SET_DATE_HEURE; // Rechargement de la tempo pour éviter les mises à jour chaque seconde...
|
||||
set_date_heure(date, heure); // Mise à jour de la date/heure système à partir de l'heure reçue du GNSS (toujours en UTC !)
|
||||
c_bus_down_commande_config_date_heure(); // Mise à jour de la date/heure du Compagnon dans la foulée (lui aussi, toujours en UTC)
|
||||
#ifdef __DEBUG_G_COMMANDES_GENERALES
|
||||
affichage_debug(__FILE__, __LINE__, "Une commande de mise à l'heure a été envoyée au Compagnon", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (flag_flags_gnss_fix_ok) // C'est ce flag qui indique su la position est déterminée ou pas.
|
||||
{
|
||||
#ifdef __DEBUG_G_COMMANDES_GENERALES
|
||||
affichage_debug(__FILE__, __LINE__, "L'aquisition de la position par le GNSS vient d'être faite avec succès", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
gnss.etat = ON;
|
||||
|
||||
// L'utilisation d'une boucle sur toutes les entrées Prédéfinies est plus efficace que plusieurs appels à 'no_entree_predefinie(0, ENTREE_PREDEFINIE_LAT)' puis test de validité de l'entrée puis lecture de la valeur...
|
||||
for (j = 0; j < MAX_NOMBRE_ENTREES_PREDEFINIES; j ++)
|
||||
{
|
||||
if (!entrees.predefinies.entrees[j].flag_validite) continue;
|
||||
if (entrees.predefinies.entrees[j].module != 0) continue; // On ne cherche que les entrées de ShipBase
|
||||
|
||||
switch(entrees.predefinies.entrees[j].no)
|
||||
{
|
||||
case ENTREE_PREDEFINIE_LAT: { entrees.predefinies.entrees[j].valeur = latitude; break; }
|
||||
case ENTREE_PREDEFINIE_LON: { entrees.predefinies.entrees[j].valeur = longitude; break; }
|
||||
case ENTREE_PREDEFINIE_ALT: { entrees.predefinies.entrees[j].valeur = height_sea; break; }
|
||||
case ENTREE_PREDEFINIE_SOG: { entrees.predefinies.entrees[j].valeur = ground_speed; break; }
|
||||
case ENTREE_PREDEFINIE_COG: { entrees.predefinies.entrees[j].valeur = heading_motion; break; }
|
||||
case ENTREE_PREDEFINIE_SIV: { entrees.predefinies.entrees[j].valeur = siv; break; }
|
||||
case ENTREE_PREDEFINIE_HPA: { entrees.predefinies.entrees[j].valeur = horizontal_accuracy; break; }
|
||||
case ENTREE_PREDEFINIE_VPA: { entrees.predefinies.entrees[j].valeur = vertical_accuracy; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __DEBUG_G_COMMANDES_GENERALES
|
||||
affichage_debug(__FILE__, __LINE__, "L'aquisition de la position par le GNSS n'est pas considérée comme valide (flag_flags_gnss_fix_ok = FALSE)", TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
#endif
|
||||
gnss.etat = OFF;
|
||||
|
||||
// SDIR # 149 : Début
|
||||
// L'utilisation d'une boucle sur toutes les entrées Prédéfinies est plus efficace que plusieurs appels à 'no_entree_predefinie(0, ENTREE_PREDEFINIE_LAT)' puis test de validité de l'entrée puis lecture de la valeur...
|
||||
for (j = 0; j < MAX_NOMBRE_ENTREES_PREDEFINIES; j ++)
|
||||
{
|
||||
if (!entrees.predefinies.entrees[j].flag_validite) continue;
|
||||
if (entrees.predefinies.entrees[j].module != 0) continue; // On ne cherche que les entrées de ShipBase
|
||||
|
||||
switch(entrees.predefinies.entrees[j].no)
|
||||
{
|
||||
// case ENTREE_PREDEFINIE_LAT: { entrees.predefinies.entrees[j].valeur = latitude; break; }
|
||||
// case ENTREE_PREDEFINIE_LON: { entrees.predefinies.entrees[j].valeur = longitude; break; }
|
||||
// case ENTREE_PREDEFINIE_ALT: { entrees.predefinies.entrees[j].valeur = height_sea; break; }
|
||||
case ENTREE_PREDEFINIE_SOG: { entrees.predefinies.entrees[j].valeur = 0; break; }
|
||||
case ENTREE_PREDEFINIE_COG: { entrees.predefinies.entrees[j].valeur = 0; break; }
|
||||
case ENTREE_PREDEFINIE_SIV: { entrees.predefinies.entrees[j].valeur = 0; break; }
|
||||
case ENTREE_PREDEFINIE_HPA: { entrees.predefinies.entrees[j].valeur = 0; break; }
|
||||
case ENTREE_PREDEFINIE_VPA: { entrees.predefinies.entrees[j].valeur = 0; break; }
|
||||
}
|
||||
}
|
||||
// SDIR # 149 : Fin
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// NB : les tabulations ci-dessous correspondent à un affichage oiptimal. Il est conseillé de ne pas y toucher...
|
||||
sprintf(tmp, "Réponse GNSS :\n \
|
||||
Date = %02i/%02i/%i %02i:%02i:%02i \n \
|
||||
Validity flags : Valid_date = %s, Valid_time = %s, Fully_resolved = %s, valid_magnetic_declination = %s \n \
|
||||
Time accuracy = %i ns \n \
|
||||
Fraction of seconds = %i ns \n \
|
||||
Fix type = %s \n \
|
||||
Fix Status Flags : Gnss_fix_ok = %s, Differential_corrections_applied = %s, Heading_of_vehicle_valid = %s, Psm_state = %i, Carrier_phase_range_solution = %i \n \
|
||||
Flags2 : Confirmed_available = %s, Confirmed_date = %s, Confirmed_time = %s \n \
|
||||
Nb de satellites en vue = %i \n \
|
||||
Longitude = %.8f° \n \
|
||||
Latitude = %.8f° \n \
|
||||
Height_ellipsoid = %.3f m \n \
|
||||
Height_sea = %.3f m \n \
|
||||
Horizontal_accuracy = %.3f m \n \
|
||||
Vertical_accuracy = %.3f m \n \
|
||||
Ned_north_velocity = %.3f knts \n \
|
||||
Ned_east_velocity = %.3f knts \n \
|
||||
Ned_down_velocity = %.3f knts \n \
|
||||
Ground_speed = %.3f knts \n \
|
||||
Heading_motion = %.5f° \n \
|
||||
Speed_accuracy = %.3f knts \n \
|
||||
Heading_accuracy = %.5f° \n \
|
||||
Position_DOP = %.2f \n \
|
||||
Flags3 : Invalid_llh = %s, flags3_last_correction_age = %i \n \
|
||||
Heading_vehicule = %.5f \n \
|
||||
Magnetic_declination = %.2f° \n \
|
||||
Magnetic_declination_accur. = %.2f ",
|
||||
date.jour, date.mois, date.annee, heure.heures, heure.minutes, heure.secondes,
|
||||
flag_validity_valid_date ? "true" : "false", flag_validity_valid_time ? "true" : "false", flag_validity_fully_resolved ? "true" : "false", flag_validity_valid_magnetic_declination ? "true" : "false",
|
||||
time_accuracy,
|
||||
nano,
|
||||
(fix_type == 0) ? "No fix" : ((fix_type == 1) ? "Dead Reckoning only" : ((fix_type == 2) ? "2D-Fix" : ((fix_type == 3) ? "3D-Fix" : ((fix_type == 4) ? "GNSS + Dead Reckoning combined" : "Time only fix")))),
|
||||
flag_flags_gnss_fix_ok ? "true" : "false", flag_flags_differential_corrections_applied ? "true" : "false", flag_flags_heading_of_vehicle_valid ? "true" : "false", flags_psm_state, flags_carrier_phase_range_solution,
|
||||
flag_flags2_confirmed_available ? "true" : "false", flag_flags2_confirmed_date ? "true" : "false", flag_flags2_confirmed_time ? "true" : "false",
|
||||
siv,
|
||||
longitude,
|
||||
latitude,
|
||||
height_ellipsoid,
|
||||
height_sea,
|
||||
horizontal_accuracy,
|
||||
vertical_accuracy,
|
||||
ned_north_velocity,
|
||||
ned_east_velocity,
|
||||
ned_down_velocity,
|
||||
ground_speed,
|
||||
heading_motion,
|
||||
speed_accuracy,
|
||||
heading_accuracy,
|
||||
position_dop,
|
||||
flag_flags3_invalid_llh ? "true" : "false", flags3_last_correction_age,
|
||||
heading_vehicule,
|
||||
magnetic_declination,
|
||||
magnetic_declination_accuracy
|
||||
);
|
||||
#ifdef __DEBUG_G_COMMANDE_NAV // NB : on laisse faire le sprintf avant dans tous les cas pour éviter les warnings à la compilation...
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
default :
|
||||
{
|
||||
erreur = G_COMMANDE_ERREUR_ID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//===============================================
|
||||
// Autres classes :
|
||||
case G_COMMANDE_CLASSE_RXM :
|
||||
case G_COMMANDE_CLASSE_INF :
|
||||
case G_COMMANDE_CLASSE_UPD :
|
||||
case G_COMMANDE_CLASSE_AID :
|
||||
case G_COMMANDE_CLASSE_TIM :
|
||||
case G_COMMANDE_CLASSE_ESF :
|
||||
case G_COMMANDE_CLASSE_MGA :
|
||||
case G_COMMANDE_CLASSE_LOG :
|
||||
case G_COMMANDE_CLASSE_SEC :
|
||||
case G_COMMANDE_CLASSE_HNR :
|
||||
default:
|
||||
{
|
||||
erreur = G_COMMANDE_ERREUR_CLASSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(erreur)
|
||||
{
|
||||
//---------------------------------
|
||||
case G_COMMANDE_ERREUR_AUCUNE :
|
||||
{
|
||||
g_bus.down.flag_attente_reponse = FALSE; // Libération du séquenceur d'émission pour passer à la commande suivante
|
||||
g_bus.protocole_tx.repetitions = 0; // RAZ du nombre de répétitions pour usage futur
|
||||
g_bus.protocole_tx.sequenceur.compteur_time_out = 0; // RAZ du time-out pour éviter tout déclenchement a postériori.
|
||||
break;
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
case G_COMMANDE_ERREUR_CLASSE :
|
||||
{
|
||||
sprintf(tmp, "La réponse reçue sur G-Bus ne correspond à aucune classe connue [%02Xh]", g_bus.down.reponse.classe);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
break;
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
case G_COMMANDE_ERREUR_ID :
|
||||
{
|
||||
sprintf(tmp, "La réponse reçue sur G-Bus dans la classe %02Xh ne correspond à aucun ID connu [%02Xh]", g_bus.down.reponse.classe, g_bus.down.reponse.id);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
break;
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
case G_COMMANDE_ERREUR_NACK :
|
||||
{
|
||||
sprintf(tmp, "La réponse reçue sur G-Bus dans la classe [%02Xh] avec ID [%02Xh] est en erreur NACK", g_bus.down.reponse.classe, g_bus.down.reponse.id);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
g_bus.down.reponse.classe = 0; // Cette valeur semble n'être utilisée par aucune classe...
|
||||
g_bus.down.reponse.lg_reponse = 0; // Repositionne le pointeur au début pour le traitement de la trame suivante. A faire dans tous les cas !!
|
||||
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier G_COMMANDES_.H
|
||||
//
|
||||
// Contient toutes définitions de constantes liées au commandes sur G_Bus
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
|
||||
// Valeur maximales
|
||||
#define G_BUS_MAX_TAILLE_CDE 300
|
||||
#define G_BUS_MAX_TAILLE_REPONSE 300
|
||||
#define G_COMMANDE_MAX_NOMBRE_PARAMETRES_REPONSE 20
|
||||
#define G_COMMANDE_MAX_LONGUEUR_PARAMETRE_REPONSE 100
|
||||
|
||||
// Timings :
|
||||
#define G_BUS_TIME_OUT_COMMANDE_UBX_NAV_PVT 15 // EN x 100ms // Cette valeur override la valeur par défaut du protocole pour cette coimmande en particulier (le GNSS faisant une acquisition toutes les secondes, le temps de réponse est, au pire, d'une seconde).
|
||||
|
||||
|
||||
// Classes commandes :
|
||||
#define G_COMMANDE_CLASSE_NAV 0x01
|
||||
#define G_COMMANDE_UBX_NAV_PVT 0x07
|
||||
|
||||
#define G_COMMANDE_CLASSE_RXM 0x02
|
||||
|
||||
#define G_COMMANDE_CLASSE_INF 0x04
|
||||
|
||||
#define G_COMMANDE_CLASSE_ACK 0x05
|
||||
#define G_COMMANDE_UBX_ACK_NACK 0x00
|
||||
#define G_COMMANDE_UBX_ACK_ACK 0x01
|
||||
|
||||
#define G_COMMANDE_CLASSE_CFG 0x06
|
||||
#define G_COMMANDE_UBX_CFG_PRT 0x00
|
||||
#define G_COMMANDE_UBX_CFG_PM2 0x3B
|
||||
#define G_COMMANDE_UBX_CFG_PMS 0x86
|
||||
|
||||
#define G_COMMANDE_CLASSE_UPD 0x09
|
||||
|
||||
#define G_COMMANDE_CLASSE_MON 0x0A
|
||||
#define G_COMMANDE_UBX_MON_VER 0x04
|
||||
|
||||
#define G_COMMANDE_CLASSE_AID 0x0B
|
||||
|
||||
#define G_COMMANDE_CLASSE_TIM 0x0D
|
||||
|
||||
#define G_COMMANDE_CLASSE_ESF 0x10
|
||||
|
||||
#define G_COMMANDE_CLASSE_MGA 0x13
|
||||
|
||||
#define G_COMMANDE_CLASSE_LOG 0x21
|
||||
|
||||
#define G_COMMANDE_CLASSE_SEC 0x27
|
||||
|
||||
#define G_COMMANDE_CLASSE_HNR 0x28
|
||||
|
||||
|
||||
|
||||
|
||||
// Codes d'erreur :
|
||||
#define G_COMMANDE_ERREUR_AUCUNE 0
|
||||
#define G_COMMANDE_ERREUR_CLASSE 1
|
||||
#define G_COMMANDE_ERREUR_ID 2
|
||||
#define G_COMMANDE_ERREUR_NACK 3
|
||||
|
||||
|
||||
|
||||
|
||||
// Etat de décodage des réponses
|
||||
#define G_BUS_REPONSE_ETAT_REPOS 0
|
||||
#define G_BUS_REPONSE_ETAT_ATTENTE_PDU 1
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier GNSS.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à la gestion du GNSS sur ShiBase V2 (GNSS indépedant du gnss de ShipBaseV1)
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
#define __DEBUG_GNSS //Décommenter cette ligne pour avoir les messages de debug du GNSS
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t init_gnss(void);
|
||||
void gestion_gnss(void);
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_gnss gnss;
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_GNSS
|
||||
|
||||
Fonction d'initialisation du GNSS
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_gnss(void)
|
||||
{
|
||||
|
||||
if ((systeme.generation_shipbase == GENERATION_SHIPBASE_V2) || (systeme.generation_shipbase == GENERATION_SHIPBASE_V3))
|
||||
{
|
||||
gnss.etat = OFF; // Par défaut.
|
||||
|
||||
// ecriture_sortie(TYPE_SORTIE_GPIO, 0, CM3P_DO_MOD_WKUP, ON); // Activation immédiate de la sortie DTR qui n'est pas utilisée mais qui doit être positionnée à 1 pour pouvoir fonctionner
|
||||
|
||||
gnss.sequenceur.etat = ETAT_SEQUENCEUR_GNSS_INIT;
|
||||
gnss.sequenceur.compteur = GNSS_TEMPO_INIT;
|
||||
gnss.sequenceur.compteur_time_out = 0; // Permet de forcer une mise à l'heure dès la première réception d'une date/heure valide
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation du GNSS\t\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation du GNSS\t\t: Devalidé car non valide sur cette version de ShipBase", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Appelée en tâche de fond, cette fonction gère les fonctions du Gnss ZOE-M8Q dans son ensemble. Il s'appuie sur les fonctions G-Bus et G_commandes pour y accéder.
|
||||
// Reçoit : Rien
|
||||
// Renvoit : Rien
|
||||
//==================================================================================================================================================================
|
||||
void gestion_gnss(void)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t cde[G_BUS_MAX_TAILLE_CDE];
|
||||
uint16_t lg_cde;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
if (systeme.generation_shipbase != GENERATION_SHIPBASE_V2) return;
|
||||
|
||||
switch(gnss.sequenceur.etat)
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_GNSS_INIT :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (gnss.sequenceur.compteur == 0)
|
||||
{
|
||||
// Activation de la sortie DO_GNSS_EXTINT :
|
||||
// NB : l'usage de cette sortie n'est pas évident lors des essais d'avril 2023...
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, CM4_DO_GNSS_EXTINT, ON); // 0 est l'adresse de ShipBase
|
||||
|
||||
// Au démarrage, le GNSS émet en NMEA toutes les secondes. La priorité est de stopper ces émissions afin de ne laisser accessible sur l'UART que le protocole µBX.
|
||||
//----------------------------------------------
|
||||
// Commande de suppression des émissions NMEA :
|
||||
//----------------------------------------------
|
||||
// Cf Page 243 : 32.10.25.2 Port configuration for UART ports
|
||||
lg_cde = 0;
|
||||
|
||||
cde[lg_cde ++] = 1; // 0=DDC (I2C), 1=UART, 3=USB, 4=SPI
|
||||
cde[lg_cde ++] = 0; // Reserved
|
||||
cde[lg_cde ++] = 0; // TxReady LSB b0=Enable, etc...
|
||||
cde[lg_cde ++] = 0; // TxReady MSB
|
||||
cde[lg_cde ++] = 0b11000000; // Mode LLSB b6 & b7 = baud rate (0b11=8 bits)
|
||||
cde[lg_cde ++] = 0b00001000; // Mode LSB b1, b2 & b3 = parity (0b10x=No_parity), b4 & b5 = stop bit (0b00=1_stop_bit)
|
||||
cde[lg_cde ++] = 0; // Mode MSB reserved
|
||||
cde[lg_cde ++] = 0; // Mode MMSB reserved
|
||||
cde[lg_cde ++] = 0x80; // Baud rate LLSB 9600b/s = 0x0000 2580
|
||||
cde[lg_cde ++] = 0x25; // Baud rate LSB
|
||||
cde[lg_cde ++] = 0x00; // Baud rate MSB
|
||||
cde[lg_cde ++] = 0x00; // Baud rate MMSB
|
||||
cde[lg_cde ++] = 0b00000001; // Masque protocoles In LSB b0 = UBX, b1=NMEA
|
||||
cde[lg_cde ++] = 0; // Masque protocoles In MSB reserved
|
||||
//cde[lg_cde ++] = 0b00000011; // Masque protocoles Out LSB b0 = UBX, b1=NMEA
|
||||
cde[lg_cde ++] = 0b00000001; // Masque protocoles Out LSB b0 = UBX, b1=NMEA
|
||||
cde[lg_cde ++] = 0; // Masque protocoles Out MSB reserved
|
||||
cde[lg_cde ++] = 0; // Flag bits LSB
|
||||
cde[lg_cde ++] = 0; // Flag bits MSB
|
||||
cde[lg_cde ++] = 0; // Reserved
|
||||
cde[lg_cde ++] = 0; // Reserved
|
||||
|
||||
if (g_bus_down_commande_libre(G_COMMANDE_CLASSE_CFG, G_COMMANDE_UBX_CFG_PRT, cde, lg_cde, M_BUS_PROTOCOLE_NORMAL, 0, -1) == 0) affichage_debug(__FILE__, __LINE__, "L'UART du GNSS est passé en mode µBX uniquement", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
else affichage_debug(__FILE__, __LINE__, "Le passage de l'UART du GNSS en mode µBX uniquement a échoué", TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------
|
||||
// Commande lecture de la configuration du GNSS :
|
||||
//----------------------------------------------
|
||||
lg_cde = 0;
|
||||
|
||||
if (g_bus_down_commande_libre(G_COMMANDE_CLASSE_MON, G_COMMANDE_UBX_MON_VER, cde, lg_cde, M_BUS_PROTOCOLE_NORMAL, 0, -1) == 0) affichage_debug(__FILE__, __LINE__, "La commande de lecture de la version du GNSS a été effectuée avec succés", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
else affichage_debug(__FILE__, __LINE__, "La commande de lecture de la version du GNSS a échoué", TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
|
||||
/* //----------------------------------------------
|
||||
// Commande de configuration étendue du power management :
|
||||
//----------------------------------------------
|
||||
// Cf Page 235 : 32.10.23.1 Extended power management configuration
|
||||
lg_cde = 0;
|
||||
|
||||
cde[lg_cde ++] = 0x01; // Message version (0x01 for this version)
|
||||
cde[lg_cde ++] = 0; // Reserved
|
||||
cde[lg_cde ++] = 0; // Maximum time to spend in Acquisition state. If 0: bound disabled (see maxStartupStateDur)
|
||||
cde[lg_cde ++] = 0; // Reserved
|
||||
|
||||
cde[lg_cde ++] = 0b01100000; // PSM config flag LLSB b4 = ExtintSel : 0 (Extint0) ou 1 (Extint1), b5 = ExtintWake : 0 (disabled) ou 1 (enabled), b6 = ExtintBackup : 0 (disabled) ou 1 (enabled)
|
||||
cde[lg_cde ++] = 0b00000000; // PSM config flag LSB b0 & b1 = LimitPeakCurrent : 00 (disabled) ou 01 (enabled) ou 10/11 (reserved), b2 = WaitTimeFix : 0 (wait for normal fix OK before starting on time) ou (1) wait for time fix OK before starting on time, b3 = UpdateRTC : 0 (do not wake up to update RTC. RTC is updated during normal on-time) ou 1 (update RTC. The receiver adds extra wake-up cycles to update the RTC), b4 = UpdateEPH = b4 : 0 (do not wake up to update Ephemeris data) ou 1 (update Ephemeris. The receiver adds extra wake-up cycles to update the Ephemeris data)
|
||||
cde[lg_cde ++] = 0b00000010; // PSM config flag MSB b0 = DoNotEnterOFff : 0 (receiver enters [Inactive] Awaiting next search state) ou 1 (receiver does not enter [Inactive] Awaiting next search state but keeps trying to acquire a fix instead), b1 & b2 = Mode : 00 ON/OFF operation ou 01 cyclic tracking operation (PSMCT) ou 10/11 reserved
|
||||
cde[lg_cde ++] = 0; // PSM config flag MMSB reserved
|
||||
|
||||
cde[lg_cde ++] = 0xE8; // Position Update period LLSB (Uint32_t) en ms 1000ms = 0x0000 03E8
|
||||
cde[lg_cde ++] = 0x03; // Position Update period LSB (Uint32_t) en ms
|
||||
cde[lg_cde ++] = 0x00; // Position Update period MSB (Uint32_t) en ms
|
||||
cde[lg_cde ++] = 0x00; // Position Update period MMSB (Uint32_t) en ms
|
||||
|
||||
cde[lg_cde ++] = 0x64; // Acquiisition retry period LLSB (Uint32_t) en ms 100ms = 0x0000 0064
|
||||
cde[lg_cde ++] = 0x00; // Acquiisition retry period LSB (Uint32_t) en ms
|
||||
cde[lg_cde ++] = 0x00; // Acquiisition retry period MSB (Uint32_t) en ms
|
||||
cde[lg_cde ++] = 0x00; // Acquiisition retry period MMSB (Uint32_t) en ms
|
||||
|
||||
cde[lg_cde ++] = 0x00; // Grids offset relative to GPS start of week LLSB (Uint32_t) en ms Not used...
|
||||
cde[lg_cde ++] = 0x00; // Acquiisition retry period LSB (Uint32_t)
|
||||
cde[lg_cde ++] = 0x00; // Acquiisition retry period MSB (Uint32_t)
|
||||
cde[lg_cde ++] = 0x00; // Acquiisition retry period MMSB (Uint32_t)
|
||||
|
||||
cde[lg_cde ++] = 0x05; // Ontime - time to stay in TRACKING State LSB (uint16_t) en s
|
||||
cde[lg_cde ++] = 0x00; // Ontime - time to stay in TRACKING State MSB (uint16_t) en s
|
||||
|
||||
cde[lg_cde ++] = 0x05; // Minimal search time LSB (uint16_t) en s
|
||||
cde[lg_cde ++] = 0x00; // Minimal search time MSB (uint16_t)
|
||||
|
||||
for (i = 0; i < 20; i ++) cde[lg_cde ++] = 0; // Reserved
|
||||
|
||||
if (g_bus_down_commande_libre(G_COMMANDE_CLASSE_CFG, G_COMMANDE_UBX_CFG_PM2, cde, lg_cde, M_BUS_PROTOCOLE_NORMAL, 0, -1) == 0) affichage_debug(__FILE__, __LINE__, "Le mode de pilotage du GNSS a ét configuré ", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
else affichage_debug(__FILE__, __LINE__, "La configuration du mode de pilotage du GNSS a échoué", TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
*/
|
||||
|
||||
//----------------------------------------------
|
||||
// Commande de configuration du Power Mode :
|
||||
//----------------------------------------------
|
||||
// Cf Page 242 : 32.10.24.1 Power Mode Setup
|
||||
lg_cde = 0;
|
||||
|
||||
cde[lg_cde ++] = 0; // Version (0x00 for this version)
|
||||
cde[lg_cde ++] = 0x03; // Power setup value : 0x00 = Full power, 0x01 = Balanced, 0x02 = Interval, 0x03 = Aggressive with 1 Hz, 0x04 = Aggressive with 2 Hz, 0x05 = Aggressive with 4 Hz, 0xFF = Invalid (only when polling)
|
||||
|
||||
cde[lg_cde ++] = 0x00; // LSB Position update period and search period (en secondes). Recommended minimum period is 10 s, although the receiver accepts any value bigger than 5 s. Only valid when powerSetupValue set to Interval, otherwise must be set to '0'.
|
||||
cde[lg_cde ++] = 0x00; // MSB ...
|
||||
|
||||
cde[lg_cde ++] = 0x00; // LSB Duration of the ON phase, must be smaller than the period. Only valid when powerSetupValue set to Interval, otherwise must be set to '0'.
|
||||
cde[lg_cde ++] = 0x00; // MSB ...
|
||||
|
||||
for (i = 0; i < 2; i ++) cde[lg_cde ++] = 0; // Reserved
|
||||
|
||||
if (g_bus_down_commande_libre(G_COMMANDE_CLASSE_CFG, G_COMMANDE_UBX_CFG_PMS, cde, lg_cde, M_BUS_PROTOCOLE_NORMAL, 0, -1) == 0) affichage_debug(__FILE__, __LINE__, "Le mode de pilotage du GNSS a été configuré ", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
else affichage_debug(__FILE__, __LINE__, "La configuration du mode de pilotage du GNSS a échoué", TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
|
||||
|
||||
gnss.sequenceur.compteur = GNSS_TEMPO_ATTENTE_FIN_INIT;
|
||||
gnss.sequenceur.etat = ETAT_SEQUENCEUR_GNSS_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_GNSS_REPOS :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (gnss.sequenceur.compteur == 0)
|
||||
{
|
||||
gnss.sequenceur.compteur = GNSS_PERIODE_MESURES;
|
||||
|
||||
//----------------------------------------------
|
||||
// Commande de lecture de la position :
|
||||
//----------------------------------------------
|
||||
lg_cde = 0;
|
||||
|
||||
if (g_bus_down_commande_libre(G_COMMANDE_CLASSE_NAV, G_COMMANDE_UBX_NAV_PVT, cde, lg_cde, M_BUS_PROTOCOLE_NORMAL, G_BUS_TIME_OUT_COMMANDE_UBX_NAV_PVT, -1) == 0) ;//affichage_debug(__FILE__, __LINE__, "La commande de lecture de la position GNSS a été effectuée avec succés", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
else affichage_debug(__FILE__, __LINE__, "La commande de lecture de la position GNSS a échoué", TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
default :
|
||||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur GNSS est inconnu [%i]. Il est repositionné au REPOS", gnss.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
gnss.sequenceur.etat = ETAT_SEQUENCEUR_GNSS_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
|
||||
Fichier GNSS.H
|
||||
|
||||
Contient tous les define liés au GNSS
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
|
||||
// Tempos :
|
||||
#define GNSS_TEMPO_INIT 20 // En x 100ms
|
||||
#define GNSS_TEMPO_ATTENTE_FIN_INIT 30 // En x 100ms Tempo nécessaire pour s'assurer que toutes les commandes de configuration sont bien exécutées avant de lancer les pollings.
|
||||
#define GNSS_PERIODE_MESURES 11 // En x 100ms Le GNSS effectue une mesure par seconde (1Hz) et ne répond à une commande de lecture qur lorsque une nouvelle acquisition est faite. Il est donc important d'avoir une période légèrement supérieure afin de ne pas remplir le buffer d'émission de G-Bus !!
|
||||
#define GNSS_PERIODE_SET_DATE_HEURE 600 // EN x 100ms Période à laquelle l'heure GNSS sera prise en compte pour mise à l'heure du CM4 et envoyée au Compagnon
|
||||
|
||||
// Fonctionnement GNSS :
|
||||
// #define GNSS_MAX_NOMBRE_CYCLES 180 // Nombre de cycles d'acquisition avant d'abandonner.
|
||||
// #define GNSS_NOMBRE_CYCLES_VALIDES 20 // Nombre de cycles valides (pas forcément consécutifs) sur une même période avant de considérer la période comme terminée. Cette valeur est importante pour avoir une précision suffisante...
|
||||
|
||||
|
||||
// Etats du séquenceur Modem :
|
||||
#define ETAT_SEQUENCEUR_GNSS_INIT 0
|
||||
#define ETAT_SEQUENCEUR_GNSS_REPOS 1
|
||||
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier HARDWARE.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à l'interface avec le matériel.
|
||||
// En particulier, permet de s'affranchir de l'utilisation de la bibiliothèque BCM2835...
|
||||
//
|
||||
// Les documents utilisés sont essentiellement :
|
||||
// - http://elinux.org/RPi_Low-level_peripherals très bon article dédié au Raspberry Pi et décrivant bien les différentes versions de RASPI.
|
||||
// - http://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf est la base de la documentation car la VRAIE doc du processeur...
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int gestion_timer(void);
|
||||
void timer(void);
|
||||
int init_timer(void);
|
||||
int init_memory_map(void);
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_hardware hardware;
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction TIMER
|
||||
|
||||
Fonction de gestion du signal de timer Linux (programmé pour se déclencher toutes les 10ms)
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void timer(void)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
|
||||
hardware.dizaines_ms ++;
|
||||
|
||||
//-------------------------------------------------- 10 ms --------------------------------------------------
|
||||
// Capteurs.c :
|
||||
if (capteurs.sequenceur.compteur > 0) capteurs.sequenceur.compteur --;
|
||||
|
||||
// Circuits.c :
|
||||
if (circuits.sequenceur.compteur > 0) circuits.sequenceur.compteur --;
|
||||
for (i=0; i<MAX_NOMBRE_CIRCUITS; i++)
|
||||
{
|
||||
if (circuits.circuits[i].sequenceur.compteur > 0) circuits.circuits[i].sequenceur.compteur --;
|
||||
}
|
||||
|
||||
// Ecran.c
|
||||
if (ecran.sequenceur.compteur > 0) ecran.sequenceur.compteur --;
|
||||
|
||||
// Entrees.c :
|
||||
if (entrees.core.sequenceur.compteur > 0) entrees.core.sequenceur.compteur --;
|
||||
if (entrees.gpio.sequenceur.compteur > 0) entrees.gpio.sequenceur.compteur --;
|
||||
if (entrees.level_sensor.sequenceur.compteur > 0) entrees.level_sensor.sequenceur.compteur --;
|
||||
|
||||
// Events.c :
|
||||
if (events.sequenceur.compteur > 0) events.sequenceur.compteur --;
|
||||
|
||||
// Gestion_bdd.c :
|
||||
if (bdd.compteur_synchro > 0) bdd.compteur_synchro --;
|
||||
|
||||
// Systeme.c :
|
||||
if (systeme.sequenceur.compteur > 0) systeme.sequenceur.compteur --;
|
||||
|
||||
|
||||
//-------------------------------------------------- 100 ms --------------------------------------------------
|
||||
if ((hardware.dizaines_ms % 10) == 0)
|
||||
{
|
||||
// Audio.c
|
||||
if (audio.sequenceur.compteur > 0) audio.sequenceur.compteur --;
|
||||
|
||||
// Batteries.c :
|
||||
if (batteries.sequenceur.compteur > 0) batteries.sequenceur.compteur --;
|
||||
|
||||
// C_bus.c :
|
||||
if (c_bus.sequenceur.compteur > 0) c_bus.sequenceur.compteur --;
|
||||
if (c_bus.sequenceur.compteur_time_out > 0) c_bus.sequenceur.compteur_time_out --;
|
||||
if (c_bus.protocole_rx.sequenceur.compteur > 0) c_bus.protocole_rx.sequenceur.compteur --;
|
||||
if (c_bus.protocole_rx.sequenceur.compteur_time_out > 0) c_bus.protocole_rx.sequenceur.compteur_time_out --;
|
||||
if (c_bus.protocole_tx.sequenceur.compteur > 0) c_bus.protocole_tx.sequenceur.compteur --;
|
||||
if (c_bus.protocole_tx.sequenceur.compteur_time_out > 0) c_bus.protocole_tx.sequenceur.compteur_time_out --;
|
||||
|
||||
// Circuits.c :
|
||||
for (i=0; i<MAX_NOMBRE_CIRCUITS; i++)
|
||||
{
|
||||
if (circuits.circuits[i].compteur_time_out > 0) circuits.circuits[i].compteur_time_out --;
|
||||
}
|
||||
|
||||
// Events.c :
|
||||
for (i=0; i<events.nb; i++)
|
||||
{
|
||||
if (events.events[i].sequenceur.compteur > 0) events.events[i].sequenceur.compteur --;
|
||||
}
|
||||
|
||||
// Fonctions.c :
|
||||
if (tempo_delai_dixieme_sec > 0) tempo_delai_dixieme_sec --; // Utilisé par la fonction DELAI_DIXIEME_SECONDE.
|
||||
|
||||
// G_bus.c :
|
||||
if (g_bus.sequenceur.compteur > 0) g_bus.sequenceur.compteur --;
|
||||
if (g_bus.sequenceur.compteur_time_out > 0) g_bus.sequenceur.compteur_time_out --;
|
||||
if (g_bus.protocole_rx.sequenceur.compteur > 0) g_bus.protocole_rx.sequenceur.compteur --;
|
||||
if (g_bus.protocole_rx.sequenceur.compteur_time_out > 0) g_bus.protocole_rx.sequenceur.compteur_time_out --;
|
||||
if (g_bus.protocole_tx.sequenceur.compteur > 0) g_bus.protocole_tx.sequenceur.compteur --;
|
||||
if (g_bus.protocole_tx.sequenceur.compteur_time_out > 0) g_bus.protocole_tx.sequenceur.compteur_time_out --;
|
||||
|
||||
// Gnss.c :
|
||||
if (gnss.sequenceur.compteur > 0) gnss.sequenceur.compteur --;
|
||||
if (gnss.sequenceur.compteur_time_out > 0) gnss.sequenceur.compteur_time_out --;
|
||||
|
||||
// Gestion_bdd.c :
|
||||
if (bdd.compteur > 0) bdd.compteur --;
|
||||
if (bdd.compteur_enregistrement_mesures > 0) bdd.compteur_enregistrement_mesures --;
|
||||
|
||||
// M_bus.c :
|
||||
if (m_bus.sequenceur.compteur > 0) m_bus.sequenceur.compteur --;
|
||||
if (m_bus.sequenceur.compteur_time_out > 0) m_bus.sequenceur.compteur_time_out --;
|
||||
if (m_bus.protocole_rx.sequenceur.compteur > 0) m_bus.protocole_rx.sequenceur.compteur --;
|
||||
if (m_bus.protocole_rx.sequenceur.compteur_time_out > 0) m_bus.protocole_rx.sequenceur.compteur_time_out --;
|
||||
if (m_bus.protocole_tx.sequenceur.compteur > 0) m_bus.protocole_tx.sequenceur.compteur --;
|
||||
if (m_bus.protocole_tx.sequenceur.compteur_time_out > 0) m_bus.protocole_tx.sequenceur.compteur_time_out --;
|
||||
|
||||
// Modem.c :
|
||||
if (modem.sequenceur.compteur > 0) modem.sequenceur.compteur --;
|
||||
if (modem.sequenceur.compteur_time_out > 0) modem.sequenceur.compteur_time_out --;
|
||||
|
||||
// Nmea.c :
|
||||
if (nmea.sequenceur.compteur > 0) nmea.sequenceur.compteur --;
|
||||
|
||||
// Reseaux.c
|
||||
if (reseaux.sequenceur.compteur > 0) reseaux.sequenceur.compteur --;
|
||||
if (reseaux.compteur_check_adresses_ip > 0) reseaux.compteur_check_adresses_ip --;
|
||||
|
||||
// Reservoirs.c :
|
||||
if (reservoirs.sequenceur.compteur > 0) reservoirs.sequenceur.compteur --;
|
||||
|
||||
// Systeme.c :
|
||||
if (chargement_code.sequenceur.compteur > 0) chargement_code.sequenceur.compteur --;
|
||||
if (chargement_code.sequenceur.compteur_time_out > 0) chargement_code.sequenceur.compteur_time_out --;
|
||||
if (systeme.faucheuse.compteur > 0) systeme.faucheuse.compteur --;
|
||||
if (systeme.sequenceur.compteur_time_out > 0) systeme.sequenceur.compteur_time_out --;
|
||||
|
||||
// Usb.c
|
||||
if (usb.sequenceur.compteur > 0) usb.sequenceur.compteur --;
|
||||
}
|
||||
|
||||
//-------------------------------------------------- 1000 ms = 1s --------------------------------------------------
|
||||
if (hardware.dizaines_ms >= 100)
|
||||
{
|
||||
// affichage_debug(__FILE__, __LINE__, "Timer: 1 seconde", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
hardware.dizaines_ms = 0; // RAZ du compteur toutes les 100 boucles (1000 ms)
|
||||
|
||||
// Batteries.c :
|
||||
for (i=0; i<MAX_NOMBRE_BATTERIES; i++)
|
||||
{
|
||||
if (batteries.batteries[i].sequenceur.compteur > 0) batteries.batteries[i].sequenceur.compteur --;
|
||||
}
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_MODULES; i++)
|
||||
{
|
||||
if (systeme.modules_config[i].courant_maxi_compteur > 0) systeme.modules_config[i].courant_maxi_compteur --;
|
||||
}
|
||||
|
||||
// Events.c :
|
||||
if (events.sequenceur.compteur_time_out > 0) events.sequenceur.compteur_time_out --;
|
||||
|
||||
// Reseaux.c :
|
||||
if (reseaux.compteur_connexion_ship2net > 0) reseaux.compteur_connexion_ship2net --;
|
||||
if (reseaux.compteur_scan_sta > 0) reseaux.compteur_scan_sta --;
|
||||
if (reseaux.compteur_check_webgl > 0) reseaux.compteur_check_webgl --;
|
||||
|
||||
// Systeme.c :
|
||||
if (systeme.compteur_check_new_download > 0) systeme.compteur_check_new_download --;
|
||||
if (systeme.compteur_sauvegarde_bdd > 0) systeme.compteur_sauvegarde_bdd --;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_TIMER
|
||||
|
||||
Initialise le Timer Linux
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int init_timer(void)
|
||||
{
|
||||
struct itimerval valeur_timer;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
// Init des variables globales :
|
||||
hardware.dizaines_ms = 0;
|
||||
|
||||
// Mise en place du handler de signal vers la fonction TIMER() :
|
||||
if (signal(SIGALRM, (void (*)(int)) timer) == SIG_ERR)
|
||||
{
|
||||
sprintf(tmp, "Mise en place du handler de timer impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
// Calcul des paramètres de chargement du timer :
|
||||
if ((BASE_TEMPS_TIMER/1000) > 0)
|
||||
{
|
||||
valeur_timer.it_value.tv_sec = BASE_TEMPS_TIMER / 1000;
|
||||
valeur_timer.it_value.tv_usec = (BASE_TEMPS_TIMER % 1000) * 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
valeur_timer.it_value.tv_sec = 0;
|
||||
valeur_timer.it_value.tv_usec = (BASE_TEMPS_TIMER * 1000);
|
||||
}
|
||||
valeur_timer.it_interval = valeur_timer.it_value;
|
||||
|
||||
// Chargement et lancement du timer :
|
||||
if (setitimer(ITIMER_REAL, &valeur_timer, NULL) == -1)
|
||||
{
|
||||
sprintf(tmp, "\tLancement du timer impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "Lancement du timer Linux (période = %i ms)\t\t\t\t\t: OK", BASE_TEMPS_TIMER);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_MEMORY_MAP
|
||||
|
||||
Créée une nouvelle projection dans l'espace d'adressage virtuel. Utilise la fonction MMAP de Linux.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int init_memory_map()
|
||||
{
|
||||
int mem_fd;
|
||||
off_t offset;
|
||||
void *ptr_map;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
//------------------------------------
|
||||
// Initialisation dépendant de la génération de ShipBase :
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1)
|
||||
{
|
||||
offset = BCM2837_ADRESSE_BASE_PERIPH + CM3P_OFFSET_GPIO_BASE;
|
||||
|
||||
hardware.offset_gpio_out_set_0 = CM3P_OFFSET_GPIO_OUT_SET_0;
|
||||
hardware.offset_gpio_out_set_1 = CM3P_OFFSET_GPIO_OUT_SET_1;
|
||||
hardware.offset_gpio_out_clear_0 = CM3P_OFFSET_GPIO_OUT_CLEAR_0;
|
||||
hardware.offset_gpio_out_clear_1 = CM3P_OFFSET_GPIO_OUT_CLEAR_1;
|
||||
hardware.offset_gpio_pin_level_0 = CM3P_OFFSET_GPIO_PIN_LEVEL_0;
|
||||
hardware.offset_gpio_pin_level_1 = CM3P_OFFSET_GPIO_PIN_LEVEL_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = BCM2711_ADRESSE_BASE_PERIPH + CM4_OFFSET_GPIO_BASE;
|
||||
|
||||
hardware.offset_gpio_out_set_0 = CM4_OFFSET_GPIO_OUT_SET_0;
|
||||
hardware.offset_gpio_out_set_1 = CM4_OFFSET_GPIO_OUT_SET_1;
|
||||
hardware.offset_gpio_out_clear_0 = CM4_OFFSET_GPIO_OUT_CLEAR_0;
|
||||
hardware.offset_gpio_out_clear_1 = CM4_OFFSET_GPIO_OUT_CLEAR_1;
|
||||
hardware.offset_gpio_pin_level_0 = CM4_OFFSET_GPIO_PIN_LEVEL_0;
|
||||
hardware.offset_gpio_pin_level_1 = CM4_OFFSET_GPIO_PIN_LEVEL_1;
|
||||
}
|
||||
|
||||
// Ouverture du fichier /dev/mem :
|
||||
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
|
||||
{
|
||||
sprintf(tmp, "Ouverture de [/dev/mem] impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return (-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// sprintf(tmp, "Ouverture de [/dev/mem] \t\t\t\t: OK");
|
||||
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
|
||||
// ****************************************************************************************************************
|
||||
// mmap du GPIO :
|
||||
ptr_map = mmap(
|
||||
NULL, // Any adddress in our space will do (indique l'endroit où est stocké le mapping...)
|
||||
BLOCK_SIZE, // Map length
|
||||
PROT_READ|PROT_WRITE, // Enable reading & writting to mapped memory
|
||||
MAP_SHARED, // Shared with other processes
|
||||
mem_fd, // File to map
|
||||
offset // Offset to GPIO peripheral
|
||||
);
|
||||
|
||||
if (ptr_map == MAP_FAILED)
|
||||
{
|
||||
sprintf(tmp, "Erreur 'mmap' pour création de l'espace GPIO. Erreur : %p", ptr_map);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "Initialisation de 'mmap' pour création de l'espace GPIO\t\t\t: OK");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
|
||||
// Toujours utiliser un pointeur VOLATILE (permet de limiter l'optimisation du compilateur et de forcer TOUS les accès au matériel)
|
||||
hardware.gpio_base = (volatile uint32_t *)ptr_map;
|
||||
|
||||
// ****************************************************************************************************************
|
||||
// Fermeture du fichier /dev/mem :
|
||||
close(mem_fd); //No need to keep mem_fd open after mmap
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/**********************************************************************************************************************************************************************************␍␍ Fichier HARDWARE.H ␍␍ Contient tous les define liés à l'interface avec le matériel.␍␍**********************************************************************************************************************************************************************************/␍␍// Nombre max physique :␍␍␍␍// Timings :␍#define BASE_TEMPS_TIMER 10 // En ms␍␍␍//**********************************************************************************************************************************************************************************␍// General :␍//**********************************************************************************************************************************************************************************␍␍#define PAGE_SIZE (4*1024)␍#define BLOCK_SIZE (4*1024)␍␍ // CM3+ :␍#define BCM2837_ADRESSE_BASE_PERIPH 0x3F000000 // Adresse physique de base de la zone I/O PERIPHERALS à partir de RPI 3 (idem RPI 2)␍␍ // CM4 :␍#define BCM2711_ADRESSE_BASE_PERIPH 0xFE000000 // Adresse physique de base de la zone I/O PERIPHERALS pour CM4 ␍␍␍␍//**********************************************************************************************************************************************************************************␍// General Purpose IO (GPIO) :␍//**********************************************************************************************************************************************************************************␍␍ // CM3+ :␍#define CM3P_OFFSET_GPIO_BASE 0x200000␍ ␍#define CM3P_OFFSET_GPIO_OUT_SET_0 7 // Positionne à HIGH les sorties 0 à 31 (1 bit / sortie) - (cf page 95)␍#define CM3P_OFFSET_GPIO_OUT_SET_1 8 // Positionne à HIGH les sorties 32 à 53 (1 bit / sortie) - (cf page 95)␍␍#define CM3P_OFFSET_GPIO_OUT_CLEAR_0 10 // Positionne à LOW les sorties 0 à 31 (1 bit / sortie) - (cf page 95)␍#define CM3P_OFFSET_GPIO_OUT_CLEAR_1 11 // Positionne à LOW les sorties 32 à 53 (1 bit / sortie) - (cf page 95 & 96)␍␍#define CM3P_OFFSET_GPIO_PIN_LEVEL_0 13 // Lecture des IO 0 à 31 (1 bit / IO) - (cf page 96)␍#define CM3P_OFFSET_GPIO_PIN_LEVEL_1 14 // Lecture des IO 32 à 53 (1 bit / IO) - (cf page 96)␍␍#define CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE 37 // Config du type de pull-up/pull-down à utiliser lors de l'application de la ENABLE_CLOCK suivante (2 bits au total) - (cf page 101)␍#define CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE_CLOCK_0 38 // Config des IO 0 à 31 (1 bit / IO) qui seront soumis au pull-up/pull-down ci-dessus - (cf page 101)␍#define CM3P_OFFSET_GPIO_PIN_PULL_UP_DOWN_ENABLE_CLOCK_1 39 // Config des IO 32 à 53 (1 bit / IO) qui seront soumis au pull-up/pull-down ci-dessus - (cf page 101)␍␍#define CM3P_NO_PUP_PDN 0x00 // 00 = No resistor is selected␍#define CM3P_PULL_DOWN 0x01 // 01 = Enable Pull Down control␍#define CM3P_PULL_UP 0x02 // 10 = Enable Pull Up control␍␍␍ // CM4 :␍#define CM4_OFFSET_GPIO_BASE 0x200000 ␍ ␍#define CM4_OFFSET_GPIO_OUT_SET_0 7 // Positionne à HIGH les sorties 0 à 31 (1 bit / sortie) - (cf page 95)␍#define CM4_OFFSET_GPIO_OUT_SET_1 8 // Positionne à HIGH les sorties 32 à 53 (1 bit / sortie) - (cf page 95)␍␍#define CM4_OFFSET_GPIO_OUT_CLEAR_0 10 // Positionne à LOW les sorties 0 à 31 (1 bit / sortie) - (cf page 95)␍#define CM4_OFFSET_GPIO_OUT_CLEAR_1 11 // Positionne à LOW les sorties 32 à 53 (1 bit / sortie) - (cf page 95 & 96)␍␍#define CM4_OFFSET_GPIO_PIN_LEVEL_0 13 // Lecture des IO 0 à 31 (1 bit / IO) - (cf page 96)␍#define CM4_OFFSET_GPIO_PIN_LEVEL_1 14 // Lecture des IO 32 à 53 (1 bit / IO) - (cf page 96)␍␍#define CM4_OFFSET_GPIO_PUP_PDN_CNTRL_REG0 57 // The GPIO Pull-up / Pull-down Registers control the actuation of the internal pull-up/down resistors. Reading these registers gives the current pull-state. (cf page 74)␍#define CM4_OFFSET_GPIO_PUP_PDN_CNTRL_REG1 58␍#define CM4_OFFSET_GPIO_PUP_PDN_CNTRL_REG2 59␍#define CM4_OFFSET_GPIO_PUP_PDN_CNTRL_REG3 60␍␍#define CM4_NO_PUP_PDN 0x00 // 00 = No resistor is selected␍#define CM4_PULL_UP 0x01 // 01 = Pull up resistor is selected␍#define CM4_PULL_DOWN 0x02 // 10 = Pull down resistor is selected␍␍ // Type d'E/S utilisés dans GPIO_FUNCTION_SEL_x :␍#define GPIO_TYPE_INPUT 0x00␍#define GPIO_TYPE_OUTPUT 0x01␍#define GPIO_TYPE_ALT_FUNCTION_0 0x04␍#define GPIO_TYPE_ALT_FUNCTION_1 0x05␍#define GPIO_TYPE_ALT_FUNCTION_2 0x06␍#define GPIO_TYPE_ALT_FUNCTION_3 0x07␍#define GPIO_TYPE_ALT_FUNCTION_4 0x03␍#define GPIO_TYPE_ALT_FUNCTION_5 0x02␍#define GPIO_TYPE_UNKNOWN 0xFF␍ ␍ // Type de pull-up/down :␍#define NO_PUP_PDN 0␍#define PULL_DOWN 1␍#define PULL_UP 2␍␍
|
||||
@@ -0,0 +1,95 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fichier LOCALISATION.H
|
||||
Contient toutes les définitions liées au site (donc tous les autres doivent être indépendants du site...)
|
||||
**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Base de données :
|
||||
#define BDD_SERVER "localhost"
|
||||
#define BDD_USER "koriolan"
|
||||
#define BDD_PASSWORD "Mp7Hgf12bV9zm"
|
||||
#define BDD_DATABASE "shipheart"
|
||||
|
||||
|
||||
// Répertoires :
|
||||
#define REPERTOIRE_SHIPHEART "/home/koriolan/shipheart" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_VERSIONS_CURRENT "/home/koriolan/shipheart/versions/current" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_LOGS "/home/koriolan/shipheart/logs" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_CONFIG "/home/koriolan/shipheart/config" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_CONFIG_IMAGES_ACCUEIL "/home/koriolan/shipheart/config/images_accueil" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_CONFIG_IMAGES_SILHOUETTE "/home/koriolan/shipheart/config/images_silhouette" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_CONFIG_RAPPORTS "/home/koriolan/shipheart/config/rapports" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_CONFIG_SAUVEGARDES "/home/koriolan/shipheart/config/sauvegardes" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_CONFIG_SONS "/home/koriolan/shipheart/config/sons" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_UTILS "/home/koriolan/shipheart/utils" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_SERVER "/home/koriolan/shipheart/server" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_SERVER_UPLOAD "/home/koriolan/shipheart/server/upload" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_SERVER_DOWNLOAD "/home/koriolan/shipheart/server/download" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_VERSIONS "/home/koriolan/shipheart/versions" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_VERSIONS_A_VALIDER "/home/koriolan/shipheart/versions/a_valider" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_VERSIONS_A_CHARGER "/home/koriolan/shipheart/versions/a_charger" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_TMP "/home/koriolan/shipheart/tmp" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_TMP_BDD "/home/koriolan/shipheart/tmp/bdd" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_TMP_CORE "/home/koriolan/shipheart/tmp/core" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_TMP_SAUVEGARDE "/home/koriolan/shipheart/tmp/sauvegarde" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_TMP_USB "/home/koriolan/shipheart/tmp/usb" // Pas de '/' de fin...
|
||||
#define REPERTOIRE_TMP_WIFI "/home/koriolan/shipheart/tmp/wifi" // Pas de '/' de fin...
|
||||
|
||||
|
||||
// Fichiers :
|
||||
#define NOM_FICHIER_DEBUG "/home/koriolan/shipheart/logs/shipheart_appli_log.txt"
|
||||
#define NOM_FICHIER_DEBUG_TMP "/home/koriolan/shipheart/logs/shipheart_appli_log_tmp.txt"
|
||||
#define NOM_FICHIER_DEBUG_BUS "/home/koriolan/shipheart/logs/shipheart_appli_bus_log.txt"
|
||||
#define NOM_FICHIER_APPLICATION "shipheart_appli"
|
||||
#define NOM_FICHIER_QT "shipheart_qt"
|
||||
#define NOM_FICHIER_LISTING_REPERTOIRE_DOWNLOAD_SERVEUR "__list_download_serveur.txt"
|
||||
#define NOM_FICHIER_SAUVEGARDE_BDD "shipheart"
|
||||
#define NOM_FICHIER_CHECK_SAUVEGARDE "check_tmp"
|
||||
#define NOM_FICHIER_WPA_SUPPLICANT "/etc/wpa_supplicant/wpa_supplicant.conf"
|
||||
#define NOM_FICHIER_HOSTAPD "/etc/hostapd/hostapd.conf"
|
||||
#define NOM_FICHIER_ARCHIVAGE "archivage.php"
|
||||
#define NOM_FICHIER_CONNEXION_SHIP2NET "connexion_ship2net.php"
|
||||
#define NOM_FICHIER_CONNEXION_SHIP2NET_LOG "connexion_ship2net_log.txt"
|
||||
#define NOM_FICHIER_SCAN_WIFI_STA "scan_wifi_sta.txt"
|
||||
#define NOM_FICHIER_ETAT_ENTREES_CORE "etat_entrees_core.txt"
|
||||
|
||||
#define PREFIXE_NOM_FICHIER_ARCHIVAGE_LOG "log_archivage"
|
||||
|
||||
|
||||
// Suffixes de fichiers :
|
||||
#define SUFFIXE_NOUVEAU_FICHIER "_NEW"
|
||||
#define SUFFIXE_ANCIEN_FICHIER "_OLD"
|
||||
#define SUFFIXE_NOM_FICHIER_COMPRESSE_SAUVEGARDE_BDD "gz" // Extensions de type '.gz'
|
||||
#define SUFFIXE_NOM_FICHIER_ENCRYPTE_SAUVEGARDE_BDD "enc" // Extensions de type '.gz.enc' puisque l'encryption est faite après la compression
|
||||
|
||||
// Marqueurs de fichiers :
|
||||
#define MARQUEUR_FICHIER_JSON ".json" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_TAR_GZIP ".tar.gz" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_ENC ".enc" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_TAR_GZIP_ENC ".tar.gz.enc" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_BASH ".sh" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_APPLICATION "shipheart_appli" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_QT "shipheart_qt" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_COMPAGNON_V1 "shipheart_compagnon_v1" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_COMPAGNON_V2 "shipheart_compagnon_v2" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_SP812 "shipheart_sp812" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_SBS "shipheart_sbs" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_SP4AC "shipheart_sp4ac" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_SP8DC "shipheart_sp8dc" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
#define MARQUEUR_FICHIER_DONE ".DONE" // Attention : 'marqueur' veut dire qu'il est recherché partout dans le nom de fichier, pas uniquement à la fin...
|
||||
|
||||
|
||||
|
||||
// Serveur distant :
|
||||
#define SERVEUR_FTP_ADRESSE "ftp.cluster028.hosting.ovh.net"
|
||||
#define SERVEUR_FTP_USER "ciuqsga-bateaux"
|
||||
#define SERVEUR_FTP_PASSWORD "u7J9K45Df9Es"
|
||||
|
||||
#define SERVEUR_SSH_ADRESSE "ssh.cluster028.hosting.ovh.net"
|
||||
#define SERVEUR_SSH_USER SERVEUR_FTP_USER
|
||||
#define SERVEUR_SSH_PASSWORD SERVEUR_FTP_PASSWORD
|
||||
|
||||
|
||||
#define REPERTOIRE_SERVEUR "" // Pas de '/' à la fin... NB : le répertoire est /bateaux/<adresse_mac> mais comme le USER 'ciuqsga-bateaux' accède uniquement au répertoire "/bateaux", ce REPERTOIRE_SERVEUR est vide.
|
||||
#define REPERTOIRE_UPLOAD_DESTINATION "/upload" // Pas de '/' à la fin...
|
||||
#define REPERTOIRE_DOWNLOAD_SOURCE "/download" // Pas de '/' à la fin...
|
||||
|
||||
+415
@@ -0,0 +1,415 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier M_BUS.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à la gestion du M_Bus (liaison avec le Modem SIM7070G)
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
#define __DEBUG_M_BUS 0 // Passer cette ligne à 0: aucun message de debug de M_bus, 1: les messages de debug de M_Bus sur l'écran, 2: sur fichier (cf NOM_FICHIER_DEBUG_BUS dans 'debug.h') ou 3: sur l'écran et fichier.
|
||||
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t init_m_bus(void);
|
||||
void gestion_m_bus(void);
|
||||
int8_t gestion_protocole_rx_m_bus(void);
|
||||
void gestion_protocole_tx_m_bus(void);
|
||||
int8_t m_bus_next_write_buffer_cdes(uint8_t priorite);
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_m_bus m_bus;
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_M_BUS
|
||||
|
||||
Fonction d'initialisation du C-Bus
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_m_bus(void)
|
||||
{
|
||||
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1)
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------------
|
||||
// Init des variables générales :
|
||||
|
||||
m_bus.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_INIT;
|
||||
m_bus.sequenceur.compteur = M_BUS_TEMPO_INIT;
|
||||
|
||||
m_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_INIT;
|
||||
m_bus.protocole_rx.sequenceur.compteur = M_BUS_PROTOCOLE_RX_TEMPO_INIT;
|
||||
|
||||
m_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_TX_INIT;
|
||||
m_bus.protocole_tx.sequenceur.compteur = M_BUS_PROTOCOLE_TX_TEMPO_INIT;
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation du M-BUS\t\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation du M-BUS\t\t: Devalidé car non valide sur cette version de ShipBase", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction GESTION_M_BUS
|
||||
|
||||
Fonction de plus haut niveau de gestion du C-Bus
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_m_bus(void)
|
||||
{
|
||||
int8_t ret;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
if (systeme.generation_shipbase != GENERATION_SHIPBASE_V1) return;
|
||||
|
||||
switch(m_bus.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_INIT :
|
||||
{
|
||||
if (m_bus.sequenceur.compteur == 0)
|
||||
{
|
||||
//.........................................................
|
||||
// Vidage du buffer de réception de tous les caractères reçus pendant la phase d'init :
|
||||
serial0.ptr_debut_buffer_rx = 0;
|
||||
serial0.ptr_fin_buffer_rx = 0;
|
||||
|
||||
//.........................................................
|
||||
// Vidage du buffer de commandes (utile dans le cas d'un reset du modem pour overflow) :
|
||||
m_bus.down.ptr_debut_buffer_cdes = 0;
|
||||
m_bus.down.ptr_fin_buffer_cdes = 0;
|
||||
|
||||
//.........................................................
|
||||
// Mise à jour des séquenceurs pour démarrage des envois :
|
||||
m_bus.protocole_rx.sequenceur.compteur = 0;
|
||||
m_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_REPOS;
|
||||
m_bus.protocole_tx.sequenceur.compteur = 0;
|
||||
m_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_TX_REPOS;
|
||||
|
||||
m_bus.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_REPOS :
|
||||
{
|
||||
if (modem.etat == ON) // Si le modem n'est pas ON, il est inutile d'essayer de communiquer avec lui.
|
||||
{
|
||||
//=================================
|
||||
// Gestion du M-Bus en émission :
|
||||
|
||||
gestion_protocole_tx_m_bus(); // Vérifie si une commande (Down) est en attente. Si oui, elle la traite et l'émet.
|
||||
|
||||
|
||||
//=================================
|
||||
// Gestion du M-Bus en réception :
|
||||
|
||||
ret = gestion_protocole_rx_m_bus();
|
||||
if (ret != 0) // Vérifie si une réponse (à une commande Down) a été reçue.
|
||||
{
|
||||
#ifdef __DEBUG_M_BUS
|
||||
m_bus.down.reponse.reponse[m_bus.down.reponse.lg_reponse] = 0; // On ajoute un /0 à la fin mais on ne change surtout pas la longueur qui est utilisée pour les transferts binaires.
|
||||
if (ret == 1) affichage_debug_bus(TYPE_BUS_DEBUG_M_BUS, "Rx", (char *) m_bus.down.reponse.reponse, __DEBUG_M_BUS); // Cas d'une réponse normale
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "[%li data bytes]", strlen((const char *)m_bus.down.reponse.reponse));
|
||||
affichage_debug_bus(TYPE_BUS_DEBUG_M_BUS, "Rx", tmp, __DEBUG_M_BUS); // Cas d'une réponse en mode binaire
|
||||
}
|
||||
#endif
|
||||
m_bus_down_analyse_reponse_commande();
|
||||
// Traitement de la réponse à la commande...
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur M-bus est inconnu [%i]. Il est repositionné au REPOS", m_bus.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
m_bus.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Appelée en tâche de fond, cette fonction lit le buffer de réception de l'UART 0 et traite les trames reçues (réponse du modem à une commande du CM3+)
|
||||
Reçoit : Rien
|
||||
Renvoit : 0 si RAS, 1 si une réponse complète a été reçue, 2 si réponse complète en mode binaire a été reçue
|
||||
******************************************************************************************************************************************************************/
|
||||
int8_t gestion_protocole_rx_m_bus(void)
|
||||
{
|
||||
uint8_t c;
|
||||
int8_t reponse_recue;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
reponse_recue = 0;
|
||||
|
||||
// Traitement de chaque caractère reçu :
|
||||
while (serial0.ptr_debut_buffer_rx != serial0.ptr_fin_buffer_rx)
|
||||
{
|
||||
// Calcul de la prochaine position à lire (avec bouclage en fin de buffer tournant) :
|
||||
if (++ serial0.ptr_debut_buffer_rx == MAX_TAILLE_RX_BUFFER_UART) serial0.ptr_debut_buffer_rx = 0;
|
||||
|
||||
// Lecture du caractère dans le buffer :
|
||||
c = serial0.buffer_rx[serial0.ptr_debut_buffer_rx]; // Lecture du caractère à traiter
|
||||
|
||||
// Traitement du caractère reçu :
|
||||
switch(m_bus.protocole_rx.sequenceur.etat)
|
||||
{
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_INIT :
|
||||
{
|
||||
// NB : Le caractère lu est jeté tant que la phase d'init n'est pas terminée...
|
||||
// NB 2 : le passage à l'état REPOS se fait par le séquenceur M-Bus, indépendemment de la réception ou non de caractères.
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_REPOS :
|
||||
{
|
||||
|
||||
if (c == ASCII_CR) // Attente de réception du CR de début de trame
|
||||
{
|
||||
m_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_ATTENTE_LF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_ATTENTE_LF :
|
||||
{
|
||||
|
||||
if (c == ASCII_CR) break; // Cas d'un CR qui suit un CR. On reste en attente d'un LF à venir...
|
||||
|
||||
if (c == ASCII_LF)
|
||||
{
|
||||
if (m_bus.down.reponse.lg_reponse != 0) reponse_recue = 1; // Si la longueur actuelle de réponse est nulle, on ne fait rien (on va juste revenir en mode data pour le prochain caractère)
|
||||
|
||||
m_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_DATA; // Dans tous les cas, après un CR/LF, on passe en mode Data car il arrive qu'un CR/LF soit juste un séparateur entre plusieurs blocs (il y a donc une fin mais pas de "début" suivant)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_DATA :
|
||||
{
|
||||
|
||||
if (c != ASCII_CR) m_bus.down.reponse.reponse[m_bus.down.reponse.lg_reponse ++] = c;
|
||||
else
|
||||
{
|
||||
m_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_ATTENTE_LF;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_FLUX_BINAIRE:
|
||||
{
|
||||
m_bus.down.reponse.reponse[m_bus.down.reponse.lg_reponse ++] = c;
|
||||
if (m_bus.down.reponse.lg_reponse == m_bus.down.reponse.lg_reponse_attendue)
|
||||
{
|
||||
reponse_recue = 2;
|
||||
m_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur M-Bus.Protocole_Rx est inconnu [%i]. Il est repositionné au REPOS", m_bus.protocole_rx.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
m_bus.protocole_rx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reponse_recue != 0) break;
|
||||
|
||||
}
|
||||
|
||||
return(reponse_recue);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Appelée en tâche de fond, cette fonction vérifie si une commande est prête à être émise
|
||||
dans le buffer de commandes Down. Si oui, elle gère via son séquenceur le formattage de la trame à émettre.
|
||||
Reçoit : Rien
|
||||
Renvoit : Rien
|
||||
*****************************************************************************************************************************************************************/
|
||||
void gestion_protocole_tx_m_bus(void)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t tx_buffer[M_BUS_MAX_TAILLE_BUFFER_TX];
|
||||
uint16_t lg_tx_buffer;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
switch(m_bus.protocole_tx.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_TX_INIT :
|
||||
{
|
||||
// NB : le passage à l'état REPOS se fait par le séquenceur C-Bus, indépendemment de la présence de commande à émettre
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_TX_REPOS :
|
||||
{
|
||||
//..................................
|
||||
// Recherche d'une trame à émettre :
|
||||
|
||||
if (m_bus.down.flag_attente_reponse) // Cas où une commande Down a déjà été émise et qu'on est en attente de réponse :
|
||||
{
|
||||
if (m_bus.protocole_tx.sequenceur.compteur_time_out == 0) // On vérifie alors si le time-out a expiré :
|
||||
{
|
||||
m_bus.down.flag_attente_reponse = FALSE; // RAZ du flag (qui sera éventuellement remis à 1 si la répétition a lieu)
|
||||
m_bus.protocole_tx.repetitions ++; // Incrémentation du nombre de répétitions
|
||||
if (m_bus.protocole_tx.repetitions > m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].max_repetitions) // Si le nombre maxi de répétitions a été dépassé, on laisse tomber la commande
|
||||
{
|
||||
|
||||
// !!! Il serait peut-être intéressant d'informer la couche supérieure que la commande est abandonnée sans avoir obtenu de réponse malgré N répétitions...
|
||||
// ==>>> Si oui, c'est ici qu'il faut le mettre....
|
||||
|
||||
m_bus.protocole_tx.repetitions = 0; // RAZ du compteur pour utilisation ultérieure
|
||||
break; // Sortie du séquenceur
|
||||
}
|
||||
}
|
||||
else break; // Tant qu'on est en attente d'une réponse et que le time-out n'est pas expiré, on ne traite aucun envoi en mode Down
|
||||
}
|
||||
else // Sinon, recherche d'une nouvelle commande à émettre en mode Down :
|
||||
{
|
||||
if (m_bus.down.ptr_debut_buffer_cdes != m_bus.down.ptr_fin_buffer_cdes) // Cas où il y a une commande en attente d'émission...
|
||||
{
|
||||
// ATTENTION : gérer les priorités ...!
|
||||
|
||||
m_bus.down.reponse.etat = M_BUS_REPONSE_ETAT_REPOS; // On prépare le traitement de la réponse à venir.
|
||||
|
||||
if (++ m_bus.down.ptr_debut_buffer_cdes == M_BUS_MAX_TAILLE_BUFFER_CDES) m_bus.down.ptr_debut_buffer_cdes = 0;
|
||||
|
||||
#ifdef __DEBUG_M_BUS
|
||||
m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].cde[m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].lg_cde] = 0; // On ajoute un /0 à la fin mais on ne change surtout pas la longueur qui est utilisée pour les transferts binaires.
|
||||
if (m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].mode_protocole != M_BUS_PROTOCOLE_DATA_BINAIRE) affichage_debug_bus(TYPE_BUS_DEBUG_M_BUS, "Tx", (char *) m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].cde, __DEBUG_M_BUS);
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "[%i data bytes]", m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].lg_cde);
|
||||
affichage_debug_bus(TYPE_BUS_DEBUG_M_BUS, "Tx", tmp, __DEBUG_M_BUS); // Cas d'une réponse en mode binaire
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else break; // Il n'y a pas de nouvelle commande en attente d'émission
|
||||
}
|
||||
|
||||
//.....................................
|
||||
// Préparation de la trame d'émission :
|
||||
lg_tx_buffer = 0;
|
||||
|
||||
for (i=0; (i < m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].lg_cde) && (lg_tx_buffer < M_BUS_MAX_TAILLE_BUFFER_TX); i++)
|
||||
{
|
||||
tx_buffer[lg_tx_buffer ++] = m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].cde[i];
|
||||
}
|
||||
|
||||
if (m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].mode_protocole != M_BUS_PROTOCOLE_DATA_BINAIRE)
|
||||
{
|
||||
tx_buffer[lg_tx_buffer ++] = ASCII_CR;
|
||||
}
|
||||
|
||||
//.............................
|
||||
// Envoi au driver d'émission :
|
||||
write(config_serial0.filestream, tx_buffer, lg_tx_buffer);
|
||||
|
||||
//..........................................................
|
||||
// Mise à jour des paramètres après l'émission de la trame :
|
||||
m_bus.down.flag_attente_reponse = TRUE;
|
||||
m_bus.protocole_tx.sequenceur.compteur_time_out = m_bus.down.buffer_cdes[m_bus.down.ptr_debut_buffer_cdes].time_out;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur M-Bus.Protocole_Tx est inconnu [%i]. Il est repositionné au REPOS", m_bus.protocole_tx.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
m_bus.protocole_tx.sequenceur.etat = ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_TX_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************************************************************************************************
|
||||
Fonction : Incrémente le pointeur du buffer de commandes en attente d'émission vers C-Bus
|
||||
La fonction gère :
|
||||
- le rebouclage en fin de buffer (buffer circulaire)
|
||||
- le dépassement (quand la fin rattrape le début) en émettant un message de debug et en choissant :
|
||||
. soit d'écraser la commande la plus ancienne si elle est de priorité inférieure (strictement)
|
||||
. soit refuser l'ajout en laissant le pointeur de fin du buffer à sa position et en renvoyant une erreur.
|
||||
Reçoit : La priorité de la commande à ajouter (permet d'arbitrer dans la cas où le buffer est plein)
|
||||
Renvoit : 0 si une position disponible a été trouvée, -1 si aucune position n'est disponible.
|
||||
******************************************************************************************************************************************************************/
|
||||
int8_t m_bus_next_write_buffer_cdes(uint8_t priorite)
|
||||
{
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
// !!! La gestion des priorités n'est pas traitée ! A vérifier mais si on écrase le début, celui-ci est probablement en cours d'utilisation...
|
||||
// Donc ATTENTION !!!!
|
||||
|
||||
|
||||
// Incrémentation :
|
||||
if (++ m_bus.down.ptr_fin_buffer_cdes == M_BUS_MAX_TAILLE_BUFFER_CDES) m_bus.down.ptr_fin_buffer_cdes = 0;
|
||||
|
||||
// Vérification si buffer plein :
|
||||
if (m_bus.down.ptr_fin_buffer_cdes == m_bus.down.ptr_debut_buffer_cdes)
|
||||
{
|
||||
// Décrémentation du pointeur puisqu'on ne va pas accepter la nouvelle commande qui n'a pas une priorité suffisante :
|
||||
if (m_bus.down.ptr_fin_buffer_cdes == 0) m_bus.down.ptr_fin_buffer_cdes = (M_BUS_MAX_TAILLE_BUFFER_CDES - 1);
|
||||
else m_bus.down.ptr_fin_buffer_cdes --;
|
||||
|
||||
// Message de débug :
|
||||
sprintf(tmp, "Buffer de commandes M-Bus plein. La demande de stockage d'une nouvelle commande a été rejetée...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
// Enregistrement dans l'historique :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_BUS_BUFFER_COMMANDES_PLEIN, (uint32_t) 'M', 0, NULL);
|
||||
|
||||
return(-1);
|
||||
}
|
||||
else return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
|
||||
Fichier M_BUS.H
|
||||
|
||||
Contient tous les define liés au M_BUS
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define M_BUS_MAX_TAILLE_BUFFER_CDES 80 // Taille du buffer de commandes (donc on stocke plusieurs commandes entières !) M-bus en mode Down
|
||||
#define M_BUS_PROTOCOLE_TX_MAX_REPETITIONS 3 // Nombre de répétitions des commandes émises sur M_Bus
|
||||
#define M_BUS_MAX_TAILLE_BUFFER_TX 3050
|
||||
#define M_BUS_MAX_TAILLE_CDE 3000 // Nécessaire pour FTP
|
||||
#define M_BUS_MAX_TAILLE_REPONSE 3000
|
||||
#define M_BUS_MAX_REPETITIONS_TEMPO_POST_ACTIVATION_MODEM 30 // Cette valeur est à relier à la TEMPO_POST_ACTIVATION_MODEM. Le produit des deux donne la durée maximale avant de déclarer que le changement d'état attendu du modem a échoué.
|
||||
#define M_BUS_MAX_REFUS_BUFFER_CDES_PLEIN 12 // Au-delà de cette valeur, si un refus supplémentaire est rencontré, le Modem sera réinitialisé
|
||||
|
||||
|
||||
// Tempos :
|
||||
#define M_BUS_TEMPO_INIT 20 // En x 100ms
|
||||
#define M_BUS_TEMPO_IMPULSION_ACTIVATION_MODEM 12 // En x 100ms (Tmin = 1s selon datasheet du SIM7070G, page 26)
|
||||
#define M_BUS_TEMPO_POST_IMPULSION_ACTIVATION_MODEM 5 // En x 100ms Cette tempo est à relier au MAX_REPETITIONS_TEMPO_POST_ACTIVATION_MODEM ci-dessus.
|
||||
#define M_BUS_PROTOCOLE_RX_TEMPO_INIT 10 // en x 100ms
|
||||
#define M_BUS_PROTOCOLE_TX_TEMPO_INIT 10 // en x 100ms
|
||||
#define M_BUS_TIME_OUT_REPONSE_TX 3 // En x 100ms
|
||||
|
||||
|
||||
// Priorité des commandes :
|
||||
#define PRIORITE_CDE_M_BUS_FAIBLE 0
|
||||
#define PRIORITE_CDE_M_BUS_HAUTE 1
|
||||
|
||||
// Mode de traitement de la commande par le protocole :
|
||||
#define M_BUS_PROTOCOLE_NORMAL 0
|
||||
#define M_BUS_PROTOCOLE_DATA_BINAIRE 1 // Dans ce cas, aucun CR n'est ajouté en fin de commande
|
||||
|
||||
|
||||
// Etats du séquenceur C-Bus :
|
||||
#define ETAT_SEQUENCEUR_M_BUS_INIT 0
|
||||
#define ETAT_SEQUENCEUR_M_BUS_INIT_ACTIVATION_MODEM 1
|
||||
#define ETAT_SEQUENCEUR_M_BUS_INIT_IMPULSION_ACTIVATION_MODEM 2
|
||||
#define ETAT_SEQUENCEUR_M_BUS_INIT_ATTENTE_FIN_ACTIVATION_MODEM 3
|
||||
#define ETAT_SEQUENCEUR_M_BUS_REPOS 4
|
||||
|
||||
// Etats séquenceur du Protocole_Rx C-bus :
|
||||
#define ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_INIT 0
|
||||
#define ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_REPOS 1
|
||||
#define ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_ATTENTE_LF 2
|
||||
#define ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_DATA 3
|
||||
#define ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_RX_FLUX_BINAIRE 4
|
||||
|
||||
// Etats séquenceur du Protocole_Tx C-bus :
|
||||
#define ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_TX_INIT 0
|
||||
#define ETAT_SEQUENCEUR_M_BUS_PROTOCOLE_TX_REPOS 1
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier M_COMMANDES_.H
|
||||
//
|
||||
// Contient toutes définitions de constantes liées au commandes sur M_Bus
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
|
||||
// Valeur maximales
|
||||
#define M_COMMANDE_MAX_LONGUEUR_NOM_CDE 50
|
||||
#define M_COMMANDE_MAX_NOMBRE_PARAMETRES_REPONSE 20
|
||||
#define M_COMMANDE_MAX_LONGUEUR_PARAMETRE_REPONSE 100
|
||||
|
||||
// Codes commandes :
|
||||
#define M_COMMANDE_INCONNUE 0
|
||||
#define M_COMMANDE_ATE 1
|
||||
#define M_COMMANDE_CCID 2
|
||||
#define M_COMMANDE_CFUN 3
|
||||
#define M_COMMANDE_CGMR 4
|
||||
#define M_COMMANDE_CGNAPN 5
|
||||
#define M_COMMANDE_CGNSINF 6
|
||||
#define M_COMMANDE_CGSN 7
|
||||
#define M_COMMANDE_CIMI 8
|
||||
#define M_COMMANDE_CMGL 9
|
||||
#define M_COMMANDE_CNACT 10
|
||||
#define M_COMMANDE_CNACT_0_X 11
|
||||
#define M_COMMANDE_CNUM 12
|
||||
#define M_COMMANDE_CPSI 13
|
||||
#define M_COMMANDE_CREG 14
|
||||
#define M_COMMANDE_CSQ 15
|
||||
#define M_COMMANDE_FTPGET_1 16
|
||||
#define M_COMMANDE_FTPGET_2 17
|
||||
#define M_COMMANDE_FTPGET_2_1 18
|
||||
#define M_COMMANDE_FTPLIST_1 19
|
||||
#define M_COMMANDE_FTPLIST_2 20
|
||||
#define M_COMMANDE_FTPLIST_2_1 21
|
||||
#define M_COMMANDE_FTPSIZE 22
|
||||
#define M_COMMANDE_FTPPUT_1 23
|
||||
#define M_COMMANDE_FTPPUT_2 24
|
||||
#define M_COMMANDE_SHREAD 25
|
||||
#define M_COMMANDE_SHREQ 26
|
||||
#define M_COMMANDE_SHSTATE 27
|
||||
|
||||
#define M_COMMANDE_FTPPUT_ENVOI_DATA 50 // Commande envoyée en binaire
|
||||
#define M_COMMANDE_FTPLIST_RECEPTION_LISTE 51 // Réception d'un bloc de données (a priori ASCII mais pas forcément) contenant la liste lue
|
||||
#define M_COMMANDE_FTPGET_RECEPTION_DATA 52 // Réception d'un bloc de données binaires contenant un bloc du fichier en cours de download
|
||||
#define M_COMMANDE_HTTP_GET_RECEPTION_DATA 53 // Réception d'un bloc de données en HTTP suite à unr requête GET
|
||||
#define M_COMMANDE_CMGL_RECEPTION_DATA_MESSAGE 54 // Réception du bloc de data du message reçu
|
||||
|
||||
|
||||
|
||||
// Codes d'erreur (cf commande ATV, page 27) :
|
||||
#define M_BUS_ERREUR_AUCUNE -1
|
||||
#define M_BUS_ERREUR_OK 0
|
||||
#define M_BUS_ERREUR_CONNECT 1
|
||||
#define M_BUS_ERREUR_RING 2
|
||||
#define M_BUS_ERREUR_NO_CARRIER 3
|
||||
#define M_BUS_ERREUR_ERROR 4 // Pas de 5....
|
||||
#define M_BUS_ERREUR_NO_DIALTONE 6
|
||||
#define M_BUS_ERREUR_BUSY 7
|
||||
#define M_BUS_ERREUR_NO_ANSWER 8
|
||||
#define M_BUS_ERREUR_PROCEEDING 9
|
||||
|
||||
|
||||
|
||||
|
||||
// Etat de décodage des réponses
|
||||
#define M_BUS_REPONSE_ETAT_REPOS 0
|
||||
#define M_BUS_REPONSE_ETAT_ATTENTE_PDU 1
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
//***********************************************************************************************************************************************************************************
|
||||
// Fichier MAIN.C
|
||||
//
|
||||
// Contient les fonctions principales...
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Include :
|
||||
#include "main.h"
|
||||
|
||||
|
||||
// Prototypes :
|
||||
int8_t init(void);
|
||||
void sigintHandler(int dummy);
|
||||
void lancement_reinit(uint16_t tempo);
|
||||
int8_t analyse_signal(void);
|
||||
int8_t init_signaux(void);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction MAIN
|
||||
|
||||
Fonction principale...
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
// Initialisation globale :
|
||||
if (init() < 0)
|
||||
{
|
||||
if (bdd.pointeur != NULL) // Utile si l'erreur d'init est déclarée avant l'initialisation de la BDD...
|
||||
{
|
||||
// Mise à jour du flag d'état du CM3P (si l'accès à la BDD est possible...) :
|
||||
mysql_query(bdd.pointeur, "UPDATE TB_Systeme SET Valeur='-1' WHERE Nom=Etat_cm3p ");
|
||||
|
||||
// Ernegistrement dans l'historique (si possible...) :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_CONFIGURATION_INVALIDE_DEMARRAGE_IMPOSSIBLE, 0, 0, NULL);
|
||||
}
|
||||
|
||||
printf("\n\033[31m----------Initialisation arrêtée - Application non lancée----------\033[0m\n\n");
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
// Boucle principale :
|
||||
while (1)
|
||||
{
|
||||
synchro_bdd();
|
||||
gestion_rx_serial0();
|
||||
gestion_rx_serial1();
|
||||
|
||||
gestion_entrees();
|
||||
|
||||
gestion_c_bus();
|
||||
gestion_g_bus();
|
||||
gestion_m_bus();
|
||||
|
||||
gestion_nmea();
|
||||
|
||||
gestion_gnss();
|
||||
gestion_modem();
|
||||
|
||||
gestion_capteurs(); // A priori, plus logique de traiter les capteurs avant les circuits
|
||||
gestion_circuits();
|
||||
gestion_batteries();
|
||||
gestion_reservoirs();
|
||||
|
||||
gestion_events();
|
||||
|
||||
gestion_usb();
|
||||
gestion_reseaux();
|
||||
gestion_ecran();
|
||||
gestion_audio();
|
||||
gestion_systeme();
|
||||
supervision();
|
||||
|
||||
if (analyse_signal() != 0) break;
|
||||
}
|
||||
|
||||
arret_programme();
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT
|
||||
|
||||
Fonction d'initialisation, elle-même faisaint appel à des fonctions d'initialisation dédiées...
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init(void)
|
||||
{
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
// Init système et hardware
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Init des variables de supervision de la boucle principale :
|
||||
supervision_boucle_principale.nb_boucles = 0;
|
||||
supervision_boucle_principale.attente_premieres_mesures = SYSTEME_ATTENTE_DEMARRAGE_COMPTEUR_BOUCLE_PRINCIPALE;
|
||||
|
||||
// Interception des signaux vers la fonction de traitement dédiée (Refer http://en.cppreference.com/w/c/program/signal) :
|
||||
if (init_signaux() < 0) return(-1);
|
||||
|
||||
// Intitialisation du mode Debug immédiatement (doit être initialisé avant toute autre action pour être disponible dès le départ...) :
|
||||
// Les paramètres correspondants sont en dur (et non en BDD) car s'ils sont corrompus, on peut perdre accès à tout Log, voire planter le démarrage.
|
||||
// De plus, par expérience, on les modifie assez peu...
|
||||
debug.mode = AFFICHAGE_DEBUG_ECRAN_ET_FICHIER;
|
||||
strcpy(debug.nom_fichier, NOM_FICHIER_DEBUG);
|
||||
if (init_affichage_debug() < 0) return(-1);
|
||||
|
||||
// Recherche de la version matérielle :
|
||||
if (version_compute_module() < 0) return(-1);
|
||||
|
||||
// Recherche du package en cours (fichier JSON) et du numéro de package en cours (1.2.3) :
|
||||
strcpy(systeme.package_version, "Inconnue"); // Valeur par défaut
|
||||
struct dirent *dir; // Les types 'dirent' ou 'DIR' sont déclarés dans le header <dirent.h>
|
||||
DIR *repertoire;
|
||||
repertoire = opendir(REPERTOIRE_VERSIONS_CURRENT); // Ouverture du répertoire
|
||||
if (repertoire != NULL)
|
||||
{
|
||||
while ((dir = readdir(repertoire)) != NULL) // Lecture de tous les fichiers du répertoire :
|
||||
{
|
||||
if (strcmp(dir->d_name, ".") == 0) continue; // On ne traite pas le répertoire '.' ...
|
||||
if (strcmp(dir->d_name, "..") == 0) continue; // ... ni le répertoire '..'
|
||||
|
||||
if (strstr(dir->d_name, MARQUEUR_FICHIER_JSON) != NULL) // Recherche d'un fichier de type JSON
|
||||
{
|
||||
strcpy(systeme.package_version, dir->d_name);
|
||||
*strstr(systeme.package_version, MARQUEUR_FICHIER_JSON) = 0; // Mise à 0 de la première position du marqueur JSON (donc on coupe la chaine avant le '.json').
|
||||
|
||||
sprintf(tmp, "Version de package en cours\t\t\t\t\t\t\t: %s", systeme.package_version);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
|
||||
// Recherche du n° de la version dans le fichier JSON :
|
||||
char nom_fichier[MAX_LONGUEUR_NOM_REPERTOIRE_LOCAL + MAX_LONGUEUR_NOM_FICHIER];
|
||||
struct Struct_json_version json_version;
|
||||
sprintf(nom_fichier, "%s/%s%s", REPERTOIRE_VERSIONS_CURRENT, systeme.package_version, MARQUEUR_FICHIER_JSON);
|
||||
json_version = parse_json_version(nom_fichier, false);
|
||||
strcpy(systeme.package_no_version, json_version.no_version); // NB : si le parsing du fichier JSON a rencontré une erreur, le N° de version remonté est "ERREUR"
|
||||
|
||||
sprintf(tmp, "N° de version de package en cours\t\t\t\t\t\t: %s", systeme.package_no_version);
|
||||
if (strstr(systeme.package_no_version, "ERREUR") == NULL) affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
else affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); // Si la lecture du fichier de version a rencontré une erreur
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(repertoire); // Fermeture du répertoire
|
||||
}
|
||||
|
||||
// Mise à jour de la version de logiciel :
|
||||
// Cette fonction est délocalisée dans '_version.c' pour être mise à jour à chaque make tout en évitant de tout recompiler systématiquement.
|
||||
// C'est la raison pour laquelle l'affichage de la version se fait ici (et pas dans la fonction) car on veut la garder aussi épurée que possible.
|
||||
sprintf(systeme.cm3p_soft_version, "%s", maj_version_logiciel());
|
||||
sprintf(tmp, "Version d'application lancée\t\t\t\t\t\t: %s", systeme.cm3p_soft_version);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
|
||||
// Initialisation du handler de signal SIGALRM et lancement du timer Linux :
|
||||
// Nécessaire d'être lancé 'tôt' car peut être utilisé dans certaines routines d'init. Dans tous les cas, la construction des timers fait que
|
||||
// les variables globales (initialisées à 0 par le compilateur) sont inactives tant qu'aucun gestionnaire ne les charge.
|
||||
if (init_timer() < 0) return(-1);
|
||||
|
||||
// Initialisation des pointeur physique du SOC du processeur (GPIO, BSC1, SPI, ...) afin d'accéder directement à ses registres :
|
||||
if (init_memory_map() < 0) return(-1);
|
||||
|
||||
// Initialisation des accès à la base de données (+ lecture de certains paramètres de configuration):
|
||||
// Cette initialisation est faite très 'tôt' car elle ouvre l'accès au mode de débug notamment qui est utilisé ensuite par les différents programmes d'init.
|
||||
if (init_bdd(BDD_MODE_INIT_RESET) < 0) return(-1);
|
||||
|
||||
// initialisation des sorties :
|
||||
if (init_sorties() < 0) return(-1);
|
||||
|
||||
// initialisation des entrées :
|
||||
if (init_entrees() < 0) return(-1);
|
||||
|
||||
// initialisation des UARTs (les GPIOs doivent être configurées AVANT) :
|
||||
if (init_serial0() < 0) return(-1);
|
||||
if (init_serial1() < 0) return(-1);
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Activations effectuées directement dans config.txt mais qu'il faut répéter ici sinon le gestionnaire de sortie va les positionner à 0 par défaut...
|
||||
//---------------------------------------------------------
|
||||
// Ecran :
|
||||
if (init_ecran() < 0) return(-1);
|
||||
|
||||
// Audio :
|
||||
if (init_audio() < 0) return(-1);
|
||||
|
||||
// initialisation des ports USB :
|
||||
if (init_usb() < 0) return(-1);
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
// Init des fonctions haut niveau
|
||||
//-------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// initialisation du C_Bus :
|
||||
if (init_c_bus() < 0) return(-1);
|
||||
|
||||
// initialisation du G_Bus :
|
||||
if (init_g_bus() < 0) return(-1);
|
||||
|
||||
// initialisation du Gnss :
|
||||
if (init_gnss() < 0) return(-1);
|
||||
|
||||
// initialisation du M_Bus :
|
||||
if (init_m_bus() < 0) return(-1);
|
||||
|
||||
// initialisation du Modem :
|
||||
if (init_modem() < 0) return(-1);
|
||||
|
||||
// initialisation du Wifi :
|
||||
if (init_reseaux() < 0) return(-1);
|
||||
|
||||
// initialisation des capteurs :
|
||||
if (init_capteurs() < 0) return(-1);
|
||||
|
||||
// initialisation des circuits :
|
||||
if (init_circuits() < 0) return(-1);
|
||||
|
||||
// initialisation des niveaux :
|
||||
if (init_reservoirs() < 0) return(-1);
|
||||
|
||||
// initialisation des batteries :
|
||||
if (init_batteries() < 0) return(-1);
|
||||
|
||||
// initialisation des évènements :
|
||||
if (init_events() < 0) return(-1);
|
||||
|
||||
// initialisation du réseau NMEA2000 :
|
||||
if (init_nmea() < 0) return(-1);
|
||||
|
||||
// initialisation Système :
|
||||
if (init_systeme() < 0) return(-1);
|
||||
|
||||
// Enregistrement dans l'historique de la bonne fin de l'initialisation :
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_REINIT, 0, 0, NULL);
|
||||
|
||||
affichage_debug(__FILE__, __LINE__, "Fin d'initialisation de tous les gestionnaires", TYPE_MESSAGE_DEBUG_OK);
|
||||
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Demande une réinit au Compagnon (qui va la temporiser à réception d'environ 5s). Lance un compteur pour laisser tourner l'application pendant
|
||||
// un certain temps avant d'arrêter la boucle principale.
|
||||
// Reçoit : La valeur de tempo, en 100ms (0 = valeur par défaut)
|
||||
// Retour : Rien
|
||||
//==================================================================================================================================================================
|
||||
void lancement_reinit(uint16_t tempo)
|
||||
{
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
systeme.faucheuse.flag_demande_reinit = TRUE;
|
||||
|
||||
systeme.faucheuse.id_message_user = enregistrement_message_users(MESSAGE_USERS_CODE_REDEMARRAGE, "", MESSAGE_USERS_ETAT_ALERTE);
|
||||
|
||||
if (tempo == 0) systeme.faucheuse.compteur = SYSTEME_TEMPO_ATTENTE_REINIT_PAR_DEFAUT;
|
||||
else systeme.faucheuse.compteur = tempo;
|
||||
|
||||
c_bus_down_commande_reset(); // Demande de réinit (elle est temporisée au niveau du Compagnon pour permettre le traitement des dernières fonctions)
|
||||
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_DEMANDE_REINIT, 0, 0, NULL); // Enregistrement dans l'historique
|
||||
|
||||
sprintf(tmp, "\t----------------------------------------------------------------------------");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
sprintf(tmp, "\t!!!!! Une demande de réinit a été lancée et sera effective dans %i ms !!!!", (systeme.faucheuse.compteur * 100));
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
sprintf(tmp, "\t----------------------------------------------------------------------------");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Analyse la valeur de signal reçu et renvoit une valeur non nulle si le signal est considéré comme devant arrêter l'application (notamment SIGINT qui
|
||||
// est reçu suite à l'appui sur CTRL+C au clavier). Dans tous les cas, la réception du signal est archivé dans l'historique.
|
||||
// Reçoit : Rien
|
||||
// Retour : 0 si pas de signal d'arrêt reçu, -1 si un signal d'arrêt a été reçu
|
||||
//==================================================================================================================================================================
|
||||
int8_t analyse_signal(void)
|
||||
{
|
||||
char commande[MAX_TAILLE_COMMANDE_SHELL];
|
||||
int8_t retour = 0;
|
||||
|
||||
if (systeme.faucheuse.flag_demande_reinit == TRUE)
|
||||
{
|
||||
if (systeme.faucheuse.compteur == 0)
|
||||
{
|
||||
systeme.faucheuse.flag_demande_reinit = FALSE; // Utile surtout en debug...
|
||||
maj_message_users(systeme.faucheuse.id_message_user, "", MESSAGE_USERS_ETAT_SUPPRESSION); // Suppression du message juste avant la réinit...
|
||||
|
||||
sprintf(commande, "sudo sync"); // Permet de s'assurer que tous les fichiers sont bien répliqués sur le disque.
|
||||
commande_shell(commande);
|
||||
|
||||
return (-1); // On est arrivé au bout... C'est la fin.
|
||||
}
|
||||
}
|
||||
|
||||
if (systeme.faucheuse.signal_recu == SYSTEME_SIGNAL_AUCUN) return (0); // Cas normal
|
||||
|
||||
// Cas où on a reçu un signal :
|
||||
switch(systeme.faucheuse.signal_recu)
|
||||
{
|
||||
case SIGINT : { retour = -1; break; } // CTRL+C notamment...
|
||||
case SIGQUIT : { retour = -1; break; }
|
||||
case SIGABRT : { retour = -1; break; }
|
||||
case SIGTERM : { retour = -1; break; }
|
||||
case SIGKILL : { retour = -1; break; } // A priori inutile car on n'aura pas le temps d'arriver ici...
|
||||
default : retour = 0;
|
||||
}
|
||||
|
||||
// Enregistrement dans l'historique, quel que soit le signal (et s'il nous en laisse l'occasion...) :
|
||||
if (systeme.faucheuse.signal_recu != SIGCHLD)
|
||||
{
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_SIGNAL_RECU, 0, systeme.faucheuse.signal_recu, NULL);
|
||||
}
|
||||
|
||||
systeme.faucheuse.signal_recu = SYSTEME_SIGNAL_AUCUN;
|
||||
|
||||
return(retour);
|
||||
}
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Initialisation des handlers de signaux (vers une seule et même fonction).
|
||||
// Reçoit : Rien
|
||||
// Retour : 0 si pas d'erreur, -1 si erreur
|
||||
//==================================================================================================================================================================
|
||||
int8_t init_signaux(void)
|
||||
{
|
||||
systeme.faucheuse.signal_recu = SYSTEME_SIGNAL_AUCUN;
|
||||
|
||||
signal(SIGHUP, sigintHandler); // 1 SIGHUP Instruction (HANG UP) - Fin de session
|
||||
signal(SIGINT, sigintHandler); // 2 SIGINT Interruption
|
||||
signal(SIGQUIT, sigintHandler); // 3 SIGQUIT Instruction (QUIT)
|
||||
signal(SIGILL, sigintHandler); // 4 SIGILL Instruction illégale
|
||||
signal(SIGTRAP, sigintHandler); // 5 SIGTRAP Trace trap
|
||||
signal(SIGABRT, sigintHandler); // 6 SIGABRT (ANSI) Instruction (ABORT)
|
||||
signal(SIGIOT, sigintHandler); // 6 SIGIOT (BSD) IOT Trap
|
||||
signal(SIGBUS, sigintHandler); // 7 SIGBUS Bus error
|
||||
signal(SIGFPE, sigintHandler); // 8 SIGFPE Floating-point exception - Exception arithmétique
|
||||
signal(SIGKILL, sigintHandler); // 9 SIGKILL Instruction (KILL) - termine le processus immédiatement
|
||||
signal(SIGUSR1, sigintHandler); // 10 SIGUSR1 Signal utilisateur 1
|
||||
signal(SIGSEGV, sigintHandler); // 11 SIGSEGV Violation de mémoire
|
||||
signal(SIGUSR2, sigintHandler); // 12 SIGUSR2 Signal utilisateur 2
|
||||
signal(SIGPIPE, sigintHandler); // 13 SIGPIPE Broken PIPE - Erreur PIPE sans lecteur
|
||||
signal(SIGALRM, sigintHandler); // 14 SIGALRM Alarme horloge
|
||||
signal(SIGTERM, sigintHandler); // 15 SIGTERM Signal de terminaison
|
||||
signal(SIGSTKFLT, sigintHandler); // 16 SIGSTKFLT Stack Fault
|
||||
signal(SIGCHLD, sigintHandler); // 17 SIGCHLD ou SIGCLD modification du statut d'un processus fils
|
||||
signal(SIGCLD, sigintHandler); // 17 SIGCHLD ou SIGCLD modification du statut d'un processus fils
|
||||
signal(SIGCONT, sigintHandler); // 18 SIGCONT Demande de reprise du processus
|
||||
signal(SIGSTOP, sigintHandler); // 19 SIGSTOP Demande de suspension imbloquable
|
||||
signal(SIGTSTP, sigintHandler); // 20 SIGTSTP Demande de suspension depuis le clavier
|
||||
signal(SIGTTIN, sigintHandler); // 21 SIGTTIN lecture terminal en arrière-plan
|
||||
signal(SIGTTOU, sigintHandler); // 22 SIGTTOU écriture terminal en arrière-plan
|
||||
signal(SIGURG, sigintHandler); // 23 SIGURG évènement urgent sur socket
|
||||
signal(SIGXCPU, sigintHandler); // 24 SIGXCPU temps maximum CPU écoulé
|
||||
signal(SIGXFSZ, sigintHandler); // 25 SIGXFSZ taille maximale de fichier atteinte
|
||||
signal(SIGVTALRM, sigintHandler); // 26 SIGVTALRM alarme horloge virtuelle
|
||||
signal(SIGPROF, sigintHandler); // 27 SIGPROF Profiling alarm clock
|
||||
signal(SIGWINCH, sigintHandler); // 28 SIGWINCH changement de taille de fenêtre
|
||||
signal(SIGPOLL, sigintHandler); // 29 SIGPOLL (System V) occurence d'un évènement attendu
|
||||
signal(SIGIO, sigintHandler); // 29 SIGIO (BSD) I/O possible actuellement
|
||||
signal(SIGPWR, sigintHandler); // 30 SIGPWR Power failure restart
|
||||
signal(SIGSYS, sigintHandler); // 31 SIGSYS Erreur d'appel système
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================================================================================
|
||||
// Fonction : Handler unique de tous les signaux. Récupére la valeur du signal et met à jour la variable globale correspondante.
|
||||
// ATTENTION : il ne faut PAS faire de printf (ou équivalent) ici car il y a des restrictions dans les signals handlers.
|
||||
// En l'occurence, le traitement en fonction du numéro de signal est fait dans la fonction 'analyse_signal()' ci-dessus.
|
||||
// Reçoit : Rien
|
||||
// Retour : Rien
|
||||
//==================================================================================================================================================================
|
||||
void sigintHandler(int32_t signal)
|
||||
{
|
||||
|
||||
systeme.faucheuse.signal_recu = signal; // Permet de passer l'information de réception du signal à la boucle infinie du MAIN.
|
||||
}
|
||||
|
||||
|
||||
+1600
File diff suppressed because it is too large
Load Diff
+1603
File diff suppressed because it is too large
Load Diff
+145
@@ -0,0 +1,145 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
|
||||
Fichier MODEM.H
|
||||
|
||||
Contient tous les define liés au Modem
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MODEM_MAX_REPETITIONS_TEMPO_ATTENTE_CHANGEMENT_ETAT 30 // Cette valeur est à relier à la TEMPO_ATTENTE_ACTIVATION.
|
||||
// Le produit des deux donne la durée maximale avant de déclarer que le changement d'état attendu du modem a échoué.
|
||||
// Après essais,la durée à la coupure d'alim est de 1.2s et à l'activation de 6.1s. Donc un maxi de l'ordre de 12-15s parait très bien.
|
||||
#define MODEM_MAX_REPETITIONS_TEMPO_CHECK_INIT_LIAISON 30 // Cette valeur est à relier à la MODEM_TEMPO_CHECK_INIT_LIAISON.
|
||||
#define MODEM_MAX_REPETITIONS_PAQUET_UPLOAD 3 // Permet de limiter le nombre de répétitions consécutives d'un même bloc lors d'un Upload.
|
||||
#define MODEM_MAX_TAILLE_TRAME_FTPLIST 1024 // Cette valeur est liée au modem mais aucune doc (ni commande) ne donne la valeur exacte...
|
||||
#define MODEM_MAX_NOMBRE_PAQUETS_LIST 5 // On considère qu'au-delà, c'est qu'il y a un souci...
|
||||
#define MODEM_MAX_TAILLE_TRAME_FTPGET 1024 // Cette valeur est liée au modem mais aucune doc (ni commande) ne donne la valeur exacte...
|
||||
#define MODEM_MAX_TAILLE_MESSAGE_SMS 170 // A priori, 140 suffit mlais il y a un flou sur les 160
|
||||
#define MODEM_MAX_TAILLE_NUMERO_EMETTEUR_SMS 18 // De la forme '+33 6 xx xx xx xx'
|
||||
|
||||
// Tempos :
|
||||
#define MODEM_PERIODE_SURVEILLANCE_MODEM 10 // En x 100ms
|
||||
#define MODEM_TEMPO_APRES_RESET_SOFT 10 // En x 100ms
|
||||
#define MODEM_TEMPO_ATTENTE_CHANGEMENT_ETAT 5 // En x 100ms Cette tempo est à relier au MAX_REPETITIONS_TEMPO_ATTENTE_ACTIVATION ci-dessus.
|
||||
#define MODEM_TEMPO_ATTENTE_RESET 120 // En x 100ms Il ne semble pas y avoir de timing précis sur ce sujet mais en essayant avec différentes valeurs, il faut attendre au moins 6-8 secondes pour qu les premières commandes ATE passent correctement...
|
||||
#define MODEM_TEMPO_CHECK_INIT_LIAISON 10 // En x 100ms Cette tempo n'est pas critique (mais de préférence supérieure aux répétitions x time-out = 900ms) car on boucle plusieurs fois tant qu'on n'a pas reçu un OK suite à la configuration de l'echo. Et si au bout du nombre de rtépétition on n'a pas réussi à établir la liaison, on réinitialise le modem.
|
||||
#define MODEM_TEMPO_IMPULSION_CHANGEMENT_ETAT 15 // En x 100ms (Tmin = 1s selon datasheet du SIM7070G, page 26)
|
||||
#define MODEM_TEMPO_IMPULSION_RESET 150 // En x 100ms (Tmin = 12s selon datasheet du SIM7070G, page 23)
|
||||
#define MODEM_TEMPO_INIT 80 // En x 100ms Durée volontairement longue pour s'assurer qu'aucun changement d'état du modem n'est plus en cours au moment du démarrage effectif (évite de se retrouver à contre-temps et avoir besoin de plusieurs boucles pour se repositionner)
|
||||
#define MODEM_TIME_OUT_ATTENTE_FIN_INIT 1200 // En x 100ms La valeur de retour de '+APP PDP: 0,ACTIVE' est très variable. Souvent de 600-800ms mais parfois de 20 voire 30s. Dans tous les cas, il est important d'attendre patiemment sous peine d'empiler les erreurs...
|
||||
|
||||
|
||||
// Attention : les valeurs de MODEM_GNSS_PERIODE_ACQUISITION, MODEM_UPLOAD_PERIODE_CHECK
|
||||
// et MODEM_DOWNLOAD_PERIODE_CHECK sont bien exécutées en secondes. MAIS le temps de traitement
|
||||
// de chaque tâche (GNSS, Upload et Download) fige les 3 compteurs pendant son exécution. Cela
|
||||
// implique que sur une période longue, le moment de déclenchement effectif ne peut pas être
|
||||
// pré-estimé. Ce n'est a priori pas gênant (au contraire car cela mixe les timings de connexion),
|
||||
// mais cela peut surprendre qu'en demandant un Upload toutes les heures à partir de 12h00, on n'ai
|
||||
// pas le prochain à 13h00 et ainsi de suite. Ce sera probablement 13h01 ou 13h02 puis... 18h07 par
|
||||
// exemple.
|
||||
|
||||
#define MODEM_GNSS_PERIODE_ACQUISITION_SANS_4G_LTE 120 // En secondes Attention : la valeur réelle est obtenue par : [(MODEM_GNSS_PERIODE_ACQUISITION * 10) / MODEM_PERIODE_SURVEILLANCE_MODEM] x [MODEM_PERIODE_SURVEILLANCE_MODEM x 100ms]
|
||||
#define MODEM_GNSS_PERIODE_ACQUISITION_AVEC_4G_LTE 300 // En secondes Attention : la valeur réelle est obtenue par : [(MODEM_GNSS_PERIODE_ACQUISITION * 10) / MODEM_PERIODE_SURVEILLANCE_MODEM] x [MODEM_PERIODE_SURVEILLANCE_MODEM x 100ms]
|
||||
#define MODEM_GNSS_TEMPO_ATTENTE_COUPURE_4G_LTE 20 // En x 100ms Tempo entre la coupure de la 4G-LTE et l'alimentation du GNSS.
|
||||
#define MODEM_GNSS_TEMPO_ATTENTE_ACTIVATION 50 // En x 100ms Tempo entre l'activation du GNSS et la première commande de lecture de localisation. Si la durée n'est pas suffisante, ce n'est pas grave (on commence alors à interroger le modem mais s'il n'a pas de data, on boucle)
|
||||
#define MODEM_GNSS_TIME_OUT_ATTENTE_LECTURE 20 // En x 100ms Time-out entre l'envoi de la commande de lecture de la localisation et la réponse (en général, très rapide, quitte à recevoir une trame sans data si elles ne sont pas dispos)
|
||||
#define MODEM_GNSS_TEMPO_ENTRE_LECTURES 10 // En x 100ms
|
||||
|
||||
#define MODEM_HTTP_GET_PERIODE_CHECK 3602 // En secondes Attention : la valeur réelle est obtenue par : [(MODEM_HTTP_GET_PERIODE_CHECK * 10) / MODEM_PERIODE_SURVEILLANCE_MODEM] x [MODEM_PERIODE_SURVEILLANCE_MODEM x 100ms]
|
||||
#define MODEM_HTTP_GET_REPETITIONS_SHCONN 1 // Il est inutile de répéter plus d'une fois car le délai est très long...
|
||||
#define MODEM_HTTP_GET_TIME_OUT_SHCONN 200 // En x 100ms Time-out de réponse à une commande de connexion SHCONN.
|
||||
#define MODEM_HTTP_GET_REPETITIONS_SHREQ 1 // Il est inutile de répéter plus d'une fois car le délai est très long...
|
||||
#define MODEM_HTTP_GET_TIME_OUT_SHREQ 600 // En x 100ms Time-out de réponse à une commande GET.
|
||||
#define MODEM_HTTP_GET_REPETITIONS_SHREAD 1 // Il est inutile de répéter plus d'une fois car le délai est très long...
|
||||
#define MODEM_HTTP_GET_TIME_OUT_SHREAD 600 // En x 100ms Time-out de réponse à une commande GET.
|
||||
|
||||
|
||||
|
||||
#define MODEM_UPLOAD_PERIODE_CHECK 600 // En secondes Attention : la valeur réelle est obtenue par : [(MODEM_UPLOAD_PERIODE_CHECK * 10) / MODEM_PERIODE_SURVEILLANCE_MODEM] x [MODEM_PERIODE_SURVEILLANCE_MODEM x 100ms]
|
||||
#define MODEM_UPLOAD_TEMPO_DEMANDE_ENVOI_DATA 0 // En x 100ms Cette tempo permet d'attendre entre plusieurs phases de FTPPUT. Si ce délai est trop court, on génère des erreurs (qui se récupèrent mais qui, finalement, font échouer le transfert du fichier)
|
||||
#define MODEM_UPLOAD_TEMPO_ATTENTE_ACCEPTATION_DONNEES 20 // En x 100ms Tempo entre la commande de PUT avec la taille du paquet et l'envoi du paquet (mesuré à 100ms environ)
|
||||
#define MODEM_UPLOAD_TIME_OUT_ENVOI_DONNEES 50 // En x 100ms Tempo entre l'envoi du paquet de données et la recherche d'un autre paquet (mesuré à 125ms environ pour 1360 octets ; l'essentiel de ce temps étant l'émission des données => entre le dernier octet de données et l'Ack du modem, il y a à peine 5-6ms)
|
||||
#define MODEM_UPLOAD_TEMPO_ATTENTE_FIN_TRANSFERT 500 // En x 100ms Tempo entre l'envoi de la demande de fermeture de port FTP (FTP=2,0) et la réception que le port est bien fermé
|
||||
#define MODEM_UPLOAD_TEMPO_ATTENTE_OUVERTURE_SESSION 800 // En x 100ms Tempo entre l'envoi de la demande de connexion FTP et l'envoi des données (le time-out du modem est de 75s mais mesuré 1.6s....)
|
||||
#define MODEM_UPLOAD_TIME_OUT_ATTENTE_GETSIZE 500 // En x 100ms Tempo d'attente après l'envoi de la commande de la commande FTPSIZE (mesurée à 1.2-1.3s). La tempo est remise à 0 dès réception de la réponse.
|
||||
|
||||
#define MODEM_DOWNLOAD_PERIODE_CHECK 1200 // En secondes Attention : la valeur réelle est obtenue par : [(MODEM_DOWNLOAD_PERIODE_CHECK * 10) / MODEM_PERIODE_SURVEILLANCE_MODEM] x [MODEM_PERIODE_SURVEILLANCE_MODEM x 100ms]
|
||||
#define MODEM_DOWNLOAD_TEMPO_DEMANDE_DATA 2 // En x 100ms Cette tempo permet d'attendre un peu entre la réception de la réponse à 'FTPGET=1' et la demande proprement-dite 'FTPGET=2,NB'. Si ce délai est trop court, on génère des erreurs (qui se récupèrent mais qui, finalement, font perdre du temps)
|
||||
#define MODEM_DOWNLOAD_TEMPO_DEMANDE_LISTE 2 // En x 100ms Cette tempo permet d'attendre un peu entre la réception de la réponse à 'FTPLIST=1' et la demande proprement-dite 'FTPLIST=2,NB'. Si ce délai est trop court, on génère des erreurs (qui se récupèrent mais qui, finalement, font perdre du temps)
|
||||
#define MODEM_DOWNLOAD_TIME_OUT_ATTENTE_DISPO_DATA 800 // En x 100ms Tempo entre l'envoi de la demande de connexion FTP et l'envoi des données (le time-out du modem est de 75s....)
|
||||
#define MODEM_DOWNLOAD_TIME_OUT_ATTENTE_INFO 500 // En x 100ms
|
||||
#define MODEM_DOWNLOAD_TIME_OUT_ATTENTE_LISTE 500 // En x 100ms
|
||||
#define MODEM_DOWNLOAD_TIME_OUT_ATTENTE_RECEPTION_DATA 500 // En x 100ms
|
||||
|
||||
|
||||
// Fonctionnement GNSS :
|
||||
#define MODEM_GNSS_MAX_NOMBRE_CYCLES 180 // Nombre de cycles d'acquisition avant d'abandonner. Il vaut mieux que cette valeur x MODEM_GNSS_TEMPO_ENTRE_LECTURES soit < MODEM_GNSS_PERIODE_ACQUISITION
|
||||
#define MODEM_GNSS_NOMBRE_CYCLES_VALIDES 20 // Nombre de cycles valides (pas forcément consécutifs) sur une même période avant de considérer la période comme terminée. Cette valeur est importante pour avoir une précision suffisante...
|
||||
|
||||
|
||||
// Etat HTTP :
|
||||
#define MODEM_HTTP_ETAT_REPOS 0
|
||||
#define MODEM_HTTP_ETAT_DEMANDE 1
|
||||
#define MODEM_HTTP_ETAT_EN_COURS 2
|
||||
#define MODEM_HTTP_ETAT_TERMINE 3
|
||||
|
||||
|
||||
// Demande de connexion par l'utilisateur :
|
||||
#define MODEM_DEMANDE_UTILISATEUR_AUCUNE 0
|
||||
#define MODEM_DEMANDE_UTILISATEUR_DOWNLOAD 1
|
||||
#define MODEM_DEMANDE_UTILISATEUR_UPLOAD 2
|
||||
#define MODEM_DEMANDE_UTILISATEUR_DOWNLOAD_UPLOAD 3
|
||||
|
||||
#define MODEM_DEMANDE_UTILISATEUR_TEMPO_MINI 2 // En seconde. Indique la valeur à laquelle sera ramené le compteur de download et/ou upload lors de la demande (NB : si la valeur courante est inférieure, elle ne sera pas modifiée)
|
||||
|
||||
// Demandes FTP :
|
||||
// #define MODEM_DEMANDE_FTP_AUCUNE 0
|
||||
// #define MODEM_DEMANDE_FTP_GET 1
|
||||
// #define MODEM_DEMANDE_FTP_PUT 2
|
||||
|
||||
|
||||
// Etats du séquenceur Modem :
|
||||
#define ETAT_SEQUENCEUR_MODEM_INIT 0
|
||||
#define ETAT_SEQUENCEUR_MODEM_CHANGEMENT_ETAT_INIT 1
|
||||
#define ETAT_SEQUENCEUR_MODEM_CHANGEMENT_ETAT_IMPULSION 2
|
||||
#define ETAT_SEQUENCEUR_MODEM_CHANGEMENT_ETAT_ATTENTE_STATUS 3
|
||||
#define ETAT_SEQUENCEUR_MODEM_INIT_LIAISON 4
|
||||
#define ETAT_SEQUENCEUR_MODEM_COMMANDES_INIT 5
|
||||
#define ETAT_SEQUENCEUR_MODEM_ATTENTE_FIN_INIT 6
|
||||
#define ETAT_SEQUENCEUR_MODEM_REPOS 7
|
||||
|
||||
#define ETAT_SEQUENCEUR_MODEM_GNSS_ACTIVATION 10
|
||||
#define ETAT_SEQUENCEUR_MODEM_GNSS_ATTENTE_COUPURE_4G_LTE 11
|
||||
#define ETAT_SEQUENCEUR_MODEM_GNSS_ATTENTE_LECTURE 12
|
||||
#define ETAT_SEQUENCEUR_MODEM_GNSS_LECTURE 13
|
||||
|
||||
#define ETAT_SEQUENCEUR_MODEM_HTTP_GET_LANCEMENT 20
|
||||
#define ETAT_SEQUENCEUR_MODEM_HTTP_GET_ATTENTE_CONNEXION 21
|
||||
#define ETAT_SEQUENCEUR_MODEM_HTTP_GET_ATTENTE_RETOUR_REQUETE 22
|
||||
#define ETAT_SEQUENCEUR_MODEM_HTTP_GET_ATTENTE_RETOUR_DATA 23
|
||||
#define ETAT_SEQUENCEUR_MODEM_HTTP_GET_CLOTURE 24
|
||||
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_GET_LANCEMENT 30
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_GET_ATTENTE_INFORMATION 31
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_GET_ATTENTE_LISTE 32
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_GET_RECHERCHE_FICHIER 33
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_GET_DEBUT_FICHIER 34
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_GET_ATTENTE_DISPO_DATA 35
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_GET_ATTENTE_RECEPTION_DATA 36
|
||||
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_PUT_LANCEMENT 40
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_PUT_ATTENTE_OUVERTURE_SESSION 41
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_PUT_ATTENTE_ACCEPTATION_DONNEES 42
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_PUT_ATTENTE_FIN_TRANSFERT 43
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_PUT_LANCEMENT_CHECK 44
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_PUT_ATTENTE_GETSIZE 45
|
||||
#define ETAT_SEQUENCEUR_MODEM_FTP_PUT_ATTENTE_FERMETURE_SESSION 46
|
||||
|
||||
|
||||
#define ETAT_SEQUENCEUR_MODEM_DEBUT_IMPULSION_RESET 90
|
||||
#define ETAT_SEQUENCEUR_MODEM_FIN_IMPULSION_RESET 91
|
||||
|
||||
|
||||
|
||||
|
||||
+3083
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier NMEA.H
|
||||
//
|
||||
// Contient tous les define liés au réseau NMEA
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define NMEA_MAX_NOMBRE_PGN 250
|
||||
#define NMEA_MAX_TAILLE_DATA_PGN 223 // C'est la taille maxi des DATA d'un Fast Packet
|
||||
// #define NMEA_MAX_NOMBRE_PGN_ACTIFS 50
|
||||
|
||||
// Tempos :
|
||||
#define NMEA_TEMPO_INIT 10 // En x 100ms
|
||||
#define NMEA_PERIODE_CHECK 5 // EN x 100ms
|
||||
|
||||
|
||||
// Type de PGN :
|
||||
#define NMEA_PGN_TYPE_INCONNU -1
|
||||
#define NMEA_PGN_TYPE_SYSTEM_SINGLE_FRAME 0
|
||||
#define NMEA_PGN_TYPE_SYSTEM_FAST_PACKET 1
|
||||
#define NMEA_PGN_TYPE_DEFAULT_SINGLE_FRAME 2
|
||||
#define NMEA_PGN_TYPE_MANDATORY_FAST_PACKET 3
|
||||
#define NMEA_PGN_TYPE_DEFAULT_FAST_PACKET 4
|
||||
#define NMEA_PGN_TYPE_PROPRIETARY_FAST_PACKET 5
|
||||
|
||||
|
||||
// Mode de parse des PGN :
|
||||
#define NMEA_PARSE_MODE_CREATION 0
|
||||
#define NMEA_PARSE_MODE_MISE_A_JOUR 1
|
||||
#define NMEA_PARSE_MODE_SUPPRESSION 2
|
||||
|
||||
|
||||
// Fields de PGN :
|
||||
#define NMEA_126992_TIME_SOURCE 2
|
||||
// #define NMEA_126992_RESERVED 3
|
||||
#define NMEA_126992_SYSTEM_DATE 4
|
||||
#define NMEA_126992_SYSTEM_TIME 5
|
||||
|
||||
#define NMEA_129029_DAYS_SINCE_1970 2
|
||||
#define NMEA_129029_SECONDS_SINCE_MIDNIGHT 3
|
||||
#define NMEA_129029_LATITUDE 4
|
||||
#define NMEA_129029_LONGITUDE 5
|
||||
#define NMEA_129029_ALTITUDE 6
|
||||
#define NMEA_129029_GNSS_TYPE 7
|
||||
#define NMEA_129029_GNSS_METHOD 8
|
||||
//#define NMEA_129029_RESERVED 9
|
||||
#define NMEA_129029_SATELLITES_NUMBER 11
|
||||
#define NMEA_129029_HDOP 12
|
||||
#define NMEA_129029_PDOP 13
|
||||
|
||||
#define NMEA_129540_SATELLITES_IN_VIEW 4
|
||||
|
||||
#define NMEA_130306_WIND_SPEED_TRUE_NORTH 20
|
||||
#define NMEA_130306_WIND_ANGLE_TRUE_NORTH 30
|
||||
#define NMEA_130306_WIND_SPEED_MAGNETIC 21
|
||||
#define NMEA_130306_WIND_ANGLE_MAGNETIC 31
|
||||
#define NMEA_130306_WIND_SPEED_APPARENT 22
|
||||
#define NMEA_130306_WIND_ANGLE_APPARENT 32
|
||||
#define NMEA_130306_WIND_SPEED_TRUE_BOAT 23
|
||||
#define NMEA_130306_WIND_ANGLE_TRUE_BOAT 33
|
||||
#define NMEA_130306_WIND_SPEED_TRUE_WATER 24
|
||||
#define NMEA_130306_WIND_ANGLE_TRUE_WATER 34
|
||||
|
||||
|
||||
// Etats du séquenceur Nmea :
|
||||
#define ETAT_SEQUENCEUR_NMEA_INIT 0
|
||||
#define ETAT_SEQUENCEUR_NMEA_REPOS 1
|
||||
|
||||
|
||||
|
||||
|
||||
+1080
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier RESEAUX.H
|
||||
//
|
||||
// Contient tous les define liés au Wifi
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MAX_RESEAUX_WIFI_STA_TAILLE_SSID 100
|
||||
#define MAX_RESEAUX_WIFI_STA_TAILLE_BSSID 20 // Du type "94:A6:7E:B0:BE:C7"
|
||||
#define MAX_RESEAUX_WIFI_STA_TAILLE_PSK 100
|
||||
#define MAX_RESEAUX_WIFI_AP_TAILLE_SSID 32
|
||||
#define MAX_RESEAUX_WIFI_AP_TAILLE_PWD 63
|
||||
#define MAX_LONGUEUR_LIGNE_FICHIER_CONFIG_RESEAUX 150 // 63+1 caractères pour PWD + entête de paramètre (15 caractères pour celui-ci)
|
||||
#define MAX_LONGUEUR_STA_SCAN_LIST 2000 // Une entrée comprend le nom du SSID (32 max), le canal (2 max) et la qualité de réception (3max) soit un peu moins de 40 caractères/SSID
|
||||
#define MAX_NOMBRE_PROCESS_WEBGL 3 // A gérer conjointement avec Qt qui gère le paramétrage
|
||||
#define MAX_LONGUEUR_PARAMETRES_WEBGL 200 // A priori, une chaine de la forme '-platform webgl:port=8081:wsserverport=8082'
|
||||
|
||||
// Timings :
|
||||
#define RESEAUX_TEMPO_INIT 50 // En x 100ms
|
||||
#define RESEAUX_PERIODE_SURVEILLANCE 10 // En x 100ms
|
||||
#define RESEAUX_PERIODE_CHECK_ADRESSE_IP_INIT 5 // En secondes, tempo avant la première recherche d'adresse IP
|
||||
#define RESEAUX_PERIODE_CONNEXION_SHIP2NET_INIT 90 // En secondes
|
||||
#define RESEAUX_PERIODE_SCAN_WIFI_STA_INIT 30 // En secondes
|
||||
#define RESEAUX_PERIODE_CHECK_DOWWNLOAD_APRES_CONNEXION 60 // En secondes
|
||||
#define RESEAUX_TIME_OUT_LECTURE_FICHIER_SCAN_STA 20 // En TEMPO_ATTENTE_BOUCLE_SCAN_WIFI_STA (a priori, 1s)
|
||||
#define RESEAUX_PERIODE_CHECK_WEBGL_INIT 5 // En secondes
|
||||
#define RESEAUX_PERIODE_CHECK_WEBGL 1 // En secondes
|
||||
|
||||
#define TEMPO_ATTENTE_FIN_MAJ_FICHIER_WPA_SUPPLICANT 20 // En x 100ms. Mesuré à environ 400ms
|
||||
#define TEMPO_ATTENTE_FIN_DHCPCD_RESTART 50 // En x 100ms. Les commandes en console durent 1.5-2s à l'oeil.
|
||||
#define TEMPO_ATTENTE_FIN_DAMEON_SERVICES_RESTART 50 // En x 100ms. Les commandes en console durent 1s à l'oeil.
|
||||
#define TEMPO_ATTENTE_FIN_COMMANDE_WIFI_STA_UP 80 // En x 100ms. Les commandes en console sont quasi instantanées
|
||||
#define TEMPO_ATTENTE_FIN_COMMANDE_WIFI_STA_DOWN 80 // En x 100ms. Les commandes en console durent 700-800ms à l'oeil.
|
||||
|
||||
#define TEMPO_ATTENTE_FIN_MAJ_FICHIER_HOSTAPD 20 // En x 100ms. Mesuré à environ 400ms
|
||||
#define TEMPO_ATTENTE_FIN_HOSTAPD_RESTART 50 // En x 100ms. Les commandes en console durent 1.5-2s à l'oeil.
|
||||
#define TEMPO_ATTENTE_FIN_COMMANDE_WIFI_AP_UP 80 // En x 100ms. Les commandes en console sont quasi instantanées
|
||||
#define TEMPO_ATTENTE_FIN_COMMANDE_WIFI_AP_DOWN 80 // En x 100ms. Les commandes en console durent 700-800ms à l'oeil.
|
||||
|
||||
#define TEMPO_ATTENTE_BOUCLE_SCAN_WIFI_STA 10 // En x 100ms. Cette tempo est utilisée pour vérifier régulièrement si le fichier de sortie du scan est toujours vide
|
||||
#define TEMPO_ATTENTE_FIN_SCAN_WIFI_STA 3 // En x 100ms. Cette tempo permet correspond à l'attente entre la détection du fichier de sortie non vide et le traitement. Elle est fait pour le cas où la détection de fichier non vide se fait au milieu du remplissage du fichier (permet d'attendre la fin du remplissage dans ce cas)
|
||||
|
||||
|
||||
// Modes :
|
||||
#define RESEAUX_WIFI_MODE_STA 0
|
||||
#define RESEAUX_WIFI_MODE_AP 1
|
||||
#define RESEAUX_WIFI_MODE_STA_ET_AP 2
|
||||
|
||||
|
||||
// Etat séquenceur Wifi :
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_INIT 0
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_REPOS 1
|
||||
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_LANCEMENT_MISE_A_JOUR_WIFI_STA 10
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_MAJ_FICHIER_WPA_SUPPLICANT 11
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_COMMANDE_DHCPCD_RESTART 12
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_COMMANDE_DAMEON_SERVICES_RESTART 13
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_COMMANDE_WIFI_STA_UP 14
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_COMMANDE_WIFI_STA_DOWN 15
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_FIN_MISE_A_JOUR_WIFI_STA 16
|
||||
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_LANCEMENT_MISE_A_JOUR_WIFI_AP 20
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_MAJ_FICHIER_HOSTPAD 21
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_COMMANDE_HOSTAPD_RESTART 22
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_COMMANDE_WIFI_AP_UP 23
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_COMMANDE_WIFI_AP_DOWN 24
|
||||
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_FIN_MISE_A_JOUR_WIFI 30
|
||||
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_SCAN_WIFI_STA_LANCEMENT 40
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_SCAN_WIFI_STA_ATTENTE_FIN 41
|
||||
#define ETAT_SEQUENCEUR_RESEAUX_SCAN_WIFI_STA_TRAITEMENT 42
|
||||
@@ -0,0 +1,258 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier RESERVOIRS.C
|
||||
//
|
||||
// Contient toutes les fonctions liées aux réservoirs de ShipHeart
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// #define __DEBUG_RESERVOIRS
|
||||
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t init_reservoirs(void);
|
||||
void gestion_reservoirs(void);
|
||||
int16_t reservoir_cle_primaire(uint16_t cle_primaire);
|
||||
int16_t variable_reservoir_cle_primaire(uint16_t cle_primaire);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_reservoirs reservoirs;
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction : Initialise les différents paramètres des reservoirs au démarrage de l'application
|
||||
Reçoit : Rien
|
||||
Retour : -1 si erreur, 0 sinon.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_reservoirs(void)
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------------
|
||||
// Init des variables générales :
|
||||
|
||||
reservoirs.sequenceur.etat = ETAT_SEQUENCEUR_RESERVOIRS_INIT;
|
||||
reservoirs.sequenceur.compteur = RESERVOIRS_TEMPO_INIT;
|
||||
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation des reservoirs\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction : Fonction de plus haut niveau de gestion reservoirs
|
||||
Reçoit : Rien
|
||||
Retour : Rien
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_reservoirs(void)
|
||||
{
|
||||
uint16_t i, j;
|
||||
uint16_t val_u16;
|
||||
float val;
|
||||
float niv;
|
||||
bool flag_erreur;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
if (!systeme.flag_cm3p_ready) return; // Evite que le traitement soit fait au milieu d'une reconfiguration...
|
||||
|
||||
switch(reservoirs.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_RESERVOIRS_INIT :
|
||||
{
|
||||
if ((systeme.flag_cm3p_ready) && // Permet de s'assurer que le cycle d'init système est terminé. En particulier, on est sûr que 'init_bdd()' puis 'annuaire_k_bus()' ont été traités.
|
||||
(reservoirs.sequenceur.compteur == 0))
|
||||
{
|
||||
|
||||
affichage_debug(__FILE__, __LINE__, "------------------RESERVOIRS INIT", TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
reservoirs.sequenceur.etat = ETAT_SEQUENCEUR_RESERVOIRS_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_RESERVOIRS_REPOS :
|
||||
{
|
||||
if (reservoirs.sequenceur.compteur == 0)
|
||||
{
|
||||
reservoirs.sequenceur.compteur = RESERVOIRS_PERIODE_MESURES;
|
||||
|
||||
for (i=0; i<reservoirs.nb; i++)
|
||||
{
|
||||
if (reservoirs.reservoirs[i].flag_validite == FALSE) continue;
|
||||
|
||||
flag_erreur = FALSE;
|
||||
val = 0;
|
||||
|
||||
switch(reservoirs.reservoirs[i].type_entrees)
|
||||
{
|
||||
//--------------------------------------------------------------------------
|
||||
case TYPE_ENTREES_AUXILIAIRES :
|
||||
{
|
||||
// Calcul de la valeur brute en fonction de l'état des entrées AUX :
|
||||
val_u16 = 0;
|
||||
for (j = 0; j < reservoirs.reservoirs[i].nb_entrees; j ++) // Boucle sur toutes les entrées du réservoir :
|
||||
{
|
||||
if (entrees.aux.entrees[reservoirs.reservoirs[i].no_entrees[j]].valeur == 1) val_u16 |= (1 << j);
|
||||
}
|
||||
reservoirs.reservoirs[i].valeur_brute = (float) val_u16; // SDIR #288 Note : on ne traite pas ici le 'flag_dde_maj_bdd' car si la valeur brute a changée, le niveau -ou l'erreur d'entrées) a changé et déclenchera la demande de MAJ...
|
||||
|
||||
// Détection d'électrodes mal configurées :
|
||||
uint16_t masque = 1;
|
||||
for (j = 0; j < (reservoirs.reservoirs[i].nb_entrees + 1); j ++)
|
||||
{
|
||||
if (val_u16 == (masque - 1)) break; // Permet de tester la valeur juste en-dessous des puissances de 2 : 0, 1, 3, 7, 15, 31, ...
|
||||
masque <<= 1; // Permet de balayer toutes les puissances de 2 : 1, 2, 4, 8, 16, 32...
|
||||
}
|
||||
|
||||
if (j < (reservoirs.reservoirs[i].nb_entrees + 1)) reservoirs.reservoirs[i].etat_entrees = RESERVOIRS_ETAT_ENTREES_OK; // Pas d'erreur
|
||||
else // Erreur :
|
||||
{
|
||||
flag_erreur = TRUE;
|
||||
reservoirs.reservoirs[i].etat_entrees = RESERVOIRS_ETAT_ENTREES_ELECTRODES_PLONGEES_INVERSEES;
|
||||
reservoirs.reservoirs[i].flag_dde_maj_bdd = TRUE;
|
||||
// break;
|
||||
}
|
||||
|
||||
val = val_u16;
|
||||
|
||||
#ifdef __DEBUG_RESERVOIRS
|
||||
sprintf(tmp, "Réservoir #%i : valeur brute des entrées = %.2f et état entrées = %i", (i+1), val, reservoirs.reservoirs[i].etat_entrees);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
case TYPE_ENTREES_LEVEL_SENSOR :
|
||||
{
|
||||
// Récupération de l'état de l'entrées Level Sensor configurée sur ce réservoir :
|
||||
// NB : en V si 0-10V, en Ohms si 500R ou en mA pour tous les autres cas
|
||||
val = entrees.level_sensor.entrees[reservoirs.reservoirs[i].no_entrees[0]].valeur;
|
||||
|
||||
// SDIR #288 : Début
|
||||
if (fabs(reservoirs.reservoirs[i].valeur_brute - val) > 0)
|
||||
{
|
||||
reservoirs.reservoirs[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
}
|
||||
|
||||
reservoirs.reservoirs[i].valeur_brute = val;
|
||||
// SDIR #288 : Fin
|
||||
|
||||
#ifdef __DEBUG_RESERVOIRS
|
||||
sprintf(tmp, "Réservoir #%i : valeur brute de l'entrée = %.2f", (i+1), val);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "Le 'Type_entrées' du réservoir #%i est invalide [%i]. Le réservoir est dévalidé", (i+1), reservoirs.reservoirs[i].type_entrees);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
reservoirs.reservoirs[i].flag_validite = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Traitement :
|
||||
if (flag_erreur == FALSE)
|
||||
{
|
||||
// Calcul de la nouvelle moyenne à partir de l'ancienne et de la valeur lue :
|
||||
niv = calcul_niveau(reservoirs.reservoirs[i].liste_valeurs_niveaux, MAX_NOMBRE_VALEURS_NIVEAUX_RESERVOIRS, val);
|
||||
if (niv >= 0) // S'il y a une erreur lors du calcul du niveau, on ne traite pas le résultat...
|
||||
{
|
||||
// Calcul de la nouvelle moyenne de valeur courante à partir de l'ancienne et de la valeur lue :
|
||||
reservoirs.reservoirs[i].variables[0].valeur_courante = (((reservoirs.reservoirs[i].variables[0].valeur_courante * (reservoirs.reservoirs[i].niveau_coeff_filtrage - 1))) + niv) / reservoirs.reservoirs[i].niveau_coeff_filtrage;
|
||||
if (reservoirs.reservoirs[i].variables[0].valeur_courante > 100) reservoirs.reservoirs[i].variables[0].valeur_courante = 100;
|
||||
|
||||
// Mise à jour du cumul :
|
||||
reservoirs.reservoirs[i].variables[0].cumul += reservoirs.reservoirs[i].variables[0].valeur_courante;
|
||||
reservoirs.reservoirs[i].cumuls_nb_val ++; // MàJ du nombre d'échantillons dans le cumul
|
||||
|
||||
// Traitement si la valeur a suffisemment évolué :
|
||||
// if (fabs(reservoirs.reservoirs[i].variables[0].valeur_bdd - reservoirs.reservoirs[i].variables[0].valeur_courante) >= reservoirs.variables[0].marge)
|
||||
if (fabs(reservoirs.reservoirs[i].variables[0].valeur_bdd - reservoirs.reservoirs[i].variables[0].valeur_courante) > 0)
|
||||
{
|
||||
reservoirs.reservoirs[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
|
||||
#ifdef __DEBUG_RESERVOIRS
|
||||
sprintf(tmp, "Réservoir #%i : Niveau = %.2f% (coeff filtrage niveau = %i)", i, reservoirs.reservoirs[i].variables[0].valeur_courante, reservoirs.reservoirs[i].niveau_coeff_filtrage);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "Erreur de calcul de niveau sur réservoir #%i avec Valeur = %.3f. La valeur lue n'est pas exploitée.\n", i, val);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
}
|
||||
|
||||
|
||||
// Mise à jour des valeurs BDD des variables :
|
||||
if (reservoirs.reservoirs[i].flag_dde_maj_bdd)
|
||||
{
|
||||
for (j = 0; j < MAX_NOMBRE_VARIABLES_RESERVOIRS; j ++) reservoirs.reservoirs[i].variables[j].valeur_bdd = reservoirs.reservoirs[i].variables[j].valeur_courante;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur Réservoirs est inconnu [%i]. Il est repositionné au REPOS", reservoirs.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
reservoirs.sequenceur.etat = ETAT_SEQUENCEUR_RESERVOIRS_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Recherche le réservoir dont la Clé_primaire est reçue en paramètre
|
||||
// Reçoit : La Cle_primaire du réservoir à rechercher
|
||||
// Retourne : le numéro de réservoir correspondant (ou -1 si aucun circuit valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_RESERVOIRS - 1.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int16_t reservoir_cle_primaire(uint16_t cle_primaire)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < reservoirs.nb; i ++)
|
||||
{
|
||||
if ((reservoirs.reservoirs[i].cle_primaire == cle_primaire) && (reservoirs.reservoirs[i].flag_validite)) return(i);
|
||||
}
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction VARIABLE_RESERVOIR_CLE_PRIMAIRE
|
||||
// Reçoit en paramètre :
|
||||
// - La Cle_primaire de la variable à rechercher
|
||||
// Retourne :
|
||||
// - le numéro de variable correspondant (ou -1 si aucune variable valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_VARIABLES_RESERVOIRS-1.
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int16_t variable_reservoir_cle_primaire(uint16_t cle_primaire)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_VARIABLES_RESERVOIRS; i++)
|
||||
{
|
||||
if (reservoirs.variables[i].cle_primaire == cle_primaire) return(i);
|
||||
|
||||
}
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**********************************************************************************************************************************************************************************
|
||||
|
||||
Fichier RESERVOIRS.H
|
||||
|
||||
Contient tous les define liés aux RESERVOIRS
|
||||
|
||||
**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MAX_NOMBRE_RESERVOIRS 16
|
||||
#define MAX_NOMBRE_ENTREES_PAR_RESERVOIR 12 // Indique le nombre max d'entrées physiques pour un même réservoir (doit être <= 16 ; sinon il faut changer le type dans les calculs...)
|
||||
#define MAX_NOMBRE_VALEURS_NIVEAUX_RESERVOIRS 100
|
||||
#define MAX_NOMBRE_VARIABLES_RESERVOIRS 1
|
||||
#define MAX_TAILLE_VALEUR_BRUTE_RESERVOIR 50 // Soit un float, soit une chaine pour les entrées AUX (vérifier la cohérence si MAX_NOMBRE_ENTREES_PAR_RESERVOIR est étendu significativement !). SDIR #288
|
||||
|
||||
// Tempos :
|
||||
#define RESERVOIRS_TEMPO_INIT 10 // En x 100ms
|
||||
#define RESERVOIRS_PERIODE_MESURES 3 // En x 100ms // Valeur calée sur la période de remontée de l'état des Level Sensors de la part du Compagnon (250ms)
|
||||
|
||||
|
||||
// Etat entrées :
|
||||
#define RESERVOIRS_ETAT_ENTREES_OK 0
|
||||
#define RESERVOIRS_ETAT_ENTREES_ELECTRODES_PLONGEES_INVERSEES 1
|
||||
|
||||
// Variables du réservoir :
|
||||
#define RESERVOIR_VARIABLE_NIVEAU 0
|
||||
// NB : ces valeurs doivent rester strictement inférieures à MAX_NOMBRE_VARIABLES_PAR_RESERVOIR
|
||||
|
||||
// Etats du séquenceur Tests :
|
||||
#define ETAT_SEQUENCEUR_RESERVOIRS_INIT 0
|
||||
#define ETAT_SEQUENCEUR_RESERVOIRS_REPOS 1
|
||||
@@ -0,0 +1,610 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier SERIAL.C
|
||||
//
|
||||
// Contient toutes les fonctions liées aux ports série
|
||||
//
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
void gestion_rx_serial0(void);
|
||||
void gestion_rx_serial1(void);
|
||||
int init_serial0(void);
|
||||
int init_serial1(void);
|
||||
|
||||
// Variables globales :
|
||||
|
||||
struct Struct_config_serial config_serial0;
|
||||
struct Struct_config_serial config_serial1;
|
||||
struct Struct_serial serial0;
|
||||
struct Struct_serial serial1;
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction gestion_rx_serial0
|
||||
|
||||
Fonction de réception des caractères provenant de Serial0 et leur enregistrement dans un buffer tournant (avec gestion de dépassement si 'ptr_fin' rattrape 'ptr_début')
|
||||
|
||||
Ce port SERIAL 0 est affecté au M-Bus sur les CM3P (ShipBase V1)
|
||||
Ce port SERIAL 0 est affecté au GNSS sur les CM4 (ShipBase V2)
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_rx_serial0(void)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t tmp_rx_buffer[MAX_TAILLE_TMP_RX_BUFFER_UART];
|
||||
int16_t lg_tmp_rx_buffer;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
if ((config_serial0.validite == 1) && (config_serial0.filestream != -1))
|
||||
{
|
||||
lg_tmp_rx_buffer = read(config_serial0.filestream, tmp_rx_buffer, MAX_TAILLE_TMP_RX_BUFFER_UART); //Filestream, buffer to store in, number of bytes to read (max)
|
||||
if (lg_tmp_rx_buffer > 0)
|
||||
{
|
||||
for (i=0; i<lg_tmp_rx_buffer; i++)
|
||||
{
|
||||
if (++ serial0.ptr_fin_buffer_rx == MAX_TAILLE_RX_BUFFER_UART) serial0.ptr_fin_buffer_rx = 0; // Recherche de la prochaine position dans le buffer.
|
||||
|
||||
if (serial0.ptr_fin_buffer_rx != serial0.ptr_debut_buffer_rx) // Cas où le buffer de réception n'est pas plein :
|
||||
{
|
||||
serial0.buffer_rx[serial0.ptr_fin_buffer_rx] = tmp_rx_buffer[i];
|
||||
}
|
||||
else // Cas où le buffer de réception est plein (car la fin rattrape le début) :
|
||||
{
|
||||
// Enregistrement log :
|
||||
sprintf(tmp, "Buffer de réception de l'UART0 plein. Ecriture impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
// Enregistrement dans l'historique :
|
||||
// SDIR #84 : pour éviter de remplir l'historique Système dans le cas où l'appli est bloquée pendant un archivage par exemple.
|
||||
// Il faudra voir s'il est possible de le remettre en fonctionnement après avoir vérifié que l'ajout du break ci-dessous limite le nombre d'entrées
|
||||
// dans l'historique en cas de pb.
|
||||
// enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_UART_BUFFER_RX_PLEIN, 0, 0, NULL);
|
||||
|
||||
// Repositionnement du ptr_fin_buffer_rx à sa valeur précédente :
|
||||
if (serial0.ptr_fin_buffer_rx != 0) serial0.ptr_fin_buffer_rx --;
|
||||
else serial0.ptr_fin_buffer_rx = MAX_TAILLE_RX_BUFFER_UART - 1;
|
||||
|
||||
break; // SDIR #84. Si le buffer est plein, il est inutile d'essayer de loger les autres caractères lus dans le driver... Cela évite de dupliquer plus que nécessaires les messages d'erreur...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction gestion_rx_serial1
|
||||
|
||||
Fonction de réception des caractères provenant de l'UART1 (serial1) et leur enregistrement dans un buffer tournant
|
||||
(avec gestion de dépassement si 'ptr_fin' rattrape 'ptr_début')
|
||||
|
||||
Ce port SERIAL 1 est affecté à C-Bus sur les CM3P (ShipBase V1)
|
||||
Ce port SERIAL 1 est affecté à C-Bus sur les CM4 (ShipBase V2)
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void gestion_rx_serial1(void)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t tmp_rx_buffer[MAX_TAILLE_TMP_RX_BUFFER_UART];
|
||||
int16_t lg_tmp_rx_buffer;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
if ((config_serial1.validite == 1) && (config_serial1.filestream != -1))
|
||||
{
|
||||
lg_tmp_rx_buffer = read(config_serial1.filestream, tmp_rx_buffer, MAX_TAILLE_TMP_RX_BUFFER_UART); //Filestream, buffer to store in, number of bytes to read (max)
|
||||
if (lg_tmp_rx_buffer > 0)
|
||||
{
|
||||
for (i=0; i<lg_tmp_rx_buffer; i++)
|
||||
{
|
||||
if (++ serial1.ptr_fin_buffer_rx == MAX_TAILLE_RX_BUFFER_UART) serial1.ptr_fin_buffer_rx = 0; // Recherche de la prochaine position dans le buffer.
|
||||
|
||||
if (serial1.ptr_fin_buffer_rx != serial1.ptr_debut_buffer_rx) // Cas où le buffer de réception n'est pas plein :
|
||||
{
|
||||
serial1.buffer_rx[serial1.ptr_fin_buffer_rx] = tmp_rx_buffer[i];
|
||||
}
|
||||
else // Cas où le buffer de réception est plein (car la fin rattrape le début) :
|
||||
{
|
||||
// Enregistrement log :
|
||||
sprintf(tmp, "Buffer de réception de l'UART1 plein. Ecriture impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
// Enregistrement dans l'historique :
|
||||
// SDIR #84 : pour éviter de remplir l'historique Système dans le cas où l'appli est bloquée pendant un archivage par exemple.
|
||||
// Il faudra voir s'il est possible de le remettre en fonctionnement après avoir vérifié que l'ajout du break ci-dessous limite le nombre d'entrées
|
||||
// dans l'historique en cas de pb.
|
||||
// enregistrement_historique(TYPE_SOURCE_HISTORIQUE_SYSTEME, SYSTEME_UART_BUFFER_RX_PLEIN, 0, 1, NULL);
|
||||
|
||||
// Repositionnement du ptr_fin_buffer_rx à sa valeur précédente :
|
||||
if (serial1.ptr_fin_buffer_rx != 0) serial1.ptr_fin_buffer_rx --;
|
||||
else serial1.ptr_fin_buffer_rx = MAX_TAILLE_RX_BUFFER_UART - 1;
|
||||
|
||||
break; // SDIR #84. Si le buffer est plein, il est inutile d'essayer de loger les autres caractères lus dans le driver... Cela évite de dupliquer plus que nécessaires les messages d'erreur...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction init_serial0
|
||||
|
||||
Fonction d'initialisation de l'UART0
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int init_serial0(void)
|
||||
{
|
||||
char chaine_temp[MAX_TAILLE_CHAINE_TEMP_UARTS];
|
||||
struct termios options;
|
||||
speed_t speed;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
// Paramètres de configuration (en dur car inutile de les importer de la BDD) :
|
||||
config_serial0.validite = 1;
|
||||
config_serial0.vitesse = 9600; // 1200 à 115200
|
||||
config_serial0.longueur = 8; // 7 ou 8
|
||||
config_serial0.parite = 0; // 0=No, 1=Odd et 2=Even
|
||||
config_serial0.stops = 1; // 1 ou 2
|
||||
|
||||
|
||||
if (config_serial0.validite == 1) // Cas où la config en cours prévoit l'utilisation de l'UART0 :
|
||||
{
|
||||
|
||||
config_serial0.filestream = -1;
|
||||
sprintf(tmp, "Initialisation de l'UART0 (");
|
||||
|
||||
config_serial0.filestream = open("/dev/serial0", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
|
||||
// O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
|
||||
// if there is no input immediately available (instead of blocking). Likewise, write requests can also return
|
||||
// immediately with a failure status if the output can't be written immediately.
|
||||
// O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.
|
||||
|
||||
if (config_serial0.filestream != -1)
|
||||
{
|
||||
|
||||
//The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
|
||||
// Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
|
||||
// CSIZE:- CS5, CS6, CS7, CS8
|
||||
// CLOCAL - Ignore modem status lines
|
||||
// CREAD - Enable receiver
|
||||
// IGNPAR = Ignore characters with parity errors
|
||||
// ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for binary comms!)
|
||||
// PARENB - Parity enable
|
||||
// PARODD - Odd parity (else even)
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Lecture de la configuration en cours => variable locale options :
|
||||
if (tcgetattr(config_serial0.filestream, &options) < 0)
|
||||
{
|
||||
sprintf(tmp, "Initialisation de l'UART0 impossible : erreur lors de lecture des paramètres du port...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Mise à jour des paramètres non configurables dans la BDD :
|
||||
|
||||
// Configuration du registre 'cflag' :
|
||||
// options.c_cflag = 0;
|
||||
options.c_cflag |= CLOCAL; // Ignore modem status lines
|
||||
options.c_cflag |= CREAD; // Enable receiver
|
||||
options.c_cflag &= ~CRTSCTS; // no hardware flowcontrol
|
||||
// options.c_cflag |= CMSPAR; // force Even parity to SPACE
|
||||
|
||||
// Configuration du registre 'lflag' :
|
||||
// options.c_lflag = 0;
|
||||
options.c_lflag &= ~ECHO;
|
||||
options.c_lflag &= ~ECHOE;
|
||||
options.c_lflag &= ~ECHONL;
|
||||
options.c_lflag &= ~ICANON;
|
||||
options.c_lflag &= ~ISIG;
|
||||
options.c_lflag &= ~IEXTEN;
|
||||
|
||||
// Configuration du registre 'iflag' :
|
||||
// options.c_iflag = 0;
|
||||
options.c_iflag &= ~IGNCR; // preserve carriage return
|
||||
options.c_iflag &= ~INLCR; // Don't map NL to CR on input
|
||||
options.c_iflag &= ~ICRNL; // Don't map CR to NL on input
|
||||
options.c_iflag &= ~IUCLC; // Don't map upper-case to lower-case on input
|
||||
options.c_iflag &= ~IUCLC; // Don't convert uppecase to lowercase on input
|
||||
options.c_iflag &= ~IMAXBEL; // Don't beep on reception as input buffer is full
|
||||
options.c_iflag &= ~IXANY; // Don't enable any character to restart outputno SW flowcontrol
|
||||
options.c_iflag &= ~IXON; // Don't enable start output control
|
||||
options.c_iflag &= ~IXOFF; // Don't enable stop output control (attention : doc pas très claire entre Xon et Xoff)
|
||||
options.c_iflag |= IGNBRK; // ignore breaks
|
||||
options.c_iflag &= ~ISTRIP; // Don't clear MSB (b8) on input
|
||||
options.c_iflag &= ~IGNPAR; // Don't ignore (check) parity errors
|
||||
options.c_iflag |= INPCK; // test parity
|
||||
options.c_iflag &= ~PARMRK; // Don't use verbose parity error (Signaler les erreurs de parité par une séquence 255-0-car. )
|
||||
|
||||
// Configuration du registre 'oflag' :
|
||||
options.c_oflag &= ~OPOST; // Don't use post-process output (?)
|
||||
|
||||
// Configuration des caractères de contrôle 'c_cc' :
|
||||
// options.c_cc[VEOL] = 0;
|
||||
// options.c_cc[VEOL2] = 0;
|
||||
// options.c_cc[VEOF] = 0x04;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Initialisation de la vitesse de communication :
|
||||
switch(config_serial0.vitesse)
|
||||
{
|
||||
case 1200: { speed = B1200; break; }
|
||||
case 2400: { speed = B2400; break; }
|
||||
case 4800: { speed = B4800; break; }
|
||||
case 9600: { speed = B9600; break; }
|
||||
case 19200: { speed = B19200; break; }
|
||||
case 38400: { speed = B38400; break; }
|
||||
case 57600: { speed = B57600; break; }
|
||||
case 115200: { speed = B115200; break; }
|
||||
case 921600 : { speed = B921600; break; }
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "\tInitialisation de l'UART0 impossible : vitesse de communication non valide (%i b/s) ...", config_serial0.vitesse);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// Mise à jour de la valeur dans la structure :
|
||||
cfsetospeed(&options, speed);
|
||||
cfsetispeed(&options, speed);
|
||||
|
||||
// Mise à jour du message de configuration :
|
||||
sprintf(chaine_temp, "%i b/s", config_serial0.vitesse);
|
||||
strcat(tmp, chaine_temp);
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Initialisation du nombre de bits de données :
|
||||
options.c_cflag &= ~CSIZE; // RAZ des bits concernés
|
||||
|
||||
switch(config_serial0.longueur)
|
||||
{
|
||||
case 8: { options.c_cflag |= CS8; break; }
|
||||
case 7: { options.c_cflag |= CS7; break; }
|
||||
case 6: { options.c_cflag |= CS6; break; }
|
||||
case 5: { options.c_cflag |= CS5; break; }
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "Initialisation de l'UART0 impossible : nombre de bits de données non valide (%i bits) ...", config_serial0.longueur);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// Mise à jour du message de configuration :
|
||||
sprintf(chaine_temp, ", %i bits", config_serial0.longueur);
|
||||
strcat(tmp, chaine_temp);
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Initialisation de la parité :
|
||||
|
||||
// ATTENTION : les tests de parité ne semblent pas fonctionner !!! Leur configuration ne semble avoir aucun effet (pas d'erreur générée).
|
||||
|
||||
switch(config_serial0.parite)
|
||||
{
|
||||
case 0: // Pas de parité :
|
||||
{
|
||||
options.c_cflag &= ~PARENB; /* Disable parity */
|
||||
strcat(tmp, ", pas de parité");
|
||||
break;
|
||||
}
|
||||
case 1: // Parité impaire :
|
||||
{
|
||||
options.c_cflag |= PARENB; // Parité validée
|
||||
options.c_cflag |= PARODD; /* Odd parity */
|
||||
strcat(tmp, ", parité impaire");
|
||||
break;
|
||||
}
|
||||
case 2: // Parité paire :
|
||||
{
|
||||
options.c_cflag |= PARENB; // Parité validée
|
||||
options.c_cflag &= ~PARODD; /* Even parity */
|
||||
strcat(tmp, ", parité paire");
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "\tInitialisation de l'UART0 impossible : parité non valide (%i) ...", config_serial0.parite);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Initialisation du nombre de bits de stop :
|
||||
switch(config_serial0.stops)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
options.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
|
||||
strcat(tmp, ", un bit de stop");
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
options.c_cflag |= CSTOPB; /* activate double stop bits */
|
||||
strcat(tmp, ", deux bits de stop");
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "Initialisation de l'UART0 impossible : nombre de bits de stop non valide (%i) ...", config_serial0.stops);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Mise à jour des nouveaux paramètres :
|
||||
tcsetattr(config_serial0.filestream, TCSANOW, &options); // Mise à jour des nouvelles valeurs de configuration (depuis 'options')
|
||||
delai_dixieme_sec(2); // Délai nécessaire pour que le flush fonctionne (testé avec délai = 1 : Ok)
|
||||
tcflush(config_serial0.filestream, TCIOFLUSH); // Vidage du port (en Inputs et en Ouptuts)
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Finalisation du message de débug :
|
||||
strcat(tmp, ")\t: OK");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
|
||||
return(0);
|
||||
}
|
||||
else // Cas où l'ouverture du port ne s'est pas passée correctement :
|
||||
{
|
||||
sprintf(tmp, "Initialisation de l'UART0 impossible : erreur lors de l'ouverture du port...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
else // L'UART n'est pas validé :
|
||||
{
|
||||
sprintf(tmp, "La configuration en cours ne prévoit pas l'utilisation de l'UART0 (la configuration de celui-ci n'a pas été affectée par l'application)...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
return(0); // On ne considère pas cela comme une erreur et l'init peut continuer.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction init_serial1
|
||||
|
||||
Fonction d'initialisation de la liaison 'serial1'.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int init_serial1(void)
|
||||
{
|
||||
char chaine_temp[MAX_TAILLE_CHAINE_TEMP_UARTS];
|
||||
struct termios options;
|
||||
speed_t speed;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
// Paramètres de configuration (en dur car inutile de les importer de la BDD) :
|
||||
config_serial1.validite = 1;
|
||||
config_serial1.vitesse = 115200; // 1200 à 115200
|
||||
config_serial1.longueur = 8; // 7 ou 8
|
||||
config_serial1.parite = 0; // 0=No, 1=Odd et 2=Even
|
||||
config_serial1.stops = 1; // 1 ou 2
|
||||
|
||||
|
||||
if (config_serial1.validite == 1) // Cas où la config en cours prévoit l'utilisation de l'UART1 :
|
||||
{
|
||||
|
||||
config_serial1.filestream = -1;
|
||||
sprintf(tmp, "Initialisation de l'UART1 (");
|
||||
|
||||
config_serial1.filestream = open("/dev/serial1", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
|
||||
// O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
|
||||
// if there is no input immediately available (instead of blocking). Likewise, write requests can also return
|
||||
// immediately with a failure status if the output can't be written immediately.
|
||||
// O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.
|
||||
|
||||
if (config_serial1.filestream != -1)
|
||||
{
|
||||
|
||||
//The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
|
||||
// Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
|
||||
// CSIZE:- CS5, CS6, CS7, CS8
|
||||
// CLOCAL - Ignore modem status lines
|
||||
// CREAD - Enable receiver
|
||||
// IGNPAR = Ignore characters with parity errors
|
||||
// ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for binary comms!)
|
||||
// PARENB - Parity enable
|
||||
// PARODD - Odd parity (else even)
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Lecture de la configuration en cours => variable locale options :
|
||||
if (tcgetattr(config_serial1.filestream, &options) < 0)
|
||||
{
|
||||
sprintf(tmp, "Initialisation de l'UART1 impossible : erreur lors de lecture des paramètres du port...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Mise à jour des paramètres non configurables dans la BDD :
|
||||
|
||||
// Configuration du registre 'cflag' :
|
||||
// options.c_cflag = 0;
|
||||
options.c_cflag |= CLOCAL; // Ignore modem status lines
|
||||
options.c_cflag |= CREAD; // Enable receiver
|
||||
options.c_cflag &= ~CRTSCTS; // no hardware flowcontrol
|
||||
// options.c_cflag |= CMSPAR; // force Even parity to SPACE
|
||||
|
||||
// Configuration du registre 'lflag' :
|
||||
// options.c_lflag = 0;
|
||||
options.c_lflag &= ~ECHO;
|
||||
options.c_lflag &= ~ECHOE;
|
||||
options.c_lflag &= ~ECHONL;
|
||||
options.c_lflag &= ~ICANON;
|
||||
options.c_lflag &= ~ISIG;
|
||||
options.c_lflag &= ~IEXTEN;
|
||||
|
||||
// Configuration du registre 'iflag' :
|
||||
// options.c_iflag = 0;
|
||||
options.c_iflag &= ~IGNCR; // preserve carriage return
|
||||
options.c_iflag &= ~INLCR; // Don't map NL to CR on input
|
||||
options.c_iflag &= ~ICRNL; // Don't map CR to NL on input
|
||||
options.c_iflag &= ~IUCLC; // Don't map upper-case to lower-case on input
|
||||
options.c_iflag &= ~IUCLC; // Don't convert uppecase to lowercase on input
|
||||
options.c_iflag &= ~IMAXBEL; // Don't beep on reception as input buffer is full
|
||||
options.c_iflag &= ~IXANY; // Don't enable any character to restart outputno SW flowcontrol
|
||||
options.c_iflag &= ~IXON; // Don't enable start output control
|
||||
options.c_iflag &= ~IXOFF; // Don't enable stop output control (attention : doc pas très claire entre Xon et Xoff)
|
||||
options.c_iflag |= IGNBRK; // ignore breaks
|
||||
options.c_iflag &= ~ISTRIP; // Don't clear MSB (b8) on input
|
||||
options.c_iflag &= ~IGNPAR; // Don't ignore (check) parity errors
|
||||
options.c_iflag |= INPCK; // test parity
|
||||
options.c_iflag &= ~PARMRK; // Don't use verbose parity error (Signaler les erreurs de parité par une séquence 255-0-car. )
|
||||
|
||||
// Configuration du registre 'oflag' :
|
||||
options.c_oflag &= ~OPOST; // Don't use post-process output (?)
|
||||
|
||||
// Configuration des caractères de contrôle 'c_cc' :
|
||||
// options.c_cc[VEOL] = 0;
|
||||
// options.c_cc[VEOL2] = 0;
|
||||
// options.c_cc[VEOF] = 0x04;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Initialisation de la vitesse de communication :
|
||||
switch(config_serial1.vitesse)
|
||||
{
|
||||
case 1200: { speed = B1200; break; }
|
||||
case 2400: { speed = B2400; break; }
|
||||
case 4800: { speed = B4800; break; }
|
||||
case 9600: { speed = B9600; break; }
|
||||
case 19200: { speed = B19200; break; }
|
||||
case 38400: { speed = B38400; break; }
|
||||
case 57600: { speed = B57600; break; }
|
||||
case 115200: { speed = B115200; break; }
|
||||
case 921600 : { speed = B921600; break; }
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "\tInitialisation de l'UART1 impossible : vitesse de communication non valide (%i b/s) ...", config_serial1.vitesse);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// Mise à jour de la valeur dans la structure :
|
||||
cfsetospeed(&options, speed);
|
||||
cfsetispeed(&options, speed);
|
||||
|
||||
// Mise à jour du message de configuration :
|
||||
sprintf(chaine_temp, "%i b/s", config_serial1.vitesse);
|
||||
strcat(tmp, chaine_temp);
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Initialisation du nombre de bits de données :
|
||||
options.c_cflag &= ~CSIZE; // RAZ des bits concernés
|
||||
|
||||
switch(config_serial1.longueur)
|
||||
{
|
||||
case 8: { options.c_cflag |= CS8; break; }
|
||||
case 7: { options.c_cflag |= CS7; break; }
|
||||
case 6: { options.c_cflag |= CS6; break; }
|
||||
case 5: { options.c_cflag |= CS5; break; }
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "Initialisation de l'UART1 impossible : nombre de bits de données non valide (%i bits) ...", config_serial1.longueur);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// Mise à jour du message de configuration :
|
||||
sprintf(chaine_temp, ", %i bits", config_serial1.longueur);
|
||||
strcat(tmp, chaine_temp);
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Initialisation de la parité :
|
||||
|
||||
// ATTENTION : les tests de parité ne semblent pas fonctionner !!! Leur configuration ne semble avoir aucun effet (pas d'erreur générée).
|
||||
|
||||
switch(config_serial1.parite)
|
||||
{
|
||||
case 0: // Pas de parité :
|
||||
{
|
||||
options.c_cflag &= ~PARENB; /* Disable parity */
|
||||
strcat(tmp, ", pas de parité");
|
||||
break;
|
||||
}
|
||||
case 1: // Parité impaire :
|
||||
{
|
||||
options.c_cflag |= PARENB; // Parité validée
|
||||
options.c_cflag |= PARODD; /* Odd parity */
|
||||
strcat(tmp, ", parité impaire");
|
||||
break;
|
||||
}
|
||||
case 2: // Parité paire :
|
||||
{
|
||||
options.c_cflag |= PARENB; // Parité validée
|
||||
options.c_cflag &= ~PARODD; /* Even parity */
|
||||
strcat(tmp, ", parité paire");
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "\tInitialisation de l'UART1 impossible : parité non valide (%i) ...", config_serial1.parite);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Initialisation du nombre de bits de stop :
|
||||
switch(config_serial1.stops)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
options.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
|
||||
strcat(tmp, ", un bit de stop");
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
options.c_cflag |= CSTOPB; /* activate double stop bits */
|
||||
strcat(tmp, ", deux bits de stop");
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "Initialisation de l'UART1 impossible : nombre de bits de stop non valide (%i) ...", config_serial1.stops);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Mise à jour des nouveaux paramètres :
|
||||
tcsetattr(config_serial1.filestream, TCSANOW, &options); // Mise à jour des nouvelles valeurs de configuration (depuis 'options')
|
||||
delai_dixieme_sec(2); // Délai nécessaire pour que le flush fonctionne (testé avec délai = 1 : Ok)
|
||||
tcflush(config_serial1.filestream, TCIOFLUSH); // Vidage du port (en Inputs et en Ouptuts)
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------
|
||||
// Finalisation du message de débug :
|
||||
strcat(tmp, ")\t: OK");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
|
||||
return(0);
|
||||
}
|
||||
else // Cas où l'ouverture du port ne s'est pas passée correctement :
|
||||
{
|
||||
sprintf(tmp, "Initialisation de l'UART1 impossible : erreur lors de l'ouverture du port...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
else // L'UART n'est pas validé :
|
||||
{
|
||||
sprintf(tmp, "La configuration en cours ne prévoit pas l'utilisation de l'UART1 (la configuration de celui-ci n'a pas été affectée par l'application)...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
return(0); // On ne considère pas cela comme une erreur et l'init peut continuer.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/**********************************************************************************************************************************************************************************
Fichier SERIAL.H
Contient tous les define liés aux liaisons série
**********************************************************************************************************************************************************************************/
// Maximums :
#define MAX_TAILLE_RX_BUFFER_UART 10000
#define MAX_TAILLE_TMP_RX_BUFFER_UART 255 // NB : doit être < MAX_TAILLE_RX_BUFFER_UART
#define MAX_TAILLE_CHAINE_TEMP_UARTS 200
// Codes ASCII :
#define ASCII_NULL 0x00
#define ASCII_SOH 0x01
#define ASCII_STX 0x02
#define ASCII_ETX 0x03
#define ASCII_EOT 0x04
#define ASCII_ENQ 0x05
#define ASCII_ACK 0x06
#define ASCII_LF 0x0A
#define ASCII_FF 0x0C
#define ASCII_CR 0x0D
#define ASCII_DLE 0x10
#define ASCII_NACK 0x15
#define ASCII_ETB 0x17
#define ASCII_ESC 0x1B
#define ASCII_SP 0x20
|
||||
@@ -0,0 +1,372 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier SORTIES.C
|
||||
//
|
||||
// Contient toutes les fonctions liées à l'écriture sur les sorties, quel que soit leur type
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Includes :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
void ecriture_sortie(uint8_t type, uint8_t module, uint8_t no, uint8_t valeur);
|
||||
void ecriture_sortie_gpio(int16_t no, int8_t valeur, int8_t logique);
|
||||
int8_t init_sorties(void);
|
||||
int8_t init_sorties_gpio(void);
|
||||
int16_t sortie_no(uint8_t type, uint8_t module, uint8_t no);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_sorties sorties;
|
||||
struct gpiod_chip *gpiod_chip0_sorties; // Nécessaire pour CM5
|
||||
struct gpiod_line_request *gpiod_sorties_request; // Nécessaire pour CM5
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ECRITURE_SORTIE
|
||||
|
||||
Fonction utilisée pour mettre à jour l'état d'une sortie, quel que soit sont type.
|
||||
Reçoit en paramètre : le Type de sortie, le module comportant la sortie, le n° sur le module et la valeur à appliquer
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void ecriture_sortie(uint8_t type, uint8_t module, uint8_t no, uint8_t valeur)
|
||||
{
|
||||
int x;
|
||||
|
||||
x = sortie_no(type, module, no);
|
||||
|
||||
if (x != -1)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case TYPE_SORTIE_GPIO :
|
||||
{
|
||||
sorties.gpio.sorties[x].valeur = valeur;
|
||||
|
||||
ecriture_sortie_gpio(sorties.gpio.sorties[x].no, sorties.gpio.sorties[x].valeur, sorties.gpio.sorties[x].logique);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_SORTIES
|
||||
|
||||
Intitialisation des entrées, quel que soit leur type.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_sorties(void)
|
||||
{
|
||||
|
||||
// Init des sorties GPIO :
|
||||
if (init_sorties_gpio() == -1) return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction INIT_SORTIES_GPIO
|
||||
|
||||
Configure les I/O du GPIO
|
||||
Renvoi -1 en cas d'erreur lors de l'initialisation.
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int8_t init_sorties_gpio(void)
|
||||
{
|
||||
int flag_erreur = 0;
|
||||
uint8_t groupe;
|
||||
uint8_t position_groupe;
|
||||
uint8_t i;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
i = 0;
|
||||
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1)
|
||||
{
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_MOD_WKUP;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_USB_AVANT_PWR_EN;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_TO_UC;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_Pdown_HDMI_CMD_N;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_WIFI_CHIP_EN;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_PWKEY_MOD;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_AUDIO_SD;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_TEST_TP1140;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_TEST_TP1141;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_TEST_TP1142;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_LCD_EN_VGx;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM3P_DO_LCD_EN_VDD;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
}
|
||||
else // V2 et V3 :
|
||||
{
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_DO_TO_UC;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_DO_USB_ARRIERE_PWR_EN;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_DO_GNSS_EXTINT;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_DO_AUDIO_SD;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_DO_GNSS_SAFEBOOT;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_Pdown_HDMI_CMD_N;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_DO_USB_AVANT_PWR_EN;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_DO_EN_LCD_VGx;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
|
||||
sorties.gpio.sorties[i].flag_validite = TRUE;
|
||||
sorties.gpio.sorties[i].no = CM4_DO_EN_LCD_VDD;
|
||||
sorties.gpio.sorties[i].pull = NO_PUP_PDN;
|
||||
sorties.gpio.sorties[i].logique = 1;
|
||||
i ++;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================================================
|
||||
// V3 (CM5) : réservation groupée des lignes GPIO via libgpiod, en sortie,
|
||||
// avec valeur initiale LOW (comportement identique à l'ancienne méthode mmap au premier boot).
|
||||
//====================================================================================================
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V3)
|
||||
{
|
||||
unsigned int offsets[MAX_NOMBRE_SORTIES_GPIO];
|
||||
uint8_t nb_lignes = 0;
|
||||
|
||||
struct gpiod_line_settings *settings = gpiod_line_settings_new();
|
||||
gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT);
|
||||
gpiod_line_settings_set_output_value(settings, GPIOD_LINE_VALUE_INACTIVE); // Etat bas par défaut, cf discussion
|
||||
|
||||
struct gpiod_line_config *line_cfg = gpiod_line_config_new();
|
||||
|
||||
struct gpiod_request_config *req_cfg = gpiod_request_config_new();
|
||||
gpiod_request_config_set_consumer(req_cfg, "shipheart_sorties");
|
||||
|
||||
gpiod_chip0_sorties = gpiod_chip_open("/dev/gpiochip0");
|
||||
if (gpiod_chip0_sorties == NULL)
|
||||
{
|
||||
sprintf(tmp, "Ouverture de /dev/gpiochip0 (sorties) impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
for (i=0; i<MAX_NOMBRE_SORTIES_GPIO; i++)
|
||||
{
|
||||
if (!sorties.gpio.sorties[i].flag_validite) continue;
|
||||
|
||||
offsets[nb_lignes] = sorties.gpio.sorties[i].no;
|
||||
gpiod_line_config_add_line_settings(line_cfg, &offsets[nb_lignes], 1, settings);
|
||||
nb_lignes++;
|
||||
|
||||
sprintf(tmp, "GPIO #%2i configurée en SORTIE (via libgpiod)", sorties.gpio.sorties[i].no);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
}
|
||||
|
||||
gpiod_sorties_request = gpiod_chip_request_lines(gpiod_chip0_sorties, req_cfg, line_cfg);
|
||||
|
||||
gpiod_request_config_free(req_cfg);
|
||||
gpiod_line_config_free(line_cfg);
|
||||
gpiod_line_settings_free(settings);
|
||||
|
||||
if (gpiod_sorties_request == NULL)
|
||||
{
|
||||
sprintf(tmp, "Réservation des lignes GPIO de sortie impossible...");
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0); // On sort ici : la boucle V1/V2 ci-dessous ne doit pas s'exécuter pour V3
|
||||
}
|
||||
|
||||
//====================================================================================================
|
||||
// V1 et V2 :
|
||||
//====================================================================================================
|
||||
for (i=0; i<MAX_NOMBRE_SORTIES_GPIO; i++)
|
||||
{
|
||||
if (!sorties.gpio.sorties[i].flag_validite) continue;
|
||||
|
||||
groupe = sorties.gpio.sorties[i].no / 10;
|
||||
position_groupe = sorties.gpio.sorties[i].no % 10;
|
||||
|
||||
// Configuration en Sortie de l'E/S GPIO :
|
||||
*(hardware.gpio_base + groupe) &= ~(7<<(position_groupe*3)); // Mets d'abord à 0 les 3 bits correspondant à N0
|
||||
*(hardware.gpio_base + groupe) |= (1<<(position_groupe*3)); // Mets ensuite à 1 le bit correspondant à N0 en sortie (sortie = 001)
|
||||
sprintf(tmp, "GPIO #%2i configurée en SORTIE", sorties.gpio.sorties[i].no);
|
||||
|
||||
// Configuration des résitances de pull-up/down :
|
||||
// Les fonctions de pull-up/down ne sont pas codées pour les sorties car non utilisées.
|
||||
// Si besoin, reprendre le code équivalent dans 'entrees.c'
|
||||
|
||||
// Affichage du message de débug :
|
||||
if (flag_erreur == 0) affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
|
||||
else affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
// Arrêt de l'intitialisation si erreur :
|
||||
if (flag_erreur != 0) return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction SORTIE_NO
|
||||
Reçoit en paramètre :
|
||||
- le type de sortie concerné
|
||||
- le module (adresse_k_bus) sur lequel la sortie se situe
|
||||
- Le n° de la sortie sur le module
|
||||
Retourne :
|
||||
- le numéro de sortie correspondant (ou -1 si aucune sortie valide ne correspond). La numérotation allant de 0 à MAX_SORTIES_xxxx (fonction du type).
|
||||
**********************************************************************************************************************************************************************************/
|
||||
int16_t sortie_no(uint8_t type, uint8_t module, uint8_t no)
|
||||
{
|
||||
int16_t i;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case TYPE_SORTIE_GPIO:
|
||||
{
|
||||
for (i=0; i<MAX_NOMBRE_SORTIES_GPIO; i++)
|
||||
{
|
||||
if ((sorties.gpio.sorties[i].flag_validite) &&
|
||||
(sorties.gpio.sorties[i].no == no)) return(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default : return(-1);
|
||||
}
|
||||
|
||||
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************************************************************
|
||||
Fonction ECRITURE_SORTIE_GPIO
|
||||
|
||||
Fonction utilisée pour écrire 'VALEUR' (0 ou 1) dans les registres du BCM283x en fonction du N° de sortie GPIO (0 à 53) et de la logique (-1 = logique inversée)
|
||||
Le fonctionnemengt a été adapté pour les CM5 pour lesquels les E/S GPIO ne sont plus accessiobles via des registres du SOC
|
||||
NB : cette fonction ne doit PAS être appelée en direct car elle ne met pas à jour l'état de la variable 'sorties.gpio.sorties[].etat' donc il y aura conflit avec le gestionnaire synchrone...!
|
||||
**********************************************************************************************************************************************************************************/
|
||||
void ecriture_sortie_gpio(int16_t no, int8_t valeur, int8_t logique)
|
||||
{
|
||||
int8_t on;
|
||||
|
||||
// Cas d'une sortie à logique inversée :
|
||||
if (logique == -1) on = OFF;
|
||||
else on = ON;
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
// V3 :
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V3)
|
||||
{
|
||||
enum gpiod_line_value val = (valeur == on) ? GPIOD_LINE_VALUE_ACTIVE : GPIOD_LINE_VALUE_INACTIVE;
|
||||
gpiod_line_request_set_value(gpiod_sorties_request, no, val);
|
||||
return;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// V1 & V2 :
|
||||
// Mise à jour des registres du BCM283x :
|
||||
if (no < 32) // Sorties 0 à 31 :
|
||||
{
|
||||
if (valeur == on) (*(hardware.gpio_base + hardware.offset_gpio_out_set_0)) = (1 << (no)); // Mise à 1 dans le registre de SET.
|
||||
else (*(hardware.gpio_base + hardware.offset_gpio_out_clear_0)) = (1 << (no)); // Mise à 1 dans le registre de RESET.
|
||||
}
|
||||
else // Sorties 32 à 53 :
|
||||
{
|
||||
if (valeur == on) (*(hardware.gpio_base + hardware.offset_gpio_out_set_1)) = (1 << (no - 32)); // Mise à 1 dans le registre de SET.
|
||||
else (*(hardware.gpio_base + hardware.offset_gpio_out_clear_1)) = (1 << (no - 32)); // Mise à 1 dans le registre de RESET.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier SORTIES.H
|
||||
//
|
||||
// Contient tous les define liés à la lecture de l'état des entrées
|
||||
//**********************************************************************************************************************************************************************************
|
||||
|
||||
// Sorties GPIO :
|
||||
#define CM3P_DO_MOD_WKUP 5 // Exemple: GPIO #5
|
||||
#define CM3P_DO_USB_AVANT_PWR_EN 11
|
||||
#define CM3P_DO_TO_UC 29
|
||||
#define CM3P_Pdown_HDMI_CMD_N 37
|
||||
#define CM3P_DO_WIFI_CHIP_EN 38
|
||||
#define CM3P_DO_PWKEY_MOD 39
|
||||
#define CM3P_DO_AUDIO_SD 40
|
||||
#define CM3P_DO_TEST_TP1140 41
|
||||
#define CM3P_DO_TEST_TP1141 42
|
||||
#define CM3P_DO_TEST_TP1142 43
|
||||
#define CM3P_DO_LCD_EN_VGx 44
|
||||
#define CM3P_DO_LCD_EN_VDD 45
|
||||
|
||||
#define CM4_DO_TO_UC 5
|
||||
#define CM4_DO_USB_ARRIERE_PWR_EN 7
|
||||
#define CM4_DO_GNSS_EXTINT 9
|
||||
#define CM4_DO_AUDIO_SD 10
|
||||
#define CM4_DO_GNSS_SAFEBOOT 11
|
||||
#define CM4_Pdown_HDMI_CMD_N 22
|
||||
#define CM4_DO_USB_AVANT_PWR_EN 23
|
||||
#define CM4_DO_EN_LCD_VGx 24
|
||||
#define CM4_DO_EN_LCD_VDD 25
|
||||
|
||||
|
||||
// Général :
|
||||
|
||||
|
||||
// Nombre max physique :
|
||||
#define MAX_NOMBRE_SORTIES_GPIO 54 // Il y a 54 E/S GPIO qui peuvent être configurées en Entrée ou en Sortie mais ce nombre peut-être < 54 (vérifié au chargement de la BDD)
|
||||
|
||||
|
||||
// Timings :
|
||||
#define PERIODE_ECRITURE_SORTIES_GPIO 5 // En x10ms.
|
||||
|
||||
|
||||
// Types d'Entrées/Sorties :
|
||||
#define TYPE_SORTIE_GPIO 0
|
||||
|
||||
|
||||
+2113
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,171 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier SYSTEME.H
|
||||
//
|
||||
// Contient tous les define liés aux fonctions système...
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
// Maximums :
|
||||
#define MAX_NOMBRE_MODULES (32+1) // Nombre maximal de cartes (y compris Compagnon) commandées par ShipHeart. A priori, toutes sont sur le k-bus + Compagnon
|
||||
#define MAX_NOMBRE_DEVICES_OW 32 // Nombre physique de device max (!= de MAX_NOMBRE_ENTREES_OW dans 'entrees.h')
|
||||
#define MAX_TAILLE_UNIQUE_ID 12 // Nombre d'octets de l'Unique ID stocké en ROM du µC
|
||||
#define MAX_TAILLE_TYPE_SOFT 20 // Taille de la chaine de caractère contenant les infos de type de logiciel (EXTENSION ou COMPAGNON)
|
||||
#define MAX_TAILLE_VERSION_SOFT 100 // Taille de la chaine de caractères contenant les infos de version logicielle
|
||||
#define MAX_TAILLE_EEPROM 256 // Taille, en octets, de la zone d'EEPROM utilisée pour stocker des paramètres de configuration. NB : cette dimension a un lien avec le champ 'Eeprom' dans TB_Modules_physiques qui fait 2xMAX_TAILLE_EEPROM pour pouvoir stocker chaque valeur sur 2 caractères alphas codés en hexa.
|
||||
#define MAX_BOUCLES_CALCUL_CRC 3 // Nombre de boucles max pour vérifier la lecture du CRC de l'application
|
||||
#define TAILLE_ADRESSE_MAC 6 // 6 octets stockés directement
|
||||
#define TAILLE_ADRESSE_IP_V4 16 // en caractères, pour stocker sous forme de chaine. Exemple : '123.123.123.123'
|
||||
#define TAILLE_ADRESSE_IP_V6 40 // en caractères, pour stocker sous forme de chaine. Exemple : '0123:0123:0123:0123:0123:0123:0123:0123'
|
||||
#define TAILLE_ADRESSE_IP TAILLE_ADRESSE_IP_V6 // Dans le doute...
|
||||
#define TAILLE_ROM_CODE_OW 8 // Nombre d'octets utilisés par les ROM Codes
|
||||
#define MAX_TAILLE_CRC 20 // Nombre maxi de caractères pour un CRC
|
||||
#define MAX_LONGUEUR_TOKEN_SHA256 32 // Le SHA256 est formé de... 256 bits, soit 32 octets. Attention : la chaine correspondante est formée de 65 caractères (32 x 2 car (hexa codé en Ascii) + NULL de fin)
|
||||
|
||||
#define MAX_LONGUEUR_CHAINE_VERSION_CM 100 // Longueur maxi de la chaine représentant la version de Compute Module (renvoyée dans TB_Systeme.Version_cm)
|
||||
#define MAX_LONGUEUR_NOM_REPERTOIRE_LOCAL 200 // Longueur maxi du nom d'un répertoire local
|
||||
#define MAX_LONGUEUR_NOM_FICHIER 100 // Longueur maxi, y compris NULL de fin de chaine, d'un nom de fichier (SANS répertoire)
|
||||
#define MAX_LONGUEUR_NOM_BATEAU 50 // Nomre maxi de caractères du nom de bateau
|
||||
#define MAX_TAILLE_COMMANDE_SHELL 2000 // Taille maxi d'une commande Shell lancée via 'systeme()'
|
||||
#define MAX_LONGUEUR_URL 256 // Longueur maxi de l'URL (notament en HTTP). A priori, selon retour de AT+SHCONF?, le max serait 512.
|
||||
#define MAX_LONGUEUR_REQUETE_HTTP 512 // Longueur maxi de la requête HTTP (notamment GET). Cette longueur est vérifiable par 'AT+SHREQ=?'
|
||||
#define MAX_TAILLE_FICHIER_UPLOAD 10000000 // En octets. Tout fichier de taille supérieure ne pourra pas être uploadé
|
||||
#define MAX_TAILLE_BUFFER_UPLOAD 1500 // A priori, le modem limite à 1360 mais c'est quelque chose qui peut évoluer en fonction de la version de firmware, vorie en dynamique.
|
||||
#define MAX_TAILLE_FICHIER_DOWNLOAD 10000000 // En octets. Tout fichier de taille supérieure ne pourra pas être downloadé
|
||||
#define MAX_TAILLE_BUFFER_DOWNLOAD 5000
|
||||
#define MAX_NOMBRE_FICHIERS_DOWNLOAD 100 // Nombre maxi de fichiers qui pourront être traités (s'il y en a plus, ils seront traités quand les premiers seront effacés).
|
||||
#define MAX_NOMBRE_PARAMETRES_LISTE_DOWNLOAD 12 // Nombre de paramètres d'une ligne FTPLIST (type commande 'ls -l')
|
||||
#define MAX_TAILLE_BLOC_DATA_CHARGEMENT_CODE 256 // Taille maximale d'un bloc de data lors du chargement de code (nb : c'est cette quantité qui est émise par défaut. Or, le chargement ne fonctionne qu'avec des multiples de 4 octets. Donc, merci de laisser une valeur multiple de 4...!!!!!)
|
||||
#define MAX_TAILLE_FICHIER_JSON 10000 // Taille maximale d'un fichier JSON
|
||||
#define MAX_TAILLE_DESCRIPTION_PACKAGE 4096 // Taille maxi du champ 'Description' d'un fichier JSON de version.
|
||||
#define MAX_REPETITIONS_CHARGEMENT_CODE 5 // Nb max de tentatives de répétitions lorsque le chargement sur une carte ne fonctionne pas
|
||||
|
||||
|
||||
|
||||
// Timings :
|
||||
#define SYSTEME_TEMPO_INIT 0 // En x 10ms
|
||||
#define SYSTEME_TEMPO_ATTENTE_REINIT_PAR_DEFAUT 60 // En x 100ms Temporisation entre la réception d'une demande de réinit (transmise au Compagnon pour action) et l'arrêt "propre" de l'application. NB : sur le compagnon, l'exécution est temporisé de 8s ; il est donc prudent de caler cette tempo là en-dessous de cette valeur...
|
||||
#define SYSTEME_TEMPO_PERIODE_CHECK_NEW_DOWNLOAD 3600 // En secondes En pratique, la tempo est ramenée à 1min après chaque connexion réseau. Cette valeur est donc un max si aucune connexion réseau n'est faite...
|
||||
#define SYSTEME_TEMPO_REPORT_SAUVEGARDE 5 // En secondes Temporisation si une sauvagarde est demandée alors qu'un archivage est déjà en cours (non critique car la test d'archivage en cours sera effectué à la fin de cette tempo et, si besoin, relancée)
|
||||
#define SYSTEME_TEMPO_ATTENTE_DISPO_C_BUS 10 // En x 10ms NB : tempo non critique car attentes multiples jusqu'à ce que C-Bus soit dispo
|
||||
#define SYSTEME_TEMPO_LECTURE_ID_CARTES 1 // En x 10ms NB : Tempo non critique, elle permet juste de ne pas faire des tests en permanence en attendant la réception de tous les ID
|
||||
#define SYSTEME_TIME_OUT_LECTURE_ID_CARTES 10 // En x 100ms SDIR #304
|
||||
#define SYSTEME_TIME_OUT_ANNUAIRE_ONE_WIRE 5 // En x 100ms
|
||||
#define SYSTEME_TEMPO_ATTENTE_CONFIG_CARTES 30 // En x 10ms NB : tempo non critique car permet juste d'éviter de recevoir des commandes UP sur des cartes non configurées (donc générant des retours d'erreur vers le Compagnon). NB : les commandes UP génériques ET avec Haute Priorité passent quand même pendant ce temps...
|
||||
#define SYSTEME_ATTENTE_DEMARRAGE_COMPTEUR_BOUCLE_PRINCIPALE 5 // en secondes. Défini l'attente avant prise en compte des mesures de nb de boucles principales
|
||||
#define SYSTEME_ATTENTE_BOUCLE_PRINCIPALE_TEMPO 1000 // en nanosecondes théoriquement... Cf ci-dessous
|
||||
// Mesures effectuées le 28/04/2018, le 02/09/2020 et le 26/03/2021 sur CM3+ pour ShipHeart :
|
||||
// Valeur Boucles/secondes Load average @1min (première valeur de HTOP)
|
||||
// 0 65 000 3.2 - 3.8 (sur 4.0 max !) (==> mise en commentaires du 'delai_nano_sec')
|
||||
// 1 10 000 - 11000 3.1 - 3.8
|
||||
// 2 9 500 - 11 000 2.3 - 2.6
|
||||
// 5 9 500 - 10 500 2.3 - 2.6
|
||||
// 10 => environ 11 000 boucles/sec. Charge CPU = 40%
|
||||
// 100 => environ 11 000 boucles/sec. Charge CPU = 40%
|
||||
// 1 000 => environ 10 500 boucles/sec. Charge CPU = 39%
|
||||
// 10 000 => environ 9 500 boucles/sec. Charge CPU = 35-38%. Load Average (@1min) = 0.25-0.30 avec pointes à 0.55
|
||||
// 100 000 => environ 4 300 boucles/sec. Charge CPU = 29%
|
||||
// 1 000 000 => environ 800 boucles/sec. Charge CPU = 6% ==> déclenche des erreurs de bus SPI (plusieurs dizaines par jour... d'où ces mesures)
|
||||
// 10 000 000 => environ 90 boucles/sec. Charge CPU = 1%
|
||||
|
||||
// Nouvelles mesures sur CM4 (4Go) le 23/12/2023 :
|
||||
// 1 000 => environ 12 000 boucles/sec (très stable !). Charge CPU = 30-35%. Load average 0.33-0.35 avec des pointes à 0.50
|
||||
// 10 000 => entre 7000 et 11000 (avg = 9500) boucles/sec (assez instable). Charge CPU = 28-35%. Load average 0.60-0.80 avec des pointes à 0.90
|
||||
|
||||
|
||||
|
||||
#define MISE_A_JOUR_TEMPO_INIT 20 // En x 100ms Dans tous les cas, l'init du séquenceur de Mise_à_jour ne se fera que lorsque l'analyse de l'annuaire aura été fait. Cette tempo n'est donc pas critique...
|
||||
#define MISE_A_JOUR_TIME_OUT_HTTP_GET 600 // En x 100ms Time-out de l'échange HTTP GET
|
||||
|
||||
#define CHARGEMENT_CODE_TEMPO_INIT 2 // En x 100ms // Il n'y a aucune raison d'attendre...
|
||||
#define CHARGEMENT_CODE_TEMPO_ATTENTE_EFFACEMENT_FLASH 50 // En x 100ms // Durée théorique env. 1.9s voire 3.4s pour les L151 @12MHz
|
||||
#define CHARGEMENT_CODE_TIME_OUT_ATTENTE_ECRITURE_BLOC 10 // En x 100ms
|
||||
#define CHARGEMENT_CODE_TEMPO_ATTENTE_INTER_BLOCS_COMPAGNON 1 // En x 100ms
|
||||
#define CHARGEMENT_CODE_TEMPO_ATTENTE_INTER_BLOCS_K_BUS 3 // En x 100ms // Tests Ok fait avec 200ms sur ShipBS (lent...) mais 2 noeuds sur K-Bus. Par sécurité, la tempo est laissée à 300ms...
|
||||
#define CHARGEMENT_CODE_TEMPO_ATTENTE_FIN_ACTIVATION 50 // En x 100ms // Durée entre l'envoi des commandes d'activation après chargement et demande de réinitialisation
|
||||
|
||||
|
||||
// Erreurs système :
|
||||
#define ERREUR_SYSTEME_AUCUNE 0
|
||||
#define ERREUR_SYSTEME_CONFIG -1
|
||||
#define ERREUR_SYSTEME_RESEAU -2
|
||||
|
||||
|
||||
|
||||
|
||||
// Types de cartes :
|
||||
#define TYPE_CARTE_INCONNU -1
|
||||
#define TYPE_CARTE_SHIPBASE 0
|
||||
#define TYPE_CARTE_SP812 1
|
||||
#define TYPE_CARTE_SBS 2
|
||||
#define TYPE_CARTE_SP4AC 3
|
||||
#define TYPE_CARTE_SP8DC 4
|
||||
|
||||
#define GENERATION_SHIPBASE_INCONNUE 0
|
||||
#define GENERATION_SHIPBASE_V1 1 // Entre 2020 et 2022, équipés de CM3+
|
||||
#define GENERATION_SHIPBASE_V2 2 // A partir de 2023, équipés de CM4. A noter que la 'hardware_version' reçue du Compagnon doit correspondre à cette évolution.
|
||||
#define GENERATION_SHIPBASE_V3 3 // Les SHipBase V2, équipés de CM5 (début = 08/2026)
|
||||
|
||||
// Adresses IP :
|
||||
#define ADRESSE_IP_INCONNUE "inconnue" // Valeur utilisée par défaut, au démarrage de l'application. Attention, la taille doit être inférieure à TAILLE_ADRESSE_IP - 1.
|
||||
|
||||
|
||||
// Demandes Système :
|
||||
#define SYSTEME_SIGNAL_AUCUN 0 // Valeur par défaut. Les valeurs de signaux ont toute une valeur > 0
|
||||
|
||||
// Valeurs de Mode_validation_maj :
|
||||
#define MODE_VALIDATION_MAJ_AUCUNE 0
|
||||
#define MODE_VALIDATION_MAJ_MANUELLE 1
|
||||
#define MODE_VALIDATION_MAJ_AUTOMATIQUE 2
|
||||
|
||||
// Valeurs de Mode_maj_firmwares :
|
||||
#define MODE_MAJ_FIRMWARES_NORMAL 0
|
||||
#define MODE_MAJ_FIRMWARES_SI_DIFFERENTS 1
|
||||
#define MODE_MAJ_FIRMWARES_TOUJOURS 2
|
||||
|
||||
// Valeurs de Demande_maj_soft :
|
||||
// #define DEMANDE_MAJ_SOFT_AUCUNE 0 // Valeur de repos
|
||||
// #define DEMANDE_MAJ_SOFT_VALIDATION 1 // Vlaidation du fichier dans A_VALIDER qui sera copié dans A_CHARGER
|
||||
// #define DEMANDE_MAJ_SOFT_CHARGEMENT 2 // Idem VALIDATION + demande de reset pour prise en compte immédiate
|
||||
// #define DEMANDE_MAJ_SOFT_ANNULATION -1 // Suppression du fichier présent dans A_VALIDER ou dans A_CHARGER (les 2 sont vidés)
|
||||
|
||||
// Etat de veille
|
||||
#define SYSTEME_VEILLE_AUCUNE 0
|
||||
#define SYSTEME_VEILLE_LEGERE 1
|
||||
#define SYSTEME_VEILLE_PROFONDE 2
|
||||
|
||||
|
||||
// Modes de chargement de code :
|
||||
#define CHARGEMENT_CODE_MODE_EFFACEMENT_FLASH 0
|
||||
#define CHARGEMENT_CODE_MODE_CHARGEMENT_BLOC 1
|
||||
#define CHARGEMENT_CODE_MODE_CHECK_CRC 2
|
||||
#define CHARGEMENT_CODE_MODE_VALIDATION_VERSION 3
|
||||
|
||||
|
||||
// Etat séquenceur Système :
|
||||
#define ETAT_SEQUENCEUR_SYSTEME_INIT 0
|
||||
#define ETAT_SEQUENCEUR_SYSTEME_ATTENTE_ANNUAIRE_K_BUS 1
|
||||
#define ETAT_SEQUENCEUR_SYSTEME_LECTURE_ID_CARTES 2
|
||||
#define ETAT_SEQUENCEUR_SYSTEME_ATTENTE_ANNUAIRE_ONE_WIRE 3
|
||||
#define ETAT_SEQUENCEUR_SYSTEME_CHARGEMENT_CONFIG_CARTES 4
|
||||
#define ETAT_SEQUENCEUR_SYSTEME_ATTENTE_CONFIG_CARTES 5
|
||||
#define ETAT_SEQUENCEUR_SYSTEME_REPOS 10
|
||||
#define ETAT_SEQUENCEUR_SYSTEME_DEMARRAGE_IMPOSSIBLE 20
|
||||
|
||||
|
||||
// Etat séquenceur Chargement de Code :
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_INIT 0
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_REPOS 1
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT 2
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_LANCEMENT_CARTE 3
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_EFFACEMENT_FLASH 4
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_CHARGEMENT_BLOC 5
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_ATTENTE_INTER_BLOCS 6
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_VERIFICATION_CRC 7
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_CARTE 8
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_CHARGEMENT 9
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_FIN_ACTIVATION 10
|
||||
#define ETAT_SEQUENCEUR_CHARGEMENT_CODE_ERREUR 11
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
// **********************************************************************************************************************************************************************************
|
||||
// Fichier USB.C
|
||||
//
|
||||
// Contient toutes les fonctions liées aux ports USB
|
||||
// **********************************************************************************************************************************************************************************
|
||||
|
||||
// Include :
|
||||
#include "main.h"
|
||||
|
||||
// Prototypes :
|
||||
int8_t init_usb(void);
|
||||
void gestion_usb(void);
|
||||
|
||||
|
||||
// Variables globales :
|
||||
struct Struct_usb usb;
|
||||
|
||||
uint16_t test;
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Gestion des ports USB
|
||||
// Reçoit : Rien
|
||||
// Retourne : Rien
|
||||
//**********************************************************************************************************************************************************************************
|
||||
void gestion_usb(void)
|
||||
{
|
||||
uint8_t i;
|
||||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||||
|
||||
|
||||
switch(usb.sequenceur.etat)
|
||||
{
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_USB_INIT :
|
||||
{
|
||||
if (usb.sequenceur.compteur == 0)
|
||||
{
|
||||
usb.sequenceur.etat = ETAT_SEQUENCEUR_USB_REPOS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
case ETAT_SEQUENCEUR_USB_REPOS :
|
||||
{
|
||||
if (usb.sequenceur.compteur == 0)
|
||||
{
|
||||
usb.sequenceur.compteur = USB_PERIODE_SURVEILLANCE;
|
||||
|
||||
//---------------------------------------------
|
||||
// Recherche des éventuels défauts :
|
||||
for (i = 0; i < USB_MAX_NOMBRE_PORTS; i ++)
|
||||
{
|
||||
if (usb.ports[i].flag_validite == FALSE) continue;
|
||||
|
||||
if ((usb.ports[i].defaut == USB_ETAT_PORT_OK) && (lecture_entree(TYPE_ENTREES_GPIO, 0, usb.ports[i].no_entree_defaut, TRUE) == ON)) // 0 est l'adresse de ShipBase
|
||||
{
|
||||
usb.ports[i].defaut = USB_ETAT_PORT_DEFAUT;
|
||||
|
||||
sprintf(tmp, "Le port USB n° %i vient de passer en défaut", (i+1));
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_USB, USB_PASSAGE_DEFAUT, (i+1), 0, NULL);
|
||||
}
|
||||
|
||||
if ((usb.ports[i].defaut == USB_ETAT_PORT_DEFAUT) && (lecture_entree(TYPE_ENTREES_GPIO, 0, usb.ports[i].no_entree_defaut, TRUE) == OFF)) // 0 est l'adresse de ShipBase
|
||||
{
|
||||
usb.ports[i].defaut = USB_ETAT_PORT_OK;
|
||||
|
||||
sprintf(tmp, "Le défaut sur le port USB n° %i vient de disparaitre", (i+1));
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||||
|
||||
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_USB, USB_PASSAGE_OK, (i+1), 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Ports avant - Lien avec le circuit de commande:
|
||||
if (usb.no_circuit_usb_avant != -1)
|
||||
{
|
||||
// Etat des ports :
|
||||
circuits.circuits[usb.no_circuit_usb_avant].etat = (usb.ports[USB_FACE_AVANT_HAUT].defaut << 2) |
|
||||
(usb.ports[USB_FACE_AVANT_MILIEU].defaut << 1) |
|
||||
(usb.ports[USB_FACE_AVANT_BAS].defaut);
|
||||
|
||||
// Commande de l'alimentation :
|
||||
if (circuits.circuits[usb.no_circuit_usb_avant].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante == OFF)
|
||||
{
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, usb.sortie_gpio_cm_do_usb_avant_pwr_en, OFF); // Coupure de l'alimentation des ports. 0 est l'adresse de ShipBase
|
||||
}
|
||||
else ecriture_sortie(TYPE_SORTIE_GPIO, 0, usb.sortie_gpio_cm_do_usb_avant_pwr_en, ON); // Commande de l'alimentation des ports. 0 est l'adresse de ShipBase
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Port arrière - Lien avec le circuit de commande:
|
||||
if ((usb.ports[USB_FACE_ARRIERE].flag_validite) &&
|
||||
(usb.no_circuit_usb_arriere != -1))
|
||||
{
|
||||
// Etat des ports :
|
||||
circuits.circuits[usb.no_circuit_usb_arriere].etat = usb.ports[USB_FACE_ARRIERE].defaut;
|
||||
|
||||
// Commande de l'alimentation :
|
||||
if (circuits.circuits[usb.no_circuit_usb_arriere].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante == OFF)
|
||||
{
|
||||
ecriture_sortie(TYPE_SORTIE_GPIO, 0, usb.sortie_gpio_cm_do_usb_arriere_pwr_en, OFF); // Coupure de l'alimentation des ports. 0 est l'adresse de ShipBase
|
||||
}
|
||||
else ecriture_sortie(TYPE_SORTIE_GPIO, 0, usb.sortie_gpio_cm_do_usb_arriere_pwr_en, ON); // Commande de l'alimentation des ports. 0 est l'adresse de ShipBase
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
default :
|
||||
{
|
||||
sprintf(tmp, "L'état du séquenceur Usb est inconnu [%i]. Il est repositionné au REPOS", usb.sequenceur.etat);
|
||||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||||
usb.sequenceur.etat = ETAT_SEQUENCEUR_USB_REPOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fonction : Init des ports USB
|
||||
// Reçoit : Rien
|
||||
// Retourne : 0 si aucune erreur, -1 sinon
|
||||
//**********************************************************************************************************************************************************************************
|
||||
int8_t init_usb(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
|
||||
if (systeme.generation_shipbase == GENERATION_SHIPBASE_V1)
|
||||
{
|
||||
// Init des paramètres de chaque port :
|
||||
for (i = 0; i < USB_MAX_NOMBRE_PORTS; i ++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case USB_FACE_AVANT_HAUT :
|
||||
{
|
||||
usb.ports[i].flag_validite = TRUE;
|
||||
usb.ports[i].no_entree_defaut = CM3P_DI_USB3_ALERT_N; // Attention : on a gardé le références du schéma qui sont inversées (ici, c'est le port du HAUT)
|
||||
break;
|
||||
}
|
||||
case USB_FACE_AVANT_MILIEU :
|
||||
{
|
||||
usb.ports[i].flag_validite = TRUE;
|
||||
usb.ports[i].no_entree_defaut = CM3P_DI_USB2_ALERT_N;
|
||||
break;
|
||||
}
|
||||
case USB_FACE_AVANT_BAS :
|
||||
{
|
||||
usb.ports[i].flag_validite = TRUE;
|
||||
usb.ports[i].no_entree_defaut = CM3P_DI_USB1_ALERT_N; // Attention : on a gardé le références du schéma qui sont inversées (ici, c'est le port du BAS)
|
||||
break;
|
||||
}
|
||||
case USB_FACE_ARRIERE :
|
||||
{
|
||||
usb.ports[i].flag_validite = FALSE;
|
||||
usb.ports[i].no_entree_defaut = 0;
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
usb.ports[i].flag_validite = FALSE;
|
||||
usb.ports[i].no_entree_defaut = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Affectation des sorties d'activation des ports :
|
||||
usb.sortie_gpio_cm_do_usb_avant_pwr_en = CM3P_DO_USB_AVANT_PWR_EN;
|
||||
usb.sortie_gpio_cm_do_usb_arriere_pwr_en = 0;
|
||||
}
|
||||
else // V2 & V3
|
||||
{
|
||||
// Init des paramètres de chaque port :
|
||||
for (i = 0; i < USB_MAX_NOMBRE_PORTS; i ++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case USB_FACE_AVANT_HAUT :
|
||||
{
|
||||
usb.ports[i].flag_validite = TRUE;
|
||||
usb.ports[i].no_entree_defaut = CM4_DI_USB_HAUT_ALERT_N;
|
||||
break;
|
||||
}
|
||||
case USB_FACE_AVANT_MILIEU :
|
||||
{
|
||||
usb.ports[i].flag_validite = TRUE;
|
||||
usb.ports[i].no_entree_defaut = CM4_DI_USB_MILIEU_ALERT_N;
|
||||
break;
|
||||
}
|
||||
case USB_FACE_AVANT_BAS :
|
||||
{
|
||||
usb.ports[i].flag_validite = TRUE;
|
||||
usb.ports[i].no_entree_defaut = CM4_DI_USB_BAS_ALERT_N;
|
||||
break;
|
||||
}
|
||||
case USB_FACE_ARRIERE :
|
||||
{
|
||||
usb.ports[i].flag_validite = TRUE;
|
||||
usb.ports[i].no_entree_defaut = CM4_DI_USB_ARRIERE_ALERT_N;
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
usb.ports[i].flag_validite = FALSE;
|
||||
usb.ports[i].no_entree_defaut = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Affectation des sorties d'activation des ports :
|
||||
usb.sortie_gpio_cm_do_usb_avant_pwr_en = CM4_DO_USB_AVANT_PWR_EN;
|
||||
usb.sortie_gpio_cm_do_usb_arriere_pwr_en = CM4_DO_USB_ARRIERE_PWR_EN;
|
||||
}
|
||||
|
||||
// Variables générales :
|
||||
usb.sequenceur.compteur = USB_TEMPO_INIT;
|
||||
usb.sequenceur.etat = ETAT_SEQUENCEUR_USB_INIT;
|
||||
|
||||
// Note importante :
|
||||
// Les valeurs de 'usbb.no_circuit_usb_avant' et 'usb.no_circuit_usb_arriere' ont DEJA été mises à jour dans 'bdd_init.c' dans la partie CIRCUITS.
|
||||
// Il ne faut donc surtout pas les initialiser (à -1 par exemple) ici...!
|
||||
|
||||
// Affichage du message de débug :
|
||||
affichage_debug(__FILE__, __LINE__, "Initialisation des ports USB\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//**********************************************************************************************************************************************************************************
|
||||
// Fichier USB.H
|
||||
//
|
||||
// Contient tous les define liés aux ports USB
|
||||
//**********************************************************************************************************************************************************************************/
|
||||
|
||||
|
||||
// Maximums :
|
||||
#define USB_MAX_NOMBRE_PORTS 4
|
||||
|
||||
|
||||
// Timings :
|
||||
#define USB_TEMPO_INIT 20 // En x 100ms
|
||||
#define USB_PERIODE_SURVEILLANCE 10 // En x 100ms
|
||||
|
||||
// Affectation des ports :
|
||||
#define USB_FACE_AVANT_HAUT 0
|
||||
#define USB_FACE_AVANT_MILIEU 1
|
||||
#define USB_FACE_AVANT_BAS 2
|
||||
#define USB_FACE_ARRIERE 3
|
||||
|
||||
// Etat des ports :
|
||||
#define USB_ETAT_PORT_OK 0
|
||||
#define USB_ETAT_PORT_DEFAUT 1
|
||||
|
||||
|
||||
// Etat séquenceur Usb :
|
||||
#define ETAT_SEQUENCEUR_USB_INIT 0
|
||||
#define ETAT_SEQUENCEUR_USB_REPOS 1
|
||||
Reference in New Issue
Block a user