Lab_interaccio/2012/ASK-Shield/References/waspmote-api-v.021/WaspGPS.cpp
Miguel Angel de Heras 451795bb92 Second commit
2025-03-05 15:57:19 +01:00

1464 lines
38 KiB
C++

/*
* Copyright (C) 2009 Libelium Comunicaciones Distribuidas S.L.
* http://www.libelium.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Version: 0.6
* Design: David Gascón
* Implementation: Alberto Bielsa, David Cuartielles, Mikal Hart
*/
/******************************************************************************
* Includes
******************************************************************************/
#ifndef __WPROGRAM_H__
#include "WaspClasses.h"
#endif
/******************************************************************************
* Definitions & Declarations
******************************************************************************/
/******************************************************************************
* Constructors
******************************************************************************/
WaspGPS::WaspGPS()
{
_baudRate = 4800; // by default we choose NMEA's speed for the port
//_baudRate = 9600; // by default we choose NMEA's speed for the port
_uart=1;
// basic GPS configuration
reboot=COLD; // reboot the system or init the system the first time
flag = ACK; // init the flag at ACK
commMode = GPS_NMEA; // communication mode: software or hardware serial
pwrMode = GPS_ON; // power on the GPS
wakeMode = COLD; // wake up erasing the internal data
clkOffset= (char*) "96000";
timeOfWeek= (char*) "497260";
weekNo= (char*) "921";
channel= (char*) "12";
resetCfg= (char*) "1";
coordinateLat = (char*) "4140.8217"; // Zaragoza, Spain, coordinates for Libelium
coordinateLon = (char*) "00053.1736"; // Zaragoza, Spain, coordinates for Libelium
coordinateAl = (char*) "198"; // Zaragoza, Spain, coordinates for Libelium
checksum=0;
}
/******************************************************************************
* User API
******************************************************************************/
/******************************************************************************
* PRIVATE FUNCTIONS *
******************************************************************************/
/*
* extractDate (void) - private function getting the Date from the GPS
*
* makes a call to the GPRMC sentence type to extract the date from the GPS, it
* separates the data using the inBuffer and breaking it into Utils.arguments
*
* Stores the final value in the dateGPS variable
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
void WaspGPS::extractDate(void)
{
// store current state to return to it later
uint16_t currentSentences = commMode;
long previous=0;
// get Date information
serialFlush(1);
previous=millis();
while(!setCommMode(GPS_NMEA_RMC) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
Utils.strExplode(inBuffer, ','); // separates all the subarrays from inBuffer into the Utils.arguments array
if( !strcmp(Utils.arguments[0],"$GPRMC") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) dateGPS[i]=Utils.arguments[9][i];
}
else
{
flag |=GPS_INVALID;
}
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000);
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
/*
* extractTime (void) - private function getting the Time from the GPS
*
* makes a call to the GPGGA sentence type to extract the time from the GPS, it
* separates the data using the inBuffer and breaking it into Utils.arguments
*
* Stores the final value in the timeGPS variable
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
void WaspGPS::extractTime(void)
{
// store current state to return to it later
uint16_t currentSentences = commMode;
long previous=0;
// get Time
serialFlush(1);
previous=millis();
while(!setCommMode(GPS_NMEA_GGA) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
Utils.strExplode(inBuffer, ','); // separates all the subarrays from inBuffer into the Utils.arguments array
if( !strcmp(Utils.arguments[0],"$GPGGA") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) timeGPS[i]=Utils.arguments[1][i];
}
else
{
flag |= GPS_INVALID;
}
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000);
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
/*
* parse_decimal (str) - get a number out of a string
*
* It gets a number out of a string
*/
long WaspGPS::parse_decimal(char *str)
{
bool isneg = *str == '-';
if (isneg) *str++;
unsigned long ret = 100UL * gpsatol(str);
while (gpsisdigit(*str)) ++str;
if (*str == '.')
{
if (gpsisdigit(str[1]))
{
ret += 10 * (str[1] - '0');
if (gpsisdigit(str[2]))
ret += str[2] - '0';
}
}
return isneg ? -ret : ret;
}
/*
* parse_degrees (str) - get a number out of a string
*
* It gets a number out of a string
*/
unsigned long WaspGPS::parse_degrees(char *str)
{
unsigned long left = gpsatol(str);
unsigned long tenk_minutes = (left % 100UL) * 10000UL;
while (gpsisdigit(*str)) ++str;
if (*str == '.')
{
unsigned long mult = 1000;
while (gpsisdigit(*++str))
{
tenk_minutes += mult * (*str - '0');
mult /= 10;
}
}
return (left / 100) * 100000 + tenk_minutes / 6;
}
/*
* gpsatol (str) - get a number out of a string
*
* It gets a number out of a string
*/
long WaspGPS::gpsatol(char *str)
{
long ret = 0;
while (gpsisdigit(*str))
ret = 10 * ret + *str++ - '0';
return ret;
}
/******************************************************************************
* PUBLIC FUNCTIONS
******************************************************************************/
/* ON(void) - opens UART1 and powers the GPS module
*
* It opens UART1 and powers the GPS module
*
* Returns nothing
*/
void WaspGPS::ON()
{
setMode(GPS_ON);
begin();
init();
}
/* OFF(void) - closes UART1 and powers off the GPRS module
*
* This function closes UART1 and powers off the GPRS module
*
* Returns nothing
*/
void WaspGPS::OFF()
{
close();
setMode(GPS_OFF);
}
/*
* init (void) - initialize the GPS on default parms
*
* this function initializes the GPS with the default time, date, and coordinates
* taken from the constructor. It is possible to modify the corresponding public variables
* and then call init() to reconfigure the
* GPS with the new conditions
*
* The system is not answering anything, therefore it is not possible, at this
* point to check whether the GPS is malfunctioning
*/
void WaspGPS::init()
{
init(coordinateLat, coordinateLon, coordinateAl, clkOffset, timeOfWeek, weekNo, channel, resetCfg);
}
/*
* init (void) - initialize the GPS using grouped parameters
*
* this function initializes the GPS with the specific parameters determined by
* three strings which are equivalent to the public variables in the system.
* This will try to reconfigure the GPS with the new conditions.
*
* The system is not answering anything, therefore it is not possible, at this
* point to check whether the GPS is malfunctioning
*/
void WaspGPS::init(const char* _coordinateLat, const char* _coordinateLon, const char* _coordinateAl, const char* _clkOffset, const char* _timeOfWeek, const char* _weekNo, const char* _channel, const char* _resetCfg)
{
long previous=0;
// set up the initial coordinates, time and date
if(reboot)
{
begin();
delay(3000);
}
sprintf(inBuffer,"$PSRF104,%s,%s,%s,%s,%s,%s,%s,%s*00",_coordinateLat,_coordinateLon,_coordinateAl,_clkOffset,_timeOfWeek,_weekNo,_channel,_resetCfg);
setChecksum();
serialFlush(1);
printString(inBuffer,1);
printByte('\r',1);
printByte('\n',1);
// Set GPS on binary mode without sending data
previous=millis();
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
previous=millis();
while(!setCommMode(GPS_BINARY_OFF) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
serialFlush(1);
reboot=HOT;
}
/* setCommMode(mode) - set communication mode: Binary or NMEA
*
* It sets the communication mode. There are two possibilities : Binary Mode or NMEA Mode
*/
uint8_t WaspGPS::setCommMode(uint16_t mode)
{
uint8_t tempBuffer[32] =
{0xA0,0xA2,0x00,0x18,0x81,0x02,0x01,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x00,0x01,0x00,0x01,0x12,0xC0,0x01,0x60,0xB0,0xB3};
uint8_t tempBuffer2[16] ={0xA0,0xA2,0x00,0x08,0xA6,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xAA,0xB0,0xB3};
uint8_t* byteIN = (uint8_t*) calloc(10,sizeof(uint8_t));
if( byteIN==NULL ) return -1;
commMode = mode;
uint8_t valid=0;
switch(commMode)
{
case GPS_BINARY: sprintf(inBuffer,"$PSRF100,0,%u,8,1,0*0F",_baudRate);
serialFlush(_uart);
printString(inBuffer,_uart);
printByte('\r',_uart);
printByte('\n',_uart);
delay(10);
serialFlush(_uart);
delay(10);
if(serialAvailable(_uart)){
byteIN[0]=serialRead(_uart);
if( (byteIN[0]=='$') || ( (byteIN[0]>'0') && (byteIN[0]<'Z') ) ) valid=0;
else valid=1;
}
break;
case GPS_BINARY_OFF: serialFlush(_uart);
for(int a=0;a<16;a++)
{
printByte(tempBuffer2[a],_uart);
}
delay(100);
if(serialAvailable(_uart))
{
for(int a=0;a<10;a++)
{
byteIN[a]=serialRead(_uart);
}
}
if(byteIN[5]==0xA6) valid=1;
else valid=0;
break;
case GPS_NMEA: tempBuffer[8]=0x01;
tempBuffer[10]=0x01;
tempBuffer[12]=0x01;
tempBuffer[14]=0x01;
tempBuffer[16]=0x01;
tempBuffer[29]=0x65;
for(int b=0;b<32;b++)
{
printByte(tempBuffer[b],1);
}
delay(10);
getRaw(100);
Utils.strExplode(inBuffer, ',');
if( strcmp(Utils.arguments[0],"$GPGGA") )
{
valid=0;
}
else valid=1;
break;
case GPS_NMEA_GGA: for(int c=0;c<32;c++)
{
printByte(tempBuffer[c],1);
}
delay(10);
getRaw(100);
Utils.strExplode(inBuffer, ',');
if( strcmp(Utils.arguments[0],"$GPGGA") )
{
valid=0;
}
else valid=1;
break;
case GPS_NMEA_GLL: tempBuffer[6]=0x00;
tempBuffer[8]=0x01;
for(int d=0;d<32;d++)
{
printByte(tempBuffer[d],1);
}
getRaw(100);
Utils.strExplode(inBuffer, ',');
if( strcmp(Utils.arguments[0],"$GPGLL") )
{
valid=0;
}
else valid=1;
break;
case GPS_NMEA_GSA: tempBuffer[6]=0x00;
tempBuffer[10]=0x01;
for(int e=0;e<32;e++)
{
printByte(tempBuffer[e],1);
}
getRaw(100);
Utils.strExplode(inBuffer, ',');
if( strcmp(Utils.arguments[0],"$GPGSA") )
{
valid=0;
}
else valid=1;
break;
case GPS_NMEA_GSV: tempBuffer[6]=0x00;
tempBuffer[12]=0x01;
for(int f=0;f<32;f++)
{
printByte(tempBuffer[f],1);
}
getRaw(100);
Utils.strExplode(inBuffer, ',');
if( strcmp(Utils.arguments[0],"$GPGSV") )
{
valid=0;
}
else valid=1;
break;
case GPS_NMEA_RMC: tempBuffer[6]=0x00;
tempBuffer[14]=0x01;
for(int g=0;g<32;g++)
{
printByte(tempBuffer[g],1);
}
getRaw(100);
Utils.strExplode(inBuffer, ',');
if( strcmp(Utils.arguments[0],"$GPRMC") )
{
valid=0;
}
else valid=1;
break;
case GPS_NMEA_VTG: tempBuffer[6]=0x00;
tempBuffer[16]=0x01;
for(int h=0;h<32;h++)
{
printByte(tempBuffer[h],1);
}
getRaw(100);
Utils.strExplode(inBuffer, ',');
if( strcmp(Utils.arguments[0],"$GPVTG") )
{
valid=0;
}
else valid=1;
break;
}
free(byteIN);
return valid;
}
/* getCommMode() - get the communication mode
*
* It gets the communication mode in use.
*/
uint8_t WaspGPS::getCommMode(void)
{
return commMode;
}
/*
* setMode (void) - sets the current internal Power Mode on the GPS
*
* GPS has three different power modes: ON, OFF, STANDBY, we map it
* to four different software ones: ON (ON), OFF (OFF), SLEEP (STANDBY),
* HIBERNATE (STANDBY). It is done this way to keep consistency with the
* rest of the design
*
* The function will set up the GPS.pwrMode public variable to one of the
* four values, but also send the serial command to the GPS module
*/
void WaspGPS::setMode(uint8_t mode)
{
pwrMode = mode;
pinMode(GPS_PW,OUTPUT);
// set the GPS in the defined power mode
switch (pwrMode)
{
case GPS_ON:
digitalWrite(GPS_PW,HIGH);
break;
case GPS_OFF:
digitalWrite(GPS_PW,LOW);
break;
}
}
/*
* getMode (void) - answers the current internal Power Mode on the GPS
*
* this GPS has three different power modes: ON, OFF, STANDBY, we map it
* to four different software ones: ON (ON), OFF (OFF), SLEEP (STANDBY),
* HIBERNATE (STANDBY). It is done this way to keep consistency with the
* rest of the design
*/
uint8_t WaspGPS::getMode(void)
{
return pwrMode;
}
/* check() - get if receiver is connected to some satellite
*
* It gets if receiver is connected to some satellite
*
* It returns '1' if connected, '0' if not
*/
bool WaspGPS::check()
{
uint16_t currentSentences = commMode;
bool connection=0;
long previous=0;
serialFlush(1);
while(!setCommMode(GPS_NMEA_GGA) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
// separates all the subarrays from inBuffer into the Utils.arguments array
Utils.strExplode(inBuffer, ',');
// the data is valid only if the GPGGA position 7 is 1 or bigger
if( !strcmp(Utils.arguments[0],"$GPGGA") )
{
connection = (Utils.arguments[6][0] - '0');
}
else connection=0;
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000);
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
return connection;
}
/*
* getTime (void) - answers the current time on the GPS
*
* gets the time from the GPS and returns it in the format "065600.0000" - hhmmss.mmmm
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
char* WaspGPS::getTime(void)
{
extractTime();
return timeGPS;
}
/*
* getDate (void) - answers the current date on the GPS
*
* gets the date from the GPS and returns it in the format "180509" - ddmmyy
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
char* WaspGPS::getDate(void)
{
extractDate();
return dateGPS;
}
/*
* getLatitude (void) - gets the latitude from the GPS
*
* forces getLocation and responds the current value of the latitude
* variable (in degrees) as a string
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
char* WaspGPS::getLatitude(void)
{
flag &= ~(GPS_INVALID);
// store current state to return to it later
uint16_t currentSentences = commMode;
long previous=0;
// get latitude, longitude, altitude, but NOT time
while(!setCommMode(GPS_NMEA_GGA) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
// separates all the subarrays from inBuffer into the Utils.arguments array
Utils.strExplode(inBuffer, ',');
if( !strcmp(Utils.arguments[0],"$GPGGA") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) latitude[i]=Utils.arguments[2][i];
}
else
{
flag |=GPS_INVALID;
}
// the data is valid only if the GPGGA position 7 is 1 or bigger
fixValid = (Utils.arguments[6][0] - '0');
if (!fixValid) flag |= GPS_INVALID;
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
return latitude;
}
/*
* getLongitude (void) - gets the longitude the GPS
*
* forces getLocation and responds the current value of the longitude
* variable (in degrees) as a string
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
char* WaspGPS::getLongitude(void)
{
flag &= ~(GPS_INVALID);
// store current state to return to it later
uint16_t currentSentences = commMode;
long previous=0;
// get latitude, longitude, altitude, but NOT time
while(!setCommMode(GPS_NMEA_GGA) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
// separates all the subarrays from inBuffer into the Utils.arguments array
Utils.strExplode(inBuffer, ',');
if( !strcmp(Utils.arguments[0],"$GPGGA") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) longitude[i]=Utils.arguments[4][i];
}
else
{
flag |=GPS_INVALID;
}
// the data is valid only if the GPGGA position 7 is 1 or bigger
fixValid = (Utils.arguments[6][0] - '0');
if (!fixValid) flag |= GPS_INVALID;
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
return longitude;
}
/*
* getSpeed (void) - gets the speed from the GPS
*
* makes a call to the GPVTG sentence type to extract the data from the GPS, it
* separates the data using the inBuffer and breaking it into Utils.arguments
*
* Stores the final value in the variable speed as string.
* It does not update the fixValid variable to show whether the data from the
* GPS is valid or not
*
* Returns the speed in Km/h
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
char* WaspGPS::getSpeed(void)
{
// store current state to return to it later
uint16_t currentSentences = commMode;
long previous=0;
// get speed and course
while(!setCommMode(GPS_NMEA_VTG) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
// separates all the subarrays from inBuffer into the Utils.arguments array
Utils.strExplode(inBuffer, ',');
if( !strcmp(Utils.arguments[0],"$GPVTG") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) speed[i]=Utils.arguments[7][i];
}
else
{
flag |=GPS_INVALID;
}
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
return speed;
}
/*
* getAltitude (void) - gets the altitude from the GPS
*
* forces getLocation and responds the current value of the altitude
* variable (in meters) as a string
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
char* WaspGPS::getAltitude(void)
{
flag &= ~(GPS_INVALID);
// store current state to return to it later
uint16_t currentSentences = commMode;
long previous=0;
// get latitude, longitude, altitude, but NOT time
while(!setCommMode(GPS_NMEA_GGA) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
// separates all the subarrays from inBuffer into the Utils.arguments array
Utils.strExplode(inBuffer, ',');
if( !strcmp(Utils.arguments[0],"$GPGGA") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) altitude[i]=Utils.arguments[9][i];
}
else
{
flag |=GPS_INVALID;
}
// the data is valid only if the GPGGA position 7 is 1 or bigger
fixValid = (Utils.arguments[6][0] - '0');
if (!fixValid) flag |= GPS_INVALID;
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000);
return altitude;
}
/*
* getCourse (void) - gets the course from the GPS
*
* makes a call to the GPVTG sentence type to extract the data from the GPS, it
* separates the data using the inBuffer and breaking it into Utils.arguments
*
* Stores the final value in the variable course as string.
* It does not update the fixValid variable to show whether the data from the GPS is valid or not
*
*
* The system could time out, it could be good to double check the GPS.flag for
* the value GPS_TIMEOUT when not being sure about data consistency
*/
char* WaspGPS::getCourse(void)
{
// store current state to return to it later
uint16_t currentSentences = commMode;
long previous=0;
// get speed and course
while(!setCommMode(GPS_NMEA_VTG) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
// separates all the subarrays from inBuffer into the Utils.arguments array
Utils.strExplode(inBuffer, ',');
if( !strcmp(Utils.arguments[0],"$GPVTG") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) course[i]=Utils.arguments[1][i];
}
else
{
flag |=GPS_INVALID;
}
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
return course;
}
/*
* getRaw (int) - gets a data string from the GPS
*
* store the next consisten NMEA sentence in the internal buffer inBuffer
* if the input is 0, continue until the end of the GPS sentence or up to
* the max buffer size (GPS_BUFFER_SIZE)
*
* The system could time out, it will set the GPS.flag with the
* value GPS_TIMEOUT when the GPS is not answering after 1000 milliseconds
*
* It will return the string and not only update it in the inBuffer. In case
* of error it will write GPS_TIMEOUT_em to the buffer
*/
char* WaspGPS::getRaw(int byteAmount)
{
flag &= ~(GPS_TIMEOUT);
uint8_t byteGPS = 0; // the last byte coming through the port
int i = 0; // count the amount of bytes read
uint32_t timeout = 1000; // millis to wait before declaring timeout
if (byteAmount == 0) byteAmount = GPS_BUFFER_SIZE;
serialFlush(1); // empty the port
clearBuffer();
// wait until arrival of a byte
while(!serialAvailable(_uart) && timeout > 0) { delay(1); timeout--; };
if (timeout <= 0)
{
flag |= GPS_TIMEOUT;
return GPS_TIMEOUT_em;
}
byteGPS = serialRead(_uart); // read the first byte coming through the port
while(byteGPS != '$')
{
if(serialAvailable(_uart) > 0)
byteGPS = serialRead(_uart); // flush incomplete sentences
}
inBuffer[i]=byteGPS;
i++;
while(i <= 1 || (byteGPS != '*' && byteGPS != '$' && i < byteAmount)){ // read the GPS sentence
// while(!i || (byteGPS != '*' && byteGPS != '$' && i < byteAmount)){ // read the GPS sentence
if(serialAvailable(_uart) > 0)
{
byteGPS = serialRead(_uart);
if (byteGPS != '*' && byteGPS != '$' && i < byteAmount) inBuffer[i]=byteGPS;
/* if (byteGPS != '$' && i < byteAmount) inBuffer[i]=byteGPS; */
i++;
}
}
if (byteGPS == '\n' || i == byteAmount) inBuffer[i-1] = '\0';
else inBuffer[i] = '\0';
return inBuffer;
}
/* getChecksum(buffer) - calculate checksum for a secuence given as a parameter
*
* It calculates the corresponding checksum for a secuence given as a parameter
*
* It stores in 'checkSUM' variable the result
*/
void WaspGPS::getChecksum(uint8_t* buffer)
{
int a=4;
int check=0;
uint8_t aux=0, aux2=0;
while( (buffer[aux]!=0xB0) || (buffer[aux+1]!=0xB3) )
{
aux++;
}
buffer[aux-1]=0x00;
buffer[aux-2]=0x00;
aux=0;
while( (buffer[a]!=0xB0) || (buffer[a+1]!=0xB3) )
{
check+=buffer[a];
check &= 0x7FFF;
a++;
}
if(check>255)
{
aux=check/256;
aux2=check-(aux*256);
checkSUM[0]=aux;
checkSUM[1]=aux2;
}
else
{
checkSUM[0]=0x00;
checkSUM[1]=check;
}
}
/* saveEphems() - save ephemeris into SD
*
* It saves ephemeris into SD. It creates a file named 'FILE_EPHEMERIS' and stores ephemeris into it.
*
* It returns '2' when no ephemeris are returned by GPS receiver, '1' when error on writing and '0' on succesful.
*/
int8_t WaspGPS::saveEphems()
{
return saveEphems(FILE_EPHEMERIS);
}
/* saveEphems(filename) - save ephemeris into SD
*
* It saves ephemeris into SD. It creates a file named 'filename' and stores ephemeris into it.
*
* It returns '2' when no ephemeris are returned by GPS receiver, '0' when error on writing and '1' on succesful.
*/
int8_t WaspGPS::saveEphems(const char* filename)
{
uint8_t tempBuffer[11] ={0xA0,0xA2,0x00,0x03,0x93,0x00,0x00,0x00,0x00,0xB0,0xB3};
uint8_t* ByteIN = (uint8_t*) calloc(110,sizeof(uint8_t));
if(ByteIN==NULL) return -1;
uint8_t* tempData = (uint8_t*) calloc(92,sizeof(uint8_t));
if(tempData==NULL) return -1;
uint8_t endFile[7] ={0xAA,0xBB,0xCC,0xCC,0xBB,0xAA,0xAA};
uint8_t counter3=0;
uint8_t end=0;
uint16_t interval=1000;
long previous=millis();
int8_t error=2;
// initialize the flags
flag = 0; SD.flag = 0;
uint8_t aux=0;
if (SD.isFile(filename)) SD.del(filename);
SD.create(filename);
previous=millis();
while(!setCommMode(GPS_BINARY_OFF) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
delay(100);
while(serialAvailable(_uart)>0)
{
serialRead(_uart);
}
// Iterates asking the GPS about available ephemeris (0..32)
for(int a=1;a<33;a++)
{
tempBuffer[5]=a; // set SV ID
getChecksum(tempBuffer);
tempBuffer[7]=checkSUM[0];
tempBuffer[8]=checkSUM[1];
for(int b=0;b<11;b++)
{
printByte(tempBuffer[b],_uart);
}
// read ephemeris data and store into ByteIN
while(end==0)
{
if(serialAvailable(_uart)>0)
{
ByteIN[counter3]=serialRead(_uart);
counter3++;
previous=millis();
}
if( (millis()-previous) > interval )
{
end=1;
serialFlush(_uart);
}
}
if( counter3>100 ) // ephemeris available
{
counter3=6;
if( (ByteIN[0]!=0xA0) || (ByteIN[1]!=0xA2) ) break;
while( counter3<96 )
{
tempData[counter3-6]=ByteIN[counter3];
counter3++;
}
tempData[counter3]=0xAA;
tempData[counter3+1]=0xAA;
if(SD.writeSD(filename,tempData,aux*90)) error=1;
else error=0;
aux++;
}
counter3=0;
end=0;
previous=millis();
}
if (error==1) if(SD.writeSD(filename,endFile,aux*90)) error=1;
free(ByteIN);
free(tempData);
ByteIN=NULL;
tempData=NULL;
return error;
}
/* loadEphems() - load ephemeris from SD to GPS receiver
*
* It loads ephemeris from SD to GPS receiver.
*
* It returns '1' on success and '0' on error.
*/
int8_t WaspGPS::loadEphems()
{
return loadEphems(FILE_EPHEMERIS);
}
/* loadEphems(filename) - load ephemeris from SD file 'filename' to GPS receiver
*
* It loads ephemeris from SD to GPS receiver.
*
* It returns '1' on success and '0' on error.
*/
int8_t WaspGPS::loadEphems(const char* filename)
{
uint8_t* tempData = (uint8_t*) calloc(99,sizeof(uint8_t));
if(tempData==NULL) return -1;
uint8_t* answer = (uint8_t*) calloc(10,sizeof(uint8_t));
if(answer==NULL) return -1;
uint8_t endFile=0;
uint16_t offset=0;
uint8_t counter3=0;
uint8_t end=0;
uint16_t interval=1000;
long previous=millis();
int8_t error=2;
SD.flag = 0;
/*** Disable All Binary Messages ***/
while(!setCommMode(GPS_BINARY_OFF) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
delay(100);
while(serialAvailable(_uart)>0)
{
serialRead(_uart);
}
while( !endFile )
{
SD.catBin(filename,offset,5);
if( (SD.bufferBin[0]==0xAA) && (SD.bufferBin[1]==0xBB) && (SD.bufferBin[2]==0xCC) &&
(SD.bufferBin[3]==0xCC) && (SD.bufferBin[4]==0xBB) ) endFile=1;
if (!endFile)
{
for(int a=0;a<5;a++) // Copy first 5 already read bytes
{
tempData[a+5]=SD.bufferBin[a];
}
offset+=5;
SD.catBin(filename,offset,85);
tempData[0]=0xA0;
tempData[1]=0xA2;
tempData[2]=0x00;
tempData[3]=0x5B;
tempData[4]=0x95;
for(int b=10;b<95;b++)
{
tempData[b]=SD.bufferBin[b-10];
}
tempData[95]=0x00;
tempData[96]=0x00;
tempData[97]=0xB0;
tempData[98]=0xB3;
getChecksum(tempData);
tempData[95]=checkSUM[0];
tempData[96]=checkSUM[1];
for(int c=0;c<99;c++)
{
printByte(tempData[c],_uart);
}
delay(100);
while(end==0)
{
if(serialAvailable(_uart)>0)
{
answer[counter3]=serialRead(_uart);
counter3++;
previous=millis();
}
if( (millis()-previous) > interval )
{
end=1;
serialFlush(_uart);
}
}
counter3=0;
end=0;
previous=millis();
if( (answer[0]==0xA0) && (answer[1]==0xA2) && (answer[2]==0x00) && (answer[3]==0x02) &&
(answer[4]==0x0B) && (answer[5]==0x95) && (answer[6]==0x00) &&
(answer[7]==0xA0) && (answer[8]==0xB0) && (answer[9]==0xB3) ) error=1;
else error=0;
offset+=85;
}
}
free(answer);
free(tempData);
answer=NULL;
tempData=NULL;
return error;
}
/* getPosition() - gets the latitude, longitude, altitude, speed, course, time and date
*
* It gets the latitude, longitude, altitude, speed, course, time and date
*
* It returns '1' on success and '0' on error.
*/
uint8_t WaspGPS::getPosition()
{
flag &= ~(GPS_INVALID);
uint16_t currentSentences = commMode;
long previous=0;
uint8_t complete = 0;
uint8_t byteGPS = 0; // the last byte coming through the port
int i = 0; // count the amount of bytes read
uint32_t timeout = 1000; // millis to wait before declaring timeout
// get all NMEA sentences
while(!setCommMode(GPS_NMEA) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
// separates all the subarrays from inBuffer into the Utils.arguments array
Utils.strExplode(inBuffer, ',');
previous = millis();
while( complete<3 && (millis()-previous)<5000 )
{
if( !strcmp(Utils.arguments[0],"$GPGGA") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) timeGPS[i]=Utils.arguments[1][i];
for(int i=0;i<MAX_ARG_LENGTH;i++) latitude[i]=Utils.arguments[2][i];
for(int i=0;i<MAX_ARG_LENGTH;i++) longitude[i]=Utils.arguments[4][i];
for(int i=0;i<MAX_ARG_LENGTH;i++) altitude[i]=Utils.arguments[9][i];
complete++;
}
else if( !strcmp(Utils.arguments[0],"$GPRMC") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) dateGPS[i]=Utils.arguments[9][i];
for(int i=0;i<MAX_ARG_LENGTH;i++) timeGPS[i]=Utils.arguments[1][i];
complete++;
}
else if( !strcmp(Utils.arguments[0],"$GPVTG") )
{
for(int i=0;i<MAX_ARG_LENGTH;i++) speed[i]=Utils.arguments[7][i];
for(int i=0;i<MAX_ARG_LENGTH;i++) course[i]=Utils.arguments[1][i];
complete++;
}
while(!serialAvailable(_uart) && timeout > 0) { delay(1); timeout--; };
if (timeout <= 0)
{
flag |= GPS_TIMEOUT;
return 1;
}
byteGPS = serialRead(_uart); // read the first byte coming through the port
while(byteGPS != '$')
{
if(serialAvailable(_uart) > 0){
byteGPS = serialRead(_uart); // flush incomplete sentences
}
}
inBuffer[i]=byteGPS;
i++;
while(i <= 1 || (byteGPS != '*' && byteGPS != '$' && i < 100)){ // read the GPS sentence
if(serialAvailable(_uart) > 0)
{
byteGPS = serialRead(_uart);
if (byteGPS != '*' && byteGPS != '$' && i < 100) inBuffer[i]=byteGPS;
i++;
}
}
if (byteGPS == '\n' || i == 100) inBuffer[i-1] = '\0';
else inBuffer[i] = '\0';
i=0;
Utils.strExplode(inBuffer, ',');
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
// return to previous state
previous=millis();
if (currentSentences == GPS_BINARY_OFF )
{
while( !setCommMode(GPS_BINARY) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
}
delay(100);
previous=millis();
while(!setCommMode(currentSentences) && (millis()-previous)<3000)
{
if( millis()-previous < 0 ) previous=millis(); //avoid millis overflow problem
}
if( flag & GPS_INVALID ) return 0;
else return 1;
}
/******************************************************************************
* Serial communication functions
******************************************************************************/
/*
* begin (void) - power up the GPS, open the serial port
*
* powers up the GPS and opens the serial port at 4800. You should be careful and
* always add a delay of approximately 3 seconds after calling this command.
* Otherwise you risk that the GPS module won't be ready to accept data and your
* commands to it wouldn't be heard
*
* An example on the use of this on the code is:
*
* GPS.begin();
* delay(3000);
* GPS.init();
*
* This will leave time for the GPS to warm up and open -internally- the
* communication port to Wasp. According to the Tyco GPS datasheet, it
* should be possible to connect at faster speeds than 4800bps, and you
* could change this internally in the _baudRate variable at the WaspGPS
* constructor, or at any poing in the code before calling GPS.begin(). This
* has not been tested, though
*
* On Wasp, calling GPS.begin() means initializing the internal UART drivers
* inside the ATMEGA1281 processor. In order to push the power consumption to
* the minimum you should remember calling GPS.close() after working with the
* GPS
*/
void WaspGPS::begin(void)
{
Utils.setMuxGPS();
beginSerial(_baudRate,_uart);
}
/*
* close (void) - close the serial port
*
* closes the serial port
*
* An example on the use of this on the code is:
*
* GPS.close();
*
* On Wasp, calling GPS.close() means disconnecting the internal UART drivers
* inside the ATMEGA1281 processor. This will push the power consumption to
* the minimum, since the UART is making a massive use of resources
*/
void WaspGPS::close()
{
closeSerial(_uart);
Utils.setMux(MUX_TO_LOW,MUX_TO_LOW);
reboot=COLD;
}
/*
* checkSum (gpsString) - calculate the NMEA checkSum, leave out $, *, and the checkSum bytes
*
* returns 1 if the checksum is right, 0 if error
*
*/
uint8_t WaspGPS::checkSum(const char* gpsString)
{
// clear the checksum flag
flag &= ~(GPS_BAD_CHECKSUM);
// return error if there is no asterisk at the end of the string
if (gpsString[Utils.sizeOf(gpsString)-3] != '*') return 0;
char check = 0;
// iterate over the string, XOR each byte with the total sum:
for (int c = 1; c < Utils.sizeOf(gpsString) - 3; c++) {
check = char(check ^ gpsString[c]);
}
// get the checksum character for the string itself
char stringCheckSum = (gpsString[Utils.sizeOf(gpsString)-2] - '0') << 4 | (gpsString[Utils.sizeOf(gpsString)-1] - '0');
uint8_t result = (check == stringCheckSum);
if (!result) flag |= GPS_BAD_CHECKSUM;
// return the result
return result;
}
/* getChecksum (gpsString) - calculate the NMEA checkSum, leave out $, *, and the checkSum bytes
*
* returns 1 if the checksum is right, 0 if error
*
* credit: Tom Igoe
*/
uint8_t WaspGPS::getChecksum(const char* gpsString)
{
char check = 0;
// iterate over the string, XOR each byte with the total sum:
for (int c = 1; c < Utils.sizeOf(gpsString) - 3; c++) {
check = char(check ^ gpsString[c]);
}
return check;
}
/* setChecksum(_checksum) - set checksum to the end of inBuffer
*
* it sets checksum to the end of inBuffer
*/
void WaspGPS::setChecksum()
{
checksum= getChecksum(inBuffer);
int aux=Utils.sizeOf(inBuffer);
float aux2 = checksum%16;
if(aux2==0.0)
{
inBuffer[aux-1]=48;
inBuffer[aux-2]=(checksum/16)+48;
}
else
{
inBuffer[aux-2]=(int) (checksum/16) + 48;
aux2 = checksum/16;
inBuffer[aux-1]= (checksum-aux2*16)+48;
}
}
/* setChecksum(_checksum) - set checksum to the end of inBuffer
*
* it sets checksum to the end of inBuffer
*/
void WaspGPS::clearBuffer(void) {
for (int i = 0; i < GPS_BUFFER_SIZE; i++) inBuffer[i] = '\0';
}
// Preinstantiate Objects //////////////////////////////////////////////////////
WaspGPS GPS = WaspGPS();