/*
 * Afficheur de radars
 *
 * Christophe Le Lann <totofwebcreation@gmail.com>
 * http://www.totofweb.net/robots.php?projet=53
 *
 * Ce programme récupère une trame NMEA d'un récepteur
 * GPS sur le port série. Il compare ensuite la position
 * du véhicule à une liste de positions de radars stockée
 * dans une eeprom i2c 256k pour savoir si un radar est
 * proche.
 *
 * Une liste de radars peut être téléchargée ici :
 * http://www.radarsfixes.com
 * Chaque position de radar prend 6 octets d'eeprom :
 * longitude = octet_1 + octet_2*0.01 + octet_3*0.001
 * latitude = octet_4 + octet_5*0.01 + octet_6*0.001
 * Ainsi on peut même stocker les positions négatives.
 * car ces octets sont signés.
 * On peut donc stocker (256*1024)/(6*8) = 5461 radars
 *
 * On peut aussi utiliser le même montage pour réaliser
 * un traceur GPS, c'est-à-dire un appareil qui enregistre
 * le parcours d'un véhicule dans la mémoire eeprom.
 *
 */

//******************************
// Defines
//******************************

#define F_CPU 16000000UL

#define BUFFER_SIZE 768

#define LCD_MODE_DONNEE   0
#define LCD_MODE_COMMANDE 1

// Gestion du décalage horaire par rapport à l'heure GMT
#define GMT_DECAL_PLUS  2
#define GMT_DECAL_MOINS 0

// Nombre de radars stockés dans l'EEPROM
#define NOMBRE_DE_RADARS 4361

// Angle de détection au carré : 0.0045°^2 = 0.00005 (on déclenche l'alarme 500m avant)
// Se calcule en fonction du rayon de la terre : Angle/360 = distance / (2*Pi*6400000)
// Trop augmenter la distance augmente le risque de détecter un radar qu'on ne ferait qu'approcher
// Trop diminuer la distance augmente le risque de détecter trop tard si le récepteur GPS est un peu lent
//#define SEUIL_DETECTION 0.00002
#define SEUIL_DETECTION 0.0008

//******************************
// Inclusion de librairies
//******************************

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/twi.h>

//******************************
// Variables globales
//******************************

unsigned char buffer[BUFFER_SIZE];	// Buffer de réception série
unsigned char twst;					// Sauvegarde du statut de la communication I2C
unsigned int  buffer_datalength;	// La longueur actuellement utilisée dans le buffer
unsigned int  buffer_dataindex;		// L'index actuel
float         eeprom_latitude;		// La latitude lue sur l'eeprom
float         eeprom_longitude;		// La longitude lue sur l'eeprom
unsigned char eeprom_buffer[6];		// Buffer de réception de l'eeprom
unsigned char radar, radar_old;		// Est-on proche d'un radar ?
unsigned char compteur_tmr;			// Base de temps pour le déclenchement du buzzer
unsigned char recevoir;				// Veut-on recevoir les données rs232

//******************************;
// Fonctions
//******************************

// Buffer de réception série
unsigned char buffer_GetFromFront() {

	unsigned char data = 0;

	// Y a-t-il des données dans le buffer ?
	if (buffer_datalength) {
		// Prend le premier élément du buffer
		data = buffer[buffer_dataindex];
		// Réactualise l'index et la taille du buffer
		buffer_dataindex++;
		if (buffer_dataindex >= BUFFER_SIZE) {
			buffer_dataindex %= BUFFER_SIZE;
		}
		buffer_datalength--;
	}
	return data;
}
void buffer_AddToEnd(unsigned char data) {

	// On s'assure qu'il reste de la place, sinon on est dans la merde
	if (buffer_datalength < BUFFER_SIZE) {
		// Ajout des données en fin de buffer
		buffer[(buffer_dataindex + buffer_datalength) % BUFFER_SIZE] = data;
		// Augmente la taille du buffer
		buffer_datalength++;
	}
}

// Configuration de l'USART
void Usart_Init() {

	// Wait latest receive character was pull from UDR
	while (UCSRA & (1<<RXC));

	// Wait end of transmission
	while (!(UCSRA & (1<<UDRE)));

	// Disable transmitter and receiver
	UCSRB &= ~((1<<RXEN) | (1<<TXEN));

	// 207 => 4800baud
	// UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) = ((F_OSC)/((UART_BAUD_RATE)*16l)-1)
	UBRRH = 0;
	UBRRL = 207;

	// Async mode, no parity, 1 stop bit, 8 data bits, UCPOL set to zero for async transfert mode
	UCSRC = 0b10000110;

	// Enable transmitter and receiver (RXEN and TXEN), enable reception interrupt (RXCIE)
	UCSRB = (1<<RXCIE) | (1<<RXEN) | (1<<TXEN);

	sei();
}

// Gestion du LCD
void LCD_Write(unsigned char data, unsigned char type) {

	// Attendre la fin du Busy

	PORTD &= 0b11011111;			// RS = 0 => mode commande

	// Ports en entrée
	DDRB  &= 0b11111000;
	DDRC  &= 0b11111100;
	DDRD  &= 0b11100011;

	// Activation des pull-up
	PORTB |= 0b00000111;
	PORTD |= 0b00011100;
	PORTC |= 0b00000011;
	PORTD |= 0b11000000;			// RW = 1 => mode lecture, E = 1 => validation

	// Attendre 1µs
	asm volatile ("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");

	while (PIND & 0b00000100) {		// Attendre la fin du Busy
		PORTD &= 0b01111111;		// E = 0
		// Attendre 2µs
		asm volatile ("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");
		asm volatile ("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");
		PORTD |= 0b10000000;		// E  = 1 => validation
		// Attendre 2µs
		asm volatile ("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");
		asm volatile ("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");
	}

	PORTD &= 0b01111111;			// E = 0

	if (type == LCD_MODE_COMMANDE)
		PORTD &= 0b11011111;		// RS = 0 => mode commande
	else
		PORTD |= 0b00100000;		// RS = 1 => mode donnée

	PORTD &= 0b10111111;			// RW = 0 => mode écriture
	PORTD |= 0b10000000;			// E  = 1 => validation

	// Ports en sortie
	DDRB  |= 0b00000111;
	DDRC  |= 0b00000011;
	DDRD  |= 0b00011100;

	if (data & 0b00000001) PORTB |= 0b00000001; else PORTB &= 0b11111110;
	if (data & 0b00000010) PORTB |= 0b00000100; else PORTB &= 0b11111011;
	if (data & 0b00000100) PORTB |= 0b00000010; else PORTB &= 0b11111101;
	if (data & 0b00001000) PORTD |= 0b00010000; else PORTD &= 0b11101111;
	if (data & 0b00010000) PORTC |= 0b00000001; else PORTC &= 0b11111110;
	if (data & 0b00100000) PORTD |= 0b00001000; else PORTD &= 0b11110111;
	if (data & 0b01000000) PORTC |= 0b00000010; else PORTC &= 0b11111101;
	if (data & 0b10000000) PORTD |= 0b00000100; else PORTD &= 0b11111011;

	// Attendre 2µs
	asm volatile ("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");
	asm volatile ("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n");

	PORTD &= 0b01111111;			// E = 0
}
void LCD_GotoXY(unsigned char x, unsigned char y) {

	unsigned char DDRAMAddr;

	if (y == 1)
		DDRAMAddr = 0b01000000+x;
	else
		DDRAMAddr = 0b00000000+x;

	LCD_Write(0b10000000 | DDRAMAddr, LCD_MODE_COMMANDE);	// Ecriture de l'adresse
}
void LCD_Init() {

	// Initialisation des ports
	PORTD &= 0b00011111;			// E  = 0, RW = 0, RS = 0
	DDRD  |= 0b11100000;			// E, RW, RS en sortie
	// Ports en entrée
	DDRB  &= 0b11111000;
	DDRC  &= 0b11111100;
	DDRD  &= 0b11100011;
	// Activation des pull-up
	PORTB |= 0b00000111;
	PORTD |= 0b00011100;
	PORTC |= 0b00000011;

	LCD_Write(0b00111000, LCD_MODE_COMMANDE);	// Mode 8bit 2 lignes
	LCD_Write(0b00000001, LCD_MODE_COMMANDE);	// RàZ de l'écran
	LCD_Write(0b00000110, LCD_MODE_COMMANDE);	// Mode increment
	LCD_Write(0b00001100, LCD_MODE_COMMANDE);	// Display On
	LCD_GotoXY(0, 0);
}
void LCD_Ecrire(char* data, unsigned char nBytes) {

	unsigned char i;

	for (i = 0; i < nBytes; i++) {
		LCD_Write(data[i], LCD_MODE_DONNEE);
	}
}

// Lecture de l'EEPROM I2C externe
void Eeprom_ReadPosition(unsigned int numero) {

	unsigned char twcr, n = 0;
	signed char len = 6;
	unsigned char *buf = eeprom_buffer;

	// First cycle: master transmitter mode
restart:
	if (n++ >= 200)
	return;

begin:
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // send start condition
	while (!(TWCR & (1<<TWINT))); // wait for transmission

	switch ((twst = TW_STATUS)) {
		case TW_REP_START:		// OK, but should not happen
		case TW_START:
			break;
		case TW_MT_ARB_LOST:
			goto begin;
		default:
			return;		// error: not in start condition
							// NB: do /not/ send stop condition
	}

	// send SLA+W
	TWDR = 0b10100000 | TW_WRITE;
	TWCR = _BV(TWINT) | _BV(TWEN); // clear interrupt to start transmission
	while ((TWCR & _BV(TWINT)) == 0); // wait for transmission
	switch ((twst = TW_STATUS)) {
		case TW_MT_SLA_ACK:
			break;
		case TW_MT_SLA_NACK:	// nack during select: device busy writing
			goto restart;
		case TW_MT_ARB_LOST:	// re-arbitrate
			goto begin;
		default:
			goto quit;		// must send stop condition
	}

	// On multiplie l'adresse par 6 car il faut 6 octets par position de radar
	TWDR = (unsigned char)((numero*6)>>8);		// high 8 bits of addr
	TWCR = _BV(TWINT) | _BV(TWEN); // clear interrupt to start transmission
	while ((TWCR & _BV(TWINT)) == 0); // wait for transmission
	switch ((twst = TW_STATUS)) {
		case TW_MT_DATA_ACK:
			break;
		case TW_MT_ARB_LOST:
			goto begin;
		//case TW_MT_DATA_NACK:
		//	goto quit;
		default:
			goto quit;		// must send stop condition
	}

	TWDR = (unsigned char)((numero*6) & 0xFF);		// low 8 bits of addr
	TWCR = _BV(TWINT) | _BV(TWEN); // clear interrupt to start transmission
	while ((TWCR & _BV(TWINT)) == 0); // wait for transmission
	switch ((twst = TW_STATUS)) {
		case TW_MT_DATA_ACK:
			break;
		case TW_MT_ARB_LOST:
			goto begin;
		//case TW_MT_DATA_NACK:
		//	goto quit;
		default:
			goto quit;		// must send stop condition
	}

	// Next cycle(s): master receiver mode
	TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send (rep.) start condition
	while ((TWCR & _BV(TWINT)) == 0); // wait for transmission
	switch ((twst = TW_STATUS)) {
		case TW_START:		// OK, but should not happen
		case TW_REP_START:
			break;
		case TW_MT_ARB_LOST:
			goto begin;
		default:
			goto quit;
	}

	// send SLA+R
	TWDR = 0b10100000 | TW_READ;
	TWCR = _BV(TWINT) | _BV(TWEN); // clear interrupt to start transmission
	while ((TWCR & _BV(TWINT)) == 0) ; // wait for transmission
	switch ((twst = TW_STATUS)) {
		case TW_MR_SLA_ACK:
			break;
		case TW_MR_ARB_LOST:
			goto begin;
		//case TW_MR_SLA_NACK:
		//	goto quit;
		default:
			goto quit;
	}

	for (twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA); len > 0; len--) {
		if (len == 1)
			twcr = _BV(TWINT) | _BV(TWEN); // send NAK this time
		TWCR = twcr;		// clear int to start transmission
		while ((TWCR & _BV(TWINT)) == 0); // wait for transmission
		switch ((twst = TW_STATUS)) {
			case TW_MR_DATA_NACK:
				len = 0;		// force end of loop
								// FALLTHROUGH
			case TW_MR_DATA_ACK:
				*buf++ = TWDR;
				break;
			default:
				goto quit;
		}
	}

	// Décodage des données
/*buf[0] = 0;
buf[1] = 17;
buf[2] = 15;
buf[3] = 48;
buf[4] = 0;
buf[5] = 96;*/
	eeprom_longitude = (float)((signed char)buf[0]) + (float)((signed char)buf[1])*0.01 + (float)((signed char)buf[2])*0.0001;
	eeprom_latitude =  (float)((signed char)buf[3]) + (float)((signed char)buf[4])*0.01 + (float)((signed char)buf[5])*0.0001;
//eeprom_latitude = 48.00958;
//eeprom_longitude = 0.17155;

quit:
	TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); // send stop condition

	return;
}

// Attendre une virgule
void AttendreVirgule() {
	while (buffer_GetFromFront() != ',');
}
void AttendreDebutTrame() {
	while (buffer_GetFromFront() != '$');
}

//******************************
// Interruptions
//******************************

ISR(TIMER1_OVF_vect) { // Interruption sur Timer1

	// Recomptage pour 250ms
	TCNT1H = 0b00001011;
	TCNT1L = 0b11011100;

	// Gestion du buzzer
	if (radar) {
		compteur_tmr++;

		// Alarme plus soutenue pendant les 3 premières secondes
		if (!radar_old) {
			if (compteur_tmr%2)
				PORTC &= 0b11111011;
			else
				PORTC |= 0b00000100;

			if (compteur_tmr == 12) {
				compteur_tmr = 1;
				radar_old = radar;
			}
		}
		// Ensuite un petit bip toutes les 2 secondes
		else {
			if (compteur_tmr == 1)
				PORTC |= 0b00000100;
			else
				PORTC &= 0b11111011;

			if (compteur_tmr == 16) {
				compteur_tmr = 0;
				radar_old = radar;
			}
		}

	} else {
		radar_old = radar;
		PORTC &= 0b11111011;
	}
}
ISR(USART_RXC_vect)  { // USART RX interrupt
	unsigned char c;
	c = UDR;

	if (recevoir)
		buffer_AddToEnd(c);
}

//******************************
// Fonction principale
//******************************

int main() {

	unsigned char i;
	unsigned char heure, h1, h2, m1, m2;
	unsigned char v1, v2, v3, v4, v5;
	unsigned char afficher;
	unsigned char l1, l2, l3, l4, l5, l6, l7, l8, orientation;
	unsigned int  num_radar;
	float vitesse, latitude, longitude;
	radar = 0;
	radar_old = 0;
	recevoir = 1;

	// Initialisation du LCD
	LCD_Init();

	// Initialisation de la connexion série
	Usart_Init();

	// Initialisation du buzzer
	DDRC  |= 0b00000100;
	TCCR1B = 0b00000011;    // Prescaler 1:64
	TCNT1H = 0b00001011;    // Initialisation à 3036 pour avoir toutes les 20ms
	TCNT1L = 0b11011100;    // Initialisation à 3036 pour avoir toutes les 20ms
	TIMSK |= 0b00000100;    // Activation de l'interruption
	sei();

	// Initialisation de la connexion I2C
	TWSR = 0;	// Prescaler à 0
	TWBR = 12;	// (F_CPU / 400000UL - 16) / 2 => 400KHz

	// Message de bienvenue
	LCD_Ecrire("  Radarminator  ", 16);
	LCD_GotoXY(0, 1);
	LCD_Ecrire("   Bienvenue    ", 16);

	// Attente début des trames GPS
	AttendreDebutTrame();

	LCD_GotoXY(0, 1);
	LCD_Ecrire("Recepteur GPS OK", 16);

	// On attend quelques secondes...
	for (i = 0; i < 10; i++)
		AttendreDebutTrame();

	LCD_GotoXY(0, 1);
	LCD_Ecrire("Attente position", 16);

	while(1) {

		// Attente des caractères d'identification
		while (buffer_datalength < 5);

		// Vérification des caractères d'identification
		if (buffer_GetFromFront() == 'G' && buffer_GetFromFront() == 'P' && buffer_GetFromFront() == 'R' && buffer_GetFromFront() == 'M' && buffer_GetFromFront() == 'C') {

			// Attente d'avoir suffisament de données dans la trame
			while (buffer_datalength < 60);

			// On arrête de recevoir les données
			recevoir = 0;

			// Pas d'affichage si le récepteur ne s'est pas encore localisé
			if (afficher) {

				// Caractères inutiles
				AttendreVirgule();

				// Affichage de l'heure HH:MM
				h1 = buffer_GetFromFront();//H
				h2 = buffer_GetFromFront();//H
				heure = (h1 - '0')*10 + (h2 - '0');
				heure += GMT_DECAL_PLUS;    // Fuseau horaire décalé en positif
				heure -= GMT_DECAL_MOINS;   // Fuseau horaire décalé en négatif
				if (heure >= 24) heure -= 24;
				m1 = buffer_GetFromFront();//M
				m2 = buffer_GetFromFront();//M

				if (!radar) {
					LCD_GotoXY(11, 1);
					if (heure >= 20) {
						LCD_Write('2', LCD_MODE_DONNEE);
						heure -= 20;
					} else if (heure >= 10) {
						LCD_Write('1', LCD_MODE_DONNEE);
						heure -= 10;
					} else {
						LCD_Write('0', LCD_MODE_DONNEE);
					}
					LCD_Write('0' + heure, LCD_MODE_DONNEE);
					LCD_Write(':', LCD_MODE_DONNEE);
					LCD_Write(m1, LCD_MODE_DONNEE);
					LCD_Write(m2, LCD_MODE_DONNEE);
				}

				// Caractères inutiles
				AttendreVirgule();
				AttendreVirgule();

				// Ici la latitute
				l1 = buffer_GetFromFront(); // deg
				l2 = buffer_GetFromFront(); // deg
				l3 = buffer_GetFromFront(); // minute
				l4 = buffer_GetFromFront(); // minute
				l5 = buffer_GetFromFront(); // ,
				l6 = buffer_GetFromFront(); // minute
				l7 = buffer_GetFromFront(); // minute
				if (!radar) {
					LCD_GotoXY(0, 0);
					if (l1 == '0') {
						LCD_Write(l2, LCD_MODE_DONNEE);
						LCD_Write(l3, LCD_MODE_DONNEE);
						LCD_Write(l4, LCD_MODE_DONNEE);
						LCD_Write(l5, LCD_MODE_DONNEE);
						LCD_Write(l6, LCD_MODE_DONNEE);
						LCD_Write(l7, LCD_MODE_DONNEE);
					} else {
						LCD_Write(l1, LCD_MODE_DONNEE);
						LCD_Write(l2, LCD_MODE_DONNEE);
						LCD_Write(l3, LCD_MODE_DONNEE);
						LCD_Write(l4, LCD_MODE_DONNEE);
						LCD_Write(l5, LCD_MODE_DONNEE);
						LCD_Write(l6, LCD_MODE_DONNEE);
					}
				}
				// latitude stockée en degrés et non en degrés minutes
				latitude = (l1-'0')*10 + (l2-'0') + ((l3-'0')*10 + (l4-'0') + (l6-'0')*0.1 + (l7-'0')*0.01)/60;

				// Orientation
				AttendreVirgule();
				orientation = buffer_GetFromFront();
				if (orientation == 'W') latitude = 0 - latitude;
				if (!radar) {
					LCD_Write(orientation, LCD_MODE_DONNEE);
					LCD_Ecrire("  ", 2);
				}

				// Caractères inutile
				AttendreVirgule();

				// Ici la longitude
				l1 = buffer_GetFromFront(); // deg
				l2 = buffer_GetFromFront(); // deg
				l3 = buffer_GetFromFront(); // deg
				l4 = buffer_GetFromFront(); // minute
				l5 = buffer_GetFromFront(); // minute
				l6 = buffer_GetFromFront(); // ,
				l7 = buffer_GetFromFront(); // minute
				l8 = buffer_GetFromFront(); // minute
				if (!radar) {
					if (l1 == '0') {
						if (l2 == '0') {
							LCD_Write(l3, LCD_MODE_DONNEE);
							LCD_Write(l4, LCD_MODE_DONNEE);
							LCD_Write(l5, LCD_MODE_DONNEE);
							LCD_Write(l6, LCD_MODE_DONNEE);
							LCD_Write(l7, LCD_MODE_DONNEE);
							LCD_Write(l8, LCD_MODE_DONNEE);
						} else {
							LCD_Write(l2, LCD_MODE_DONNEE);
							LCD_Write(l3, LCD_MODE_DONNEE);
							LCD_Write(l4, LCD_MODE_DONNEE);
							LCD_Write(l5, LCD_MODE_DONNEE);
							LCD_Write(l6, LCD_MODE_DONNEE);
							LCD_Write(l7, LCD_MODE_DONNEE);
						}
					} else {
						LCD_Write(l1, LCD_MODE_DONNEE);
						LCD_Write(l2, LCD_MODE_DONNEE);
						LCD_Write(l3, LCD_MODE_DONNEE);
						LCD_Write(l4, LCD_MODE_DONNEE);
						LCD_Write(l5, LCD_MODE_DONNEE);
						LCD_Write(l6, LCD_MODE_DONNEE);
					}
				}
				// longitude stockée en degrés et non en degrés minutes
				longitude = (l1-'0')*100 + (l2-'0')*10 + (l3-'0') + ((l4-'0')*10 + (l5-'0') + (l7-'0')*0.1 + (l8-'0')*0.01)/60;

				// Orientation
				AttendreVirgule();
				LCD_GotoXY(15, 0);
				orientation = buffer_GetFromFront();
				if (orientation == 'S') longitude = 0 - longitude;
				if (!radar) {
					LCD_Write(orientation, LCD_MODE_DONNEE);
				}

				// Caractères inutile
				AttendreVirgule();

				// Vitesse
				// x.xxx ou xx.xx ou xxx.x ou xxxx. ou xxxxx
				v1 = buffer_GetFromFront();
				v2 = buffer_GetFromFront();
				v3 = buffer_GetFromFront();
				v4 = buffer_GetFromFront();
				v5 = buffer_GetFromFront();

				if (!radar) {

					// Interprétation des valeurs ASCII
					if (v1 == '.') {
						vitesse = (float)(v1 - '0')*0.1 + (float)(v3 - '0')*0.01 + (float)(v4 - '0')*0.001 + (float)(v5 - '0')*0.0001; // en noeuds
					} else if (v2 == '.') {
						vitesse = (float)(v1 - '0') + (float)(v3 - '0')*0.1 + (float)(v4 - '0')*0.01 + (float)(v5 - '0')*0.001; // en noeuds
					} else if (v3 == '.') {
						vitesse = (float)(v1 - '0')*10 + (float)(v2 - '0') + (float)(v4 - '0')*0.1 + (float)(v5 - '0')*0.01; // en noeuds
					} else if (v4 == '.') {
						vitesse = (float)(v1 - '0')*100 + (float)(v2 - '0')*10 + (float)(v3 - '0') + (float)(v5 - '0')*0.1; // en noeuds
					} else if (v5 == '.') {
						vitesse = (float)(v1 - '0')*1000 + (float)(v2 - '0')*100 + (float)(v3 - '0')*10 + (float)(v4 - '0'); // en noeuds
					} else {
						vitesse = (float)(v1 - '0')*10000 + (float)(v2 - '0')*1000 + (float)(v3 - '0')*100 + (float)(v4 - '0')*10 + (float)(v5 - '0'); // en noeuds
					}

					// Conversion en km/h
					vitesse = vitesse*1.852;

					// Retransformation en ASCII et affichage de la vitesse
					LCD_GotoXY(0, 1);
					LCD_Write('0'+(unsigned char)(vitesse*0.01), LCD_MODE_DONNEE);
					vitesse -= (float)(((unsigned char)(vitesse*0.01))*100);
					LCD_Write('0'+(unsigned char)(vitesse*0.1), LCD_MODE_DONNEE);
					vitesse -= (float)(((unsigned char)(vitesse*0.1))*10);
					LCD_Write('0'+(unsigned char)(vitesse), LCD_MODE_DONNEE);
					vitesse -= (float)((unsigned char)(vitesse));
					LCD_Write('.', LCD_MODE_DONNEE);
					LCD_Write('0'+(unsigned char)(vitesse*10), LCD_MODE_DONNEE);
					LCD_Ecrire("km/h", 4);
					LCD_Ecrire("  ", 2);
				}

				if (!radar) {

					// On vérifie toutes les positions connues de radars
					radar = 0;
					for (num_radar = 0; num_radar < NOMBRE_DE_RADARS && !radar; num_radar++) {

						Eeprom_ReadPosition(num_radar);

						if (((latitude - eeprom_latitude)*(latitude - eeprom_latitude) + (longitude - eeprom_longitude)*(longitude - eeprom_longitude)) <= SEUIL_DETECTION)
							radar = 1;
					}

					// Si on a détecté un radar, on affiche l'alerte
					if (radar) {
						LCD_GotoXY(0, 0);
						LCD_Ecrire("!!   ALERTE   !!", 16);
						LCD_GotoXY(0, 1);
						LCD_Ecrire("! RADAR PROCHE !", 16);
					}

					// On a perdu pas mal de temps à chercher tous les radars, le buffer a certainement subi des dépassements
					// On vide le bufffer, on repart à 0
					buffer_datalength = 0;

				} else {

					// On avait détecté un radar, on attend de s'en être éloigné
					if (((latitude - eeprom_latitude)*(latitude - eeprom_latitude) + (longitude - eeprom_longitude)*(longitude - eeprom_longitude)) > SEUIL_DETECTION)
						radar = 0;

				}

			} else {
				AttendreVirgule();
				AttendreVirgule();
				// Si le récepteur dit qu'il est prêt, alors on y va
				if (buffer_GetFromFront() == 'A') afficher = 1;
			}
		}

		// Activation de la réception des données séries
		recevoir = 1;

		// Attente prochaine trame
		AttendreDebutTrame();

	}

	return 0;
}
