//Written by Tiziano Wehrli

//Compile with gcc -c -g gps_library.c
//When compiling a program that uses this library, you need to include
//the gpsd library and the object file for this library. 
//Therefore, include these flags:
//-lgps -lm gps_library.o

//docs at https://gpsd.gitlab.io/gpsd/libgps.html

//Follow these instructions to setup your gps
//https://gpswebshop.com/blogs/tech-support-by-os-linux/how-to-connect-an-usb-gps-receiver-with-a-linux-computer
//Do not worry about testing with xpgs, all you need is the setup procedure and 
//installing gpsd and configuring it to run on boot

#include "gps_library.h"

#define MODE_STR_NUM 4
//Used to convert the gps stuff into something nice
static char *mode_str[MODE_STR_NUM] = {
    "n/a",
    "None",
    "2D",
    "3D"
};

/*
    Function to initalize the GPS.

    @PARAM inStructGPS The address of the GPS struct.
    @return Exit status, 0 if successful.
*/
int initializeGPS(struct gps_data_t* inStructGPS) {
    //Open GPS Comms
    if (0 != gps_open("localhost", "2947", inStructGPS)) {
        return 1;
    }

    (void)gps_stream(inStructGPS, WATCH_ENABLE | WATCH_JSON, NULL);

    return 0;
}

/*
    Call this function when there is data available and you wish to read from GPS.
    Note, this will not check if data is available, and attempt to read regardless.

    @param inSructGPS The address of the GPS struct.
    @param inLatitude The address of the latitude float to modify.
    @param inLongitude The address of the longitude float to modify.
    @param inSpeed The address of the speed float to modify.
    @return
        0 on success.
        1 on gps_read failure.
        2 on obtain mode failure.
*/
extern int readFromGPS(struct gps_data_t* inStructGPS, float* inLatitude, float* inLongitude, float* inSpeed) {
    // will not block because we know data is available.
        if (-1 == gps_read(inStructGPS)) {
            return 1;
        }
        if (MODE_SET != (MODE_SET & inStructGPS->set)) {
            // did not even get mode, nothing to see here
            return 2;
        }
        if (0 > inStructGPS->fix.mode ||
            MODE_STR_NUM <= inStructGPS->fix.mode) {
            inStructGPS->fix.mode = 0;
        }

        //Update the three gps data values
        *inLatitude = inStructGPS->fix.latitude;
        *inLongitude = inStructGPS->fix.longitude;
        *inSpeed = inStructGPS->fix.speed;
        
        return 0;
}

/*
    Call this function to check if there is any data to read from the GPS.
    @param inSructGPS The address of the GPS struct.
    @return True if there is data to read, false otherwise.
*/
extern bool isDataGPS(struct gps_data_t* inStructGPS) {
    return gps_waiting(inStructGPS, 1);
}
