Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lib_gps by
gps.cpp
- Committer:
- shaunkrnelson
- Date:
- 2017-07-24
- Revision:
- 8:7787d0060685
- Parent:
- 7:44cb21f05dcc
- Child:
- 10:007840923181
File content as of revision 8:7787d0060685:
#include "mbed.h"
#include "gps.h"
#define LAT_UNFIXED 0xaaaaa9
#define LONG_UNFIXED 0x355554e
const char NmeaDataTypeGPGGA[] = "GPGGA";
//const char NmeaDataTypeGPGSA[] = "GPGSA";
//const char NmeaDataTypeGPGSV[] = "GPGSV";
const char NmeaDataTypeGPRMC[] = "GPRMC";
/* Value used for the conversion of the position from DMS to decimal */
const int32_t MaxNorthPosition = 8388607; // 2^23 - 1
const int32_t MaxSouthPosition = 8388608; // -2^23
const int32_t MaxEastPosition = 8388607; // 2^23 - 1
const int32_t MaxWestPosition = 8388608; // -2^23
//InterruptIn pps_pin(PC_5);
GPS::GPS(PinName uart_tx, PinName uart_rx, PinName en) : m_uart(uart_tx, uart_rx), m_en_pin(en)
{
have_fix = false;
uart_rx_count = 0;
}
GPS::~GPS()
{
}
/*void GPS::pps()
{
pps_occurred = true;
}*/
void GPS::on_uart_rx()
{
//uint8_t *len = &rx_buf_lens[rx_bufs_in_idx];
uint8_t len = rx_buf_lens[rx_bufs_in_idx];
char ch;
do {
ch = m_uart.getc();
if (ch != '$') {
if (len < RX_BUF_SIZE) {
rx_bufs[rx_bufs_in_idx][len] = ch;
rx_buf_lens[rx_bufs_in_idx]++;
} else
printf("S");
} else if (len != 0) {
if(verbose)
printf("$ at %d\r\n", len);
}
if (ch == '\n') {
rx_bufs[rx_bufs_in_idx][len] = 0; // null terminate
#if 0
if(verbose)
{
printf("on_uart_rx: buf=%d, len=%d\r\n", rx_bufs_in_idx, len);
}
#endif
if (++rx_bufs_in_idx == NUM_RX_BUFS)
rx_bufs_in_idx = 0;
/* just let it overflow -- if (rx_bufs_in_idx == rx_bufs_out_idx)
printf("gps overflow\r\n");*/
rx_buf_lens[rx_bufs_in_idx] = 0;
uart_rx_count++;
}
} while (m_uart.readable());
}
void GPS::init()
{
rx_bufs_in_idx = 0;
rx_buf_lens[rx_bufs_in_idx] = 0;
rx_bufs_out_idx = 0;
//gps_uart.baud(57600);
m_uart.attach(mbed::callback(this, &GPS::on_uart_rx));
//pps_pin.rise(this, &GPS::pps);
}
void GPS::enable(bool en)
{
if (en) {
if (en_invert)
m_en_pin = 0;
else
m_en_pin = 1;
} else {
if (en_invert)
m_en_pin = 1;
else
m_en_pin = 0;
}
// reset current string index
rx_buf_lens[rx_bufs_in_idx] = 0;
}
bool GPS::enabled()
{
if (en_invert)
return !m_en_pin.read();
else
return m_en_pin.read();
}
/*char GPS::Nibble2HexChar( char a );
{
if( a < 10 )
{
return '0' + a;
}
else if( a < 16 )
{
return 'A' + ( a - 10 );
}
else
{
return '?';
}
}*/
int GPS::NmeaChecksum( char *nmeaStr, uint8_t nmeaStrSize, char * checksum )
{
int i = 0;
uint8_t checkNum = 0;
// Check input parameters
if( ( nmeaStr == NULL ) || ( checksum == NULL ) || ( nmeaStrSize <= 1 ) )
{
return -1;
}
// Skip the first '$' if necessary
if( nmeaStr[i] == '$' )
{
i += 1;
}
// XOR until '*' or max length is reached
while( nmeaStr[i] != '*' )
{
checkNum ^= nmeaStr[i];
i += 1;
if( i >= nmeaStrSize )
{
return -1;
}
}
// Convert checksum value to 2 hexadecimal characters
/*checksum[0] = Nibble2HexChar( checkNum / 16 ); // upper nibble
checksum[1] = Nibble2HexChar( checkNum % 16 ); // lower nibble
*/
sprintf(checksum, "%02X", checkNum);
return i + 1;
}
bool GPS::NmeaValidateChecksum(int idx)
{
int checksumIndex;
char checksum[4];
char *NmeaString = rx_bufs[idx];
checksumIndex = NmeaChecksum( NmeaString, rx_buf_lens[idx], checksum );
// could we calculate a verification checksum ?
if( checksumIndex < 0 )
return false;
// check if there are enough char in the serial buffer to read checksum
if( checksumIndex >= ( rx_buf_lens[idx] - 2 ) )
return false;
// check the checksum
if( ( NmeaString[checksumIndex] == checksum[0] ) && ( NmeaString[checksumIndex + 1] == checksum[1] ) )
{
return true;
}
else
return false;
}
void GPS::ConvertPositionFromStringToNumerical( )
{
int i;
double valueTmp1;
double valueTmp2;
double valueTmp3;
double valueTmp4;
// Convert the latitude from ASCII to uint8_t values
for( i = 0 ; i < 10 ; i++ )
{
NmeaGpsData.NmeaLatitude[i] = NmeaGpsData.NmeaLatitude[i] & 0xF;
}
// Convert latitude from degree/minute/second (DMS) format into decimal
valueTmp1 = ( double )NmeaGpsData.NmeaLatitude[0] * 10.0 + ( double )NmeaGpsData.NmeaLatitude[1];
valueTmp2 = ( double )NmeaGpsData.NmeaLatitude[2] * 10.0 + ( double )NmeaGpsData.NmeaLatitude[3];
valueTmp3 = ( double )NmeaGpsData.NmeaLatitude[5] * 1000.0 + ( double )NmeaGpsData.NmeaLatitude[6] * 100.0 +
( double )NmeaGpsData.NmeaLatitude[7] * 10.0 + ( double )NmeaGpsData.NmeaLatitude[8];
Latitude = valueTmp1 + ( ( valueTmp2 + ( valueTmp3 * 0.0001 ) ) / 60.0 );
if( NmeaGpsData.NmeaLatitudePole[0] == 'S' )
{
Latitude *= -1;
}
// Convert the longitude from ASCII to uint8_t values
for( i = 0 ; i < 10 ; i++ )
{
NmeaGpsData.NmeaLongitude[i] = NmeaGpsData.NmeaLongitude[i] & 0xF;
}
// Convert longitude from degree/minute/second (DMS) format into decimal
valueTmp1 = ( double )NmeaGpsData.NmeaLongitude[0] * 100.0 + ( double )NmeaGpsData.NmeaLongitude[1] * 10.0 + ( double )NmeaGpsData.NmeaLongitude[2];
valueTmp2 = ( double )NmeaGpsData.NmeaLongitude[3] * 10.0 + ( double )NmeaGpsData.NmeaLongitude[4];
valueTmp3 = ( double )NmeaGpsData.NmeaLongitude[6] * 1000.0 + ( double )NmeaGpsData.NmeaLongitude[7] * 100;
valueTmp4 = ( double )NmeaGpsData.NmeaLongitude[8] * 10.0 + ( double )NmeaGpsData.NmeaLongitude[9];
Longitude = valueTmp1 + ( valueTmp2 / 60.0 ) + ( ( ( valueTmp3 + valueTmp4 ) * 0.0001 ) / 60.0 );
if( NmeaGpsData.NmeaLongitudePole[0] == 'W' )
{
Longitude *= -1;
}
//printf("DD %f, %f\r\n", Latitude, Longitude);
}
void GPS::ConvertPositionIntoBinary( )
{
long double temp;
if( Latitude >= 0 ) // North
{
temp = Latitude * MaxNorthPosition;
LatitudeBinary = temp / 90;
}
else // South
{
temp = Latitude * MaxSouthPosition;
LatitudeBinary = temp / 90;
}
if( Longitude >= 0 ) // East
{
temp = Longitude * MaxEastPosition;
LongitudeBinary = temp / 180;
}
else // West
{
temp = Longitude * MaxWestPosition;
LongitudeBinary = temp / 180;
}
if (LatitudeBinary == LAT_UNFIXED && LongitudeBinary == LONG_UNFIXED)
have_fix = false;
else
{
have_fix = true;
if(verbose == true)
printf("GPS: latitude=%f, longitude=%f\r\n", Latitude, Longitude);
}
}
int GPS::ParseGPSData(int idx)
{
uint8_t i, j, fieldSize;
char *NmeaString;
if (NmeaValidateChecksum(idx) == false) {
return FAIL;
}
NmeaString = rx_bufs[idx];
if (NmeaString[0] == 'P' && NmeaString[1] == 'M' && NmeaString[2] == 'T' && NmeaString[3] == 'K') {
/* anything useful from PMTK packets? */
return SUCCESS;
}
fieldSize = 0;
i = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 6 )
{
printf("gps parse:%s\r\n", NmeaString);
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaDataType[j] = NmeaString[i];
}
// Parse the GPGGA data
if( strncmp( ( const char* )NmeaGpsData.NmeaDataType, ( const char* )NmeaDataTypeGPGGA, 5 ) == 0 )
{
if(verbose == true)
printf("GPGAA: %s\r\n",NmeaString);
// NmeaUtcTime
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 11 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaUtcTime[j] = NmeaString[i];
}
// NmeaLatitude
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 10 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLatitude[j] = NmeaString[i];
}
// NmeaLatitudePole
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLatitudePole[j] = NmeaString[i];
}
// NmeaLongitude
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 11 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLongitude[j] = NmeaString[i];
}
// NmeaLongitudePole
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLongitudePole[j] = NmeaString[i];
}
// NmeaFixQuality
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaFixQuality[j] = NmeaString[i];
}
// NmeaSatelliteTracked
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 3 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaSatelliteTracked[j] = NmeaString[i];
}
// NmeaHorizontalDilution
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 6 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaHorizontalDilution[j] = NmeaString[i];
}
// NmeaAltitude
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaAltitude[j] = NmeaString[i];
}
// NmeaAltitudeUnit
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaAltitudeUnit[j] = NmeaString[i];
}
// NmeaHeightGeoid
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaHeightGeoid[j] = NmeaString[i];
}
// NmeaHeightGeoidUnit
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaHeightGeoidUnit[j] = NmeaString[i];
}
//FormatGpsData( );
ConvertPositionFromStringToNumerical( );
ConvertPositionIntoBinary( );
return SUCCESS;
}
else if ( strncmp( ( const char* )NmeaGpsData.NmeaDataType, ( const char* )NmeaDataTypeGPRMC, 5 ) == 0 )
{
if(verbose == true)
printf("GPMRC: %s\r\n", NmeaString);
// NmeaUtcTime
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 11 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaUtcTime[j] = NmeaString[i];
}
// NmeaDataStatus
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaDataStatus[j] = NmeaString[i];
}
if(NmeaGpsData.NmeaDataStatus[0] != 'A')
return FAIL;
//
// NmeaLatitude
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 10 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLatitude[j] = NmeaString[i];
}
// NmeaLatitudePole
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLatitudePole[j] = NmeaString[i];
}
// NmeaLongitude
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 11 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLongitude[j] = NmeaString[i];
}
// NmeaLongitudePole
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
if(fieldSize <= 1)
return FAIL;
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLongitudePole[j] = NmeaString[i];
}
// NmeaSpeed
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaSpeed[j] = NmeaString[i];
}
// NmeaDetectionAngle
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaDetectionAngle[j] = NmeaString[i];
}
// NmeaDate
fieldSize = 0;
while( NmeaString[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaDate[j] = NmeaString[i];
}
//FormatGpsData( );
ConvertPositionFromStringToNumerical( );
ConvertPositionIntoBinary( );
return SUCCESS;
}
else
{
return FAIL;
}
}
void GPS::service()
{
while (rx_bufs_in_idx != rx_bufs_out_idx) {
ParseGPSData(rx_bufs_out_idx);
if (++rx_bufs_out_idx == NUM_RX_BUFS)
rx_bufs_out_idx = 0;
}
/*if (pps_occurred) {
pps_occurred = false;
if (verbose)
printf("gps:pps\r\n");
}*/
}
