Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 91 additions & 5 deletions src/gps/GPS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,20 @@ uint8_t GPS::makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_siz
return (payload_size + 10);
}

// Create our custom CAS packet, with specified Dynamic Mode from GPS profile
uint8_t GPS::makeCASNAVXPacket(uint8_t dynamicMode)
{
// Base configuration (mutable copy of _message_CAS_CFG_NAVX_CONF)
static uint8_t config[sizeof(_message_CAS_CFG_NAVX_CONF)];
memcpy(config, _message_CAS_CFG_NAVX_CONF, sizeof(_message_CAS_CFG_NAVX_CONF));

// Update Dynamic Mode (index 4)
config[4] = dynamicMode;

// Create CAS packet with updated configuration
return makeCASPacket(0x06, 0x07, sizeof(config), config);
}

GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
{
uint8_t buffer[768] = {0};
Expand Down Expand Up @@ -535,8 +549,21 @@ bool GPS::setup()
// only ask for RMC and GGA
_serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
delay(250);
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
_serial_gps->write("$PCAS11,3*1E\r\n");

// Set Dynamic Mode based on GPS Profile
if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_FIXED_POSITION) {
_serial_gps->write("$PCAS11,1*1C\r\n");
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_PEDESTRIAN) {
_serial_gps->write("$PCAS11,2*1F\r\n");
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_VEHICLE) {
_serial_gps->write("$PCAS11,3*1E\r\n");
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_AIRBORNE) {
_serial_gps->write("$PCAS11,6*1B\r\n");
} else {
// Default to pedestrian mode
_serial_gps->write("$PCAS11,2*1F\r\n");
}

delay(250);
} else if (gnssModel == GNSS_MODEL_MTK_L76B) {
// Waveshare Pico-GPS hat uses the L76B with 9600 baud
Expand All @@ -555,8 +582,19 @@ bool GPS::setup()
// Enable PPS for 2D/3D fix only
_serial_gps->write("$PMTK285,3,100*3F\r\n");
delay(250);
// Switch to Fitness Mode, for running and walking purpose with low speed (<5 m/s)
_serial_gps->write("$PMTK886,1*29\r\n");
// Set Dynamic Mode based on GPS Profile
if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_FIXED_POSITION) {
_serial_gps->write("$PMTK886,1*29\r\n"); // No fixed mode, so limit to pedestrian.
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_PEDESTRIAN) {
_serial_gps->write("$PMTK886,1*29\r\n");
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_VEHICLE) {
_serial_gps->write("$PMTK886,0*28\r\n");
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_AIRBORNE) {
_serial_gps->write("$PMTK886,3*2B\r\n"); // technically balloon mode, since Aviation mode has 10 ft cieling
} else {
// Default to Fitness Mode, for running and walking purpose with low speed (<5 m/s)
_serial_gps->write("$PMTK886,1*29\r\n");
}
delay(250);
} else if (gnssModel == GNSS_MODEL_MTK_PA1010D) {
// PA1010D is used in the Pimoroni GPS board.
Expand All @@ -571,6 +609,13 @@ bool GPS::setup()
// Enable SBAS / WAAS
_serial_gps->write("$PMTK301,2*2E\r\n");
delay(250);
// PA1010D doesn't support dynamic modes,
// we set FIXED_POSITION so it doesn't change anything if speed < 2 m/s (maximum value supported)
if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_FIXED_POSITION) {
_serial_gps->write("$PMTK386,2.0*3F\r\n");
} else {
_serial_gps->write("$PMTK386,0.0*3C\r\n"); // turn off if we're not in fixed position mode
}
} else if (gnssModel == GNSS_MODEL_MTK_PA1616S) {
// PA1616S is used in some GPS breakout boards from Adafruit
// PA1616S does not have GLONASS capability. PA1616D does, but is not implemented here.
Expand All @@ -583,9 +628,28 @@ bool GPS::setup()
// Enable SBAS / WAAS
_serial_gps->write("$PMTK301,2*2E\r\n");
delay(250);
// PA1616S doesn't support dynamic modes,
// we set FIXED_POSITION so it doesn't change anything if speed < 2 m/s (maximum value supported)
if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_FIXED_POSITION) {
_serial_gps->write("$PMTK386,2.0*3F\r\n");
} else {
_serial_gps->write("$PMTK386,0.0*3C\r\n"); // turn off if we're not in fixed position mode
}

} else if (gnssModel == GNSS_MODEL_ATGM336H) {
// Set the intial configuration of the device - these _should_ work for most AT6558 devices
msglen = makeCASPacket(0x06, 0x07, sizeof(_message_CAS_CFG_NAVX_CONF), _message_CAS_CFG_NAVX_CONF);
if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_FIXED_POSITION) {
msglen = makeCASNAVXPacket(0x01);
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_PEDESTRIAN) {
msglen = makeCASNAVXPacket(0x02);
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_VEHICLE) {
msglen = makeCASNAVXPacket(0x03);
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_AIRBORNE) {
msglen = makeCASNAVXPacket(0x06); // Airborne <2g acceleration. OK for jets, need 0x07 for rockets.
} else {
// Default to pedestrian mode
msglen = makeCASNAVXPacket(0x02);
}
_serial_gps->write(UBXscratch, msglen);
if (getACKCas(0x06, 0x07, 250) != GNSS_RESPONSE_OK) {
LOG_WARN("ATGM336H: Could not set Config");
Expand Down Expand Up @@ -629,6 +693,13 @@ bool GPS::setup()
delay(250);
_serial_gps->write("$CFGMSG,6,1,0\r\n");
delay(250);
// UC6580 doesn't support dynamic modes (UM620 does - but we've never seen it in the wild),
// we set FIXED_POSITION so it doesn't change anything if speed < 31500 cm/s (maximum value supported)
if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_FIXED_POSITION) {
_serial_gps->write("$CFGDYN,h11,0,51500\r\n");
} else {
_serial_gps->write("$CFGDYN,h11,0,0\r\n"); // turn off if we're not in fixed position mode
}
} else if (IS_ONE_OF(gnssModel, GNSS_MODEL_AG3335, GNSS_MODEL_AG3352)) {

if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_IN ||
Expand All @@ -652,6 +723,21 @@ bool GPS::setup()

delay(250);
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration

// Set Dynamic Mode based on GPS Profile
if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_FIXED_POSITION) {
_serial_gps->write("$PAIR080,4*2A\r\n");
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_PEDESTRIAN) {
_serial_gps->write("$PAIR080,1*2F\r\n");
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_VEHICLE) {
_serial_gps->write("$PAIR080,0*2E\r\n"); // technically 'normal' mode
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_AIRBORNE) {
_serial_gps->write("$PAIR080,3*2D\r\n"); // technically balloon mode
} else {
// Default to pedestrian mode
_serial_gps->write("$PAIR080,1*2F\r\n");
}

} else if (gnssModel == GNSS_MODEL_UBLOX6) {
clearBuffer();
SEND_UBX_PACKET(0x06, 0x02, _message_DISABLE_TXT_INFO, "disable text info messages", 500);
Expand Down
1 change: 1 addition & 0 deletions src/gps/GPS.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class GPS : private concurrency::OSThread
// Create a ublox packet for editing in memory
uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
uint8_t makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
uint8_t makeCASNAVXPacket(uint8_t dynamicMode);

// scratch space for creating ublox packets
uint8_t UBXscratch[250] = {0};
Expand Down
126 changes: 80 additions & 46 deletions src/mesh/NodeDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -623,28 +623,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
config.security.private_key.size = 0;
}
config.security.public_key.size = 0;
#ifdef PIN_GPS_EN
config.position.gps_en_gpio = PIN_GPS_EN;
#endif
#if defined(USERPREFS_CONFIG_GPS_MODE)
config.position.gps_mode = USERPREFS_CONFIG_GPS_MODE;
#elif !HAS_GPS || GPS_DEFAULT_NOT_PRESENT
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
#elif !defined(GPS_RX_PIN)
if (config.position.rx_gpio == 0)
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
else
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
#else
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
#endif
#ifdef USERPREFS_CONFIG_SMART_POSITION_ENABLED
config.position.position_broadcast_smart_enabled = USERPREFS_CONFIG_SMART_POSITION_ENABLED;
#else
config.position.position_broadcast_smart_enabled = true;
#endif
config.position.broadcast_smart_minimum_distance = 100;
config.position.broadcast_smart_minimum_interval_secs = 30;

if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER)
config.device.node_info_broadcast_secs = default_node_info_broadcast_secs;
config.security.serial_enabled = true;
Expand Down Expand Up @@ -691,12 +670,6 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
config.bluetooth.mode = hasScreen ? meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
#endif
// for backward compat, default position flags are ALT+MSL
config.position.position_flags =
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
meshtastic_Config_PositionConfig_PositionFlags_DOP | meshtastic_Config_PositionConfig_PositionFlags_SATINVIEW);

// Set default value for 'Mesh via UDP'
#if HAS_UDP_MULTICAST
#ifdef USERPREFS_NETWORK_ENABLED_PROTOCOLS
Expand Down Expand Up @@ -746,21 +719,11 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
#endif

initConfigIntervals();
initConfigGPS();
}

void NodeDB::initConfigIntervals()
{
#ifdef USERPREFS_CONFIG_GPS_UPDATE_INTERVAL
config.position.gps_update_interval = USERPREFS_CONFIG_GPS_UPDATE_INTERVAL;
#else
config.position.gps_update_interval = default_gps_update_interval;
#endif
#ifdef USERPREFS_CONFIG_POSITION_BROADCAST_INTERVAL
config.position.position_broadcast_secs = USERPREFS_CONFIG_POSITION_BROADCAST_INTERVAL;
#else
config.position.position_broadcast_secs = default_broadcast_interval_secs;
#endif

config.power.ls_secs = default_ls_secs;
config.power.min_wake_secs = default_min_wake_secs;
config.power.sds_secs = default_sds_secs;
Expand All @@ -775,6 +738,77 @@ void NodeDB::initConfigIntervals()
#endif
}

void NodeDB::initConfigGPS()
{
#ifdef PIN_GPS_EN
config.position.gps_en_gpio = PIN_GPS_EN;
#endif
#if defined(USERPREFS_CONFIG_GPS_MODE)
config.position.gps_mode = USERPREFS_CONFIG_GPS_MODE;
#elif !HAS_GPS || GPS_DEFAULT_NOT_PRESENT
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
#elif !defined(GPS_RX_PIN)
if (config.position.rx_gpio == 0)
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
else
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
#else
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
#endif
#ifdef USERPREFS_CONFIG_SMART_POSITION_ENABLED
config.position.position_broadcast_smart_enabled = USERPREFS_CONFIG_SMART_POSITION_ENABLED;
#else
config.position.position_broadcast_smart_enabled = true;
#endif

const uint32_t base_flags =
(meshtastic_Config_PositionConfig_PositionFlags_DOP | meshtastic_Config_PositionConfig_PositionFlags_SATINVIEW |
meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE);

if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_FIXED_POSITION ||
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER, meshtastic_Config_DeviceConfig_Role_ROUTER_LATE,
meshtastic_Config_DeviceConfig_Role_CLIENT_BASE)) {
config.position.position_flags = base_flags;
config.position.position_broadcast_smart_enabled = false;
config.position.position_broadcast_secs = ONE_DAY / 2;
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_PEDESTRIAN) {
config.position.position_flags = (base_flags | meshtastic_Config_PositionConfig_PositionFlags_SPEED |
meshtastic_Config_PositionConfig_PositionFlags_HEADING);
config.position.broadcast_smart_minimum_distance = 50;
config.position.broadcast_smart_minimum_interval_secs = 60;
config.position.position_broadcast_secs = 900;
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_VEHICLE) {

config.position.position_flags = (base_flags | meshtastic_Config_PositionConfig_PositionFlags_SPEED |
meshtastic_Config_PositionConfig_PositionFlags_HEADING);
config.position.broadcast_smart_minimum_distance = 500;
config.position.broadcast_smart_minimum_interval_secs = 120;
config.position.position_broadcast_secs = 900;
} else if (config.position.gps_profile == meshtastic_Config_PositionConfig_GpsProfile_AIRBORNE) {
config.position.position_flags =
(base_flags | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
meshtastic_Config_PositionConfig_PositionFlags_GEOIDAL_SEPARATION |
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING);
config.position.broadcast_smart_minimum_distance = 200;
config.position.broadcast_smart_minimum_interval_secs = 60;
config.position.position_broadcast_secs = 900;

} else { // original settings
config.position.position_flags =
(base_flags | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING);
config.position.broadcast_smart_minimum_distance = 100;
config.position.broadcast_smart_minimum_interval_secs = 30;
config.position.position_broadcast_secs = 900;
}
#ifdef USERPREFS_CONFIG_GPS_UPDATE_INTERVAL
config.position.gps_update_interval = USERPREFS_CONFIG_GPS_UPDATE_INTERVAL;
#endif
#ifdef USERPREFS_CONFIG_POSITION_BROADCAST_INTERVAL
config.position.position_broadcast_secs = USERPREFS_CONFIG_POSITION_BROADCAST_INTERVAL;
#endif
}

void NodeDB::installDefaultModuleConfig()
{
LOG_INFO("Install default ModuleConfig");
Expand Down Expand Up @@ -905,6 +939,7 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
if (role == meshtastic_Config_DeviceConfig_Role_ROUTER) {
initConfigIntervals();
initModuleConfigIntervals();
initConfigGPS();
moduleConfig.telemetry.device_update_interval = default_telemetry_broadcast_interval_secs;
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY;
owner.has_is_unmessagable = true;
Expand Down Expand Up @@ -1214,11 +1249,10 @@ void NodeDB::loadFromDisk()
&meshtastic_DeviceState_msg, &devicestate);

// See https://github.com/meshtastic/firmware/issues/4184#issuecomment-2269390786
// It is very important to try and use the saved prefs even if we fail to read meshtastic_DeviceState. Because most of our
// critical config may still be valid (in the other files - loaded next).
// Also, if we did fail on reading we probably failed on the enormous (and non critical) nodeDB. So DO NOT install default
// device state.
// if (state != LoadFileResult::LOAD_SUCCESS) {
// It is very important to try and use the saved prefs even if we fail to read meshtastic_DeviceState. Because most of
// our critical config may still be valid (in the other files - loaded next). Also, if we did fail on reading we probably
// failed on the enormous (and non critical) nodeDB. So DO NOT install default device state. if (state !=
// LoadFileResult::LOAD_SUCCESS) {
// installDefaultDeviceState(); // Our in RAM copy might now be corrupt
//} else {
if ((state != LoadFileResult::LOAD_SUCCESS) || (devicestate.version < DEVICESTATE_MIN_VER)) {
Expand Down Expand Up @@ -1829,8 +1863,8 @@ bool NodeDB::isFromOrToFavoritedNode(const meshtastic_MeshPacket &p)
if (seenFrom && seenTo)
return false; // we've seen both, and neither is a favorite, so we can stop searching early

// Note: if we knew that sortMeshDB was always called after any change to is_favorite, we could exit early after searching
// all favorited nodes first.
// Note: if we knew that sortMeshDB was always called after any change to is_favorite, we could exit early after
// searching all favorited nodes first.
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion src/mesh/NodeDB.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class NodeDB
*/
size_t getNumOnlineMeshNodes(bool localOnly = false);

void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(), removeNodeByNum(NodeNum nodeNum);
void initConfigIntervals(), initModuleConfigIntervals(), initConfigGPS(), resetNodes(), removeNodeByNum(NodeNum nodeNum);

bool factoryReset(bool eraseBleBonds = false);

Expand Down
Loading