/*
* gps.c
*
* Created on: Nov 15, 2019
* Author: Bulanov Konstantin
*
* Contact information
* -------------------
*
* e-mail : leech001@gmail.com
*/
/*
* |---------------------------------------------------------------------------------
* | Copyright (C) Bulanov Konstantin,2019
* |
* | This program is free software: you can redistribute it and/or modify
* | it under the terms of the GNU General Public License as published by
* | the Free Software Foundation, either version 3 of the License, or
* | any later version.
* |
* | This program is distributed in the hope that it will be useful,
* | but WITHOUT ANY WARRANTY; without even the implied warranty of
* | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* | GNU General Public License for more details.
* |
* | You should have received a copy of the GNU General Public License
* | along with this program. If not, see .
* |---------------------------------------------------------------------------------
*/
#include
#include
//#include
#include "gps.h"
#include "../admisc/ad0x0_timman.h"
#include "stm32f1xx_hal_uart.h"
#include
#if (GPS_DEBUG == 1)
#include
#endif
uint8_t rx_data = 0;
uint8_t rx_buffer[GPSBUFSIZE];
uint8_t rx_index = 0;
UART_HandleTypeDef *p_huart;
uint32_t last_recieve_tick=0;
uint32_t last_HAL_res=0;
HAL_UART_StateTypeDef last_UART_state;
uint8_t gps_enable=0;
uint8_t isinint=0;
static GPS_t GPS;
static gps_data_t gps_data;//для рф24
void (*gps_data_ready_func)(gps_data_t*);
static void update_gps_data(void);
uint8_t gps_wakeup(void);
static void gps_err(void){
__ASM("nop");
}
#if (GPS_DEBUG == 1)
void GPS_print(char *data){
char buf[GPSBUFSIZE] = {0,};
sprintf(buf, "%s\n", data);
CDC_Transmit_FS((unsigned char *) buf, (uint16_t) strlen(buf));
}
#endif
static uint32_t get_period_ms(uint32_t _tick_start){
uint32_t t=(HAL_GetTick()<_tick_start)
?((uint64_t)HAL_GetTick()+UINT32_MAX-_tick_start)
:(HAL_GetTick()-_tick_start);
return t;
}
void GPS_Init(UART_HandleTypeDef *_huart,void (*p_data_ready_func)(gps_data_t*))
{
p_huart=_huart;
gps_data_ready_func=p_data_ready_func;
ad0x0_timman_remove(gps_wakeup);
ad0x0_timman_add(100,gps_wakeup);
//HAL_UART_Receive_IT(p_huart, &rx_data, 1);// перенес в старт
}
void GPS_UART_CallBack(void){
if(isinint){
ad0x0_err();
return;
}
isinint=true;
if (rx_data != '\n' && rx_index < sizeof(rx_buffer)) {
rx_buffer[rx_index++] = rx_data;
} else {
#if (GPS_DEBUG == 1)
GPS_print((char*)rx_buffer);
#endif
if(GPS_validate((char*) rx_buffer)){
// GPS_parse((char*) rx_buffer);
GPS_parse_ad0x0((char*) rx_buffer);
}
rx_index = 0;
memset(rx_buffer, 0, sizeof(rx_buffer));
}
//last_HAL_res=HAL_UART_Receive_IT(p_huart, &rx_data, 1);
last_HAL_res=HAL_UART_GetError(p_huart);
last_UART_state=HAL_UART_GetState(p_huart);
if(HAL_OK==last_HAL_res){
if(HAL_UART_STATE_READY!=last_UART_state){
__ASM("nop");
}else{
last_HAL_res=HAL_UART_Receive_IT(p_huart, &rx_data, 1);
}
}
last_recieve_tick=HAL_GetTick();
isinint=false;
}
void GPS_AbortReceiveCpltCallback(void){
gps_start();
}
uint8_t gps_retransmit(void){
last_UART_state=HAL_UART_GetState(p_huart);
if(last_UART_state==HAL_UART_STATE_READY){
last_HAL_res=HAL_UART_Receive_IT(p_huart, &rx_data, 1);
}else{
if(last_UART_state==HAL_UART_STATE_RESET){
gps_enable=false;
last_UART_state=HAL_UART_GetState(p_huart);
last_HAL_res=HAL_UART_AbortReceive_IT(p_huart);
return 0;
// gps_enable=true;
}
if(last_UART_state & HAL_UART_ERROR_ORE){
__HAL_UART_CLEAR_OREFLAG(p_huart);
uint8_t tmpdr=p_huart->Instance->DR;
last_UART_state=HAL_UART_GetState(p_huart);
}
if(last_UART_state & HAL_UART_ERROR_FE){
__HAL_UART_CLEAR_FEFLAG(p_huart);
last_UART_state=HAL_UART_GetState(p_huart);
gps_enable=false;
last_UART_state=HAL_UART_GetState(p_huart);
last_HAL_res=HAL_UART_AbortReceive_IT(p_huart);
}
if(last_UART_state & HAL_UART_ERROR_NE){
__HAL_UART_CLEAR_NEFLAG(p_huart);
last_UART_state=HAL_UART_GetState(p_huart);
}
last_UART_state=HAL_UART_GetState(p_huart);
if(last_UART_state==HAL_UART_STATE_READY){
last_HAL_res=HAL_UART_Receive_IT(p_huart, &rx_data, 1);
}
}
//if(HAL_OK!=last_HAL_res){ gps_err(); }
// last_recieve_tick=HAL_GetTick();
// ad0x0_timman_remove(gps_retransmit);
// ad0x0_timman_add(10,gps_retransmit);
return 1;
}
void gps_start(void){
gps_enable=true;
gps_retransmit();
}
void GPS_UART_ErrorCallback(void){
last_HAL_res=HAL_UART_GetError(p_huart);
last_UART_state=HAL_UART_GetState(p_huart);
if(last_UART_state & HAL_UART_ERROR_ORE){
__HAL_UART_CLEAR_OREFLAG(p_huart);
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
last_UART_state=HAL_UART_GetState(p_huart);
if(HAL_UART_STATE_READY!=last_UART_state){
__ASM("nop");
}else{
last_HAL_res=HAL_UART_Receive_IT(p_huart, &rx_data, 1);
}
/* switch(last_HAL_res){
// case HAL_UART_ERROR_NONE: // – без ошибок;
case HAL_UART_ERROR_PE: // – ошибка целостности данных;
ad0x0_err();
break;
case HAL_UART_ERROR_NE: // – выделен шум;
ad0x0_err();
break;
case HAL_UART_ERROR_FE: // – ошибка фрагментации;
ad0x0_err();
break;
case HAL_UART_ERROR_ORE: // – ошибка переполнения;
__HAL_UART_CLEAR_OREFLAG(p_huart);
last_HAL_res=HAL_UART_Receive_IT(p_huart, &rx_data, 1);
break;
case HAL_UART_ERROR_DMA: // – ошибка DMA.
ad0x0_err();
break;
// ad0x0_timman_remove(gps_retransmit);
// ad0x0_timman_add(100,gps_retransmit);
default:
ad0x0_err();
last_HAL_res=HAL_UART_Receive_IT(p_huart, &rx_data, 1);
if(HAL_OK!=last_HAL_res){
gps_err();
}
}*/
}
uint8_t gps_wakeup(void){
uint32_t delta=get_period_ms(last_recieve_tick);
if(delta>1000){
if(gps_enable){
// HAL_UART_DeInit(p_huart);
// HAL_UART_Init(p_huart);
last_HAL_res=HAL_UART_AbortReceive_IT(p_huart);
gps_retransmit();
last_recieve_tick=HAL_GetTick();
}
}
return 0;
}
int GPS_validate(char *nmeastr){
char check[3];
char checkcalcstr[3];
int i;
int calculated_check;
i=0;
calculated_check=0;
// check to ensure that the string starts with a $
if(nmeastr[i] == '$')
i++;
else
return 0;
//No NULL reached, 75 char largest possible NMEA message, no '*' reached
while((nmeastr[i] != 0) && (nmeastr[i] != '*') && (i < 75)){
calculated_check ^= nmeastr[i];// calculate the checksum
i++;
}
if(i >= 75){
return 0;// the string was too long so return an error
}
if (nmeastr[i] == '*'){
check[0] = nmeastr[i+1]; //put hex chars in check string
check[1] = nmeastr[i+2];
check[2] = 0;
}
else
return 0;// no checksum separator found there for invalid
sprintf(checkcalcstr,"%02X",calculated_check);
return((checkcalcstr[0] == check[0])
&& (checkcalcstr[1] == check[1])) ? 1 : 0 ;
}
void setval(char _pt,void *p,char *str_p){
/*ну да, б, заморочился с парсером, ваще не хотел его писАть, но решил задрочить себе мозги*/
int d=0xFFFF;
float f;
if(!str_p){
ad0x0_err();
return;
}
switch(_pt){
case 's':
if(p)strcpy((char*)p,str_p);
break;
case 'c':
if(p)*((char*)p)=*str_p;
break;
case 'f':
f=atof(str_p);
if(p)*((float*)p)=f;
break;
case 'd':
sscanf(str_p,"%d",&d);
if(p)*((int*)p)=d;
break;
default:
gps_err();
ad0x0_err();
}
}
void parse_g(char *s,char *t,void **p){
char b[32],*pb;
uint8_t i=0;
pb=b;
if(!s){
ad0x0_err();
return;
}
memset(b,'x',sizeof(b));
while((i<75)&&(*s!='*')&&(*s)&&(*t)){
if(*s==','){
*pb++=0;
if(*t && *b)setval(*t,*p,b);
pb=b;
p++;
t++;
}else{
*pb++=*s;
}
s++;
i++;
}
}
void GPS_parse_ad0x0(char *s){
//$GNRMC,180159.00,A,5137.81278,N,03815.19037,E,2.468,71.94,050119,,,A*4C
if(!strncmp(s, "$GNRMC", 6)){//ad0x0
char t[]="sfcfcfcffd\0";
void *p[]={NULL,&GPS.utc_time, NULL, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.speed_k, &GPS.course_d, &GPS.date};
parse_g(s,t,p);
GPS.dec_latitude = GPS_nmea_to_dec(GPS.nmea_latitude, GPS.ns);
GPS.dec_longitude = GPS_nmea_to_dec(GPS.nmea_longitude, GPS.ew);
update_gps_data();
}else
if(!strncmp(s, "$GNGGA", 6)){
char t[]="sffcfcddffc\0";
void *p[]={NULL,&GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.lock, &GPS.satelites, &GPS.hdop, &GPS.msl_altitude, &GPS.msl_units};
parse_g(s,t,p);
GPS.dec_latitude = GPS_nmea_to_dec(GPS.nmea_latitude, GPS.ns);
GPS.dec_longitude = GPS_nmea_to_dec(GPS.nmea_longitude, GPS.ew);
update_gps_data();
}
}
void GPS_parse(char *GPSstrParse){
char m;
if (!strncmp(GPSstrParse, "$GNRMC", 6)){//ad0x0
//$GNRMC,180159.00,A,5137.81278,N,03815.19037,E,2.468,71.94,050119,,,A*4C
if(sscanf(GPSstrParse, "$GNRMC,%f,%c,%f,%c,%f,%c,%f,%f,%d", &GPS.utc_time, &m, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.speed_k, &GPS.course_d, &GPS.date) >= 1){
GPS.dec_latitude = GPS_nmea_to_dec(GPS.nmea_latitude, GPS.ns);
GPS.dec_longitude = GPS_nmea_to_dec(GPS.nmea_longitude, GPS.ew);
update_gps_data();
return;
}
}else
if(!strncmp(GPSstrParse, "$GNGGA", 6)){
if (sscanf(GPSstrParse, "$GNGGA,%f,%f,%c,%f,%c,%d,%d,%f,%f,%c", &GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.lock, &GPS.satelites, &GPS.hdop, &GPS.msl_altitude, &GPS.msl_units) >= 1){
GPS.dec_latitude = GPS_nmea_to_dec(GPS.nmea_latitude, GPS.ns);
GPS.dec_longitude = GPS_nmea_to_dec(GPS.nmea_longitude, GPS.ew);
update_gps_data();
return;
}
}else
if(!strncmp(GPSstrParse, "$GPGGA", 6)){
if (sscanf(GPSstrParse, "$GPGGA,%f,%f,%c,%f,%c,%d,%d,%f,%f,%c", &GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.lock, &GPS.satelites, &GPS.hdop, &GPS.msl_altitude, &GPS.msl_units) >= 1){
GPS.dec_latitude = GPS_nmea_to_dec(GPS.nmea_latitude, GPS.ns);
GPS.dec_longitude = GPS_nmea_to_dec(GPS.nmea_longitude, GPS.ew);
update_gps_data();
return;
}
}
else if (!strncmp(GPSstrParse, "$GPRMC", 6)){
if(sscanf(GPSstrParse, "$GPRMC,%f,%f,%c,%f,%c,%f,%f,%d", &GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.speed_k, &GPS.course_d, &GPS.date) >= 1){
update_gps_data();
return;
}
}
else if (!strncmp(GPSstrParse, "$GPGLL", 6)){
if(sscanf(GPSstrParse, "$GPGLL,%f,%c,%f,%c,%f,%c", &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.utc_time, &GPS.gll_status) >= 1){
update_gps_data();
return;
}
}
else if (!strncmp(GPSstrParse, "$GPVTG", 6)){
if(sscanf(GPSstrParse, "$GPVTG,%f,%c,%f,%c,%f,%c,%f,%c", &GPS.course_t, &GPS.course_t_unit, &GPS.course_m, &GPS.course_m_unit, &GPS.speed_k, &GPS.speed_k_unit, &GPS.speed_km, &GPS.speed_km_unit) >= 1)
update_gps_data();
return;
}
}
float GPS_nmea_to_dec(float deg_coord, char nsew) {
int degree = (int)(deg_coord/100);
float minutes = deg_coord - degree*100;
float dec_deg = minutes / 60;
float decimal = degree + dec_deg;
if (nsew == 'S' || nsew == 'W') { // return negative
decimal *= -1;
}
return decimal;
}
void update_gps_data(void){
gps_data.latitude=GPS.dec_latitude;
gps_data.longitude=GPS.dec_longitude;
gps_data.satelites=GPS.satelites;
gps_data.speed_km=GPS.utc_time;
if(gps_data_ready_func)gps_data_ready_func(&gps_data);
}