GPS GMS-6 Module

Dependents:   RwSDCard_Xml_GPS

GPSGms6.cpp

Committer:
Lucyjungz
Date:
2017-03-01
Revision:
10:1311a69b0857
Parent:
9:12519423b85f

File content as of revision 10:1311a69b0857:

/**
  ******************************************************************************
  * @file    GPSGms6.cpp
  * @author  Narut T
  * @version V1
  * @date    19/05/2016
  * @brief   Library for GPS GMS6
  ******************************************************************************/

#include "mbed.h"
#include "GPSGms6.h"
#include <string>


/* ###############  Method Defination  ################## */
#define GET_GPRMC_SECTION_SIZE(state)                   (unsigned int)gprms_tbl[state].size
#define GET_GPRMC_VARIABLE_ADDR(state)                  gprms_tbl[state].p_val
#define GET_GPRMC_NEXT_STATE(state)                     (GPS_ProcessState)gprms_tbl[state+1].state


GPRMC_Data_TypeDef m_gprmc;         // Latest GPRMC data
GPRMC_Data_TypeDef m_valid_gprmc;   // Latest valid GPRMC Data
char m_RxBuf[RX_BUF_SIZE];          // Reading Buffer 
bool m_available;                   // Flag to indicate availability of GPRMC data
int m_index;                        // an index

/** 
 * Initializaion of the GPS Module by using serial and selected PIN
 */
Serial serial_gps(PA_9, PA_10);

/**
 * Table for GPRMC structure that use for decoding GPRMC message of the GPS
 * This table contain 3 element which are index, section size and pointer to variable
 * Once GPS process routine is called data will be populated in variable that define in third column
 */
const GPRMC_Tbl_TypeDef gprms_tbl[] = {
    //  index                       , section size                       , variable
    {GPS_Process_Start              , INVALID_VALUE              ,(char *)INVALID_VALUE},
    {GPS_Process_Header             , HEADER_SIZE                , m_gprmc.header},
    {GPS_Process_Time               , GPRMC_TIME_SIZE            , m_gprmc.time},
    {GPS_Process_Status             , GPRMC_STATUS_SIZE          , m_gprmc.status},
    {GPS_Process_Latitude           , GPRMC_LATITUDE_SIZE        , m_gprmc.latitude},
    {GPS_Process_Latitude_hemis     , GPRMC_LATITUDE_HEMI_SIZE   , m_gprmc.latitude_hemi},
    {GPS_Process_Longitude          , GPRMC_LONGITUDE_SIZE       , m_gprmc.longitude},
    {GPS_Process_Longitude_hemis    , GPRMC_LONGITUDE_HEMI_SIZE  , m_gprmc.longitude_hemi},
    {GPS_Process_Speed              , GPRMC_SPEED_SIZE           , m_gprmc.speed},
    {GPS_Process_Course             , GPRMC_COURSE_SIZE          , m_gprmc.course},
    {GPS_Process_Date               , GPRMC_DATE_SIZE            , m_gprmc.date},
    {GPS_Process_Magnetic           , GPRMC_MAGNETIC_SIZE        , m_gprmc.magnetic},
    {GPS_Process_Magnetic_Dir       , GPRMC_MAGNETIC_DIR_SIZE    , m_gprmc.magnetic_dir},
    {GPS_Process_Indicator          , GPRMC_INDICATOR_SIZE       , m_gprmc.indicator},
    {GPS_Process_Complete           ,INVALID_VALUE              ,(char *)INVALID_VALUE}

};

/* Private function prototypes -----------------------------------------------*/
static void GPSGMS6_CompleteCallback();
static GPS_ProcessStatus GPSGMS6_ProcessGprmcSection(GPS_ProcessState state,char * buf , unsigned int buf_index,unsigned int buf_size, unsigned int section_size, char * ret_value);
static void GPSGMS6_ByteCallback();
static void GPSGMS6_ProcessGpsData(char * buf, unsigned int size);


/**
 * @brief Utility for processing GPRMC message from the GPS 
 * @note 
 * @param state : current state that program is processing
 * @param buf : pointer to buffer that supposed to have GPS message
 * @param buf index : index to the current offset of the buffer 
 * @param buf size : size of the buffer 
 * @param section size  : size of the processing section
 * @retval pointer of return value
 */
static GPS_ProcessStatus GPSGMS6_ProcessGprmcSection(GPS_ProcessState state,char * buf , unsigned int buf_index,unsigned int buf_size, unsigned int section_size, char * ret_value)
{
    /* Initialize status  */
    GPS_ProcessStatus status = GPS_Status_Valid;
    if (buf_index >= (buf_size - section_size)) 
    {
        /* Data not Enough to process  */
        status = GPS_Status_NotEnough;
    } 
    else if (buf[buf_index] == GPS_DELIMITER) 
    {
        /* Empty Data  */
        status = GPS_Status_Empty;
        memset(ret_value,GPS_DEFAULT_DATA_VALUE, section_size);
    } 
    else 
    {
        /* Populate the data  */
        unsigned int idx;
        for(idx = 0; idx < section_size; idx++) {
            ret_value[idx] = buf[buf_index + idx];
        }

    }
    
    /* Return status  */
    return status;

}
/**
 * @brief Utility for processing GPS data 
 * @note this rely on gprmc table 
 * @param buf : pointer to buffer that supposed to have GPS message
 * @param buf size : size of the buffer 
 * @retval variable that define in the table will be populated the data
 */
static void GPSGMS6_ProcessGpsData(char * buf, unsigned int size)
{
    unsigned int index;
    unsigned int adv_index = 0;
    
    /* Initialize status and state  */
    GPS_ProcessStatus status = GPS_Status_Valid;
    GPS_ProcessState state = GPS_Process_Start;
    
    /* Walk through the buffer  */
    for(index = 0; index < size; index++) 
    {
        /* Start the process  */
        if (state == GPS_Process_Start) 
        {
            /* Process the message   */
            if (buf[index] == GPS_MESSAGE_HEADER_PREFIX) 
            {
                /* Found header  */
                state = GPS_Process_Header;
            } 
            else 
            {
                /* Continue searching  */
                continue;
            }
        } 
        else if (state == GPS_Process_Header) 
        {
            /* Process Header  */
            if (index < (size - HEADER_SIZE)) 
            {
                /* Check for GPRMC   */
                if (IS_HEADER_GPRPC(buf)) 
                {
                    
                    /* Populate the header to the variable  */
                    unsigned int h_index;
                    for(h_index = 0; h_index < HEADER_SIZE; h_index++) 
                    {
                        m_gprmc.header[h_index] = buf[index + h_index];
                    }
                    
                    /* Move to the next section  */
                    index += HEADER_SIZE;
                    state = GPS_Process_Time;
                }
            } 
            else 
            {
                break;
            }

        } 
        else 
        {
            /* Process GRPMC section  */
            status = GPSGMS6_ProcessGprmcSection(state, buf ,index, size, GET_GPRMC_SECTION_SIZE(state), GET_GPRMC_VARIABLE_ADDR(state));
            
            /* Move to the next section  */
            adv_index = GET_GPRMC_SECTION_SIZE(state);
            state = GET_GPRMC_NEXT_STATE(state) ;
        }


        if (status == GPS_Status_NotEnough || state == GPS_Process_Complete) 
        {
            /* In case of status not normal, then done  */
            break;
        } 
        else if (status == GPS_Status_Valid) 
        {
            /* Status is valid, move on  */
            index += adv_index;
        }
    }

    /* Check validity of the data  */
    if (IS_INDICATOR_VALID(m_gprmc.indicator[0])) 
    {
        /* If valid, populate to the valid variable  */
        m_available= true;
        memcpy(&m_valid_gprmc, &m_gprmc , sizeof(m_gprmc));
    }
}

/**
 * @brief Callback function that process when the message is completed 
 * @note Rx Serial Interrupt must be properly started 
 * @retval
 */
static void GPSGMS6_CompleteCallback()
{
    /* Process GPS Data once message is completed read  */
    GPSGMS6_ProcessGpsData(m_RxBuf, RX_BUF_SIZE);
}
/**
 * @brief Callback function that process when a charector is transfered 
 * @note Rx Serial Interrupt must be properly started 
 * @retval
 */
static void GPSGMS6_ByteCallback()
{
    /* Note: you need to actually read from the serial to clear the RX interrupt */ 
    m_RxBuf[m_index] = serial_gps.getc();
    m_index++;
    if (m_index == RX_BUF_SIZE) 
    {
        /* Buffer is full, call complete callback */
        m_index = 0;
        GPSGMS6_CompleteCallback();
    }
}


/**
 * @brief Constructor for GPS module 
 * @note 
 * @retval
 */
GPSGms6::GPSGms6()
{

    m_index = 0;
    m_available = false;

    #if EABLE_GPS_BAUDRATE
    /* Talking on  9600 bps */
    serial_gps.baud(GPS_BAUD_RATE);
    #endif

}

/**
 * @brief Function to start GPS Module  
 * @note after started, interrupt will always be active 
 * @retval 
 */
void GPSGms6::start_GPS()
{
    /* Start Rx interrupt  */
    serial_gps.attach(&GPSGMS6_ByteCallback);
}

/**
 * @brief Function to get latest GPRMC data  
 * @note
 * @retval latest GPRMC data
 */
GPRMC_Data_TypeDef * GPSGms6::latestGPRMC()
{
    return (&m_gprmc);
}
/**
 * @brief Function to get latest and valid GPRMC  
 * @note
 * @retval valid GPRMC data
 */
GPRMC_Data_TypeDef * GPSGms6::validGPRMC()
{
    m_available = false;
    return (&m_valid_gprmc);
}

/**
 * @brief Function to get available flag of the valid GPRMC data  
 * @note
 * @retval latest GPRMC data
 */
bool GPSGms6::available()
{
    return (m_available);
}
/**
 * @brief Function to get UTC time  
 * @note
 * @retval UTC time tn fm struct format
 */
tm GPSGms6::UTCTime()
{
    struct tm t;
    
    /* Check available of date and time  */
    if (m_gprmc.date[GPS_TIME_DATE_OFFSET] != ' ' && m_gprmc.time[GPS_TIME_HOUR_OFFSET] != ' ' )
    {
        
        /* Allocate buffer for buffering  */
        char str[GPS_STRING_BUFFER_SIZE];
        
        /* populate the second  */
        memcpy( str, &m_gprmc.time[GPS_TIME_SECOND_OFFSET], GPS_TIME_SECOND_SIZE );
        t.tm_sec =  atoi(str);
        
        /* populate the minute  */
        memcpy( str, &m_gprmc.time[GPS_TIME_MINUTE_OFFSET], GPS_TIME_MINUTE_SIZE );
        t.tm_min =  atoi(str);
        
        /* populate the hour  */
        memcpy( str, &m_gprmc.time[GPS_TIME_HOUR_OFFSET], GPS_TIME_HOUR_SIZE );
        t.tm_hour =  atoi(str);
        
        /* populate the date  */
        memcpy( str, &m_gprmc.date[GPS_TIME_DATE_OFFSET], GPS_TIME_DATE_SIZE );
        t.tm_mday =  atoi(str);
        
        /* populate the month  */
        memcpy( str, &m_gprmc.date[GPS_TIME_MONTH_OFFSET], GPS_TIME_MONTH_SIZE );
        t.tm_mon =  atoi(str);
        
        /* populate the year  */
        memcpy( str, &m_gprmc.date[GPS_TIME_YEAR_OFFSET], GPS_TIME_YEAR_SIZE );
        t.tm_year =  atoi(str);
    }
    else
    {
        /* Found nothing  */
        t.tm_mday = INVALID_TIME_DATE;
        t.tm_mon  = INVALID_TIME_MONTH;
        t.tm_year = INVALID_TIME_YEAR;
    }
    
    /* Return the time !!  */
    return (t);
}