1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-17 02:52:12 +01:00

Better separation between UBX and NMEA parser

Make GPS protocol a user selectable option
Support for UBX protocol on CopterControl
This commit is contained in:
Werner Backes 2012-06-28 09:02:14 +02:00
parent 29fd85f0e2
commit 0424172398
11 changed files with 507 additions and 428 deletions

View File

@ -199,6 +199,8 @@ SRC += $(OPUAVSYNTHDIR)/attitudesettings.c
SRC += $(OPUAVSYNTHDIR)/camerastabsettings.c
SRC += $(OPUAVSYNTHDIR)/cameradesired.c
SRC += $(OPUAVSYNTHDIR)/gpsposition.c
SRC += $(OPUAVSYNTHDIR)/gpsvelocity.c
SRC += $(OPUAVSYNTHDIR)/gpssettings.c
SRC += $(OPUAVSYNTHDIR)/hwsettings.c
SRC += $(OPUAVSYNTHDIR)/gcsreceiver.c
SRC += $(OPUAVSYNTHDIR)/receiveractivity.c

View File

@ -58,7 +58,8 @@
#define PIOS_INCLUDE_TELEMETRY_RF
#define PIOS_INCLUDE_GPS
#define PIOS_GPS_MINIMAL
#define PIOS_INCLUDE_GPS_NMEA_PARSER /* Include the NMEA protocol parser */
#define PIOS_INCLUDE_GPS_UBX_PARSER /* Include the UBX protocol parser */
#define PIOS_INCLUDE_SERVO
#define PIOS_INCLUDE_SPI
#define PIOS_INCLUDE_SYS

View File

@ -33,7 +33,7 @@
#include "openpilot.h"
#include "GPS.h"
#include <stdbool.h>
//#include <stdbool.h>
#include "NMEA.h"
@ -41,6 +41,8 @@
#include "homelocation.h"
#include "gpstime.h"
#include "gpssatellites.h"
#include "gpsvelocity.h"
#include "gpssettings.h"
#include "WorldMagModel.h"
#include "CoordinateConversions.h"
#include "hwsettings.h"
@ -62,19 +64,17 @@ static float GravityAccel(float latitude, float longitude, float altitude);
#define GPS_TIMEOUT_MS 500
#if defined(REVOLUTION)
#define NMEA_MAX_PACKET_LENGTH MAX_SVINFO_MSG_SIZE
#else
#define NMEA_MAX_PACKET_LENGTH 96 // 82 max NMEA msg size plus 12 margin (because some vendors add custom crap) plus CR plus Linefeed
// same as in COM buffer
#endif
#ifdef PIOS_GPS_SETS_HOMELOCATION
// Unfortunately need a good size stack for the WMM calculation
#define STACK_SIZE_BYTES 950
#define STACK_SIZE_BYTES 750
#else
#if defined(PIOS_GPS_MINIMAL)
#define STACK_SIZE_BYTES 500
#else
#define STACK_SIZE_BYTES 650
#endif
#endif // PIOS_GPS_MINIMAL
#endif // PIOS_GPS_SETS_HOMELOCATION
#define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
@ -124,6 +124,7 @@ int32_t GPSStart(void)
int32_t GPSInitialize(void)
{
gpsPort = PIOS_COM_GPS;
uint8_t gpsProtocol;
#ifdef MODULE_GPS_BUILTIN
gpsEnabled = true;
@ -141,6 +142,7 @@ int32_t GPSInitialize(void)
if (gpsPort && gpsEnabled) {
GPSPositionInitialize();
GPSVelocityInitialize();
#if !defined(PIOS_GPS_MINIMAL)
GPSTimeInitialize();
GPSSatellitesInitialize();
@ -150,7 +152,19 @@ int32_t GPSInitialize(void)
#endif
updateSettings();
gps_rx_buffer = pvPortMalloc(NMEA_MAX_PACKET_LENGTH);
if (gpsPort && gpsEnabled) {
GPSSettingsInitialize();
GPSSettingsDataProtocolGet(&gpsProtocol);
switch (gpsProtocol) {
case GPSSETTINGS_DATAPROTOCOL_NMEA:
gps_rx_buffer = pvPortMalloc(NMEA_MAX_PACKET_LENGTH);
break;
case GPSSETTINGS_DATAPROTOCOL_UBX:
gps_rx_buffer = pvPortMalloc(sizeof(UBXPacket));
break;
default:
gps_rx_buffer = NULL;
}
PIOS_Assert(gps_rx_buffer);
return 0;
@ -169,14 +183,13 @@ MODULE_INITCALL(GPSInitialize, GPSStart)
static void gpsTask(void *parameters)
{
portTickType xDelay = 100 / portTICK_RATE_MS;
uint32_t timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;;
GPSPositionData GpsData;
uint8_t rx_count = 0;
bool start_flag = false;
bool found_cr = false;
int32_t gpsRxOverflow = 0;
uint32_t timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
GPSPositionData gpsposition;
uint8_t gpsProtocol;
GPSSettingsDataProtocolGet(&gpsProtocol);
numUpdates = 0;
numChecksumErrors = 0;
numParsingErrors = 0;
@ -184,202 +197,65 @@ static void gpsTask(void *parameters)
timeOfLastUpdateMs = timeNowMs;
timeOfLastCommandMs = timeNowMs;
GPSPositionGet(&gpsposition);
// Loop forever
while (1)
{
uint8_t c;
// NMEA or SINGLE-SENTENCE GPS mode
// This blocks the task until there is something on the buffer
while (PIOS_COM_ReceiveBuffer(gpsPort, &c, 1, xDelay) > 0)
{
// detect start while acquiring stream
if (!start_flag && (c == '$'))
{
case START: // detect protocol
switch (c)
{
case UBX_SYNC1: // first UBX sync char found
proto_state = UBX_SY2;
continue;
case '$': // NMEA identifier found
proto_state = NMEA;
found_cr = false;
rx_count = 0;
break;
default:
continue;
}
int res;
switch (gpsProtocol) {
#if defined(PIOS_INCLUDE_GPS_NMEA_PARSER)
case GPSSETTINGS_DATAPROTOCOL_NMEA:
res = parse_nmea_stream (c,gps_rx_buffer, &gpsposition);
break;
case UBX_SY2:
if (c == UBX_SYNC2) // second UBX sync char found
{
proto_state = UBX_CLASS;
found_cr = false;
rx_count = 0;
}
else
{
proto_state = START; // reset state
}
continue;
case UBX_CLASS:
ubx->header.class = c;
proto_state = UBX_ID;
continue;
case UBX_ID:
ubx->header.id = c;
proto_state = UBX_LEN1;
continue;
case UBX_LEN1:
ubx->header.len = c;
proto_state = UBX_LEN2;
continue;
case UBX_LEN2:
ubx->header.len += (c << 8);
if ((sizeof (UBXHeader)) + ubx->header.len > NMEA_MAX_PACKET_LENGTH)
{
gpsRxOverflow++;
proto_state = START;
found_cr = false;
rx_count = 0;
}
else
{
proto_state = UBX_PAYLOAD;
}
continue;
case UBX_PAYLOAD:
if (rx_count < ubx->header.len)
{
ubx->payload.payload[rx_count] = c;
if (++rx_count == ubx->header.len)
proto_state = UBX_CHK1;
}
else
proto_state = START;
continue;
case UBX_CHK1:
ubx->header.ck_a = c;
proto_state = UBX_CHK2;
continue;
case UBX_CHK2:
ubx->header.ck_b = c;
if (checksum_ubx_message(ubx)) // message complete and valid
{
parse_ubx_message(ubx, &GpsData);
timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
timeOfLastUpdateMs = timeNowMs;
timeOfLastCommandMs = timeNowMs;
}
proto_state = START;
continue;
case NMEA:
#endif
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER)
case GPSSETTINGS_DATAPROTOCOL_UBX:
res = parse_ubx_stream (c,gps_rx_buffer, &gpsposition);
break;
#endif
default:
res = NO_PARSER; // this should not happen
break;
}
else
if (!start_flag)
continue;
if (rx_count >= NMEA_MAX_PACKET_LENGTH)
{
// The buffer is already full and we haven't found a valid NMEA sentence.
// Flush the buffer and note the overflow event.
gpsRxOverflow++;
start_flag = false;
found_cr = false;
rx_count = 0;
}
else
{
gps_rx_buffer[rx_count] = c;
rx_count++;
}
// look for ending '\r\n' sequence
if (!found_cr && (c == '\r') )
found_cr = true;
else
if (found_cr && (c != '\n') )
found_cr = false; // false end flag
else
if (found_cr && (c == '\n') )
{
// The NMEA functions require a zero-terminated string
// As we detected \r\n, the string as for sure 2 bytes long, we will also strip the \r\n
gps_rx_buffer[rx_count-2] = 0;
// prepare to parse next sentence
start_flag = false;
found_cr = false;
rx_count = 0;
// Our rxBuffer must look like this now:
// [0] = '$'
// ... = zero or more bytes of sentence payload
// [end_pos - 1] = '\r'
// [end_pos] = '\n'
//
// Prepare to consume the sentence from the buffer
// Validate the checksum over the sentence
if (!NMEA_checksum(&gps_rx_buffer[1]))
{ // Invalid checksum. May indicate dropped characters on Rx.
//PIOS_DEBUG_PinHigh(2);
++numChecksumErrors;
//PIOS_DEBUG_PinLow(2);
}
else
{ // Valid checksum, use this packet to update the GPS position
if (!NMEA_update_position(&gps_rx_buffer[1])) {
//PIOS_DEBUG_PinHigh(2);
++numParsingErrors;
//PIOS_DEBUG_PinLow(2);
}
else
++numUpdates;
timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
timeOfLastUpdateMs = timeNowMs;
timeOfLastCommandMs = timeNowMs;
}
if (res == PARSER_COMPLETE) {
timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
timeOfLastUpdateMs = timeNowMs;
timeOfLastCommandMs = timeNowMs;
}
}
// Check for GPS timeout
timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
if ((timeNowMs - timeOfLastUpdateMs) >= GPS_TIMEOUT_MS)
{ // we have not received any valid GPS sentences for a while.
if ((timeNowMs - timeOfLastUpdateMs) >= GPS_TIMEOUT_MS) {
// we have not received any valid GPS sentences for a while.
// either the GPS is not plugged in or a hardware problem or the GPS has locked up.
GPSPositionGet(&GpsData);
GpsData.Status = GPSPOSITION_STATUS_NOGPS;
GPSPositionSet(&GpsData);
uint8_t status = GPSPOSITION_STATUS_NOGPS;
GPSPositionStatusSet(&status);
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_ERROR);
}
else
{ // we appear to be receiving GPS sentences OK, we've had an update
GPSPositionGet(&GpsData);
#ifdef PIOS_GPS_SETS_HOMELOCATION
HomeLocationData home;
HomeLocationGet(&home);
if ((GpsData.Status == GPSPOSITION_STATUS_FIX3D) && (home.Set == HOMELOCATION_SET_FALSE))
setHomeLocation(&GpsData);
#endif
} else {
// we appear to be receiving GPS sentences OK, we've had an update
//criteria for GPS-OK taken from this post...
//http://forums.openpilot.org/topic/1523-professors-insgps-in-svn/page__view__findpost__p__5220
if ((GpsData.PDOP < 3.5) && (GpsData.Satellites >= 7))
if ((gpsposition.PDOP < 3.5) && (gpsposition.Satellites >= 7) &&
(gpsposition.Status == GPSPOSITION_STATUS_FIX3D)) {
AlarmsClear(SYSTEMALARMS_ALARM_GPS);
else
if (GpsData.Status == GPSPOSITION_STATUS_FIX3D)
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_WARNING);
else
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_CRITICAL);
#ifdef PIOS_GPS_SETS_HOMELOCATION
HomeLocationData home;
HomeLocationGet(&home);
if (home.Set == HOMELOCATION_SET_FALSE)
setHomeLocation(&gpsposition);
#endif
} else if (gpsposition.Status == GPSPOSITION_STATUS_FIX3D)
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_WARNING);
else
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_CRITICAL);
}
}

View File

@ -30,10 +30,15 @@
#include "openpilot.h"
#include "pios.h"
#if defined(PIOS_INCLUDE_GPS_NMEA_PARSER)
#include "gpsposition.h"
#include "NMEA.h"
#include "gpsposition.h"
#include "gpstime.h"
#include "gpssatellites.h"
#include "GPS.h"
//#define ENABLE_DEBUG_MSG ///< define to enable debug-messages
#define DEBUG_PORT PIOS_COM_TELEM_RF ///< defines which serial port is ued for debug-messages
@ -75,6 +80,9 @@ static bool nmeaProcessGPGSA(GPSPositionData * GpsData, bool* gpsDataUpdated, ch
static bool nmeaProcessGPGSV(GPSPositionData * GpsData, bool* gpsDataUpdated, char* param[], uint8_t nbParam);
#endif //PIOS_GPS_MINIMAL
static uint32_t numUpdates;
static uint32_t numChecksumErrors;
static uint32_t numParsingErrors;
static struct nmea_parser nmea_parsers[] = {
{
@ -111,6 +119,88 @@ static struct nmea_parser nmea_parsers[] = {
#endif //PIOS_GPS_MINIMAL
};
int parse_nmea_stream (uint8_t c, char *gps_rx_buffer, GPSPositionData *GpsData)
{
static uint8_t rx_count = 0;
static bool start_flag = false;
static bool found_cr = false;
// detect start while acquiring stream
if (!start_flag && (c == '$')) // NMEA identifier found
{
start_flag = true;
found_cr = false;
rx_count = 0;
}
else
if (!start_flag)
return PARSER_ERROR;
if (rx_count >= NMEA_MAX_PACKET_LENGTH)
{
// The buffer is already full and we haven't found a valid NMEA sentence.
// Flush the buffer and note the overflow event.
// gpsRxOverflow++;
start_flag = false;
found_cr = false;
rx_count = 0;
return PARSER_OVERRUN;
}
else
{
gps_rx_buffer[rx_count] = c;
rx_count++;
}
// look for ending '\r\n' sequence
if (!found_cr && (c == '\r') )
found_cr = true;
else
if (found_cr && (c != '\n') )
found_cr = false; // false end flag
else
if (found_cr && (c == '\n') )
{
// The NMEA functions require a zero-terminated string
// As we detected \r\n, the string as for sure 2 bytes long, we will also strip the \r\n
gps_rx_buffer[rx_count-2] = 0;
// prepare to parse next sentence
start_flag = false;
found_cr = false;
rx_count = 0;
// Our rxBuffer must look like this now:
// [0] = '$'
// ... = zero or more bytes of sentence payload
// [end_pos - 1] = '\r'
// [end_pos] = '\n'
//
// Prepare to consume the sentence from the buffer
// Validate the checksum over the sentence
if (!NMEA_checksum(&gps_rx_buffer[1]))
{ // Invalid checksum. May indicate dropped characters on Rx.
//PIOS_DEBUG_PinHigh(2);
++numChecksumErrors;
//PIOS_DEBUG_PinLow(2);
return PARSER_ERROR;
}
else
{ // Valid checksum, use this packet to update the GPS position
if (!NMEA_update_position(&gps_rx_buffer[1], GpsData)) {
//PIOS_DEBUG_PinHigh(2);
++numParsingErrors;
//PIOS_DEBUG_PinLow(2);
}
else
++numUpdates;
return PARSER_COMPLETE;
}
}
return PARSER_INCOMPLETE;
}
static struct nmea_parser *NMEA_find_parser_by_prefix(const char *prefix)
{
if (!prefix) {
@ -352,7 +442,7 @@ bool NMEA_update_position(char *nmea_sentence)
// All is fine :) Update object if data has changed
if (gpsDataUpdated) {
if (gpsDataUpdated || (GpsData->Status == GPSPOSITION_STATUS_NOFIX)) {
#ifdef DEBUG_MGSID_IN
DEBUG_MSG("U");
#endif
@ -400,6 +490,12 @@ static bool nmeaProcessGPGGA(GPSPositionData * GpsData, bool* gpsDataUpdated, ch
return false;
}
// check for invalid GPS fix
if (param[6][0] == '0') {
// return false;
GpsData->Status = GPSPOSITION_STATUS_NOFIX; // treat invalid fix as NOFIX
}
// get number of satellites used in GPS solution
GpsData->Satellites = atoi(param[7]);
@ -669,3 +765,4 @@ static bool nmeaProcessGPGSA(GPSPositionData * GpsData, bool* gpsDataUpdated, ch
return true;
}
#endif // PIOS_INCLUDE_GPS_NMEA_PARSER

View File

@ -30,11 +30,96 @@
#include "openpilot.h"
#include "pios.h"
#include "gpsvelocity.h"
#include "gpssatellites.h"
#include "gpsposition.h"
#include "gpstime.h"
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER)
#include "UBX.h"
#include "gps.h"
static uint32_t gpsRxReceived = 0;
static uint32_t gpsRxChkSumError = 0;
static uint32_t gpsRxOverflow = 0;
// parse incoming character stream for messages in UBX binary format
int parse_ubx_stream (uint8_t c, char *gps_rx_buffer, GPSPositionData *GpsData)
{
enum proto_states {START,UBX_SY2,UBX_CLASS,UBX_ID,UBX_LEN1,
UBX_LEN2,UBX_PAYLOAD,UBX_CHK1,UBX_CHK2,FINISHED};
static enum proto_states proto_state = START;
static uint8_t rx_count = 0;
UBXPacket *ubx = (UBXPacket *)gps_rx_buffer;
switch (proto_state) {
case START: // detect protocol
if (c == UBX_SYNC1) // first UBX sync char found
proto_state = UBX_SY2;
break;
case UBX_SY2:
if (c == UBX_SYNC2) // second UBX sync char found
proto_state = UBX_CLASS;
else
proto_state = START; // reset state
break;
case UBX_CLASS:
ubx->header.class = c;
proto_state = UBX_ID;
break;
case UBX_ID:
ubx->header.id = c;
proto_state = UBX_LEN1;
break;
case UBX_LEN1:
ubx->header.len = c;
proto_state = UBX_LEN2;
break;
case UBX_LEN2:
ubx->header.len += (c << 8);
if (ubx->header.len > sizeof(UBXPayload)) {
gpsRxOverflow++;
proto_state = START;
} else {
rx_count = 0;
proto_state = UBX_PAYLOAD;
}
break;
case UBX_PAYLOAD:
if (rx_count < ubx->header.len) {
ubx->payload.payload[rx_count] = c;
if (++rx_count == ubx->header.len)
proto_state = UBX_CHK1;
} else {
gpsRxOverflow++;
proto_state = START;
}
break;
case UBX_CHK1:
ubx->header.ck_a = c;
proto_state = UBX_CHK2;
break;
case UBX_CHK2:
ubx->header.ck_b = c;
if (checksum_ubx_message(ubx)) { // message complete and valid
parse_ubx_message(ubx, GpsData);
proto_state = FINISHED;
} else {
gpsRxChkSumError++;
proto_state = START;
}
break;
default: break;
}
if (proto_state == START)
return PARSER_ERROR; // parser couldn't use this byte
else if (proto_state == FINISHED) {
gpsRxReceived++;
proto_state = START;
return PARSER_COMPLETE; // message complete & processed
}
return PARSER_INCOMPLETE; // message not (yet) complete
}
// Keep track of various GPS messages needed to make up a single UAVO update
@ -50,25 +135,21 @@
static struct msgtracker{
uint32_t currentTOW; // TOW of the message set currently in progress
uint8_t msg_received; // Flag received messages
uint8_t msg_received; // keep track of received message types
} msgtracker;
// Check if a message belongs to the current data set and register it as 'received'
bool check_msgtracker (uint32_t tow, uint8_t msg_flag)
{
if ((tow > msgtracker.currentTOW) || // start of a new message set
(tow < 60000 && msgtracker.currentTOW > (7*24-1)*3600*1000)) // TOW wrap around
{
if (tow > msgtracker.currentTOW ? true // start of a new message set
: (msgtracker.currentTOW - tow > 6*24*3600*1000)) { // 6 days, TOW wrap around occured
msgtracker.currentTOW = tow;
msgtracker.msg_received = NONE_RECEIVED;
}
else
{
if (tow < msgtracker.currentTOW) // message outdated (don't process)
} else if (tow < msgtracker.currentTOW) // message outdated (don't process)
return false;
}
msgtracker.msg_received |= msg_flag;
msgtracker.msg_received |= msg_flag; // register reception of this msg type
return true;
}
@ -89,137 +170,133 @@ bool checksum_ubx_message (UBXPacket *ubx)
ck_a += ubx->header.len >> 8;
ck_b += ck_a;
for (i = 0; i < ubx->header.len; i++)
{
for (i = 0; i < ubx->header.len; i++) {
ck_a += ubx->payload.payload[i];
ck_b += ck_a;
}
if (ubx->header.ck_a == ck_a &&
ubx->header.ck_b == ck_b)
{
return true;
}
else
return false;
}
void parse_ubx_nav_posllh (UBXPayload payload, GPSPositionData *gpsposition)
void parse_ubx_nav_posllh (UBX_NAV_POSLLH *posllh, GPSPositionData *GpsPosition)
{
if (check_msgtracker(payload.nav_posllh.iTOW, POSLLH_RECEIVED))
{
gpsposition->Altitude = (float)payload.nav_posllh.hMSL*0.001f;
gpsposition->GeoidSeparation = (float)(payload.nav_posllh.height -
payload.nav_posllh.hMSL)*0.001f;
gpsposition->Latitude = payload.nav_posllh.lat;
gpsposition->Longitude = payload.nav_posllh.lon;
}
}
void parse_ubx_nav_status (UBXPayload payload, GPSPositionData *gpsposition)
{
if (check_msgtracker(payload.nav_status.iTOW, STATUS_RECEIVED))
{
switch (payload.nav_status.gpsFix)
{
case STATUS_GPSFIX_2DFIX:
gpsposition->Status = GPSPOSITION_STATUS_FIX2D;
break;
case STATUS_GPSFIX_3DFIX:
gpsposition->Status = GPSPOSITION_STATUS_FIX3D;
break;
default: gpsposition->Status = GPSPOSITION_STATUS_NOFIX;
if (check_msgtracker(posllh->iTOW, POSLLH_RECEIVED)) {
if (GpsPosition->Status != GPSPOSITION_STATUS_NOFIX) {
GpsPosition->Altitude = (float)posllh->hMSL*0.001f;
GpsPosition->GeoidSeparation = (float)(posllh->height - posllh->hMSL)*0.001f;
GpsPosition->Latitude = posllh->lat;
GpsPosition->Longitude = posllh->lon;
}
}
}
void parse_ubx_nav_sol (UBXPayload payload, GPSPositionData *gpsposition)
void parse_ubx_nav_status (UBX_NAV_STATUS *status, GPSPositionData *GpsPosition)
{
if (check_msgtracker(payload.nav_dop.iTOW, SOL_RECEIVED))
{
gpsposition->Satellites = (float)payload.nav_sol.numSV;
switch (payload.nav_sol.gpsFix)
{
#if 0 // we already get this info from NAV_SOL
if (check_msgtracker(status->iTOW, STATUS_RECEIVED)) {
switch (status->gpsFix) {
case STATUS_GPSFIX_2DFIX:
gpsposition->Status = GPSPOSITION_STATUS_FIX2D;
GpsPosition->Status = GPSPOSITION_STATUS_FIX2D;
break;
case STATUS_GPSFIX_3DFIX:
gpsposition->Status = GPSPOSITION_STATUS_FIX3D;
GpsPosition->Status = GPSPOSITION_STATUS_FIX3D;
break;
default: gpsposition->Status = GPSPOSITION_STATUS_NOFIX;
default: GpsPosition->Status = GPSPOSITION_STATUS_NOFIX;
}
}
#endif
}
void parse_ubx_nav_dop (UBXPayload payload, GPSPositionData *gpsposition)
void parse_ubx_nav_sol (UBX_NAV_SOL *sol, GPSPositionData *GpsPosition)
{
if (check_msgtracker(payload.nav_dop.iTOW, DOP_RECEIVED))
{
gpsposition->HDOP = (float)payload.nav_dop.hDOP * 0.01f;
gpsposition->VDOP = (float)payload.nav_dop.vDOP * 0.01f;
gpsposition->PDOP = (float)payload.nav_dop.pDOP * 0.01f;
if (check_msgtracker(sol->iTOW, SOL_RECEIVED)) {
GpsPosition->Satellites = sol->numSV;
if (sol->flags & STATUS_FLAGS_GPSFIX_OK) {
switch (sol->gpsFix) {
case STATUS_GPSFIX_2DFIX:
GpsPosition->Status = GPSPOSITION_STATUS_FIX2D;
break;
case STATUS_GPSFIX_3DFIX:
GpsPosition->Status = GPSPOSITION_STATUS_FIX3D;
break;
default: GpsPosition->Status = GPSPOSITION_STATUS_NOFIX;
}
}
else // fix is not valid so we make sure to treat is as NOFIX
GpsPosition->Status = GPSPOSITION_STATUS_NOFIX;
}
}
void parse_ubx_nav_velned (UBXPayload payload, GPSPositionData *gpsposition)
void parse_ubx_nav_dop (UBX_NAV_DOP *dop, GPSPositionData *GpsPosition)
{
if (check_msgtracker(dop->iTOW, DOP_RECEIVED)) {
GpsPosition->HDOP = (float)dop->hDOP * 0.01f;
GpsPosition->VDOP = (float)dop->vDOP * 0.01f;
GpsPosition->PDOP = (float)dop->pDOP * 0.01f;
}
}
void parse_ubx_nav_velned (UBX_NAV_VELNED *velned, GPSPositionData *GpsPosition)
{
GPSVelocityData GpsVelocity;
GpsVelocity.North = (float)payload.nav_velned.velN/100.0f;
GpsVelocity.East = (float)payload.nav_velned.velE/100.0f;
GpsVelocity.Down = (float)payload.nav_velned.velD/100.0f;
GPSVelocitySet(&GpsVelocity);
if (check_msgtracker(payload.nav_velned.iTOW, VELNED_RECEIVED))
{
gpsposition->Groundspeed = (float)payload.nav_velned.gSpeed * 0.01f;
gpsposition->Heading = (float)payload.nav_velned.heading * 1.0e-5f;
if (check_msgtracker(velned->iTOW, VELNED_RECEIVED)) {
if (GpsPosition->Status != GPSPOSITION_STATUS_NOFIX) {
GpsVelocity.North = (float)velned->velN/100.0f;
GpsVelocity.East = (float)velned->velE/100.0f;
GpsVelocity.Down = (float)velned->velD/100.0f;
GPSVelocitySet(&GpsVelocity);
GpsPosition->Groundspeed = (float)velned->gSpeed * 0.01f;
GpsPosition->Heading = (float)velned->heading * 1.0e-5f;
}
}
}
void parse_ubx_nav_timeutc (UBXPayload payload)
#if !defined(PIOS_GPS_MINIMAL)
void parse_ubx_nav_timeutc (UBX_NAV_TIMEUTC *timeutc)
{
if (!(payload.nav_timeutc.valid & TIMEUTC_VALIDUTC))
if (!(timeutc->valid & TIMEUTC_VALIDUTC))
return;
GPSTimeData gpst;
GPSTimeData GpsTime;
gpst.Year = payload.nav_timeutc.year;
gpst.Month = payload.nav_timeutc.month;
gpst.Day = payload.nav_timeutc.day;
gpst.Hour = payload.nav_timeutc.hour;
gpst.Minute = payload.nav_timeutc.min;
gpst.Second = payload.nav_timeutc.sec;
GpsTime.Year = timeutc->year;
GpsTime.Month = timeutc->month;
GpsTime.Day = timeutc->day;
GpsTime.Hour = timeutc->hour;
GpsTime.Minute = timeutc->min;
GpsTime.Second = timeutc->sec;
GPSTimeSet(&gpst);
GPSTimeSet(&GpsTime);
}
#endif
void parse_ubx_nav_svinfo (UBXPayload payload)
#if !defined(PIOS_GPS_MINIMAL)
void parse_ubx_nav_svinfo (UBX_NAV_SVINFO *svinfo)
{
GPSSatellitesData svdata;
uint8_t chan;
GPSSatellitesData svdata;
svdata.SatsInView = 0;
for (chan = 0; chan < payload.nav_svinfo.numCh; chan++)
{
if ((payload.nav_svinfo.sv[chan].elev > 0) && // some unhealthy SV report negative elevation
(svdata.SatsInView < GPSSATELLITES_PRN_NUMELEM))
{
svdata.Azimuth[svdata.SatsInView] = (float)payload.nav_svinfo.sv[chan].azim;
svdata.Elevation[svdata.SatsInView] = (float)payload.nav_svinfo.sv[chan].elev;
svdata.PRN[svdata.SatsInView] = payload.nav_svinfo.sv[chan].svid;
svdata.SNR[svdata.SatsInView] = payload.nav_svinfo.sv[chan].cno;
for (chan = 0; chan < svinfo->numCh; chan++) {
if ((svinfo->sv[chan].elev > 0) && // some unhealthy SV report negative elevation
(svdata.SatsInView < GPSSATELLITES_PRN_NUMELEM)) {
svdata.Azimuth[svdata.SatsInView] = (float)svinfo->sv[chan].azim;
svdata.Elevation[svdata.SatsInView] = (float)svinfo->sv[chan].elev;
svdata.PRN[svdata.SatsInView] = svinfo->sv[chan].svid;
svdata.SNR[svdata.SatsInView] = svinfo->sv[chan].cno;
svdata.SatsInView++;
}
}
// fill remaining slots (if any)
for (chan = svdata.SatsInView; chan < GPSSATELLITES_PRN_NUMELEM; chan++)
{
for (chan = svdata.SatsInView; chan < GPSSATELLITES_PRN_NUMELEM; chan++) {
svdata.Azimuth[chan] = (float)0.0f;
svdata.Elevation[chan] = (float)0.0f;
svdata.PRN[chan] = 0;
@ -228,51 +305,51 @@ void parse_ubx_nav_svinfo (UBXPayload payload)
GPSSatellitesSet(&svdata);
}
#endif
// UBX message parser
// returns true on valid position updates
// returns UAVObjectID if a UAVObject structure is ready for further processing
bool parse_ubx_message (UBXPacket *ubx, GPSPositionData *gpsposition)
uint32_t parse_ubx_message (UBXPacket *ubx, GPSPositionData *GpsPosition)
{
#if defined(REVOLUTION)
uint32_t id = 0;
switch (ubx->header.class)
{
switch (ubx->header.class) {
case UBX_CLASS_NAV:
switch (ubx->header.id)
{
switch (ubx->header.id) {
case UBX_ID_POSLLH:
parse_ubx_nav_posllh (ubx->payload, gpsposition);
parse_ubx_nav_posllh (&ubx->payload.nav_posllh, GpsPosition);
break;
case UBX_ID_STATUS:
parse_ubx_nav_status (ubx->payload, gpsposition);
parse_ubx_nav_status (&ubx->payload.nav_status, GpsPosition);
break;
case UBX_ID_DOP:
parse_ubx_nav_dop (ubx->payload, gpsposition);
parse_ubx_nav_dop (&ubx->payload.nav_dop, GpsPosition);
break;
case UBX_ID_SOL:
parse_ubx_nav_sol (ubx->payload, gpsposition);
parse_ubx_nav_sol (&ubx->payload.nav_sol, GpsPosition);
break;
case UBX_ID_VELNED:
parse_ubx_nav_velned (ubx->payload, gpsposition);
parse_ubx_nav_velned (&ubx->payload.nav_velned, GpsPosition);
break;
#if !defined(PIOS_GPS_MINIMAL)
case UBX_ID_TIMEUTC:
parse_ubx_nav_timeutc (ubx->payload);
parse_ubx_nav_timeutc (&ubx->payload.nav_timeutc);
break;
case UBX_ID_SVINFO:
parse_ubx_nav_svinfo (ubx->payload);
parse_ubx_nav_svinfo (&ubx->payload.nav_svinfo);
break;
#endif
}
break;
}
if (msgtracker.msg_received == ALL_RECEIVED)
{
GPSPositionSet(gpsposition);
if (msgtracker.msg_received == ALL_RECEIVED) {
GPSPositionSet(GpsPosition);
msgtracker.msg_received = NONE_RECEIVED;
return true;
id = GPSPOSITION_OBJID;
}
return false;
#endif
return id;
}
#endif // PIOS_INCLUDE_GPS_UBX_PARSER

View File

@ -1,44 +1,55 @@
/**
******************************************************************************
* @addtogroup OpenPilotModules OpenPilot Modules
* @{
* @addtogroup GSPModule GPS Module
* @brief Process GPS information
* @{
*
* @file GPS.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Include file of the GPS module.
* As with all modules only the initialize function is exposed all other
* interactions with the module take place through the event queue and
* objects.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 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 General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef GPS_H
#define GPS_H
int32_t GPSInitialize(void);
#endif // GPS_H
/**
* @}
* @}
*/
/**
******************************************************************************
* @addtogroup OpenPilotModules OpenPilot Modules
* @{
* @addtogroup GSPModule GPS Module
* @brief Process GPS information
* @{
*
* @file GPS.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Include file of the GPS module.
* As with all modules only the initialize function is exposed all other
* interactions with the module take place through the event queue and
* objects.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 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 General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef GPS_H
#define GPS_H
#include "gpsvelocity.h"
#include "gpssatellites.h"
#include "gpsposition.h"
#include "gpstime.h"
#define NO_PARSER -3 // no parser available
#define PARSER_OVERRUN -2 // message buffer overrun before completing the message
#define PARSER_ERROR -1 // message unparsable by this parser
#define PARSER_INCOMPLETE 0 // parser needs more data to complete the message
#define PARSER_COMPLETE 1 // parser has received a complete message and finished processing
int32_t GPSInitialize(void);
#endif // GPS_H
/**
* @}
* @}
*/

View File

@ -34,7 +34,10 @@
#include <stdbool.h>
#include <stdint.h>
extern bool NMEA_update_position(char *nmea_sentence);
#define NMEA_MAX_PACKET_LENGTH 96 // 82 max NMEA msg size plus 12 margin (because some vendors add custom crap) plus CR plus Linefeed
extern bool NMEA_update_position(char *nmea_sentence, GPSPositionData *GpsData);
extern bool NMEA_checksum(char *nmea_sentence);
extern int parse_nmea_stream(uint8_t, char *, GPSPositionData *);
#endif /* NMEA_H */

View File

@ -31,6 +31,7 @@
#ifndef UBX_H
#define UBX_H
#include "openpilot.h"
#include "gpsposition.h"
#define UBX_SYNC1 0xb5 // UBX protocol synchronization characters
#define UBX_SYNC2 0x62
@ -53,13 +54,13 @@
// Geodetic Position Solution
typedef struct {
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
int32_t lon; // Longitude (deg*1e-7)
int32_t lat; // Latitude (deg*1e-7)
int32_t height; // Height above Ellipoid (mm)
int32_t hMSL; // Height abobe mean sea level (mm)
uint32_t hAcc; // Horizontal Accuracy Estimate (mm)
uint32_t vAcc; // Vertical Accuracy Estimate (mm)
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
int32_t lon; // Longitude (deg*1e-7)
int32_t lat; // Latitude (deg*1e-7)
int32_t height; // Height above Ellipoid (mm)
int32_t hMSL; // Height abobe mean sea level (mm)
uint32_t hAcc; // Horizontal Accuracy Estimate (mm)
uint32_t vAcc; // Vertical Accuracy Estimate (mm)
} UBX_NAV_POSLLH;
// Receiver Navigation Status
@ -77,61 +78,61 @@ typedef struct {
#define STATUS_FLAGS_TOWSET (1 << 3)
typedef struct {
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
uint8_t gpsFix; // GPS fix type
uint8_t flags; // Navigation Status Flags
uint8_t fixStat; // Fix Status Information
uint8_t flags2; // Additional navigation output information
uint32_t ttff; // Time to first fix (ms)
uint32_t msss; // Milliseconds since startup/reset (ms)
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
uint8_t gpsFix; // GPS fix type
uint8_t flags; // Navigation Status Flags
uint8_t fixStat; // Fix Status Information
uint8_t flags2; // Additional navigation output information
uint32_t ttff; // Time to first fix (ms)
uint32_t msss; // Milliseconds since startup/reset (ms)
} UBX_NAV_STATUS;
// Dilution of precision
typedef struct {
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
uint16_t gDOP; // Geometric DOP
uint16_t pDOP; // Position DOP
uint16_t tDOP; // Time DOP
uint16_t vDOP; // Vertical DOP
uint16_t hDOP; // Horizontal DOP
uint16_t nDOP; // Northing DOP
uint16_t eDOP; // Easting DOP
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
uint16_t gDOP; // Geometric DOP
uint16_t pDOP; // Position DOP
uint16_t tDOP; // Time DOP
uint16_t vDOP; // Vertical DOP
uint16_t hDOP; // Horizontal DOP
uint16_t nDOP; // Northing DOP
uint16_t eDOP; // Easting DOP
} UBX_NAV_DOP;
// Navigation solution
typedef struct {
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
int32_t fTOW; // fracional nanoseconds (ns)
int16_t week; // GPS week
uint8_t gpsFix; // GPS fix type
uint8_t flags; // Fix status flags
int32_t ecefX; // ECEF X coordinate (cm)
int32_t ecefY; // ECEF Y coordinate (cm)
int32_t ecefZ; // ECEF Z coordinate (cm)
uint32_t pAcc; // 3D Position Accuracy Estimate (cm)
int32_t ecefVX; // ECEF X coordinate (cm/s)
int32_t ecefVY; // ECEF Y coordinate (cm/s)
int32_t ecefVZ; // ECEF Z coordinate (cm/s)
uint32_t sAcc; // Speed Accuracy Estimate
uint16_t pDOP; // Position DOP
uint8_t reserved1; // Reserved
uint8_t numSV; // Number of SVs used in Nav Solution
uint32_t reserved2; // Reserved
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
int32_t fTOW; // fracional nanoseconds (ns)
int16_t week; // GPS week
uint8_t gpsFix; // GPS fix type
uint8_t flags; // Fix status flags
int32_t ecefX; // ECEF X coordinate (cm)
int32_t ecefY; // ECEF Y coordinate (cm)
int32_t ecefZ; // ECEF Z coordinate (cm)
uint32_t pAcc; // 3D Position Accuracy Estimate (cm)
int32_t ecefVX; // ECEF X coordinate (cm/s)
int32_t ecefVY; // ECEF Y coordinate (cm/s)
int32_t ecefVZ; // ECEF Z coordinate (cm/s)
uint32_t sAcc; // Speed Accuracy Estimate
uint16_t pDOP; // Position DOP
uint8_t reserved1; // Reserved
uint8_t numSV; // Number of SVs used in Nav Solution
uint32_t reserved2; // Reserved
} UBX_NAV_SOL;
// North/East/Down velocity
typedef struct {
uint32_t iTOW; // ms GPS Millisecond Time of Week
int32_t velN; // cm/s NED north velocity
int32_t velE; // cm/s NED east velocity
int32_t velD; // cm/s NED down velocity
uint32_t speed; // cm/s Speed (3-D)
uint32_t gSpeed; // cm/s Ground Speed (2-D)
int32_t heading; // 1e-5 *deg Heading of motion 2-D
uint32_t sAcc; // cm/s Speed Accuracy Estimate
uint32_t cAcc; // 1e-5 *deg Course / Heading Accuracy Estimate
uint32_t iTOW; // ms GPS Millisecond Time of Week
int32_t velN; // cm/s NED north velocity
int32_t velE; // cm/s NED east velocity
int32_t velD; // cm/s NED down velocity
uint32_t speed; // cm/s Speed (3-D)
uint32_t gSpeed; // cm/s Ground Speed (2-D)
int32_t heading; // 1e-5 *deg Heading of motion 2-D
uint32_t sAcc; // cm/s Speed Accuracy Estimate
uint32_t cAcc; // 1e-5 *deg Course / Heading Accuracy Estimate
} UBX_NAV_VELNED;
// UTC Time Solution
@ -141,51 +142,51 @@ typedef struct {
#define TIMEUTC_VALIDUTC (1 << 2)
typedef struct {
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
uint32_t tAcc; // Time Accuracy Estimate (ns)
int32_t nano; // Nanoseconds of second
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
uint32_t tAcc; // Time Accuracy Estimate (ns)
int32_t nano; // Nanoseconds of second
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint8_t valid; // Validity Flags
uint8_t valid; // Validity Flags
} UBX_NAV_TIMEUTC;
// Space Vehicle (SV) Information
// Single SV information block
#define SVUSED (1 << 0) // This SV is used for navigation
#define DIFFCORR (1 << 1) // Differential correction available
#define ORBITAVAIL (1 << 2) // Orbit information available
#define ORBITEPH (1 << 3) // Orbit information is Ephemeris
#define UNHEALTHY (1 << 4) // SV is unhealthy
#define ORBITALM (1 << 5) // Orbit information is Almanac Plus
#define ORBITAOP (1 << 6) // Orbit information is AssistNow Autonomous
#define SMOOTHED (1 << 7) // Carrier smoothed pseudoranges used
#define SVUSED (1 << 0) // This SV is used for navigation
#define DIFFCORR (1 << 1) // Differential correction available
#define ORBITAVAIL (1 << 2) // Orbit information available
#define ORBITEPH (1 << 3) // Orbit information is Ephemeris
#define UNHEALTHY (1 << 4) // SV is unhealthy
#define ORBITALM (1 << 5) // Orbit information is Almanac Plus
#define ORBITAOP (1 << 6) // Orbit information is AssistNow Autonomous
#define SMOOTHED (1 << 7) // Carrier smoothed pseudoranges used
typedef struct {
uint8_t chn; // Channel number
uint8_t svid; // Satellite ID
uint8_t flags; // Misc SV information
uint8_t quality; // Misc quality indicators
uint8_t cno; // Carrier to Noise Ratio (dbHz)
int8_t elev; // Elevation (integer degrees)
int16_t azim; // Azimuth (integer degrees)
int32_t prRes; // Pseudo range residual (cm)
uint8_t chn; // Channel number
uint8_t svid; // Satellite ID
uint8_t flags; // Misc SV information
uint8_t quality; // Misc quality indicators
uint8_t cno; // Carrier to Noise Ratio (dbHz)
int8_t elev; // Elevation (integer degrees)
int16_t azim; // Azimuth (integer degrees)
int32_t prRes; // Pseudo range residual (cm)
} UBX_NAV_SVINFO_SV;
// SV information message
#define MAX_SVINFO_MSG_SIZE 208
#define MAX_SVS 16
typedef struct {
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
uint8_t numCh; // Number of channels
uint8_t globalFlags; //
uint16_t reserved2; // Reserved
UBX_NAV_SVINFO_SV sv[16]; // Repeated 'numCh' times
uint32_t iTOW; // GPS Millisecond Time of Week (ms)
uint8_t numCh; // Number of channels
uint8_t globalFlags; //
uint16_t reserved2; // Reserved
UBX_NAV_SVINFO_SV sv[MAX_SVS]; // Repeated 'numCh' times
} UBX_NAV_SVINFO;
typedef union {
@ -195,8 +196,10 @@ typedef union {
UBX_NAV_DOP nav_dop;
UBX_NAV_SOL nav_sol;
UBX_NAV_VELNED nav_velned;
#if !defined(PIOS_GPS_MINIMAL)
UBX_NAV_TIMEUTC nav_timeutc;
UBX_NAV_SVINFO nav_svinfo;
#endif
} UBXPayload;
typedef struct {
@ -213,5 +216,7 @@ typedef struct {
} UBXPacket;
bool checksum_ubx_message(UBXPacket *);
bool parse_ubx_message(UBXPacket *, GPSPositionData *);
uint32_t parse_ubx_message(UBXPacket *, GPSPositionData *);
int parse_ubx_stream(uint8_t, char *, GPSPositionData *);
#endif /* UBX_H */

View File

@ -96,6 +96,8 @@
#define PIOS_TELEM_PRIORITY_QUEUE /* Enable a priority queue in telemetry */
#define PIOS_QUATERNION_STABILIZATION /* Stabilization options */
//#define PIOS_GPS_SETS_HOMELOCATION /* GPS options */
#define PIOS_INCLUDE_GPS_NMEA_PARSER /* Include the NMEA protocol parser */
#define PIOS_INCLUDE_GPS_UBX_PARSER /* Include the UBX protocol parser */
/* Alarm Thresholds */
#define HEAP_LIMIT_WARNING 4000

View File

@ -46,6 +46,7 @@ UAVOBJSRCFILENAMES += flighttelemetrystats
UAVOBJSRCFILENAMES += gcstelemetrystats
UAVOBJSRCFILENAMES += gpsposition
UAVOBJSRCFILENAMES += gpssatellites
UAVOBJSRCFILENAMES += gpssettings
UAVOBJSRCFILENAMES += gpstime
UAVOBJSRCFILENAMES += guidancesettings
UAVOBJSRCFILENAMES += homelocation

View File

@ -52,6 +52,8 @@ HEADERS += $$UAVOBJECT_SYNTHETICS/accessorydesired.h \
$$UAVOBJECT_SYNTHETICS/gpsposition.h \
$$UAVOBJECT_SYNTHETICS/gpstime.h \
$$UAVOBJECT_SYNTHETICS/gpssatellites.h \
$$UAVOBJECT_SYNTHETICS/gpssettings.h \
$$UAVOBJECT_SYNTHETICS/gpsvelocity.h \
$$UAVOBJECT_SYNTHETICS/positionactual.h \
$$UAVOBJECT_SYNTHETICS/flightbatterystate.h \
$$UAVOBJECT_SYNTHETICS/homelocation.h \
@ -112,6 +114,8 @@ SOURCES += $$UAVOBJECT_SYNTHETICS/accessorydesired.cpp \
$$UAVOBJECT_SYNTHETICS/gpsposition.cpp \
$$UAVOBJECT_SYNTHETICS/gpstime.cpp \
$$UAVOBJECT_SYNTHETICS/gpssatellites.cpp \
$$UAVOBJECT_SYNTHETICS/gpssettings.cpp \
$$UAVOBJECT_SYNTHETICS/gpsvelocity.cpp \
$$UAVOBJECT_SYNTHETICS/positionactual.cpp \
$$UAVOBJECT_SYNTHETICS/flightbatterystate.cpp \
$$UAVOBJECT_SYNTHETICS/homelocation.cpp \