First Commit

This commit is contained in:
Nigreon 2020-07-08 23:46:02 +02:00
commit d9897cb710
110 changed files with 21617 additions and 0 deletions

View file

@ -0,0 +1,14 @@
#ifndef PUBX_CFG_H
#define PUBX_CFG_H
//------------------------------------------------------------
// Enable/disable the parsing of specific proprietary NMEA sentences.
//
// Configuring out a sentence prevents its fields from being parsed.
// However, the sentence type may still be recognized by /decode/ and
// stored in member /nmeaMessage/. No valid flags would be available.
#define NMEAGPS_PARSE_PUBX_00
//#define NMEAGPS_PARSE_PUBX_04
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,347 @@
#ifndef _UBXGPS_H_
#define _UBXGPS_H_
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS 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.
//
// NeoGPS 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 NeoGPS. If not, see <http://www.gnu.org/licenses/>.
#include "NMEAGPS_cfg.h"
// Disable the entire file if derived types are not allowed.
#ifdef NMEAGPS_DERIVED_TYPES
#include "ublox/ubxNMEA.h"
#include "ublox/ubxmsg.h"
#include "GPSTime.h"
#include "ublox/ubx_cfg.h"
#if !defined(UBLOX_PARSE_STATUS) & !defined(UBLOX_PARSE_TIMEGPS) & \
!defined(UBLOX_PARSE_TIMEUTC) & !defined(UBLOX_PARSE_POSLLH) & \
!defined(UBLOX_PARSE_DOP) & !defined(UBLOX_PARSE_PVT) & \
!defined(UBLOX_PARSE_VELNED) & !defined(UBLOX_PARSE_SVINFO) & \
!defined(UBLOX_PARSE_HNR_PVT)
#warning No UBX binary messages enabled: ubloxGPS class not defined.
#else
#include <Stream.h>
#include <stddef.h>
// NOTE: millis() is used for ACK timing
class ubloxGPS : public UBLOXGPS_BASE
{
ubloxGPS & operator =( const ubloxGPS & );
ubloxGPS( const ubloxGPS & );
ubloxGPS();
public:
// Constructor needs to know the device to handle the UBX binary protocol
ubloxGPS( Stream *device )
:
storage( (ublox::msg_t *) NULL ),
reply( (ublox::msg_t *) NULL ),
reply_expected( false ),
ack_expected( false ),
m_device( device )
{};
// ublox binary UBX message type.
enum ubx_msg_t {
UBX_MSG = UBLOXGPS_BASE_LAST_MSG+1
};
static const nmea_msg_t UBX_FIRST_MSG = (nmea_msg_t) UBX_MSG;
static const nmea_msg_t UBX_LAST_MSG = (nmea_msg_t) UBX_MSG;
//................................................................
// Process one character of ublox message. The internal state
// machine tracks what part of the sentence has been received. As the
// tracks what part of the sentence has been received so far. As the
// sentence is received, members of the /fix/ structure are updated.
// @return DECODE_COMPLETED when a sentence has been completely received.
decode_t decode( char c );
//................................................................
// Received message header. Payload is only stored if /storage/ is
// overridden for that message type. This is the UBX-specific
// version of "nmeaMessage".
ublox::msg_t & rx() { return m_rx_msg; }
//................................................................
bool enable_msg( ublox::msg_class_t msg_class, ublox::msg_id_t msg_id )
{
return send( ublox::cfg_msg_t( msg_class, msg_id, 1 ) );
}
bool disable_msg( ublox::msg_class_t msg_class, ublox::msg_id_t msg_id )
{
return send( ublox::cfg_msg_t( msg_class, msg_id, 0 ) );
}
//................................................................
// Send a message (non-blocking).
// Although multiple /send_request/s can be issued,
// all replies will be handled identically.
bool send_request( const ublox::msg_t & msg )
{
write( msg );
return true;
}
bool send_request_P( const ublox::msg_t & msg )
{
write_P( msg );
return true;
}
//................................................................
// Send a message and wait for a reply (blocking).
// No event will be generated for the reply.
// If /msg/ is a UBX_CFG, this will wait for a UBX_CFG_ACK/NAK
// and return true if ACKed.
// If /msg/ is a poll, this will wait for the reply.
// If /msg/ is neither, this will return true immediately.
// If /msg/ is both, this will wait for both the reply and the ACK/NAK.
// If /storage_for/ is implemented, those messages will continue
// to be saved while waiting for this reply.
bool send( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL );
bool send_P( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL );
using NMEAGPS::send_P;
//................................................................
// Ask for a specific message (non-blocking).
// The message will receive be received later.
// See also /send_request/.
bool poll_request( const ublox::msg_t & msg )
{
ublox::msg_t poll_msg( msg.msg_class, msg.msg_id, 0 );
return send_request( poll_msg );
}
bool poll_request_P( const ublox::msg_t & msg )
{
ublox::msg_t poll_msg( (ublox::msg_class_t) pgm_read_byte( &msg.msg_class ),
(ublox::msg_id_t) pgm_read_byte( &msg.msg_id ), 0 );
return send_request( poll_msg );
}
//................................................................
// Ask for a specific message (blocking).
// See also /send/.
bool poll( ublox::msg_t & msg )
{
ublox::msg_t poll_msg( msg.msg_class, msg.msg_id, 0 );
return send( poll_msg, &msg );
}
bool poll_P( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL )
{
ublox::msg_t poll_msg( (ublox::msg_class_t) pgm_read_byte( &msg.msg_class ),
(ublox::msg_id_t) pgm_read_byte( &msg.msg_id ), 0 );
return send( poll_msg, reply_msg );
}
//................................................................
// Return the Stream that was passed into the constructor.
Stream *Device() const { return (Stream *)m_device; };
protected:
/*
* Some UBX messages can be larger than 256 bytes, so
* hide the 8-bit NMEAGPS::chrCount with this 16-bit version.
*/
uint16_t chrCount;
bool parseField( char chr );
enum ubxState_t {
UBX_IDLE = NMEA_IDLE,
UBX_SYNC2 = NMEA_LAST_STATE+1,
UBX_HEAD,
UBX_RECEIVING_DATA,
UBX_CRC_A,
UBX_CRC_B
};
static const ubxState_t UBX_FIRST_STATE = UBX_SYNC2;
static const ubxState_t UBX_LAST_STATE = UBX_CRC_B;
inline void write
( uint8_t c, uint8_t & crc_a, uint8_t & crc_b ) const
{
m_device->print( (char) c );
crc_a += c;
crc_b += crc_a;
};
void write( const ublox::msg_t & msg );
void write_P( const ublox::msg_t & msg );
//................................................................
// When the processing style is polling (not interrupt), this
// should be called frequently by any internal methods that block
// to make sure received chars continue to be processed.
virtual void run()
{
if (processing_style == PS_POLLING)
while (Device()->available())
handle( Device()->read() );
// else
// handled by interrupts
}
void wait_for_idle();
bool wait_for_ack();
// NOTE: /run/ is called from these blocking functions
bool waiting() const
{
return (ack_expected && (!ack_received && !nak_received)) ||
(reply_expected && !reply_received);
}
bool receiving() const
{
return (rxState != (rxState_t)UBX_IDLE) || (m_device && m_device->available());
}
// Override this if the contents of a particular message need to be saved.
// This may execute in an interrupt context, so be quick!
// NOTE: the ublox::msg_t.length will get stepped on, so you may need to
// set it every time if you are using a union for your storage.
virtual ublox::msg_t *storage_for( const ublox::msg_t & rx_msg )
{ return (ublox::msg_t *) NULL; }
virtual bool intervalCompleted() const
{
return ((nmeaMessage == (nmea_msg_t) UBX_MSG) &&
(m_rx_msg.msg_class == UBX_LAST_MSG_CLASS_IN_INTERVAL) &&
(m_rx_msg.msg_id == UBX_LAST_MSG_ID_IN_INTERVAL))
||
((nmeaMessage != (nmea_msg_t) UBX_MSG) &&
NMEAGPS::intervalCompleted());
}
private:
ublox::msg_t *storage; // cached ptr to hold a received msg.
// Storage for a specific received message.
// Used internally by send & poll variants.
// Checked and used before /storage_for/ is called.
ublox::msg_t *reply;
struct {
bool reply_expected NEOGPS_BF(1);
bool reply_received NEOGPS_BF(1);
bool ack_expected NEOGPS_BF(1);
bool ack_received NEOGPS_BF(1);
bool nak_received NEOGPS_BF(1);
bool ack_same_as_sent NEOGPS_BF(1);
} NEOGPS_PACKED;
struct ublox::msg_hdr_t sent;
struct rx_msg_t : ublox::msg_t
{
uint8_t crc_a; // accumulated as packet received
uint8_t crc_b; // accumulated as packet received
rx_msg_t()
{
init();
}
void init()
{
msg_class = ublox::UBX_UNK;
msg_id = ublox::UBX_ID_UNK;
length = 0;
crc_a = 0;
crc_b = 0;
}
} NEOGPS_PACKED;
rx_msg_t m_rx_msg;
void rxBegin();
bool rxEnd();
static const uint8_t SYNC_1 = 0xB5;
static const uint8_t SYNC_2 = 0x62;
Stream *m_device;
bool parseNavStatus ( uint8_t chr );
bool parseNavDOP ( uint8_t chr );
bool parseNavPosLLH ( uint8_t chr );
bool parseNavPvt ( uint8_t chr );
bool parseNavVelNED ( uint8_t chr );
bool parseNavTimeGPS( uint8_t chr );
bool parseNavTimeUTC( uint8_t chr );
bool parseNavSVInfo ( uint8_t chr );
bool parseHnrPvt( uint8_t chr );
bool parseFix( uint8_t c );
bool parseTOW( uint8_t chr )
{
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE)
if (chrCount == 0) {
m_fix.valid.date =
m_fix.valid.time = false;
}
((uint8_t *) &m_fix.dateTime)[ chrCount ] = chr;
if (chrCount == 3) {
uint32_t tow = *((uint32_t *) &m_fix.dateTime);
//trace << PSTR("@ ") << tow;
uint16_t ms;
if (GPSTime::from_TOWms( tow, m_fix.dateTime, ms )) {
m_fix.dateTime_cs = ms / 10;
m_fix.valid.time = true;
m_fix.valid.date = true;
} else
m_fix.dateTime.init();
//trace << PSTR(".") << m_fix.dateTime_cs;
}
#endif
return true;
}
} NEOGPS_PACKED;
#endif // UBX messages enabled
#endif // NMEAGPS_DERIVED_TYPES enabled
#endif

View file

@ -0,0 +1,209 @@
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS 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.
//
// NeoGPS 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 NeoGPS. If not, see <http://www.gnu.org/licenses/>.
#include "ublox/ubxNMEA.h"
// Disable the entire file if derived types are not allowed,
// *or* if no PUBX messages are enabled.
#if defined( NMEAGPS_DERIVED_TYPES) & \
(defined(NMEAGPS_PARSE_PUBX_00) | defined(NMEAGPS_PARSE_PUBX_04))
//---------------------------------------------
bool ubloxNMEA::parseField(char chr)
{
if (nmeaMessage >= (nmea_msg_t) PUBX_FIRST_MSG) {
switch (nmeaMessage) {
case PUBX_00: return parsePUBX_00( chr );
#if defined(NMEAGPS_PARSE_PUBX_04) | defined(NMEAGPS_RECOGNIZE_ALL)
case PUBX_04: return parsePUBX_04( chr );
#endif
default:
break;
}
} else
// Delegate
return NMEAGPS::parseField(chr);
return true;
} // parseField
//----------------------------
bool ubloxNMEA::parsePUBX_00( char chr )
{
bool ok = true;
switch (fieldIndex) {
case 1:
// The first field is actually a message subtype
if (chrCount == 0)
ok = (chr == '0');
else if (chrCount == 1) {
switch (chr) {
#if defined(NMEAGPS_PARSE_PUBX_00) | defined(NMEAGPS_RECOGNIZE_ALL)
case '0': break;
#endif
#if defined(NMEAGPS_PARSE_PUBX_04) | defined(NMEAGPS_RECOGNIZE_ALL)
case '4': nmeaMessage = (nmea_msg_t) PUBX_04; break;
#endif
default : ok = false;
}
} else // chrCount > 1
ok = (chr == ',');
break;
#ifdef NMEAGPS_PARSE_PUBX_00
case 2: return parseTime( chr );
PARSE_LOC(3);
case 7: return parseAlt( chr );
case 8: return parseFix( chr );
case 9: // use Horizontal accuracy for both lat and lon errors
#if defined(GPS_FIX_LAT_ERR)
ok = parse_lat_err( chr );
#if defined(GPS_FIX_LON_ERR)
// When the lat_err field is finished,
// copy it to the lon_err field.
if (chr == ',') {
m_fix.valid.lon_err = m_fix.valid.lat_err;
if (m_fix.valid.lon_err)
m_fix.lon_err_cm = m_fix.lat_err_cm;
}
#endif
#elif defined(GPS_FIX_LON_ERR)
ok = parse_lon_err( chr );
#endif
break;
case 10: return parse_alt_err( chr ); // vertical accuracy
case 11:
#ifdef GPS_FIX_SPEED
ok = parseSpeed( chr ); // PUBX,00 provides speed in km/h!
if ((chr == ',') && m_fix.valid.speed) {
uint32_t kph = m_fix.spd.int32_000();
uint32_t nmiph = (kph * 1000) / gps_fix::M_PER_NMI;
m_fix.spd.whole = nmiph / 1000;
m_fix.spd.frac = (nmiph - m_fix.spd.whole*1000);
// Convert to Nautical Miles/Hour
}
#endif
break;
case 12: return parseHeading( chr );
case 13: return parseVelocityDown( chr );
case 15: return parseHDOP( chr );
case 16: return parseVDOP( chr );
case 18: return parseSatellites( chr );
#endif
}
return ok;
} // parsePUBX_00
//---------------------------------------------
bool ubloxNMEA::parsePUBX_04( char chr )
{
#ifdef NMEAGPS_PARSE_PUBX_04
switch (fieldIndex) {
case 2: return parseTime( chr );
case 3: return parseDDMMYY( chr );
}
#endif
return true;
} // parsePUBX_04
//---------------------------------------------
bool ubloxNMEA::parseFix( char chr )
{
if (chrCount == 0) {
NMEAGPS_INVALIDATE( status );
if (chr == 'N')
m_fix.status = gps_fix::STATUS_NONE;
else if (chr == 'T')
m_fix.status = gps_fix::STATUS_TIME_ONLY;
else if (chr == 'R')
m_fix.status = gps_fix::STATUS_EST;
else if (chr == 'G')
m_fix.status = gps_fix::STATUS_STD;
else if (chr == 'D')
m_fix.status = gps_fix::STATUS_DGPS;
} else if (chrCount == 1) {
if (((chr == 'T') && (m_fix.status == gps_fix::STATUS_TIME_ONLY)) ||
((chr == 'K') && (m_fix.status == gps_fix::STATUS_EST)) ||
(((chr == '2') || (chr == '3')) &&
((m_fix.status == gps_fix::STATUS_STD) ||
(m_fix.status == gps_fix::STATUS_DGPS))) ||
((chr == 'F') && (m_fix.status == gps_fix::STATUS_NONE)))
// status based on first char was ok guess
m_fix.valid.status = true;
else if ((chr == 'R') && (m_fix.status == gps_fix::STATUS_DGPS)) {
m_fix.status = gps_fix::STATUS_EST; // oops, was DR instead
m_fix.valid.status = true;
}
}
return true;
}
//---------------------------------------------
bool ubloxNMEA::parseVelocityDown( char chr )
{
#ifdef GPS_FIX_VELNED
if (chrCount == 0)
NMEAGPS_INVALIDATE( velned );
// Checks for alias size.
char test[ (int)sizeof(m_fix.velocity_down) - (int)sizeof(gps_fix::whole_frac) ];
gps_fix::whole_frac *temp = (gps_fix::whole_frac *) &m_fix.velocity_down; // an alias for parsing
if (parseFloat( *temp, chr, 3 )) { // 0.001 m/s
if (chr == ',') {
// convert the temporary whole_frac values in place
m_fix.valid.velned = (chrCount > 0);
if (m_fix.valid.velned) {
m_fix.velocity_down = (temp->int32_000() + 5) / 10L; // mm/s to cm/s
}
}
}
#endif
return true;
} // parseVelocityDown
#endif // DERIVED types and at least one PUBX message enabled

View file

@ -0,0 +1,113 @@
#ifndef _UBXNMEA_H_
#define _UBXNMEA_H_
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS 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.
//
// NeoGPS 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 NeoGPS. If not, see <http://www.gnu.org/licenses/>.
#include "NMEAGPS_cfg.h"
// Disable the entire file if derived types are not allowed.
#ifdef NMEAGPS_DERIVED_TYPES
#include "NMEAGPS.h"
#include "PUBX_cfg.h"
// Ublox proprietary messages do not have a message type. These
// messages start with "$PUBX," which ends with the manufacturer ID. The
// message type is actually specified by the first numeric field. In order
// to parse these messages, /parse_mfr_ID/ must be overridden to set the
// /nmeaMessage/ to PUBX_00 during /parseCommand/. When the first numeric
// field is completed by /parseField/, it may change /nmeamessage/ to one
// of the other PUBX message types.
#if !defined(NMEAGPS_PARSE_PUBX_00) & !defined(NMEAGPS_PARSE_PUBX_04)
// No ublox Proprietary messages defined, ignore rest of file.
#define UBLOXGPS_BASE NMEAGPS
#define UBLOXGPS_BASE_LAST_MSG NMEA_LAST_MSG
#else
#define UBLOXGPS_BASE ubloxNMEA
#define UBLOXGPS_BASE_LAST_MSG PUBX_LAST_MSG
#if !defined(NMEAGPS_PARSE_PROPRIETARY)
#error NMEAGPS_PARSE_PROPRIETARY must be defined in NMEAGPS_cfg.h in order to parse PUBX messages!
#endif
#if !defined(NMEAGPS_PARSE_MFR_ID)
#error NMEAGPS_PARSE_MFR_ID must be defined in NMEAGPS_cfg.h in order to parse PUBX messages!
#endif
//=============================================================
// NMEA 0183 Parser for ublox Neo-6 GPS Modules.
//
// @section Limitations
// Very limited support for ublox proprietary NMEA messages.
// Only NMEA messages of types PUBX,00 and PUBX,04 are parsed.
//
class ubloxNMEA : public NMEAGPS
{
ubloxNMEA( const ubloxNMEA & );
public:
ubloxNMEA() {};
/** ublox proprietary NMEA message types. */
enum pubx_msg_t {
PUBX_00 = NMEA_LAST_MSG+1,
#if defined(NMEAGPS_PARSE_PUBX_04) | defined(NMEAGPS_RECOGNIZE_ALL)
PUBX_04,
#endif
PUBX_END
};
static const nmea_msg_t PUBX_FIRST_MSG = (nmea_msg_t) PUBX_00;
static const nmea_msg_t PUBX_LAST_MSG = (nmea_msg_t) (PUBX_END-1);
protected:
bool parseMfrID( char chr )
{ bool ok;
switch (chrCount) {
case 1: ok = (chr == 'U'); break;
case 2: ok = (chr == 'B'); break;
default: if (chr == 'X') {
ok = true;
nmeaMessage = (nmea_msg_t) PUBX_00;
} else
ok = false;
break;
}
return ok;
};
bool parsePUBX_00( char chr );
bool parsePUBX_04( char chr );
bool parseField( char chr );
bool parseFix( char chr );
bool parseVelocityDown( char chr );
} NEOGPS_PACKED;
#endif // at least one PUBX message enabled
#endif // NMEAGPS_DERIVED_TYPES enabled
#endif

View file

@ -0,0 +1,74 @@
#ifndef UBX_CFG_H
#define UBX_CFG_H
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS 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.
//
// NeoGPS 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 NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//--------------------------------------------------------------------
// Enable/disable the parsing of specific UBX messages.
//
// Configuring out a message prevents its fields from being parsed.
// However, the message type will still be recognized by /decode/ and
// stored in member /rx_msg/. No valid flags would be available.
#define UBLOX_PARSE_STATUS
#define UBLOX_PARSE_TIMEGPS
#define UBLOX_PARSE_TIMEUTC
#define UBLOX_PARSE_POSLLH
//#define UBLOX_PARSE_DOP
//#define UBLOX_PARSE_PVT
#define UBLOX_PARSE_VELNED
//#define UBLOX_PARSE_SVINFO
//#define UBLOX_PARSE_CFGNAV5
//#define UBLOX_PARSE_MONVER
//#define UBLOX_PARSE_HNR_PVT
#if defined(UBLOX_PARSE_DOP) & \
( !defined(GPS_FIX_HDOP) & \
!defined(GPS_FIX_VDOP) & \
!defined(GPS_FIX_PDOP) )
#warning UBX DOP message is enabled, but all gps_fix DOP members are disabled.
#endif
//--------------------------------------------------------------------
// Identify the last UBX message in an update interval.
// (There are two parts to a UBX message, the class and the ID.)
// For coherency, you must determine which UBX message is last!
// This section *should* pick the correct last UBX message.
#if defined(UBLOX_PARSE_HNR_PVT)
#define UBX_LAST_MSG_CLASS_IN_INTERVAL ublox::UBX_HNR
#define UBX_LAST_MSG_ID_IN_INTERVAL ublox::UBX_HNR_PVT
#else
#define UBX_LAST_MSG_CLASS_IN_INTERVAL ublox::UBX_NAV
#if defined(UBLOX_PARSE_VELNED)
#define UBX_LAST_MSG_ID_IN_INTERVAL ublox::UBX_NAV_VELNED
#elif defined(UBLOX_PARSE_DOP)
#define UBX_LAST_MSG_ID_IN_INTERVAL ublox::UBX_NAV_DOP
#elif defined(UBLOX_PARSE_POSLLH)
#define UBX_LAST_MSG_ID_IN_INTERVAL ublox::UBX_NAV_POSLLH
#elif defined(UBLOX_PARSE_STATUS)
#define UBX_LAST_MSG_ID_IN_INTERVAL ublox::UBX_NAV_STATUS
#elif defined(UBLOX_PARSE_PVT)
#define UBX_LAST_MSG_ID_IN_INTERVAL ublox::UBX_NAV_PVT
#elif defined(UBLOX_PARSE_SVINFO)
#define UBX_LAST_MSG_ID_IN_INTERVAL ublox::UBX_NAV_SVINFO
#endif
#endif
#endif

View file

@ -0,0 +1,83 @@
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS 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.
//
// NeoGPS 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 NeoGPS. If not, see <http://www.gnu.org/licenses/>.
#include "ublox/ubxGPS.h"
// Disable the entire file if derived types are not allowed.
#ifdef NMEAGPS_DERIVED_TYPES
#if !defined(UBLOX_PARSE_STATUS) & !defined(UBLOX_PARSE_TIMEGPS) & \
!defined(UBLOX_PARSE_TIMEUTC) & !defined(UBLOX_PARSE_POSLLH) & \
!defined(UBLOX_PARSE_DOP) & !defined(UBLOX_PARSE_PVT) & \
!defined(UBLOX_PARSE_VELNED) & !defined(UBLOX_PARSE_SVINFO) & \
!defined(UBLOX_PARSE_HNR_PVT)
// No UBX binary messages defined, ignore rest of file
#else
using namespace ublox;
bool ublox::configNMEA( ubloxGPS &gps, NMEAGPS::nmea_msg_t msgType, uint8_t rate )
{
static const ubx_nmea_msg_t ubx[] __PROGMEM = {
#if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL)
UBX_GPGGA,
#endif
#if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL)
UBX_GPGLL,
#endif
#if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL)
UBX_GPGSA,
#endif
#if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL)
UBX_GPGST,
#endif
#if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL)
UBX_GPGSV,
#endif
#if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL)
UBX_GPRMC,
#endif
#if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL)
UBX_GPVTG,
#endif
#if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL)
UBX_GPZDA,
#endif
};
uint8_t msg_index = (uint8_t) msgType - (uint8_t) NMEAGPS::NMEA_FIRST_MSG;
if (msg_index >= sizeof(ubx)/sizeof(ubx[0]))
return false;
msg_id_t msg_id = (msg_id_t) pgm_read_byte( &ubx[msg_index] );
return gps.send( cfg_msg_t( UBX_NMEA, msg_id, rate ) );
}
#endif // UBX messages defined
#endif // NMEAGPS_DERIVED_TYPES

View file

@ -0,0 +1,670 @@
#ifndef UBXMSG_H
#define UBXMSG_H
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS 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.
//
// NeoGPS 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 NeoGPS. If not, see <http://www.gnu.org/licenses/>.
#include "NMEAGPS_cfg.h"
// Disable the entire file if derived types are not allowed.
#ifdef NMEAGPS_DERIVED_TYPES
#include "NMEAGPS.h"
class ubloxGPS;
namespace ublox {
enum msg_class_t
{ UBX_NAV = 0x01, // Navigation results
UBX_RXM = 0x02, // Receiver Manager messages
UBX_INF = 0x04, // Informational messages
UBX_ACK = 0x05, // ACK/NAK replies to CFG messages
UBX_CFG = 0x06, // Configuration input messages
UBX_MON = 0x0A, // Monitoring messages
UBX_AID = 0x0B, // Assist Now aiding messages
UBX_TIM = 0x0D, // Timing messages
UBX_HNR = 0x28, // High rate navigation results
UBX_NMEA = 0xF0, // NMEA Standard messages
UBX_PUBX = 0xF1, // NMEA proprietary messages (PUBX)
UBX_UNK = 0xFF
} __attribute__((packed));
enum msg_id_t
{
UBX_ACK_NAK = 0x00, // Reply to CFG messages
UBX_ACK_ACK = 0x01, // Reply to CFG messages
UBX_CFG_MSG = 0x01, // Configure which messages to send
UBX_CFG_RST = 0x04, // Reset command
UBX_CFG_RATE = 0x08, // Configure message rate
UBX_CFG_NMEA = 0x17, // Configure NMEA protocol
UBX_CFG_NAV5 = 0x24, // Configure navigation engine settings
UBX_MON_VER = 0x04, // Monitor Receiver/Software version
UBX_NAV_POSLLH = 0x02, // Current Position
UBX_NAV_STATUS = 0x03, // Receiver Navigation Status
UBX_NAV_DOP = 0x04, // Dilutions of Precision
UBX_NAV_ODO = 0x09, // Odometer Solution (NEO-M8 only)
UBX_NAV_PVT = 0x07, // Position, Velocity and Time
UBX_NAV_RESETODO = 0x10, // Reset Odometer (NEO-M8 only)
UBX_NAV_VELNED = 0x12, // Current Velocity
UBX_NAV_TIMEGPS = 0x20, // Current GPS Time
UBX_NAV_TIMEUTC = 0x21, // Current UTC Time
UBX_NAV_SVINFO = 0x30, // Space Vehicle Information
UBX_HNR_PVT = 0x00, // High rate Position, Velocity and Time
UBX_ID_UNK = 0xFF
} __attribute__((packed));
struct msg_hdr_t {
msg_class_t msg_class;
msg_id_t msg_id;
bool same_kind( const msg_hdr_t & msg ) const
{ return (msg_class == msg.msg_class) && (msg_id == msg.msg_id); }
} __attribute__((packed));
struct msg_t : msg_hdr_t {
uint16_t length; // should be sizeof(this)-sizeof(msg_hdr_t)
#define UBX_MSG_LEN(msg) (sizeof(msg) - sizeof(ublox::msg_t))
msg_t()
{
length = 0;
};
msg_t( enum msg_class_t m, enum msg_id_t i, uint16_t l = 0 )
{
msg_class = m;
msg_id = i;
length = l;
}
void init()
{
uint8_t *mem = (uint8_t *) this;
memset( &mem[ sizeof(msg_t) ], 0, length );
}
} __attribute__((packed));
/**
* Configure message intervals.
*/
enum ubx_nmea_msg_t { // msg_id's for UBX_NMEA msg_class
UBX_GPGGA = 0x00,
UBX_GPGLL = 0x01,
UBX_GPGSA = 0x02,
UBX_GPGSV = 0x03,
UBX_GPRMC = 0x04,
UBX_GPVTG = 0x05,
UBX_GPGST = 0x07,
UBX_GPZDA = 0x08
} __attribute__((packed));
struct cfg_msg_t : msg_t {
msg_class_t cfg_msg_class;
msg_id_t cfg_msg;
uint8_t rate;
cfg_msg_t( msg_class_t m, msg_id_t i, uint8_t r )
: msg_t( UBX_CFG, UBX_CFG_MSG, UBX_MSG_LEN(*this) )
{
cfg_msg_class = m;
cfg_msg = i;
rate = r;
};
} __attribute__((packed));
extern bool configNMEA( ubloxGPS &gps, NMEAGPS::nmea_msg_t msgType, uint8_t rate );
// Reset command
struct cfg_reset_t : msg_t {
struct bbr_section_t
{
bool ephermeris :1;
bool almanac :1;
bool health :1;
bool klobuchard :1;
bool position :1;
bool clock_drift :1;
bool osc_param :1;
bool utc_param :1;
bool rtc :1;
bool reserved1 :2;
bool sfdr_param :1;
bool sfdr_veh_mon_param :1;
bool tct_param :1;
bool reserved2 :1;
bool autonomous_orbit_param:1;
} __attribute__((packed));
enum reset_mode_t
{
HW_RESET = 0x00,
CONTROLLED_SW_RESET = 0x01,
CONTROLLED_SW_RESET_GPS_ONLY = 0x02,
HW_RESET_AFTER_SHUTDOWN = 0x04,
CONTROLLED_GPS_STOP = 0x08,
CONTROLLED_GPS_START = 0x09
} __attribute__((packed));
bbr_section_t clear_bbr_section;
reset_mode_t reset_mode : 8;
uint8_t reserved : 8;
cfg_reset_t()
: msg_t( UBX_CFG, UBX_CFG_RST, UBX_MSG_LEN(*this) )
{ init(); }
} __attribute__((packed));
// Configure navigation rate
enum time_ref_t {
UBX_TIME_REF_UTC=0,
UBX_TIME_REF_GPS=1
} __attribute__((packed));
struct cfg_rate_t : msg_t {
uint16_t GPS_meas_rate;
uint16_t nav_rate;
enum time_ref_t time_ref:16;
cfg_rate_t( uint16_t gr, uint16_t nr, enum time_ref_t tr )
: msg_t( UBX_CFG, UBX_CFG_RATE, UBX_MSG_LEN(*this) )
{
GPS_meas_rate = gr;
nav_rate = nr;
time_ref = tr;
}
} __attribute__((packed));
// Navigation Engine Expert Settings
enum dyn_model_t {
UBX_DYN_MODEL_PORTABLE = 0,
UBX_DYN_MODEL_STATIONARY = 2,
UBX_DYN_MODEL_PEDESTRIAN = 3,
UBX_DYN_MODEL_AUTOMOTIVE = 4,
UBX_DYN_MODEL_SEA = 5,
UBX_DYN_MODEL_AIR_1G = 6,
UBX_DYN_MODEL_AIR_2G = 7,
UBX_DYN_MODEL_AIR_4G = 8
} __attribute__((packed));
enum position_fix_t {
UBX_POS_FIX_2D_ONLY = 1,
UBX_POS_FIX_3D_ONLY = 2,
UBX_POS_FIX_AUTO = 3
} __attribute__((packed));
struct cfg_nav5_t : msg_t {
struct parameter_mask_t {
bool dyn_model :1;
bool min_elev :1;
bool fix :1;
bool dr_limit :1;
bool pos_mask :1;
bool time_mask :1;
bool static_hold_thr :1;
bool dgps_timeout :1;
int _unused_ :8;
} __attribute__((packed));
union {
struct parameter_mask_t apply;
uint16_t apply_word;
} __attribute__((packed));
enum dyn_model_t dyn_model:8;
enum position_fix_t fix_mode:8;
int32_t fixed_alt; // m MSL x0.01
uint32_t fixed_alt_variance; // m^2 x0.0001
int8_t min_elev; // deg
uint8_t dr_limit; // s
uint16_t pos_dop_mask; // x0.1
uint16_t time_dop_mask; // x0.1
uint16_t pos_acc_mask; // m
uint16_t time_acc_mask; // m
uint8_t static_hold_thr; // cm/s
uint8_t dgps_timeout; // s
uint32_t always_zero_1;
uint32_t always_zero_2;
uint32_t always_zero_3;
cfg_nav5_t() : msg_t( UBX_CFG, UBX_CFG_NAV5, UBX_MSG_LEN(*this) )
{
apply_word = 0xFF00;
always_zero_1 =
always_zero_2 =
always_zero_3 = 0;
}
} __attribute__((packed));
// Geodetic Position Solution
struct nav_posllh_t : msg_t {
uint32_t time_of_week; // mS
int32_t lon; // deg * 1e7
int32_t lat; // deg * 1e7
int32_t height_above_ellipsoid; // mm
int32_t height_MSL; // mm
uint32_t horiz_acc; // mm
uint32_t vert_acc; // mm
nav_posllh_t() : msg_t( UBX_NAV, UBX_NAV_POSLLH, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
// Receiver Navigation Status
struct nav_status_t : msg_t {
uint32_t time_of_week; // mS
enum status_t {
NAV_STAT_NONE,
NAV_STAT_DR_ONLY,
NAV_STAT_2D,
NAV_STAT_3D,
NAV_STAT_GPS_DR,
NAV_STAT_TIME_ONLY
} __attribute__((packed))
status;
struct flags_t {
bool gps_fix:1;
bool diff_soln:1;
bool week:1;
bool time_of_week:1;
} __attribute__((packed))
flags;
static gps_fix::status_t to_status( enum gps_fix::status_t status, flags_t flags )
{
if (!flags.gps_fix)
return gps_fix::STATUS_NONE;
if (flags.diff_soln)
return gps_fix::STATUS_DGPS;
return status;
}
struct {
bool dgps_input:1;
bool _skip_:6;
bool map_matching:1;
} __attribute__((packed))
fix_status;
enum {
PSM_ACQUISITION,
PSM_TRACKING,
PSM_POWER_OPTIMIZED_TRACKING,
PSM_INACTIVE
}
power_safe:2; // FW > v7.01
uint32_t time_to_first_fix; // ms time tag
uint32_t uptime; // ms since startup/reset
nav_status_t() : msg_t( UBX_NAV, UBX_NAV_STATUS, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
// Dilutions of Precision
struct nav_dop_t : msg_t {
uint32_t time_of_week; // mS
uint16_t gdop; // Geometric
uint16_t pdop; // Position
uint16_t tdop; // Time
uint16_t vdop; // Vertical
uint16_t hdop; // Horizontal
uint16_t ndop; // Northing
uint16_t edop; // Easting
nav_dop_t() : msg_t( UBX_NAV, UBX_NAV_DOP, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
// Odometer Solution (NEO-M8 only)
struct nav_odo_t : msg_t {
uint8_t version;
uint8_t reserved[3];
uint32_t time_of_week; // mS
uint32_t distance; // m
uint32_t total_distance; // m
uint32_t distanceSTD; // m (1-sigma)
nav_odo_t() : msg_t( UBX_NAV, UBX_NAV_ODO, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
// Reset Odometer (NEO-M8 only)
struct nav_resetodo_t : msg_t {
// no payload, it's just a command
nav_resetodo_t() : msg_t( UBX_NAV, UBX_NAV_RESETODO, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
// Position, Velocity and Time (NEO-7 or later)
struct nav_pvt_t : msg_t {
uint32_t time_of_week; // mS
uint16_t year; // 1999..2099
uint8_t month; // 1..12
uint8_t day; // 1..31
uint8_t hour; // 0..23
uint8_t minute; // 0..59
uint8_t second; // 0..59
struct valid_t {
bool date :1;
bool time :1;
bool fully_resolved:1;
} __attribute__((packed))
valid;
uint32_t time_acc; // ns
int32_t second_frac; // ns
enum fix_t {
UBX_NAV_PVT_FIX_NONE = 0,
UBX_NAV_PVT_FIX_DEAD_RECKONING = 1,
UBX_NAV_PVT_FIX_2D = 2,
UBX_NAV_PVT_FIX_3D = 3,
UBX_NAV_PVT_FIX_GNSS_PLUS_DR = 4,
UBX_NAV_PVT_FIX_TIME = 5
} __attribute__((packed))
status;
struct flags_t {
bool validFix :1;
bool dgps :1;
uint8_t psmState :3;
} __attribute__((packed))
flags;
uint8_t reserved1;
uint8_t satellites;
int32_t lon; // deg * 1e7
int32_t lat; // deg * 1e7
int32_t height_above_ellipsoid; // mm
int32_t height_MSL; // mm
uint32_t horiz_acc; // mm
uint32_t vert_acc; // mm
int32_t vel_north; // cm/s
int32_t vel_east; // cm/s
int32_t vel_down; // cm/s
uint32_t speed_2D; // cm/s
int32_t heading; // deg * 1e5
uint32_t speed_acc; // mm/s
uint32_t heading_acc; // deg * 1e5
uint16_t pdop; // DOP * 100
uint16_t reserved2;
uint32_t reserved3;
nav_pvt_t() : msg_t( UBX_NAV, UBX_NAV_PVT, UBX_MSG_LEN(*this) ) {};
static gps_fix::status_t to_status( enum gps_fix::status_t status, fix_t pvt_status )
{
switch (pvt_status) {
case UBX_NAV_PVT_FIX_NONE :
status = gps_fix::STATUS_NONE;
break;
case UBX_NAV_PVT_FIX_DEAD_RECKONING:
status = gps_fix::STATUS_EST;
break;
case UBX_NAV_PVT_FIX_2D :
status = gps_fix::STATUS_STD;
break;
case UBX_NAV_PVT_FIX_3D :
status = gps_fix::STATUS_STD;
break;
case UBX_NAV_PVT_FIX_GNSS_PLUS_DR :
status = gps_fix::STATUS_STD;
break;
case UBX_NAV_PVT_FIX_TIME :
status = gps_fix::STATUS_TIME_ONLY;
break;
}
return status;
}
} __attribute__((packed));
// Velocity Solution in North/East/Down
struct nav_velned_t : msg_t {
uint32_t time_of_week; // mS
int32_t vel_north; // cm/s
int32_t vel_east; // cm/s
int32_t vel_down; // cm/s
uint32_t speed_3D; // cm/s
uint32_t speed_2D; // cm/s
int32_t heading; // degrees * 1e5
uint32_t speed_acc; // cm/s
uint32_t heading_acc; // degrees * 1e5
nav_velned_t() : msg_t( UBX_NAV, UBX_NAV_VELNED, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
// GPS Time Solution
struct nav_timegps_t : msg_t {
uint32_t time_of_week; // mS
int32_t fractional_ToW; // nS
int16_t week;
int8_t leap_seconds; // GPS-UTC
struct valid_t {
bool time_of_week:1;
bool week:1;
bool leap_seconds:1;
} __attribute__((packed))
valid;
nav_timegps_t() : msg_t( UBX_NAV, UBX_NAV_TIMEGPS, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
// UTC Time Solution
struct nav_timeutc_t : msg_t {
uint32_t time_of_week; // mS
uint32_t time_accuracy; // nS
int32_t fractional_ToW; // nS
uint16_t year; // 1999..2099
uint8_t month; // 1..12
uint8_t day; // 1..31
uint8_t hour; // 0..23
uint8_t minute; // 0..59
uint8_t second; // 0..59
struct valid_t {
bool time_of_week:1;
bool week_number:1;
bool UTC:1;
} __attribute__((packed))
valid;
nav_timeutc_t() : msg_t( UBX_NAV, UBX_NAV_TIMEUTC, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
// Space Vehicle Information
struct nav_svinfo_t : msg_t {
uint32_t time_of_week; // mS
uint8_t num_channels;
enum { ANTARIS_OR_4, UBLOX_5, UBLOX_6 } chipgen:8;
uint16_t reserved2;
struct sv_t {
uint8_t channel; // 255 = no channel
uint8_t id; // Satellite ID
bool used_for_nav:1;
bool diff_corr :1; // differential correction available
bool orbit_avail :1; // orbit info available
bool orbit_eph :1; // orbit info is ephemeris
bool unhealthy :1; // SV should not be used
bool orbit_alm :1; // orbit info is Almanac Plus
bool orbit_AOP :1; // orbit info is AssistNow Autonomous
bool smoothed :1; // Carrier smoothed pseudorange used
enum {
IDLE,
SEARCHING,
ACQUIRED,
UNUSABLE,
CODE_LOCK,
CODE_AND_CARRIER_LOCK_1,
CODE_AND_CARRIER_LOCK_2,
CODE_AND_CARRIER_LOCK_3
}
quality:8;
uint8_t snr; // dbHz
uint8_t elevation; // degrees
uint16_t azimuth; // degrees
uint32_t pr_res; // pseudo range residual in cm
};
// Calculate the number of bytes required to hold the
// specified number of channels.
static uint16_t size_for( uint8_t channels )
{ return sizeof(nav_svinfo_t) + (uint16_t)channels * sizeof(sv_t); }
// Initialze the msg_hdr for the specified number of channels
void init( uint8_t max_channels )
{
msg_class = UBX_NAV;
msg_id = UBX_NAV_SVINFO;
length = size_for( max_channels ) - sizeof(ublox::msg_t);
}
} __attribute__((packed));
// High Rate PVT
struct hnr_pvt_t : msg_t {
uint32_t time_of_week; // mS
uint16_t year; // 1999..2099
uint8_t month; // 1..12
uint8_t day; // 1..31
uint8_t hour; // 0..23
uint8_t minute; // 0..59
uint8_t second; // 0..59
struct valid_t {
bool date:1;
bool time:1;
bool fully_resolved:1;
} __attribute__((packed))
valid;
int32_t fractional_ToW; // nS
nav_status_t::status_t status;
struct flags_t {
bool gps_fix:1;
bool diff_soln:1;
bool week:1;
bool time_of_week:1;
bool heading_valid:1;
} __attribute__((packed))
flags;
static gps_fix::status_t to_status( enum gps_fix::status_t status, flags_t flags )
{
if (!flags.gps_fix)
return gps_fix::STATUS_NONE;
if (flags.diff_soln)
return gps_fix::STATUS_DGPS;
return status;
}
uint16_t reserved1;
int32_t lon; // deg * 1e7
int32_t lat; // deg * 1e7
int32_t height_above_ellipsoid; // mm
int32_t height_MSL; // mm
int32_t speed_2D; // mm/s
int32_t speed_3D; // mm/s
int32_t heading_motion; // degrees * 1e5
int32_t heading_vehicle; // degrees * 1e5
uint32_t horiz_acc; // mm
uint32_t vert_acc; // mm
uint32_t speed_acc; // mm/s
uint32_t heading_acc; // degrees * 1e5
uint32_t reserved4;
hnr_pvt_t() : msg_t( UBX_HNR, UBX_HNR_PVT, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
struct cfg_nmea_t : msg_t {
bool always_output_pos :1; // invalid or failed
bool output_invalid_pos :1;
bool output_invalid_time:1;
bool output_invalid_date:1;
bool use_GPS_only :1;
bool output_heading :1; // even if frozen
bool __not_used__ :2;
enum {
NMEA_V_2_1 = 0x21,
NMEA_V_2_3 = 0x23,
NMEA_V_4_0 = 0x40, // Neo M8 family only
NMEA_V_4_1 = 0x41 // Neo M8 family only
}
nmea_version : 8;
enum {
SV_PER_TALKERID_UNLIMITED = 0,
SV_PER_TALKERID_8 = 8,
SV_PER_TALKERID_12 = 12,
SV_PER_TALKERID_16 = 16
}
num_sats_per_talker_id : 8;
bool compatibility_mode:1;
bool considering_mode :1;
bool max_line_length_82:1; // Neo M8 family only
uint8_t __not_used_1__ :5;
cfg_nmea_t() : msg_t( UBX_CFG, UBX_CFG_NMEA, UBX_MSG_LEN(*this) ) {};
} __attribute__((packed));
struct cfg_nmea_v1_t : cfg_nmea_t {
bool filter_gps :1;
bool filter_sbas :1;
uint8_t __not_used_2__:2;
bool filter_qzss :1;
bool filter_glonass:1;
bool filter_beidou :1;
uint32_t __not_used_3__:25;
bool proprietary_sat_numbering; // for non-NMEA satellites
enum {
MAIN_TALKER_ID_COMPUTED,
MAIN_TALKER_ID_GP,
MAIN_TALKER_ID_GL,
MAIN_TALKER_ID_GN,
MAIN_TALKER_ID_GA,
MAIN_TALKER_ID_GB
}
main_talker_id : 8;
bool gsv_uses_main_talker_id; // false means COMPUTED
enum cfg_nmea_version_t {
CFG_NMEA_V_0, // length = 12
CFG_NMEA_V_1 // length = 20 (default)
}
version : 8;
// Remaining fields are CFG_NMEA_V_1 only!
char beidou_talker_id[2]; // NULs mean default
uint8_t __reserved__[6];
cfg_nmea_v1_t( cfg_nmea_version_t v = CFG_NMEA_V_1 )
{
version = v;
if (version == CFG_NMEA_V_0)
length = 12;
else {
length = 20;
for (uint8_t i=0; i<8;) // fills 'reserved' too
beidou_talker_id[i++] = 0;
}
};
} __attribute__((packed));
};
#endif // NMEAGPS_DERIVED_TYPES enabled
#endif