Files

419 lines
21 KiB
C

//**********************************************************************************************************************************************************************************
// 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(&current_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);
}