#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 . #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