// prototypes
void pondere (int coef_pond);
void addval (char *chaineval, uint16 num_instant, int majcmoy);
void addvalint32 (int32 val, uint16 num_instant, int majcmoy);
void addvalfloat (float val, uint16 num_instant, int majcmoy);
int testval (char *valeur);
// variables globales (pour éviter des tas de passages de paramètre)
FILE *descfic; // descripteur du fichier cyloop
desc_cyloop entetefic; // entête du fichier cyloop
desc_var entetevar; // entête de la variable du fichier cyloop
// programme principal
main (int narg, char *varg[])
{
char *nomfic; // nom du fichier cyloop
struct tm stm; // structure contenant la date et l'heure courante
uint32 timep; // date et heure dans un uint32
int maj_entetefic; // indicateur pour mise à jour fichier
uint16 num_instant; // numéro de la donnée à incrémenter
uint32 duree_cycle; // durée du cycle
// mémorisation du nom de la commande
memcom (*varg);
// test des paramètres
if (--narg > 1 && testval (varg [2]))
// récupération du nom de fichier et rajout éventuel du suffixe
nomfic = recup_nomfic (varg [1]);
else
{
// "Nom de fichier manquant ou valeur de la variable manquante"
// "Syntaxe : %s nom_fichier_cyloop valeur"
affiche_err ("MANQUE_NOM_OU_VAR");
psyntaxe ("SYNT_CYLADDVAL");
}
// ouverture en lecture / écriture du fichier cyloop
descfic = fopen (nomfic, "r+");
if (! descfic)
// "Fichier_cyloop %s inexistant ou protégé en lecture ou écriture"
err_fatale_arg ("ACCES_CYLOOP_RW",
nomfic);
// lecture de l'entête du fichier cyloop
fread (&entetefic, 16, 1, descfic);
// vérification de la signature
if (entetefic.signature [0] != 'c' || entetefic.signature [1] != 'y'
|| entetefic.signature [2] != 'l')
{
// "Le fichier %s n'est pas un fichier_cyloop"
aff_err_arg ("FICH_NON_CYLOOP", nomfic);
fclose (descfic);
return;
}
// vérification de la valeur nb_var
if (entetefic.nb_var)
{
// "Ce fichier cyloop utilise une liste de variables"
// "utiliser la version complète de cyloop"
affiche_err ("CYLOOP_LISTEVAR");
affiche_err ("UTIL_VCOMPLETE");
fclose (descfic);
return;
}
// lecture de la partie fixe de l'entête de la variable du fichier cyloop
fread (&entetevar, 6, 1, descfic);
// vérification de la nature de la variable
if (entetevar.typedon & compteur)
{
// "La variable du fichier cyloop est un compteur : utiliser cylincr"
affiche_err ("VAR_COMPTEUR");
fclose (descfic);
return;
}
// fin de lecture de l'entête de la variable si nécessaire
if (! (entetevar.typedon & cmoy_sep))
fread (&entetevar.coef_moy, 2, 1, descfic);
// récupérer la date et l'heure courante
time (&timep);
// si le début du cycle est ultérieur à l'instant présent
if (timep < entetefic.deb_cycle)
{
fclose (descfic);
// "Régression dans le temps : une intervention manuelle "
// "sur le fichier cyloop ou l'horloge est nécessaire"
affiche_err ("REGRES_TEMPS");
err_fatale ("REGRES_TEMPS2");
}
// initialisation indicateurs de mise à jour du fichier
maj_entetefic = NON;
// si on utilise l'heure locale
if (! (entetefic.caract_gen & temps_utc))
{
// récupérer le détail de la date et de l'heure locale
localtime_r (&timep, &stm);
// si changement d'heure été/hiver
if ((entetefic.etat_cyloop & heure_ete) != stm.tm_isdst)
// prendre en compte ce changement
maj_entetefic = maj_type_heure (stm.tm_isdst, timep);
}
// si changement de cycle
if (entetefic.deb_cycle + entetefic.duree_cycle <= timep)
{
// prise en compte de ce changement de cycle
changement_cycle (timep);
// une manière de mémoriser un début de cycle
entetevar.der_enreg = 0;
// on reportera la mise à jour dans le fichier cyloop
maj_entetefic = OUI;
}
// si mise à jour de l'entête du fichier cyloop nécessaire
if (maj_entetefic)
{
// recopier la nouvelle entête
rewind (descfic);
fwrite (&entetefic, 16, 1, descfic);
}
// récupération de la durée du cycle actuel
duree_cycle = duree_cycle_actuel (&timep);
// calcul de l'instant du cycle à mettre à jour
num_instant = calcul_instant (timep, duree_cycle);
// si on a changé de cycle et une seule valeur coef_moy pour la variable
if (! entetevar.der_enreg && !(entetevar.typedon & cmoy_sep))
{
// mettre à jour cette valeur
if (entetevar.ponderation)
entetevar.coef_moy += 256;
else
entetevar.coef_moy ++;
// y compris dans le fichier cyloop
fseek (descfic, 22, SEEK_SET);
fwrite (&entetevar.coef_moy, 2, 1, descfic);
}
// si c'est la première mise à jour effectuée durant ce cycle
// ou si on passe à un autre instant du même cycle
if (entetevar.der_enreg < num_instant)
{
// mettre à jour le numéro de l'instant du cycle traité
entetevar.der_enreg = num_instant;
// y compris dans le fichier cyloop
fseek (descfic, 16, SEEK_SET);
fwrite (&entetevar.der_enreg, 2, 1, descfic);
// mettre à jour la valeur de la variable et si nécessaire
// le champ coef_moy pour l'instant du cycle concerné
addval (varg [2], num_instant, OUI);
}
// sinon, si on a déjà mis à jour la variable pour cet instant du cycle
else if (entetevar.der_enreg == num_instant)
{
// si on est autorisé à le mettre à jour plusieur
// fois pour chacun des instants du cycle
if (entetevar.typedon & cumul_donnees)
// mettre à jour la valeur de la variable et si nécessaire
// le champ coef_moy pour l'instant du cycle concerné
addval (varg [2], num_instant, entetevar.typedon & cpt_toute_don);
}
// sinon, il y a régression dans le temps
else
{
// vérifier si elle est supérieure à 2 heures
if (calcul_instant (timep + 7200, duree_cycle) < entetevar.der_enreg)
{
// vérifier si elle est supérieure à 1 journée
// et afficher le message d'erreur approprié
if (calcul_instant (timep + secjour, duree_cycle) <
entetevar.der_enreg)
{
// "Forte régression dans le temps : une intervention manuelle "
// "sur le fichier cyloop ou l'horloge est nécessaire"
affiche_err ("FORTE_REGR_TEMPS");
affiche_err ("REGRES_TEMPS2");
}
else
// "Régression dans le temps : vérifier l'horloge de l'ordinateur"
affiche_err ("REGR_VERIF_HORL");
}
}
// le fichier cyloop a été mis à jour
fclose (descfic);
}
// test de la valeur passée en paramètre
int testval (char *valeur)
{
// saut du signe - éventuel
if (*valeur == '-')
valeur++;
// si la valeur commence par des chiffres
if ('0' <= *valeur && *valeur <= '9')
{
// les parcourrir
do
valeur++;
while ('0' <= *valeur && *valeur <= '9');
// si plus rien après les chiffres
if (! *valeur)
// la valeur est un entier
return OUI;
// si partie décimale
if (*valeur == '.' || *valeur == ',')
{
// la parcourir
do
valeur++;
while ('0' <= *valeur && *valeur <= '9');
}
// si exposant
if (tolower (*valeur) == 'e')
{
// on va l'analyser
valeur ++;
// saut du signe - éventuel
if (*valeur == '-')
valeur++;
// si l'exposant contient des chiffres
if ('0' <= *valeur && *valeur <= '9')
{
// les parcourrir
do
valeur++;
while ('0' <= *valeur && *valeur <= '9');
}
}
// succés de l'analyse si l'exploration de la valeur est terminé
return (*valeur == '\0');
}
// sinon, contenu de la valeur incorrect
else
return NON;
}
// calcul de pondération sur les cycles antérieurs
void pondere (int coef_pond)
{
uint16 coef_moy; // coef_moy si distinct pour chaque instant du cycle
int32 valeur32b; // valeur à pondérer si elle est entière sur 32 bits
float valeurf; // valeur à pondérer si elle est en virgule flottante
uint32 valmaj; // valeur sur 32 bits pour calcul de pondération
uint32 positfic; // positionnement sur une nouvelle valeur du cycle
int tailledon; // nombre d'octets des données pour un instant du cycle
int i; // compteur
// nombre d'octets pour chaque instant du cycle
if (entetevar.typedon & mem_min_max)
tailledon = 12;
else
tailledon = 4;
// si un coefficient coef_moy par instant du cycle
if (entetevar.typedon & cmoy_sep)
{
// corriger le calcul de tailledon
tailledon = tailledon + 2;
// position des premières données dans le fichier
positfic = 22;
// si valeurs en virgule flottante
if (entetevar.typedon & val_float)
{
// mise à jour des valeurs de coef_moy et de la variable
for (i = entetefic.nb_don_cycle; i > 0; i--)
{
// positionnement dans le fichier
fseek (descfic, positfic, SEEK_SET);
// récupération de la valeur du coef_moy
fread (&coef_moy, 2, 1, descfic);
// récupération de la valeur de la variable en virgule flottante
fread (&valeurf, 4, 1, descfic);
// calcul de pondération pour coef_moy
// le calcul de multiplication et division est fait sur 32 bits
valmaj = coef_moy;
coef_moy = (valmaj * coef_pond) >> 8;
// calcul de la nouvelle valeur
valeurf = valeurf * (coef_pond / 256.0);
// mettre à jour les valeurs dans le fichier
fseek (descfic, -6, SEEK_CUR);
fwrite (&coef_moy, 2, 1, descfic);
fwrite (&valeurf, 4, 1, descfic);
// position des données pour l'instant suivant dans le fichier
positfic = positfic + tailledon;
}
}
// sinon (valeurs de la variable entière sur 32 bits)
else
{
// mise à jour des valeurs de coef_moy et de la variable 32 bits
for (i = entetefic.nb_don_cycle; i > 0; i--)
{
// positionnement dans le fichier
fseek (descfic, positfic, SEEK_SET);
// récupération de la valeur du coef_moy
fread (&coef_moy, 2, 1, descfic);
// récupération de la valeur de la variable sur 32 bits
fread (&valeur32b, 4, 1, descfic);
// calcul de pondération pour coef_moy
// le calcul de multiplication et division est fait sur 32 bits
valmaj = coef_moy;
coef_moy = (valmaj * coef_pond) >> 8;
// calcul de pondération pour la valeur de la variable
// si risque de débordement lors du calcul
if (valeur32b & 0xFF000000)
// faire la division d'abord
valeur32b = (valeur32b >> 8) * coef_pond;
// sinon faire la multiplication d'abord
else
valeur32b = (valeur32b * coef_pond) >> 8;
// mettre à jour les valeurs dans le fichier
fseek (descfic, -6, SEEK_CUR);
fwrite (&coef_moy, 2, 1, descfic);
fwrite (&valeur32b, 4, 1, descfic);
// position des données pour l'instant suivant dans le fichier
positfic = positfic + tailledon;
}
}
}
// sinon (coefficient coef_moy global à la variable)
else
{
// position des premières données dans le fichier
positfic = 24;
// mettre à jour ce coefficient
// le calcul de multiplication et division est fait sur 32 bits
valmaj = entetevar.coef_moy;
entetevar.coef_moy = (valmaj * coef_pond) >> 8;
// ce coefficient sera mis à jour plus tard dans le fichier
// si valeurs en virgule flottante
if (entetevar.typedon & val_float)
{
// mise à jour des valeurs en virgule flottante
for (i = entetefic.nb_don_cycle; i > 0; i--)
{
// positionnement dans le fichier
fseek (descfic, positfic, SEEK_SET);
// récupération de la valeur de la variable en virgule flottante
fread (&valeurf, 4, 1, descfic);
// calcul de la nouvelle valeur
valeurf = valeurf * (coef_pond / 256.0);
// mettre à jour la valeur de la variable dans le fichier
fseek (descfic, -4, SEEK_CUR);
fwrite (&valeurf, 4, 1, descfic);
// position des données pour l'instant suivant dans le fichier
positfic = positfic + tailledon;
}
}
// sinon (valeurs de la variable entière sur 32 bits)
else
{
// mise à jour des valeurs entières sur 32 bits
for (i = entetefic.nb_don_cycle; i > 0; i--)
{
// positionnement dans le fichier
fseek (descfic, positfic, SEEK_SET);
// récupération de la valeur de la variable sur 32 bits
fread (&valeur32b, 4, 1, descfic);
// si risque de débordement lors du calcul
if (valeur32b & 0xFF000000)
// faire la division d'abord
valeur32b = (valeur32b >> 8) * coef_pond;
// sinon faire la multiplication d'abord
else
valeur32b = (valeur32b * coef_pond) >> 8;
// mettre à jour la valeur de la variable dans le fichier
fseek (descfic, -4, SEEK_CUR);
fwrite (&valeur32b, 4, 1, descfic);
// position des données pour l'instant suivant dans le fichier
positfic = positfic + tailledon;
}
}
}
}
// rajoute la valeur contenue dans chaineval à l'instant num_instant du cycle
void addval (char *chaineval, uint16 num_instant, int majcmoy)
{
// selon le type des données mémorisées
if (entetevar.typedon & val_float)
// appeler la bonne fonction d'ajout
addvalfloat (atof (chaineval), num_instant, majcmoy);
else
addvalint32 (atol (chaineval), num_instant, majcmoy);
}
// rajoute la valeur val (entière 32 bits) à l'instant num_instant du cycle
void addvalint32 (int32 val, uint16 num_instant, int majcmoy)
{
long posval; // position de la valeur à mettre à jour dans le fichier
uint16 coef_moy; // coefficient coef_moy pour la valeur à mettre à jour
int32 valeur; // valeur à mettre à jour
int32 nouv_val; // valeur mise à jour
int32 ajout; // val à rajouter à la variable avec coef multiplicateur
int32 min, max; // valeurs min et max mémorisées
int majfich; // indique si on devra mettre à jour le fichier
int maj_minmax; // indique si on devra mettre à jour la valeur min ou max
// si coefficient coef_moy à mettre à jour
if (majcmoy && (entetevar.typedon & cmoy_sep))
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval - 2, SEEK_SET);
// récupérer et mettre à jour le coefficient coef_moy
fread (&coef_moy, 2, 1, descfic);
if (entetevar.ponderation)
coef_moy += 256;
else
coef_moy += 1;
}
// sinon, se positionner sur la valeur de la variable
else
fseek (descfic, posval, SEEK_SET);
// récupération de la valeur de la variable
fread (&valeur, 4, 1, descfic);
// si valeurs min et max à mettre à jour
if (entetevar.typedon & mem_min_max)
{
// récupérer les valeurs mémorisées dans le fichier
fread (&min, 4, 1, descfic);
fread (&max, 4, 1, descfic);
// les actualiser si nécessaire
if (val < min)
{
min = val;
maj_minmax = OUI;
}
// pas de else if, la première fois, il faut actualiser min et max
if (val > max)
{
max = val;
maj_minmax = OUI;
}
}
// si calcul de pondération
if (entetevar.ponderation)
{
// calculer la valeur à ajouter
ajout = val * 256;
// si débordement numérique lors de ce calcul
if (ajout / 256 != val)
{
// "Valeur à rajouter trop grande"
// "Il faudrait utiliser une variable en virgule flottante"
affiche_err ("VAL_TROP_GRANDE");
affiche_err ("BESOIN_VARFLOAT");
// on ajoutera une valeur plus petite
if (val > 0)
ajout = max_int32;
else
ajout = min_int32;
}
}
// sinon, simple ajout de la valeur passée en paramètre
else
ajout = val;
// calculer la nouvelle valeur
nouv_val = valeur + ajout;
// si variable et valeur à rajouter du même signe
if ((float) valeur * (float) ajout > 0)
{
// et que le signe a changé lors de l'addition
if ((float) nouv_val * (float) ajout <= 0)
{
// nouvelle valeur de la variable
if (valeur < 0)
nouv_val = min_int32;
else
nouv_val = max_int32;
// si on était déjà sur la valeur limite
if (valeur == nouv_val)
{
// message d'erreur adapté
// "Rappel : Débordement numérique pour la variable"
affiche_err ("PAR_DEBORD_NUM");
// pas la peine de mettre à jour le fichier pour la variable
majfich = NON;
}
// sinon
else
{
// message d'erreur
// "Débordement numérique pour la variable"
affiche_err ("DEBORD_NUMERIQUE");
}
// fin du message d'erreur
// "Il faudrait la convertir en nombre flottant"
affiche_err ("BESOIN_CONVFLOAT");
}
}
// prise en compte de la nouvelle valeur
valeur = nouv_val;
// si coefficient coef_moy à mettre à jour
if (majcmoy && (entetevar.typedon & cmoy_sep))
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval - 2, SEEK_SET);
// mettre à jour le coefficient coef_moy
fwrite (&coef_moy, 2, 1, descfic);
}
// sinon
else if (majfich | maj_minmax)
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval, SEEK_SET);
}
// mettre à jour si nécessaire la valeur de la variable
if (majfich | maj_minmax)
fwrite (&valeur, 4, 1, descfic);
// mettre à jour si nécessaire la valeur min ou max
if (maj_minmax)
{
fwrite (&min, 4, 1, descfic);
fwrite (&max, 4, 1, descfic);
}
}
// rajoute la valeur val (flottante) à l'instant num_instant du cycle
void addvalfloat (float val, uint16 num_instant, int majcmoy)
{
long posval; // position de la valeur à mettre à jour dans le fichier
uint16 coef_moy; // coefficient coef_moy pour la valeur à mettre à jour
float valeur; // valeur à mettre à jour
float min, max; // valeurs min et max mémorisées
int maj_minmax; // indique si on devra mettre à jour la valeur min ou max
// initialisation
maj_minmax = NON;
// pour le calcul de position, le premier instant
// du cycle n'entrainera pas de décalage
num_instant --;
// calcul de la position dans le fichier de la valeur à mettre à jour
posval = 24;
if (entetevar.typedon & cmoy_sep)
posval += num_instant * 2;
// si coefficient coef_moy à mettre à jour
if (majcmoy && (entetevar.typedon & cmoy_sep))
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval - 2, SEEK_SET);
// récupérer et mettre à jour le coefficient coef_moy
fread (&coef_moy, 2, 1, descfic);
if (entetevar.ponderation)
coef_moy += 256;
else
coef_moy += 1;
}
// sinon, se positionner sur la valeur de la variable
else
fseek (descfic, posval, SEEK_SET);
// récupération de la valeur de la variable
fread (&valeur, 4, 1, descfic);
// calculer sa nouvelle valeur (pas de test de débordement ici)
valeur += val;
// si valeurs min et max à mettre à jour
if (entetevar.typedon & mem_min_max)
{
// récupérer les valeurs mémorisées dans le fichier
fread (&min, 4, 1, descfic);
fread (&max, 4, 1, descfic);
// les actualiser si nécessaire
if (val < min)
{
min = val;
maj_minmax = OUI;
}
// pas de else if, la première fois, il faut actualiser min et max
if (val > max)
{
max = val;
maj_minmax = OUI;
}
}
// si coefficient coef_moy à mettre à jour
if (majcmoy && (entetevar.typedon & cmoy_sep))
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval - 2, SEEK_SET);
// mettre à jour le coefficient coef_moy
fwrite (&coef_moy, 2, 1, descfic);
}
// sinon
else
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval, SEEK_SET);
}
// mettre à jour la valeur de la variable
fwrite (&valeur, 4, 1, descfic);
// mettre à jour si nécessaire la valeur min ou max
if (maj_minmax)
{
fwrite (&min, 4, 1, descfic);
fwrite (&max, 4, 1, descfic);
}
}