/* ---------------------------------------------------------- Routinen zum Empfang der NMEA Nachrichten und deren Auswertung $GNRMC,080947.00,A,5200.19391,N,00910.23188,E,30.585,231.29,180121,,,A*45 ---------------------------------------------------------- */ #include "gps.h" /* Indiziert einen NMEA Teststring in den Buffer und simuliert damit den einwandfreien Empfang */ #define TESTSTRING #define BAUDRATE 9600 /* -------------------- Interface Variablen --------------------- */ volatile nmea_info_t GPS; volatile nmea_info_t GPSnapshot; /* Inhalt NMEA bei Tastendruck */ volatile _Bool fGPSValidFix = false; /* 1: Gültiger Fix vorhanden */ volatile _Bool fGPSDataValid = false; /* 1: Gültiger Datensatz */ /* -------------------- Private Variablen --------------------- */ #define BUFSIZE 100 volatile char NMEAStrBuf[BUFSIZE]; volatile uint16_t NmeaBuf_Ptr = 0; /* ---- Datensatz Interface zu externen Funktionen ----*/ /* Setze Datensatz gültig / ungültig */ void GPS_SetDataValid(_Bool stat) { GPS.datavalid = stat; } /* Daten gültig oder ungültig */ uint8_t GPS_GetDataValid() { return (GPS.datavalid); } /* Liefert die aktuelle Geschwindigkeit zurück */ double* GPS_GetSpeed() { return ((double*)&GPS.speedkmh); } /* Liefert die Latitude zurück */ double* GPS_GetLatitude() { return ((double*)&GPS.latitude); } /* Liefert die Longtitude zurück */ double* GPS_GetLongtitude() { return ((double*)&GPS.longtitude); } /* Liefert Zeiger auf NMEA String */ char* GPS_GetNMEAStr() { return ((char*)&GPS.nmeastring); } /* Liefert Zeiger auf Latitude String */ char* GPS_GetLatStr() { return ((char*)&GPS.latstr); } /* Liefert Zeiger auf Longtitude String */ char* GPS_GetLongStr() { return ((char*)&GPS.longstr); } /* Liefert einen Zeiger auf die Uhrzeit mit Datum Aufruf: uint16_t test = GPS_GetDateTime()->tm_min; */ struct tm* GPS_GetStamp() { return ((struct tm*)&GPS.time); }; /* ------ Interface zu externen Funktionen --------*/ /* Initialisiert die UART1 und stellt Verbindung zur ISR her */ void Init_UART1() { USART_InitTypeDef usart1_init_struct; GPIO_InitTypeDef gpioa_init_struct; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE); /* GPIOA PA9(TX) / PA10(RX) alternative function */ gpioa_init_struct.GPIO_Pin = GPIO_Pin_9; gpioa_init_struct.GPIO_Speed = GPIO_Speed_50MHz; gpioa_init_struct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &gpioa_init_struct); gpioa_init_struct.GPIO_Pin = GPIO_Pin_10; gpioa_init_struct.GPIO_Speed = GPIO_Speed_50MHz; gpioa_init_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpioa_init_struct); /* Baud rate 9600, 8-bit data, One stop bit * No parity, Tx, No HW flow control */ usart1_init_struct.USART_BaudRate = 9600; usart1_init_struct.USART_WordLength = USART_WordLength_8b; usart1_init_struct.USART_StopBits = USART_StopBits_1; usart1_init_struct.USART_Parity = USART_Parity_No ; usart1_init_struct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; usart1_init_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1, &usart1_init_struct); /* Interruptanbindung an den NVIC */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* Pending Ints löschen */ ClearPendingIT(); /* Ints aktivieren */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* RXNE Interrupt */ USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); /* RX Idle Interrupt */ USART_Cmd(USART1, ENABLE); NVIC_EnableIRQ(USART1_IRQn); } /* Schaltet GPS Enable ein/aus + Init */ void GPS_Power(FunctionalState status) { static uint8_t merker = 0; /* Doppeldurchläufe vermeiden */ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPS_ENABLE_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; __disable_irq(); switch (status) { case ENABLE: if (merker != 1) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPS_ENABLE_PORT, &GPIO_InitStructure); /* USART und ISR einschalten */ USART_Cmd(USART1, ENABLE); ClearPendingIT(); NVIC_EnableIRQ(USART1_IRQn); merker = 1; } break; case DISABLE: if (merker != 2) { /* USART1 und ISR abschalten */ NVIC_DisableIRQ(USART1_IRQn); USART_Cmd(USART1, DISABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPS_ENABLE_PORT, &GPIO_InitStructure); GPIO_ResetBits(GPS_ENABLE_PORT, GPS_ENABLE_PIN); /* Flags ungültig setzen */ fGPSValidFix = false; merker = 2; } break; } __enable_irq(); } /* Stop Modul: B5 62 06 57 08 00 01 00 00 00 50 4F 54 53 AC 85 Start Modul: B5 62 06 57 08 00 01 00 00 00 20 4E 55 52 7B C3 */ /* Flag Verhindert mehrfaches Schalten */ volatile _Bool fGPS_OnSwitch = true; /* Stoppt das GPS Modul */ void GPS_StopGNSS() { const uint8_t stopcmd[16] = {0xB5,0x62,0x06,0x57,0x08,0x00,0x01,0x00, 0x00,0x00,0x50,0x4F,0x54,0x53,0xAC,0x85 }; __disable_irq(); if (fGPS_OnSwitch == true) { for (uint8_t i = 0; i < sizeof(stopcmd); i++) { USART_SendData(USART1,stopcmd[i]); while (!USART_GetFlagStatus(USART1,USART_FLAG_TXE)); } NVIC_DisableIRQ(USART1_IRQn); USART_Cmd(USART1, DISABLE); fGPS_OnSwitch = false; } __enable_irq(); } /* Neustart des GPS Moduls */ void GPS_StartGNSS() { const uint8_t startcmd[16] = {0xB5,0x62,0x06,0x57,0x08,0x00,0x01,0x00, 0x00,0x00,0x20,0x4E,0x55,0x52,0x7B,0xC3 }; __disable_irq(); if (fGPS_OnSwitch == false) { USART_Cmd(USART1, ENABLE); for (uint8_t i = 0; i < sizeof(startcmd); i++) { USART_SendData(USART1,startcmd[i]); while (!USART_GetFlagStatus(USART1,USART_FLAG_TXE)); } NVIC_EnableIRQ(USART1_IRQn); fGPS_OnSwitch = true; } __enable_irq(); } /* ---------------------------------------------------- UART1 Interrupt Service Routine ----------------------------------------------------- */ void USART1_IRQHandler() { #define MAX_NMEA_FIELDS 16 char* nmea_fields[MAX_NMEA_FIELDS]; /* Neues Byte wurde empfangen vom GPS Modul */ if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) { NMEAStrBuf[NmeaBuf_Ptr] = USART_ReceiveData(USART1); /* Pointer auf nächstes Byte */ NmeaBuf_Ptr = (NmeaBuf_Ptr + 1) % BUFSIZE; /* String terminieren !!! */ NMEAStrBuf[NmeaBuf_Ptr] = 0; SetLED(BOARD,ENABLE); } /* ------------------------------------------------------- */ /* Timeout, letztes Byte wurde empfangen */ if (USART_GetITStatus(USART1, USART_IT_IDLE) == SET) { /* FIXXXXXME Test */ #ifdef TESTSTRING strcpy((char*)NMEAStrBuf,"$GNRMC,162733.00,A,5158.65502,N,00916.74409,E,27.892,250.07,140421,,,A*4B\r\n"); #endif NmeaBuf_Ptr = 0; /* Reset RX Pointer */ SetLED(BOARD,DISABLE); /* ---------------- Überprüfe die ersten Zeichen auf $GNRMC -------------*/ /* Alles ungültig markieren */ fGPSValidFix = false; fGPSDataValid = false; const char str1[] = "$GNRMC"; if (strncmp((char*)NMEAStrBuf,str1,sizeof(str1)-1) == 0) { /* Stern vor prüfsumme suchen */ char* k = (char*)&NMEAStrBuf; uint8_t ilen = 0; while ((*k++ != '*') && (ilen++ < strlen((char*)&NMEAStrBuf))); /* Suchen... */ /* Prüfsumme extrahieren als int */ char foo[8] = {0,0,0,0,0,0,0,0}; strncpy(foo,k,2); uint32_t sum = hex2int((char*)&foo); // uint8_t sum = (int)strtol(strncpy(foo,k,2), NULL, 16); /* Prüfsumme des Nmea Strings bilden */ uint32_t xor = 0; for (uint8_t i = 1; i < ilen; i++) xor ^= NMEAStrBuf[i]; /* Falsche Prüfsumme, dann raus */ if (sum != xor) { goto exithandler; } /* String in SD Card Buffer kopieren mit seiner Size*/ strcpy((char*)&GPS.nmeastring,(char*)&NMEAStrBuf); /* String jetzt zerteilen, der durch , separiert ist */ k = (char*)&NMEAStrBuf; uint8_t i = 0; nmea_fields[i++] = k; /* Erstes Element setzen, NMEA Typ RMC */ /* Vektor Feld auf einzelne Teil Strings erzeugen */ while (((k = strchr(k,',')) != NULL) && (i < MAX_NMEA_FIELDS)) { *k = '\0'; nmea_fields[i++] = ++k; } /* Gültiger Fix = 1, kein Fix = 0 */ if (strncmp(nmea_fields[2],"A",1) == 0) { /* -------------------------------------------------- */ fGPSValidFix = true; /* Extrahiere die Daten aus dem NMEA String */ /* ---- Uhrzeit extrahieren ---- */ memset(foo,0,sizeof(foo)); /* 0 terminieren */ char *p = nmea_fields[1]; if (*p != '\0') { /* Strings wandeln */ uint8_t h = atoi(strncpy(foo,p,2)); p +=2; uint8_t m = atoi(strncpy(foo,p,2)); p +=2; uint8_t s = atoi(strncpy(foo,p,2)); /* Plausibilitätsprüfung */ if ((h>23) || (m>59) || (s>59)) goto exithandler; GPS.time.tm_hour = h; GPS.time.tm_min = m; GPS.time.tm_sec = s; } else goto exithandler; /* ---- Latitude (Breite) 5200.38115 ---- */ char grad[4]; char minuten[10]; memset(grad,0,sizeof(grad)); memset(minuten,0,sizeof(minuten)); p = nmea_fields[3]; if (*p != '\0') { /* Strings extrahieren */ strncpy(grad,p,2); strncpy(minuten,p+2,8); /* In DezGrad Float wandeln */ GPS.latitude = atof(grad) + atof(minuten)/60; if (GPS.latitude > 180) goto exithandler; /* DezGrad in String wandeln */ ftoa(*(double*)&GPS.latitude,(char*)&GPS.latstr,5); } else goto exithandler; /* ---- Longtitude (Laenge) 00910.09884 ---- */ p = nmea_fields[5]; memset(grad,0,sizeof(grad)); memset(minuten,0,sizeof(minuten)); if (*p != '\0') { /* Strings extrahieren */ strncpy(grad,p,3); strncpy(minuten,p+3,8); /* In DezGrad Float wandeln */ GPS.longtitude = atof(grad) + (atof(minuten)/60); if (GPS.longtitude > 90) goto exithandler; /* DezGrad in String wandeln */ ftoa(*(double*)&GPS.longtitude,(char*)&GPS.longstr,5); } else goto exithandler; /* ---- Geschwindigkeit in kmh ---- */ p = nmea_fields[7]; GPS.speedkmh = 0; if (*p != '\0') { GPS.speedkmh = (double)atoi(p) * 1.852; if (GPS.speedkmh > 250) GPS.speedkmh = 250; } else goto exithandler; /* ---- Kompass Richtung 0...360 bzgl Norden ---- */ p = nmea_fields[8]; memset(foo,0,sizeof(foo)); GPS.heading = -1; /* ungültig markieren */ if (*p != '\0') { /* Auswertung der Fahrtrichtung. Diese stellt sich erst in Bewewgung ein! */ GPS.heading = (atoi(p) < 360) ? atoi(p) : 0; } /* --- Datum DDMMYY ---- */ p = nmea_fields[9]; memset(foo,0,sizeof(foo)); if (*p != '\0') { /* String kopieren fur Filename */ //strcpy((char*)&GPS.gpsdate,p); /* Strings umwandeln */ int day = atoi(strncpy(foo,p,2)); p +=2; int mon = atoi(strncpy(foo,p,2)); p +=2; int yr = atoi(strncpy(foo,p,2)); /* Plausibilitätsprüfung */ if ((yr<21) || (mon>12) || (day>31)) goto exithandler; GPS.time.tm_year = yr + 2000; GPS.time.tm_mon = mon; GPS.time.tm_mday = day; } else goto exithandler; /* Der Datensatz war gültig */ fGPSDataValid = true; GPS.datavalid = true; } } } exithandler: /* Overflow Error abfangen */ if (USART_GetITStatus(USART1, USART_IT_ORE_RX) != RESET) { fGPSDataValid = false; NmeaBuf_Ptr = 0; /* Reset RX Pointer & Clear */ memset((void*)NMEAStrBuf,0,sizeof(NMEAStrBuf)); } /* Alle Error Flags löschen */ ClearPendingIT(); }