Files @ b113d7d76caf
Branch filter:

Location: FeatherHAB/wsprhab/src/gps.c - annotation

Ethan Zonca
Implementation of faster baud rate and new message
0d9900312165
ddd34459834e
0d9900312165
0d9900312165
0d9900312165
dd3b59fcb7a7
c1b1dfc6c2f4
0d9900312165
0d9900312165
0d9900312165
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
0d9900312165
0d9900312165
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
0d9900312165
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
0d9900312165
c1b1dfc6c2f4
0d9900312165
c1b1dfc6c2f4
0d9900312165
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
0d9900312165
0d9900312165
0d9900312165
c1b1dfc6c2f4
0d9900312165
aa624684a65e
dd3b59fcb7a7
aa624684a65e
50cc79d449a4
aa624684a65e
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
a127e9133034
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
a127e9133034
50cc79d449a4
50cc79d449a4
50cc79d449a4
a127e9133034
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
a127e9133034
a127e9133034
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
a127e9133034
a127e9133034
a127e9133034
0d9900312165
0d9900312165
0d9900312165
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
c1b1dfc6c2f4
21759af9d2ad
50cc79d449a4
c1b1dfc6c2f4
c1b1dfc6c2f4
50cc79d449a4
50cc79d449a4
50cc79d449a4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
21759af9d2ad
21759af9d2ad
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
a127e9133034
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
50cc79d449a4
21759af9d2ad
a127e9133034
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
a127e9133034
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
0d9900312165
c1b1dfc6c2f4
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
21759af9d2ad
c1b1dfc6c2f4
c1b1dfc6c2f4
50cc79d449a4
50cc79d449a4
c1b1dfc6c2f4
b113d7d76caf
b113d7d76caf
50cc79d449a4
b113d7d76caf
c1b1dfc6c2f4
c1b1dfc6c2f4
b113d7d76caf
50cc79d449a4
50cc79d449a4
c1b1dfc6c2f4
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
c1b1dfc6c2f4
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
b113d7d76caf
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
21759af9d2ad
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
a127e9133034
a127e9133034
a127e9133034
a127e9133034
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
ddd34459834e
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
ddd34459834e
0d9900312165
0d9900312165
0d9900312165
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
0d9900312165
0d9900312165
0d9900312165
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
0d9900312165
dd3b59fcb7a7
dd3b59fcb7a7
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
c1b1dfc6c2f4
dd3b59fcb7a7
c1b1dfc6c2f4
c1b1dfc6c2f4
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
dd3b59fcb7a7
0d9900312165
0d9900312165
0d9900312165
0d9900312165
// TODO: Transition to using https://github.com/cuspaceflight/joey-m/blob/master/firmware/gps.c requesting UBX data

#include "stm32f0xx_hal.h"

#include "config.h"
#include "gpio.h"
#include "uart.h"
#include "gps.h"


typedef struct _gps_data
{
    int32_t hdop;
    int32_t sats_in_view;
    int32_t speed;
    int32_t heading;


    int32_t latitude;
    int32_t longitude;
    int32_t altitude;

    uint8_t hour;
    uint8_t minute;
    uint8_t second;

} gps_data_t;

gps_data_t position;

// Private methods
static void gps_ubx_checksum(uint8_t* data, uint8_t len, uint8_t* cka, uint8_t* ckb);
static uint8_t _gps_verify_checksum(uint8_t* data, uint8_t len);



void gps_init()
{
    // Initialize serial port
   // done in poweron uart_init();

	gps_poweron();

//	// uart1 ubx only
//
//	uint8_t setUBXuart1 = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25,
//	0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x79};
//	HAL_UART_Transmit(uart_gethandle(), setUBXuart1, sizeof(setUBXuart1)/sizeof(uint8_t), 100);
//	HAL_Delay(100);
//
//
//	// uart0 ubx only
//	uint8_t setUBXuart0 = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25,
//	0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x65};
//	HAL_UART_Transmit(uart_gethandle(), setUBXuart0, sizeof(setUBXuart0)/sizeof(uint8_t), 100);
//	HAL_Delay(100);
//
//
//	// uart1 ubx only
//
//	uint8_t setUBXuart2 = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25,
//	0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x8D};
//	HAL_UART_Transmit(uart_gethandle(), setUBXuart2, sizeof(setUBXuart2)/sizeof(uint8_t), 100);
//	HAL_Delay(100);

	// Disable messages
	uint8_t setGGA[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XFF, 0X23};
	HAL_UART_Transmit(uart_gethandle(), setGGA, sizeof(setGGA)/sizeof(uint8_t), 100);
	HAL_Delay(100);

	uint8_t ackbuffer[10];
	for(uint8_t i=0; i<10; i++)
		ackbuffer[i] = 0xaa;
	HAL_UART_Receive(uart_gethandle(), ackbuffer, 10, 100);

	uint8_t setZDA[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X08, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X07, 0X5B};
	HAL_UART_Transmit(uart_gethandle(), setZDA, sizeof(setZDA)/sizeof(uint8_t), 100);
	HAL_Delay(100);

	uint8_t setGLL[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X2A};
	HAL_UART_Transmit(uart_gethandle(), setGLL, sizeof(setGLL)/sizeof(uint8_t), 100);
	HAL_Delay(100);

	uint8_t setGSA[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X02, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X01, 0X31};
	HAL_UART_Transmit(uart_gethandle(), setGSA, sizeof(setGSA)/sizeof(uint8_t), 100);
	HAL_Delay(100);

	uint8_t setGSV[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X02, 0X38};
	HAL_UART_Transmit(uart_gethandle(), setGSV, sizeof(setGSV)/sizeof(uint8_t), 100);
	HAL_Delay(100);

	uint8_t setRMC[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, 0X3F};
	HAL_UART_Transmit(uart_gethandle(), setRMC, sizeof(setRMC)/sizeof(uint8_t), 100);
	HAL_Delay(100);

	uint8_t setVTG[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X05, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X46};
	HAL_UART_Transmit(uart_gethandle(), setVTG, sizeof(setRMC)/sizeof(uint8_t), 100);
	HAL_Delay(100);


//    // Disable GLONASS mode
//    uint8_t disable_glonass[20] = {0xB5, 0x62, 0x06, 0x3E, 0x0C, 0x00, 0x00, 0x00, 0x20, 0x01, 0x06, 0x08, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x01, 0x8F, 0xB2};
//
//    //gps_sendubx(disable_glonass, 20);
//    volatile HAL_StatusTypeDef res = HAL_UART_Transmit(uart_gethandle(), disable_glonass, 20, 100);
//
//    // Enable power saving
//    uint8_t enable_powersave[10] = {0xB5, 0x62, 0x06, 0x11, 0x02, 0x00, 0x08, 0x01, 0x22, 0x92};
//    //gps_sendubx(enable_powersave, 10);
//    res = HAL_UART_Transmit(uart_gethandle(), enable_powersave, 10, 100);
//
//
//    // Set dynamic model 6 (<1g airborne platform)
//    uint8_t airborne_model[] = { 0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC };
//    //gps_sendubx(airborne_model, sizeof(airborne_model)/sizeof(uint8_t));
//    res = HAL_UART_Transmit(uart_gethandle(), airborne_model, sizeof(airborne_model)/sizeof(uint8_t), 100);




}


void gps_update_position()
{
    // Request a NAV-POSLLH message from the GPS
    uint8_t request[8] = {0xB5, 0x62, 0x01, 0x02, 0x00, 0x00, 0x03, 0x0A};

    volatile uint8_t check_a = 0;
    volatile uint8_t check_b = 0;
    for(uint8_t i = 2; i<6; i++)
    {
    	check_a += request[i];
    	check_b += check_a;
    }


    //_gps_send_msg(request, 8);
    uint8_t flushed = uart_gethandle()->Instance->RDR;
    volatile HAL_StatusTypeDef txres = HAL_UART_Transmit(uart_gethandle(), request, 8, 100);

    uint8_t buf[36];
    for(uint8_t i =0; i<36; i++)
    	buf[i] = 0xaa;
    volatile HAL_StatusTypeDef result = HAL_UART_Receive(uart_gethandle(), buf, 36, 1000);

    //for(uint8_t i = 0; i < 36; i++)
    //    buf[i] = _gps_get_byte();

//    // Verify the sync and header bits
//    if( buf[0] != 0xB5 || buf[1] != 0x62 )
//        led_set(LED_RED, 1);
//    if( buf[2] != 0x01 || buf[3] != 0x02 )
//        led_set(LED_RED, 1);

    // 4 bytes of longitude (1e-7)
    position.longitude = (int32_t)buf[10] | (int32_t)buf[11] << 8 |
        (int32_t)buf[12] << 16 | (int32_t)buf[13] << 24;

    // 4 bytes of latitude (1e-7)
    position.latitude = (int32_t)buf[14] | (int32_t)buf[15] << 8 |
        (int32_t)buf[16] << 16 | (int32_t)buf[17] << 24;

    // 4 bytes of altitude above MSL (mm)
    position.altitude = (int32_t)buf[22] | (int32_t)buf[23] << 8 |
        (int32_t)buf[24] << 16 | (int32_t)buf[25] << 24;

    if( !_gps_verify_checksum(&buf[2], 32) )
        led_blink(2);
}


void gps_update_time(uint8_t* hour, uint8_t* minute, uint8_t* second)
{
    // Send a NAV-TIMEUTC message to the receiver
    uint8_t request[8] = {0xB5, 0x62, 0x01, 0x21, 0x00, 0x00, 0x22, 0x67};

    volatile uint8_t check_a = 0;
    volatile uint8_t check_b = 0;
    for(uint8_t i = 2; i<6; i++)
    {
    	check_a += request[i];
    	check_b += check_a;
    }


    uint8_t flushed = uart_gethandle()->Instance->RDR;
    volatile HAL_StatusTypeDef res = HAL_UART_Transmit(uart_gethandle(), request, 8, 100);

    // Get the message back from the GPS
    uint8_t buf[28];
    res = HAL_UART_Receive(uart_gethandle(), buf, 28, 500);

//    // Verify the sync and header bits
//    if( buf[0] != 0xB5 || buf[1] != 0x62 )
//        led_set(LED_RED, 1);
//    if( buf[2] != 0x01 || buf[3] != 0x21 )
//        led_set(LED_RED, 1);

    *hour = buf[22];
    *minute = buf[23];
    *second = buf[24];

//    if( !_gps_verify_checksum(&buf[2], 24) ) led_set(LED_RED, 1);
}

/**
 * Check the navigation status to determine the quality of the
 * fix currently held by the receiver with a NAV-STATUS message.
 */
void gps_check_lock(uint8_t* lock, uint8_t* sats)
{
    // Construct the request to the GPS
    uint8_t request[8] = {0xB5, 0x62, 0x01, 0x07, 0x00, 0x00, 0xFF, 0xFF};


    volatile uint8_t check_a = 0;
    volatile uint8_t check_b = 0;
    for(uint8_t i = 2; i<6; i++)
    {
    	check_a += request[i];
    	check_b += check_a;
    }
    request[6] = check_a;
    request[7] = check_b;

    uint8_t flushed = uart_gethandle()->Instance->RDR;
    HAL_UART_Transmit(uart_gethandle(), request, 8, 100);



    // Get the message back from the GPS
    uint8_t buf[100];
    for(uint8_t i=0; i<100; i++)
    	buf[i] = 0xaa;
    volatile HAL_StatusTypeDef res = HAL_UART_Receive(uart_gethandle(), buf, 100, 3000);

    // Check 60 bytes minus SYNC and CHECKSUM (4 bytes)
    if( !_gps_verify_checksum(&buf[2], 96) )
        led_blink(2);


    //volatile uint32_t gpstime_ms = (buf[6+0] << 24) | (buf[6+1] << 16) | buf[6+2] << 8) | (buf[6+3]);

    volatile uint8_t month = buf[6+6];
    volatile uint8_t day = buf[6+7];
    volatile uint8_t hour = buf[6+8];
    volatile uint8_t minute = buf[6+9];
    volatile uint8_t second = buf[6+10];
    volatile uint8_t valid = buf[6+11] & 0b1111;
    volatile uint8_t fixtype = buf[6+20];

    volatile uint8_t sats_in_solution = buf[6+23];

    volatile uint32_t longitude = (buf[6+24] << 24) | (buf[6+25] << 16) | (buf[6+26] << 8) | (buf[6+27]);
    volatile uint32_t latitude = (buf[6+28] << 24) | (buf[6+29] << 16) | (buf[6+30] << 8) | (buf[6+31]);
    volatile uint32_t altitude_sealevel = (buf[6+36] << 24) | (buf[6+37] << 16) | (buf[6+38] << 8) | (buf[6+39]);
    volatile uint32_t groundspeed = (buf[6+60] << 24) | (buf[6+61] << 16) | (buf[6+62] << 8) | (buf[6+63]);
    volatile uint16_t pdop = (buf[6+76] << 8) | (buf[6+77]);
//
//    // Return the value if GPSfixOK is set in 'flags'
//    if( buf[17] & 0x01 )
//        *lock = buf[16];
//    else
//        *lock = 0;
    *lock = fixtype;

    *sats = sats_in_solution;
}

/**
 * Verify that the uBlox 6 GPS receiver is set to the <1g airborne
 * navigaion mode.
 */
uint8_t gps_check_nav(void)
{
    uint8_t request[8] = {0xB5, 0x62, 0x06, 0x24, 0x00, 0x00,
        0x2A, 0x84};
    uint8_t flushed = uart_gethandle()->Instance->RDR;
    HAL_UART_Transmit(uart_gethandle(), request, 8, 100);

    // Get the message back from the GPS
    uint8_t buf[44];
    HAL_UART_Receive(uart_gethandle(), buf, 44, 100);

//    // Verify sync and header bytes
//    if( buf[0] != 0xB5 || buf[1] != 0x62 )
//        led_set(LED_RED, 1);
//    if( buf[2] != 0x06 || buf[3] != 0x24 )
//        led_set(LED_RED, 1);

    // Check 40 bytes of message checksum
//    if( !_gps_verify_checksum(&buf[2], 40) ) led_set(LED_RED, 1);

    // Clock in and verify the ACK/NACK
    uint8_t ack[10];
//    for(uint8_t i = 0; i < 10; i++)
//        ack[i] = _gps_get_byte();

    HAL_UART_Receive(uart_gethandle(), ack, 10, 100);

    // If we got a NACK, then return 0xFF
    if( ack[3] == 0x00 ) return 0xFF;

    // Return the navigation mode and let the caller analyse it
    return buf[8];
}

/**
 * Verify the checksum for the given data and length.
 */

static uint8_t _gps_verify_checksum(uint8_t* data, uint8_t len)
{
    uint8_t a, b;
    gps_ubx_checksum(data, len, &a, &b);
    if( a != *(data + len) || b != *(data + len + 1))
        return 0;
    else
        return 1;
}

// Calculate a UBX checksum using 8-bit Fletcher (RFC1145)
static void gps_ubx_checksum(uint8_t* data, uint8_t len, uint8_t* cka, uint8_t* ckb)
{
    *cka = 0;
    *ckb = 0;
    for( uint8_t i = 0; i < len; i++ )
    {
        *cka += *data;
        *ckb += *cka;
        data++;
    }
}


void gps_poweron(void)
{
    // NOTE: pchannel
    HAL_GPIO_WritePin(GPS_NOTEN, 0);
    uart_init();

    // Begin DMA reception
    //HAL_UART_Receive_DMA(uart_gethandle(), nmeaBuffer, NMEABUFFER_SIZE);
}


void gps_poweroff(void)
{
    // NOTE: pchannel
    uart_deinit();
    HAL_GPIO_WritePin(GPS_NOTEN, 1);
}

//
//uint8_t gps_hadfix = 0;
//uint8_t gps_hasfix()
//{
//	uint8_t hasFix = get_latitudeTrimmed()[0] != 0x00;
//	gps_hadfix = hasFix;
//	return hasFix;
//}



//void gps_sendubx(uint8_t* dat, uint8_t size)
//{
//    uint8_t sendctr;
//    for(sendctr = 0; sendctr < size; sendctr++)
//    {
//        HAL_UART_Transmit(huart1, dat[sendctr]);
//    }
//}

uint8_t gps_acquiring= 0;
uint32_t gps_lastfix_time;

void gps_acquirefix(void)
{
    gps_poweron();

    // Wait for fix
    gps_acquiring = 1;
}

uint8_t gps_getstate(void)
{
    if(gps_acquiring)
        return GPS_STATE_ACQUIRING;
    else if(gps_lastfix_time == 0)
        return GPS_STATE_NOFIX;
    else if(HAL_GetTick() - gps_lastfix_time < GPS_STALEFIX_MS)
        return GPS_STATE_FRESHFIX;
    else
        return GPS_STATE_STALEFIX;

}




// vim:softtabstop=4 shiftwidth=4 expandtab