Projet

Général

Profil

/*SP4_TP12
MOISAN Maxence ge3A groupe 5
date rendu : 19/05/2021
*/

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <math.h>
#include "trame.h"
#define M_PI 3.14159265358979323846

//Diff?rentes structures : position et zone
typedef struct
{
float latitude;
float longitude;
} Position;

Position p_prec; // position du point pr?c?dent (utilis? dans le traitement)

typedef struct
{
Position rpos;
float vitmax;
} Zone;

//Trames et zones de tests
char * trames[]= {"$GPGSV,3,2,10,15,03,077,,18,04,041,42,19,85,271,,20,08,214,*7C",
"$GPGSV,3,3,10,22,39,053,50,28,15,320,*7E",
"$GPRMC,141914.00,A,4545.6424,N,00306.6036,E,0.4,99.4,010206,,*0C",
"$GPGLL,4545.6424,N,00306.6036,E,141914.00,A*0E",
"$GPGGA,141914.00,4545.0000,N,00306.6036,E,1,05,3.4,499.3,M,,M,,*7D",
"$GPGSA,A,3,,03,,22,14,,01,,18,,,,3.9,3.4,1.9*39",
"$GPVTG,99.4,T,,M,0.4,N,0.7,K*57",
"$GPZDA,141914.00,01,02,2006,00,00*69",
0};
Zone zones[]={
{{44.7887762, -3.012}, 50}, /* Descripteur de la premi?re zone */
{{44.7891220, -3.013}, 70},
{{45.7896227, -3.014}, 70},
{{45.8791420, -3.014}, 70},
{{46.2971220, -3.011}, 70},
{{45.75, 3.110000}, 70},
{{45.752018, 3.110060}, 70},
{{45.754017, 3.110077}, 70},
};

int nbre_zone = 8; // nombre de zones dans le tableau de zone test

//fonction comparant 2 chaines de caract?res
//pr?condition : trame et type 2 chaines de caract?re, longueur de type < longueur de trame
//postcondition : renvoie 1 si la trame commence par la cha?ne de caract?re type et 0 dans les autres cas
int trame_cmp(char * trame, char * type)
{
int i = 0; //compteur de la boucle
int result = 1; //valeur de retour
while (type[i]!='\0') //tant que la chaine type n'est pas termin?e on ex?cute le code suivant
{
if(trame[i+1]!=type[i])//si les caract?res de trame et type sont identique
{
result = 0;//le resultat passe ? 0
}
i++;//+1 au compteur
}
return result;//si les caract?res de trame et type sont identiques jusqu'? la fin de type on retourne la valeur 0 sinon on retourne la valeur par d?faut : 1
}

//fonction qui renvoie la valeur d?cimale associ?e ? un caract?re donn? en param?tre
//ici on veut que le '0' ASCII soit identique au 0 d?cimal
int decode_int(char a)
{
if((a>='0') && (a<='9')) //on veut d?coder que les chiffres (de 0 ? 9)
{
return (a-48);//le '0' ASCII correspond ? la valeur 48 en d?cimal donc on soustrait juste 48 au caract?re que l'on veut d?coder
} else
{
return -1;//si le caract?re n'est pas entre '0' et '9' on retourne -1
}
}

//fonction test unitaire qui teste si decode_int fonctionne
void test_decode_int(void)
{
if (decode_int('0')!=0){
printf ("Erreur Test decode_int.\n");
exit(-1);
}
if (decode_int('5')!=5){
printf ("Erreur Test decode_int.\n");
exit(-1);
}
if (decode_int('A')!=-1){
printf ("Erreur Test decode_int.\n");
exit(-1);
}
}

//fonction qui renvoie la valeur d?cimale des n premiers caract?res de la cha?ne de caract?res ch
int decode_nombre(char * ch,int n)
{
int i;//le compteur, curseur pour savoir o? l'on est dans ch
int res=0; //initialisation du r?sultat
for (i=0;i<n;i++)//on parcours ch
{
res += pow(10,(n-i-1))*decode_int(ch[i]);//chaque chiffre est d?cod? avec decode_int puis multipli? par la puissance de 10 selon la place o? il est dans ch et on ajoute ?a au resultat
}
return res;//on retourne le resultat
}

//fonction alternative ? la premi?re du m?me nom
int decode_nombre2(char * ch,int n)//n est le chiffre auquel on doit s'arr?ter
{
int i;//le compteur, curseur pour savoir o? l'on est dans ch
int res=0;//initialisation du r?sultat
for (i=0;i<n;i++)//on parcours ch jusqu'au n-i?me charact?re
{
res = 10*res + decode_int(ch[i]);//on multiplie le resultat par 10 puis on ajoute le chiffre d'apr?s pr?alablement d?cod? par decode_int
}
return res;//on retourne le resultat
}

//test unitaire pour savoir si decode_nombre fonctionne
void test_decode_nombre(void)
{
if (decode_nombre("7541",2)!=75){
printf ("Erreur Test decode_nombre.\n");
exit(-1);
}
if (decode_nombre("7541",3)!=754){
printf ("Erreur Test decode_nombre.\n");
exit(-1);
}
if (decode_nombre("123",3)!=123){
printf ("Erreur Test decode_nombre.\n");
exit(-1);
}
if (decode_nombre("987654321",2)!=98){
printf ("Erreur Test decode_nombre.\n");
exit(-1);
}
}

//test unitaire pour savoir si decode_nombre2 fonctionne
void test_decode_nombre2(void)
{
if (decode_nombre2("7541",2)!=75){
printf ("Erreur Test decode_nombre.\n");
exit(-1);
}
if (decode_nombre2("7541",3)!=754){
printf ("Erreur Test decode_nombre.\n");
exit(-1);
}
if (decode_nombre2("123",3)!=123){
printf ("Erreur Test decode_nombre.\n");
exit(-1);
}
if (decode_nombre2("987654321",2)!=98){
printf ("Erreur Test decode_nombre.\n");
exit(-1);
}
}

//fonction convertissant la cha?ne de caract?re contenant la latitude en nombre flottant
float latDMStoDec(char * lat_DMS)//lat_DMS est sous la forme : 3723.2475
{
float deg = decode_nombre(lat_DMS,2);//les degr?s de la latitude sont les 2 premiers chiffres on les d?code ainsi avec decode_nombre pour les convertir en flottant
float min = decode_int(lat_DMS[2])*10+decode_int(lat_DMS[3])+(0.1*decode_int(lat_DMS[5]))+(0.01*decode_int(lat_DMS[6]))+(0.001*decode_int(lat_DMS[7]))+(0.0001*decode_int(lat_DMS[8]));//on d?compose les minutes en d?codant chiffre apr?s chiffre ? l'aide de decode_int
float latDec = deg+(min/60);//la latitude en d?cimal est le nombre de degr?s + le nombre de minutes divis? par 60
return latDec;//on retourne cette valeur
}

//test unitaire permettant de voir si latDMStoDec fonctionne (il peut y avoir une erreur de pr?cision)
void test_latDMStoDec(void)
{
if (latDMStoDec("3723.2475")!= 37.387458){
printf ("Erreur Test latDMStoDec.%f\n", latDMStoDec("3723.2475"));
latDMStoDec("3723.2475");
exit(-1);
}
}

//fonction convertissant la cha?ne de caract?re contenant la longitude en nombre flottant
//on effectue le m?me raisonnement sauf que lon_DMS est sous la forme 00306.6036 c'est-?-dire un charact?re de plus que lat_DMS
float lonDMStoDec(char * lon_DMS)
{
float deg = decode_nombre(lon_DMS,3);
float min = decode_int(lon_DMS[3])*10+decode_int(lon_DMS[4])+(0.1*decode_int(lon_DMS[6]))+(0.01*decode_int(lon_DMS[7]))+(0.001*decode_int(lon_DMS[8]))+(0.0001*decode_int(lon_DMS[9]));
float lonDec = deg+(min/60);
return lonDec;
}

//test unitaire permettant de voir si lonDMStoDec fonctionne (il peut y avoir une erreur de pr?cision)
void test_lonDMStoDec(void)
{
if (latDMStoDec("00306.6036")!= 3.11006){
printf ("Erreur Test latDMStoDec. %f\n",latDMStoDec("00306.6036"));
exit(-1);
}
}

//on rassemble les deux derni?res fonctions pour n'en faire qu'une seule
float lontlatDMStoDec(char * coord)
{
if(decode_nombre(coord,3)>=100)//si il y a 5 chiffres avant la virgule on retourne une longitude
{
return lonDMStoDec(coord);
} else //sinon on retourne une latitude
{
return latDMStoDec(coord);
}
}

//fonction qui d?code la trame, la d?composant en un ensemble de chaine de caract?re "GPGGA" et de position avec la structure d?finie avant
//si la trame est valid?e alors on retourne 1 sinon on retourne 0
int decode_trame(char *trame, Position *p)
{
if(trame_cmp(trame,"GPGGA")==1)//si la trame commence par les 5 premiers caract?res que l'on souhaite
{
//d?finition des variable
char *lon;
char *lat;
int i;
for(i=0;i<=7;i++){
lat[i]=trame[i+17];
}
for(i=0;i<=8;i++){
lon[i]=trame[i+29];
}
p->latitude = latDMStoDec(*lat);//on "traduit" la latitude de char ? flottant pour pouvoir les utiliser
p->longitude = lonDMStoDec(*lon);// on fait de m?me avec la longitude
if((p->latitude>=0)&&(p->latitude<=90)){
if((p->longitude>=0)&&(p->longitude<=180))//v?rification dut format de la longitude et de la latitude
{
return 1;// la trame est valid?e
} else{
return 0;// la trame n'est pas valid?e
}
} else{
return 0;// la trame n'est pas valid?e
}
} else {
return 0;// la trame n'est pas valid?e
}
}

// test unitaire pour savoir si decode_trame fonctionne
void test_decode_trame(void)
{
Position p;
if (decode_trame("$GPGLL,4545.6419,N,00306.6043,E,141921.00,A*04",&p)!= 0){
printf ("Erreur Test decode_trame.\n");
exit(-1);
}
if (decode_trame("$GPGGA,141922.00,4545.1810,N,00306.6046,E,1,05,3.4,500.6,M,,M,,*74",&p)!= 1){
printf ("Erreur Test decode_trame.\n");
exit(-1);
}
}


//petite fonction permettant de transform? les degr?s en radiant
float deg2rad(deg)
{
return deg * (M_PI/180);
}

//fonction qui calcul la distance entre 2 position
float calcule_distance(Position p_1, Position p_2){
float lonP1 = deg2rad(p_1.longitude);//on convertit en radian les longitudes et latitudes
float lonP2 = deg2rad(p_2.longitude);
float latP1 = deg2rad(p_1.latitude);
float latP2 = deg2rad(p_2.latitude);
float r=6371; //rayon de la terre
float d = r * acos(sin(latP1)*sin(latP2)+cos(latP1)*cos(latP2)*cos(lonP1-lonP2));//on applique la formule
return d; //on retourne la distance en km
}

//on calcul la vitesse correspondant au parcours de la distance entre les points p_1 et p_2 pendant 1s
float calcule_vitesse(Position p_1, Position p_2)
{
float d = calcule_distance(p_1, p_2);//on utilise la fonction pr?c?dente pour calculer la distance
return d*3600;//on multiplie cette distance par le nombre de seconde dans une heure car on veut la distance en km/h
}

//fonction qui renvoie le num?ro de la zone la plus proche du point p ainsi que sa distance
int distance_a_la_proche_zone(Position p, Zone r[],int nb_zones, float *d)
{
int i,res = 0; //curseur pour se d?placer dans le tableau des zones et initialisation du r?sultat
if (nb_zones == 0) //s'il n'y a pas de zones dangereuses
{
return -1;//on revoie -1
} else
{
*d = calcule_distance(p,r[0].rpos);//on initialise la distance la plus proche ? la distance entre le point p et la premi?re position
for (i=1;i<nb_zones;i++)//on parcours les zones
{
if(calcule_distance(p,r[i].rpos)<*d)//on estime la valeur de la distance et si elle est plus petite on entre dans cette boucle
{
*d = calcule_distance(p,r[i].rpos);//nouvelle distance plus petite
res = i;// resultat devient le num?ro de la zone la plus proche
}
}
return res;//on retourne ce num?ro
}
}

//Fonction ? modifier !!!!!
void traitement(char * trame) //traitement qui accepte ou non la trame, calcul la vitesse et la distance ? la zone la plus proche et, si cette distance est inf?rieure ? un seuil et que la vitesse du v?hicule est sup?rieure ? celle d?finie pour cette zone, de d?clencher une alarme.
{
int res;
float v,d,seuil = 50;//initialisation des variables utiles v(vitesse), d(distance) et du seuil ? ne pas d?passer
Position p;//position ? l'instant pr?sent, ? l'instant pr?c?dent p_prec

static int cpt=0;
cpt++;

if(trame_cmp(trame,"GPGGA")==1)
{
printf ("> %s\n",trame);
res = decode_trame(trame,&p);
if (res==1)//si la trame est valid?e
{
printf("Votre position est est de : %f en longitude et %f en latitude\n",p.longitude,p.latitude);//on ?crit la position de la voiture
v = calcule_vitesse(p,p_prec);//calcul de la vitesse
printf("Vous roulez ? %f\n",v);//on indique sa vitesse
res = distance_a_la_proche_zone(p, zones, nbre_zone,&d);//on indique le num?ro de la zone la plus proche
if ((d<seuil)&&(v>zones[res].vitmax))//si la distance de la zone dangereuse est plus faible que le seuil et que l'on roule ? une vitesse sup?rieur ? celle indiqu?e par la zone
{
printf("Alarme ON au niveau de la zone %d \n",res);//Alarme ON
} else
{
printf("Alarme OFF");//Alarme OFF
}
}
p_prec.longitude = p.longitude;//le point prec?dent devient le point que l'on vient de traiter
p_prec.latitude = p.latitude;//le point prec?dent devient le point que l'on vient de traiter
}
}

//Ajouter vos tests unitaires dans cette fonction.
//On ex?cute les test unitaire pour sacoir si on a fait des erreurs
void tests_unitaires(void){
if (5!=5){
printf ("Erreur Test unitaire basique.\n");
exit(-1);
}
if (trame_cmp("$GPGGA suite chaine","GPGGA")!=1){
printf ("Erreur Test unitaire trame_cmp.\n");
exit(-1);
}
if (trame_cmp("$GPRMC suite chaine","GPGGA")!=0){
printf ("Erreur Test unitaire trame_cmp.\n");
exit(-1);
}
if (trame_cmp("$GPRMC... ", "GPRMC" )!=1){
printf ("Erreur Test unitaire trame_cmp.\n");
exit(-1);
}
if (trame_cmp("$APRMC...", "GPGGA")!=0){
printf ("Erreur Test unitaire trame_cmp.\n");
exit(-1);
}
test_decode_nombre();
test_decode_int();
test_latDMStoDec();
test_lonDMStoDec();
test_decode_nombre2();
test_decode_trame();
}

// Ne pas modifier cette fonction
int main(int argc,char ** argv)
{

tests_unitaires();

// Affichage des trames definies dans la table trames.
printf ("Trames de tests tableau trames:\n");
int i=0;
while (trames[i])
traitement(trames[i++]);

if (!trame_init())
exit(-1);
// Affichage des trames du fichier gps.log
char *trame;
printf ("Trames de tests du fichier gps.log\n");
while ((trame = trame_suivante()))
traitement(trame);

return 0;
}
(2-2/5)