Merge branch 'master' into nomad-gemini

This commit is contained in:
Thomas Göttgens
2025-03-02 12:01:43 +01:00
committed by GitHub
240 changed files with 14401 additions and 2127 deletions

View File

@@ -123,23 +123,23 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
* Getters
*/
case meshtastic_AdminMessage_get_owner_request_tag:
LOG_INFO("Client got owner");
LOG_DEBUG("Client got owner");
handleGetOwner(mp);
break;
case meshtastic_AdminMessage_get_config_request_tag:
LOG_INFO("Client got config");
LOG_DEBUG("Client got config");
handleGetConfig(mp, r->get_config_request);
break;
case meshtastic_AdminMessage_get_module_config_request_tag:
LOG_INFO("Client got module config");
LOG_DEBUG("Client got module config");
handleGetModuleConfig(mp, r->get_module_config_request);
break;
case meshtastic_AdminMessage_get_channel_request_tag: {
uint32_t i = r->get_channel_request - 1;
LOG_INFO("Client got channel %u", i);
LOG_DEBUG("Client got channel %u", i);
if (i >= MAX_NUM_CHANNELS)
myReply = allocErrorResponse(meshtastic_Routing_Error_BAD_REQUEST, &mp);
else
@@ -151,35 +151,35 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
* Setters
*/
case meshtastic_AdminMessage_set_owner_tag:
LOG_INFO("Client set owner");
LOG_DEBUG("Client set owner");
handleSetOwner(r->set_owner);
break;
case meshtastic_AdminMessage_set_config_tag:
LOG_INFO("Client set config");
LOG_DEBUG("Client set config");
handleSetConfig(r->set_config);
break;
case meshtastic_AdminMessage_set_module_config_tag:
LOG_INFO("Client set module config");
LOG_DEBUG("Client set module config");
if (!handleSetModuleConfig(r->set_module_config)) {
myReply = allocErrorResponse(meshtastic_Routing_Error_BAD_REQUEST, &mp);
}
break;
case meshtastic_AdminMessage_set_channel_tag:
LOG_INFO("Client set channel %d", r->set_channel.index);
LOG_DEBUG("Client set channel %d", r->set_channel.index);
if (r->set_channel.index < 0 || r->set_channel.index >= (int)MAX_NUM_CHANNELS)
myReply = allocErrorResponse(meshtastic_Routing_Error_BAD_REQUEST, &mp);
else
handleSetChannel(r->set_channel);
break;
case meshtastic_AdminMessage_set_ham_mode_tag:
LOG_INFO("Client set ham mode");
LOG_DEBUG("Client set ham mode");
handleSetHamMode(r->set_ham_mode);
break;
case meshtastic_AdminMessage_get_ui_config_request_tag: {
LOG_INFO("Client is getting device-ui config");
LOG_DEBUG("Client is getting device-ui config");
handleGetDeviceUIConfig(mp);
handled = true;
break;
@@ -285,7 +285,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->set_favorite_node);
if (node != NULL) {
node->is_favorite = true;
saveChanges(SEGMENT_DEVICESTATE, false);
saveChanges(SEGMENT_NODEDATABASE, false);
}
break;
}
@@ -294,7 +294,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->remove_favorite_node);
if (node != NULL) {
node->is_favorite = false;
saveChanges(SEGMENT_DEVICESTATE, false);
saveChanges(SEGMENT_NODEDATABASE, false);
}
break;
}
@@ -307,7 +307,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
node->has_position = false;
node->user.public_key.size = 0;
node->user.public_key.bytes[0] = 0;
saveChanges(SEGMENT_DEVICESTATE, false);
saveChanges(SEGMENT_NODEDATABASE, false);
}
break;
}
@@ -316,7 +316,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->remove_ignored_node);
if (node != NULL) {
node->is_ignored = false;
saveChanges(SEGMENT_DEVICESTATE, false);
saveChanges(SEGMENT_NODEDATABASE, false);
}
break;
}
@@ -327,7 +327,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
node->position = TypeConversions::ConvertToPositionLite(r->set_fixed_position);
nodeDB->setLocalPosition(r->set_fixed_position);
config.position.fixed_position = true;
saveChanges(SEGMENT_DEVICESTATE | SEGMENT_CONFIG, false);
saveChanges(SEGMENT_DEVICESTATE | SEGMENT_NODEDATABASE | SEGMENT_CONFIG, false);
#if !MESHTASTIC_EXCLUDE_GPS
if (gps != nullptr)
gps->enable();
@@ -340,7 +340,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
LOG_INFO("Client received remove_fixed_position command");
nodeDB->clearLocalPosition();
config.position.fixed_position = false;
saveChanges(SEGMENT_DEVICESTATE | SEGMENT_CONFIG, false);
saveChanges(SEGMENT_DEVICESTATE | SEGMENT_NODEDATABASE | SEGMENT_CONFIG, false);
break;
}
case meshtastic_AdminMessage_set_time_only_tag: {
@@ -391,7 +391,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
LOG_DEBUG("Did not responded to a request that wanted a respond. req.variant=%d", r->which_payload_variant);
} else if (handleResult != AdminMessageHandleResult::HANDLED) {
// Probably a message sent by us or sent to our local node. FIXME, we should avoid scanning these messages
LOG_INFO("Ignore irrelevant admin %d", r->which_payload_variant);
LOG_DEBUG("Ignore irrelevant admin %d", r->which_payload_variant);
}
break;
}
@@ -450,11 +450,14 @@ void AdminModule::handleSetOwner(const meshtastic_User &o)
if (owner.is_licensed != o.is_licensed) {
changed = 1;
owner.is_licensed = o.is_licensed;
if (channels.ensureLicensedOperation()) {
sendWarning(licensedModeMessage);
}
}
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
service->reloadOwner(!hasOpenEditTransaction);
saveChanges(SEGMENT_DEVICESTATE);
saveChanges(SEGMENT_DEVICESTATE | SEGMENT_NODEDATABASE);
}
}
@@ -748,6 +751,9 @@ bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
void AdminModule::handleSetChannel(const meshtastic_Channel &cc)
{
channels.setChannel(cc);
if (channels.ensureLicensedOperation()) {
sendWarning(licensedModeMessage);
}
channels.onConfigChanged(); // tell the radios about this change
saveChanges(SEGMENT_CHANNELS, false);
}
@@ -1085,15 +1091,14 @@ void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY;
// Remove PSK of primary channel for plaintext amateur usage
auto primaryChannel = channels.getByIndex(channels.getPrimaryIndex());
auto &channelSettings = primaryChannel.settings;
channelSettings.psk.bytes[0] = 0;
channelSettings.psk.size = 0;
channels.setChannel(primaryChannel);
if (channels.ensureLicensedOperation()) {
sendWarning(licensedModeMessage);
}
channels.onConfigChanged();
service->reloadOwner(false);
saveChanges(SEGMENT_CONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
saveChanges(SEGMENT_CONFIG | SEGMENT_NODEDATABASE | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
}
AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_APP, &meshtastic_AdminMessage_msg)
@@ -1179,4 +1184,4 @@ void disableBluetooth()
nrf52Bluetooth->shutdown();
#endif
#endif
}
}

View File

@@ -64,6 +64,9 @@ class AdminModule : public ProtobufModule<meshtastic_AdminMessage>, public Obser
void sendWarning(const char *message);
};
static constexpr const char *licensedModeMessage =
"Licensed mode activated, removing admin channel and encryption from all channels";
extern AdminModule *adminModule;
void disableBluetooth();

View File

@@ -20,6 +20,11 @@ bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mesh
if ((nodeDB->getMeshNode(mp.from) == NULL || !nodeDB->getMeshNode(mp.from)->has_user) &&
(nodeDB->getMeshNode(mp.to) == NULL || !nodeDB->getMeshNode(mp.to)->has_user))
return false;
} else if (owner.is_licensed && nodeDB->getLicenseStatus(mp.from) == UserLicenseStatus::NotLicensed) {
// Don't let licensed users to rebroadcast packets from unlicensed users
// If we know they are in-fact unlicensed
LOG_DEBUG("Packet from unlicensed user, ignoring packet");
return false;
}
printPacket("Routing sniffing", &mp);

View File

@@ -31,7 +31,6 @@ int32_t PowerTelemetryModule::runOnce()
doDeepSleep(nightyNightMs, true, false);
}
uint32_t result = UINT32_MAX;
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
@@ -46,25 +45,33 @@ int32_t PowerTelemetryModule::runOnce()
return disable();
}
uint32_t sendToMeshIntervalMs = Default::getConfiguredOrDefaultMsScaled(
moduleConfig.telemetry.power_update_interval, default_telemetry_broadcast_interval_secs, numOnlineNodes);
if (firstTime) {
// This is the first time the OSThread library has called this function, so do some setup
firstTime = 0;
uint32_t result = UINT32_MAX;
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
if (moduleConfig.telemetry.power_measurement_enabled) {
LOG_INFO("Power Telemetry: init");
// it's possible to have this module enabled, only for displaying values on the screen.
// therefore, we should only enable the sensor loop if measurement is also enabled
if (ina219Sensor.hasSensor() && !ina219Sensor.isInitialized())
result = ina219Sensor.runOnce();
if (ina226Sensor.hasSensor() && !ina226Sensor.isInitialized())
result = ina226Sensor.runOnce();
if (ina260Sensor.hasSensor() && !ina260Sensor.isInitialized())
result = ina260Sensor.runOnce();
if (ina3221Sensor.hasSensor() && !ina3221Sensor.isInitialized())
result = ina3221Sensor.runOnce();
if (max17048Sensor.hasSensor() && !max17048Sensor.isInitialized())
result = max17048Sensor.runOnce();
// If sensor is already initialized by EnvironmentTelemetryModule, then we don't need to initialize it again,
// but we need to set the result to != UINT32_MAX to avoid it being disabled
if (ina219Sensor.hasSensor())
result = ina219Sensor.isInitialized() ? 0 : ina219Sensor.runOnce();
if (ina226Sensor.hasSensor())
result = ina226Sensor.isInitialized() ? 0 : ina226Sensor.runOnce();
if (ina260Sensor.hasSensor())
result = ina260Sensor.isInitialized() ? 0 : ina260Sensor.runOnce();
if (ina3221Sensor.hasSensor())
result = ina3221Sensor.isInitialized() ? 0 : ina3221Sensor.runOnce();
if (max17048Sensor.hasSensor())
result = max17048Sensor.isInitialized() ? 0 : max17048Sensor.runOnce();
}
// it's possible to have this module enabled, only for displaying values on the screen.
// therefore, we should only enable the sensor loop if measurement is also enabled
return result == UINT32_MAX ? disable() : setStartDelay();
#else
return disable();
@@ -74,10 +81,7 @@ int32_t PowerTelemetryModule::runOnce()
if (!moduleConfig.telemetry.power_measurement_enabled)
return disable();
if (((lastSentToMesh == 0) ||
!Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled(
moduleConfig.telemetry.power_update_interval,
default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
if (((lastSentToMesh == 0) || !Throttle::isWithinTimespanMs(lastSentToMesh, sendToMeshIntervalMs)) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();
lastSentToMesh = millis();
@@ -89,8 +93,9 @@ int32_t PowerTelemetryModule::runOnce()
lastSentToPhone = millis();
}
}
return min(sendToPhoneIntervalMs, result);
return min(sendToPhoneIntervalMs, sendToMeshIntervalMs);
}
bool PowerTelemetryModule::wantUIFrame()
{
return moduleConfig.telemetry.power_screen_enabled;

View File

@@ -109,7 +109,7 @@ void TraceRouteModule::appendMyIDandSNR(meshtastic_RouteDiscovery *updated, floa
void TraceRouteModule::printRoute(meshtastic_RouteDiscovery *r, uint32_t origin, uint32_t dest, bool isTowardsDestination)
{
#ifdef DEBUG_PORT
std::string route = "Route traced:";
std::string route = "Route traced:\n";
route += vformat("0x%x --> ", origin);
for (uint8_t i = 0; i < r->route_count; i++) {
if (i < r->snr_towards_count && r->snr_towards[i] != INT8_MIN)
@@ -129,6 +129,7 @@ void TraceRouteModule::printRoute(meshtastic_RouteDiscovery *r, uint32_t origin,
// If there's a route back (or we are the destination as then the route is complete), print it
if (r->route_back_count > 0 || origin == nodeDB->getNodeNum()) {
route += "\n";
if (r->snr_towards_count > 0 && origin == nodeDB->getNodeNum())
route += vformat("(%.2fdB) 0x%x <-- ", (float)r->snr_back[r->snr_back_count - 1] / 4, origin);
else
@@ -150,6 +151,12 @@ meshtastic_MeshPacket *TraceRouteModule::allocReply()
{
assert(currentRequest);
// Ignore multi-hop broadcast requests
if (isBroadcast(currentRequest->to) && currentRequest->hop_limit < currentRequest->hop_start) {
ignoreRequest = true;
return NULL;
}
// Copy the payload of the current request
auto req = *currentRequest;
const auto &p = req.decoded;

View File

@@ -144,9 +144,9 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state,
bearingToOther -= myHeading;
screen->drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther);
float bearingToOtherDegrees = (bearingToOther < 0) ? bearingToOther + 2*PI : bearingToOther;
bearingToOtherDegrees = bearingToOtherDegrees * 180 / PI;
float bearingToOtherDegrees = (bearingToOther < 0) ? bearingToOther + 2 * PI : bearingToOther;
bearingToOtherDegrees = bearingToOtherDegrees * 180 / PI;
// Distance to Waypoint
float d = GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
@@ -161,7 +161,6 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state,
snprintf(distStr, sizeof(distStr), "%.1fkm %.0f°", d / 1000, bearingToOtherDegrees);
}
}
// If our node doesn't have position