#ifndef GPS_H
#define GPS_H

#include <stdbool.h>
#include "exo_types.h"
#include <stdint.h>
#include <time.h>

#define OEM7_SCS  0
#define OEM7_FAIL 1

//#define GPS_DEBUG_PRINT 1

#define OEM7_CRC_LEN 4
#define OEM7_HEADER_LEN 28
#define OEM719_MAX_RSP_LEN 150
#define OEM719_ACK_LEN 15
#define NMEA_RSP_LEN 100
#define BEST_RSP_LEN OEM7_HEADER_LEN+112+OEM7_CRC_LEN
#define TIME_RSP_LEN OEM7_HEADER_LEN+44+OEM7_CRC_LEN
#define OEM7_HEADER_LEN 28
#define OEM7_PORT_ADDR 0xC0
#define CRC32_POLYNOMIAL 0xEDB88320L
#define GPS_SYNC_TIME_DIFF 5

#define OEM719_MSG_ID_BEST_XYZ 241
#define OEM719_MSG_ID_TIME  101


/**
 * @brief GPS UTC Time
 */
typedef enum
{
    OEM7_UTC_TIME_INVALID = 0, ///< Invalid UTC time
    OEM7_UTC_TIME_VALID,       ///< valid UTC time
    OEM7_UTC_TIME_WARNING     ///< warning
}e_oem7_utc_time_sts;

/**
 * @brief GPS UTC time sync
 */
typedef enum
{
    SYNC_SUCCESS = 0, ///< Time sync success
    SYNC_FAIL         ///< Time sync fail
}e_oem7_utc_time_sync;

typedef struct
{
    int day;
    int month;
    int year;
}gps_date;

typedef struct
{
    int hours;
    int minutes;
    int seconds;
    int microseconds;
}gps_time;

typedef struct
{
    gps_time time;
    float latitude;
    float longitude;
    int fix_quality;
    int satellites_tracked;
    float hdop;
    float altitude;
    char altitude_units;
    float height;
    char height_units;
    float dgps_age;
}__attribute__((__packed__)) gps_location_data1; //gga

typedef struct
{
    gps_time time;
    bool valid;
    float latitude;
    float longitude;
    float speed;
    float course;
    gps_date date;
    float variation;
}__attribute__((__packed__)) gps_location_data2;  //rmc

typedef struct
{
    gps_time time;
    gps_date date;
    int hour_offset;
    int minute_offset;
}__attribute__((__packed__)) gps_time_data;  //zda


typedef struct
{
    uint32_t p_sts;
    uint32_t p_type;
    double p_x;
    double p_y;
    double p_z;
    uint32_t v_sts;
    uint32_t v_type;
    double v_x;
    double v_y;
    double v_z;
}__attribute__((__packed__)) s_oem7_best_xyz;


typedef struct
{
   uint32_t clock_status;
   double offset;
   double offset_std;
   double utc_offset;
   uint32_t utc_year;
   uint8_t utc_month;
   uint8_t utc_day;
   uint8_t utc_hour;
   uint8_t utc_min;
   uint32_t utc_ms;
   uint32_t utc_status;

}__attribute__((__packed__)) s_oem7_time;



void oem7_gps_init();
/**
 * @brief This function get the GPS time information from the GPS
 *
 * @param[out] time_info : pointer to GPS time information
 *
 * @return status of get information
 * @retval OEM7_SCS operation success, OEM7_FAIl operation fail
 */
uint8_t oem7_get_time_info(s_oem7_time* time_info);
uint8_t oem7_get_gpgga(gps_location_data1* loc_data);
uint8_t oem7_get_gprmc(gps_location_data2* loc_data);
uint8_t oem7_get_gpzda(gps_time_data* loc_data);

/**
 * @brief This function get the best xyz information from the GPS
 *
 * @param[out] best_xyz : pointer to best xyz information
 *
 * @return status of get information
 * @retval OEM7_SCS operation success, OEM7_FAIl operation fail
 */
uint8_t oem7_get_bestxyz(s_oem7_best_xyz *best_xyz);

/**
 * @brief This function decode the GPS best xyz information
 *
 * @param[in] msg_id : Identity of Telecommand
 * @param[out] frame : pointer to GPS best xyz structure
 * @param[in] recv_data : pointer to get data from GPS
 *
 * @return status of operation
 * @retval OEM7_SCS operation success, OEM7_FAIl operation fail
 */
uint8_t parse_bestxyz(uint16_t msg_id, s_oem7_best_xyz *frame, \
        uint8_t* recv_data);
/**
 * @brief This function decode the current GPS Time information and pack into
 * time structure
 *
 * @param[in] msg_id : Identity of Telecommand
 * @param[out] frame : pointer to GPS time structure
 * @param[in] recv_data : pointer to get data from GPS
 *
 * @return status of operation
 * @retval OEM7_SCS operation success, OEM7_FAIl operation fail
 */
uint8_t parse_timeinfo(uint16_t msg_id,s_oem7_time *frame, \
        uint8_t* recv_data);

/**
 * @brief This API encode the GPS header data's
 *
 * @param[in] msg_id : Identity of Telecomamnd or Telemetry
 * @param[out] cmd : pointer to encoded data based on GPS
 * @param[in] msg_len : Length of the input message
 * @param[in] msg_buff : pointer to input data buffer
 *
 * @return void
 */
void cmd_encode(uint16_t msg_id, uint8_t* cmd, uint16_t msg_len, \
        uint8_t* msg_buff);

/**
 * @brief This API check the GPS header
 *
 * @param[in] recv_data : pointer to received data from GPS
 * @param[in] msg_id : Identity of message
 *
 * @return status of header check
 * @retval OEM7_SCS(0) header is proper, OEM7_FAIl(1) header mismatch
 */
uint8_t header_check(uint8_t* recv_data, uint16_t msg_id);

unsigned long CRC32Value(int i);
unsigned long CalculateBlockCRC32( unsigned long ulCount, unsigned char*ucBuffer );





#endif
