#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "uart.h"
#include "tff.h"
#include "diskio.h"

#include "bits.h"
#include "lcd.h"
#include "delay.h"


#define B1 (PINA&BIT0) //вверх
#define B2 (PINA&BIT1) //влево
#define B3 (PINA&BIT2) //средний
#define B4 (PINA&BIT3) //вправо
#define B5 (PINA&BIT4) //вниз

FATFS fatfs; /* Файловая система логических дисков  */
BYTE Buff[100]; /* Tyopuskuri */
char* endptr;
double Latitud;
double Longitud;
unsigned int altitude;
char *Alt = NULL;
char *Latitude = NULL;
char *Longitude = NULL;
char *North = NULL;
char *West = NULL;
char *Fix = NULL;
double minutes;
double degrees;
char Lat[30];
char Long[12];
BYTE b, *p = NULL;
WORD s;
FIL pointFile;
FIL pathFile;

/* I/O - инициализация */
static
void IoInit ()
{
PORTA = 0b00000000; // Port A - Интерфейсы с ключом, PA0-PA4 
DDRA = 0b00000000;  // Pin из 7 (koekytkentakortin реле), другими входе 
PORTB = 0b10110000; // Порт B - Включает шину SPI-смешанный диск защищен от записи 
DDRB = 0b11000000;
PORTC = 0b00000000; // Порт C - экраны Подключения koekytkentakortin 
DDRC = 0b11110111;
PORTD = 0b11111111; // Порт D - Неиспользованные 
PORTE = 0b11110010; // Port E - GPS: к, RXD0 и TXD0
DDRE = 0b10000010;
PORTF = 0b11111111; // Порта F - Неиспользованные 
PORTG = 0b11111;    // Порт G - Неиспользованные 
uart_init();          // Инициализация UART 
sei();                // разрешить прерывания
}

/* Сравнение строк. Получает в качестве параметра строку адреса и сравните строку .*/ 
/* Если параметры совпадают, возвращает нуль .*/

static
BYTE gp_comp (BYTE *str1, const prog_uint8_t *str2)
{
BYTE c;
do {
c = pgm_read_byte(str2++);
} while (c && c == *str1++);
return c;
}

/* Column-разделения. Получает в качестве параметров в теореме указателя и столбцов jarjestysluvun .*/ 
/* Возвращает jarjestysluvun места содержания колонки, и нулю, если столбец является пустым .*/ 

static
BYTE* gp_col (const BYTE* buf, BYTE col) {
BYTE c;
while (col) {
do {
c = *buf++;
if (c <= ' ') return NULL;
} while (c != ',');
col--;
}
return (BYTE*)buf;
}
/* Строка поиска USART: вечер. Возвращает число байт, и нулю, если ошибка происходит Suo-Ритус. */ static
BYTE get_line (void) {
BYTE c, i = 0;
for (;;) {
c = uart_get();
if (!c || (i == 0 && c != '$')) continue; // Jos ei rivia tai rivin alussa muu merkki kuin dollari
Buff[i++] = c; // Tallentaa indeksoidun merkin puskuriin (Buff[100])
if (c == '\n') break; // Jos rivi loppuu, tallennus lopetetaan
if (i >= sizeof(Buff)) i = 0;
}
return i;
}
/* Подпрограмма, которая выводится на экран desimaalikoordinaatit */
/******************************************************************************************/
void NMEA_on_display(void){
SEND_CMD(CLR_DISP); // Tyhjennetaan naytto
while(get_line()){ // Niin kauan, kun saadaan kelvollisia riveja..
if (!gp_comp(Buff, PSTR("$GPRMC"))) // Jos vastaanotetaan RMC-lause
{
Latitude= gp_col(Buff, 3); // RMC-lauseen neljas kentta sisaltaa latitudin
Longitude = gp_col(Buff, 5); // RMC-lauseen kuudes kentta sisaltaa longitudin
North = gp_col(Buff, 4); // Pallonpuolisko-indikaattorit
West = gp_col(Buff, 6);
Longitud = strtod(Longitude, &endptr); //Muutetaan merkkijono desimaaliluvuksi
minutes = modf(Longitud/100, &degrees); //Eristetaan desimaaliosa
Longitud = degrees + (minutes*100)/60; //Pistetaan takaisin "kasaan"
Latitud = strtod(Latitude, &endptr); //Sama tehdaan latitudille
minutes = modf(Latitud/100, &degrees);
Latitud = degrees + (minutes*100)/60;
if(North == 'S') Latitud = -Latitud; //etelainen vai pohjoinen pallonpuolisko?
if(West == 'W') Longitud = -Longitud; //itainen vai lantinen pallonpuolisko?
sprintf(Lat, "%f", Latitud); // Nailla riveilla liukuluvut tulostetaan takaisin
sprintf(Long, "%f", Longitud); // merkkijonoon
strncat(Lat, " ", strlen(Lat) + 6);
strncat(Lat, Long, strlen(Lat) + strlen(Long) - 1);
SEND_STR(Lat); // Merkkijono tulostetaan naytolle
}
if(B5 == 0){ // Jos kesken ohjelmasuorituksen painetaan nappainta,
SEND_CMD(CLR_DISP); // palaa ohjelmasuoritus paavalikkoon
break;
}
}
}
/* Koordinaattidatan записи на SD карте */ 
/******************************************************************************************/
int NMEA_on_sd(void){

disk_initialize(0); // Levyn ja tiedostojarjestelman alustus
f_mount(0, &fatfs);
do{
get_line(); // Odotetaan lausetta, josta saadaan poimittua paivamaara
}while(gp_comp(Buff, PSTR("$GPRMC")));
p = gp_col(Buff,9); // Poimitaan kymmenennessa kentassa sijaitseva paivamaara
strcpy_P(&Buff[6], PSTR(".log")); // Avataan tiedosto nimella “paivays.log”
if (f_open(&pointFile, Buff, FA_OPEN_ALWAYS | FA_WRITE)
|| f_lseek(&pointFile, pointFile.fsize)) {
SEND_STR("AVAUSVIRHE!"); // Mikali tiedoston avaus epaonnistuu,
delay_ms(50); // virheilmoitus ja palataan paaohjelmaan
return 0;
}
// Ohjelma tallentaa tassa maaritellyt lausetyypit.
while ((b = get_line()) > 0){
if ( !gp_comp(Buff, PSTR("$GPGGA"))
|| !gp_comp(Buff, PSTR("$GPRMC"))
// || !gp_comp(Buff, PSTR("$GPGSA"))
// || !gp_comp(Buff, PSTR("$GPGLL"))
// || !gp_comp(Buff, PSTR("$GPGSV"))
// || !gp_comp(Buff, PSTR("$GPZDA"))
// || !gp_comp(Buff, PSTR("$GPVTG"))
) {
if (f_write(&pointFile, Buff, b, &s) || b != s){
SEND_CMD(CLR_DISP);
SEND_STR("KIRJOITUSVIRHE!"); // Mikali kirjoitus epaonnistuu,
return 0; // virheilmoitus ja palataan paaohjelmaan
}
}
if (B5==0){ // Kun painetaan nappainta, ohjelma sulkee tiedoston ja palaa
// paaohjelmaan
f_close(&pointFile);
SEND_CMD(CLR_DISP);
break;
}
}
return 1;
}

/* Координаты записи на карту формата SD, CML */
/******************************************************************************************/
int KML_on_sd(void){
disk_initialize(0); // Levyn ja tiedostojarjestelman alustus
f_mount(0, &fatfs);
do{
get_line(); // Odotetaan lausetta, josta saadaan poimittua paivamaara
}while(gp_comp(Buff, PSTR("$GPRMC")));
p = gp_col(Buff,9); // Avataan tiedosto nimella “paivays.kml”
strcpy_P(&Buff[6], PSTR(".kml"));
if (f_open(&pathFile, Buff, FA_OPEN_ALWAYS | FA_WRITE)
|| f_lseek(&pathFile, pathFile.fsize)) {
SEND_STR("AVAUSVIRHE!"); // Jos virhe, palataan paaohjelmaan
delay_ms(50);
return 0;
}
// Kirjoitetaan KML-formaatin vaatimat kuvaukset muistikortille
f_printf(&pathFile, "<kml>\n");
f_printf(&pathFile, "\t<Document>\n");
f_printf(&pathFile, "<Placemark>\n");
f_printf(&pathFile, "\t<name>Reittix</name>\n");
f_printf(&pathFile, "\t<description>");
f_printf(&pathFile, gp_col(Buff,9));
f_printf(&pathFile, "\t</description>\n");
f_printf(&pathFile, "\t<LineString>\n");
f_printf(&pathFile, "\t\t<extrude>1</extrude>\n");
f_printf(&pathFile, "\t\t<altitudeMode>absolute</altitudeMode>\n");
f_printf(&pathFile, "\t\t<coordinates>");
// Tulostetaan koordinaattitiedot kyseisesta reitista.
while (get_line()) {
if (!gp_comp(Buff, PSTR("$GPGGA")))
{
Latitude = gp_col(Buff, 2); // Poimitaan paikkadata GGA-lauseesta
Longitude = gp_col(Buff, 4);
North = gp_col(Buff, 3);
West = gp_col(Buff, 5);
Alt = gp_col(Buff, 9);
// Muutetaan koordinaatit desimaalimuotoon
Longitud = strtod(Longitude, &endptr);
minutes = modf(Longitud/100, &degrees);
Longitud = degrees + (minutes*100)/60;
Latitud = strtod(Latitude, &endptr);
minutes = modf(Latitud/100, &degrees);
Latitud = degrees + (minutes*100)/60;
if(North == 'S') Latitud = -Latitud;
if(West == 'W') Longitud = -Longitud;
sprintf(Latitude, "%f", Latitud);
sprintf(Longitude, "%f", Longitud);
altitude = strtod(Alt, &endptr);
sprintf(Alt, "%i", altitude);
// Tulostetaan koordinaatit keskelle KML-tiedostoa
f_printf(&pathFile, "%s,%s,%s,",
Longitude,
Latitude,
Alt);
f_sync(&pathFile); // Tiedoston synkronointi ja puskurin tyhjennys
f_truncate(&pathFile);
}
if (B5==0){ // Mikali painetaan nappia, tallennus keskeytyy
SEND_CMD(CLR_DISP);
break;
}
}
// Tulostetaan KML-tiedoston vaatimat kuvaukset
f_printf(&pathFile, "</coordinates>\n");
f_printf(&pathFile, "\t</LineString>\n");
f_printf(&pathFile, "</Placemark>\n");
f_printf(&pathFile, "\t</Document>\n");
f_printf(&pathFile, "</kml>\n");
f_close(&pathFile); // Suljetaan tiedosto
SEND_CMD(CLR_DISP); // Tyhjennetaan naytto
return 1;
}
/* Paaohjelmasilmukka */
/*********************************************************************************/
int main(void)
{
IoInit(); // инициализация портов ввода вывода
LCD_Ini(); // LCD-дисплей инициализация
SEND_CMD(DISP_ON); // дисплей включить
SEND_CMD(CLR_DISP); // Дисплей очистить
SEND_STR("GPSlogger v.0.4"); // Приветствие 
delay_ms(50);
SEND_CMD(CLR_DISP); // Очистить дисплей
while (1) {
// Выводится на экран и начать paavalikkoteksti Клавиатура избирательном цикле вечного наличными 
SEND_STR("-- Главное меню --");
// ВВЕРХ 
if (B1==0) {
SEND_CMD(CLR_DISP);                 // Очистить дисплей
SEND_CMD(DD_RAM_ADDR);
SEND_STR("Координаты на экран");  // Вывод на экран 
delay_ms(50);                     // задержка 50 мс
NMEA_on_display();                // Вывод на дисплей
}
// ВЛЕВО 
if (B2==0) {
SEND_CMD(CLR_DISP);              // Очистить дисплей
SEND_CMD(DD_RAM_ADDR);
SEND_STR("NMEA-log");      // Вывод на экран 
delay_ms(50);                    // задержка 50 мс
NMEA_on_sd();                    // запись на карту памяти
}
// ПРАВО 
if (B4==0) {
SEND_CMD(CLR_DISP);        // Очистить дисплей
SEND_CMD(DD_RAM_ADDR);
SEND_STR("KML-база");      // Вывод на экран 
delay_ms(50);              // задержка 50 мс
KML_on_sd();               // запись на карту памяти
}
}
}