Files

1151 lines
52 KiB
C++
Raw Permalink Normal View History

2025-01-12 18:08:57 +01:00
#include "graphics/common/ViewController.h"
2024-03-08 11:40:39 +01:00
#include "assert.h"
2025-01-12 18:08:57 +01:00
#include "graphics/common/MeshtasticView.h"
#include "util/ILog.h"
#include "util/LogMessage.h"
2024-03-08 11:40:39 +01:00
#include <algorithm>
2024-02-28 20:49:18 +01:00
2024-12-31 22:00:20 +01:00
#if defined(ARCH_PORTDUINO)
#include "PortduinoFS.h"
2025-01-05 22:36:45 +01:00
fs::FS &persistentFS = PortduinoFS;
2024-12-31 22:00:20 +01:00
#else
#include "LittleFS.h"
2025-01-05 22:36:45 +01:00
fs::FS &persistentFS = LittleFS;
2024-12-31 22:00:20 +01:00
#endif
2024-05-22 21:23:11 +02:00
const size_t DATA_PAYLOAD_LEN = meshtastic_Constants_DATA_PAYLOAD_LEN;
2024-12-31 22:00:20 +01:00
constexpr const char *logDir = "/messages";
2024-05-22 21:23:11 +02:00
/**
* @brief mediate between GUI view and client interface
2024-03-07 16:21:28 +01:00
*
*/
ViewController::ViewController()
: view(nullptr), log(persistentFS, logDir, sizeof(LogMessage)), client(nullptr), sendId(1), myNodeNum(0), setupDone(false),
configCompleted(false), messagesRestored(false), requestConfigRequired(true)
{
}
2024-02-28 20:49:18 +01:00
2024-03-08 11:40:39 +01:00
void ViewController::init(MeshtasticView *gui, IClientBase *_client)
{
time(&lastrun1);
2024-03-19 01:29:50 +01:00
time(&lastrun10);
2024-03-08 11:40:39 +01:00
view = gui;
client = _client;
2024-04-04 19:52:27 +02:00
if (client) {
// client status handler
client->setNotifyCallback([this](IClientBase::ConnectionStatus status, const char *info) {
if (status == IClientBase::eConnected) {
view->notifyConnected(info);
} else {
view->notifyDisconnected(info);
}
});
2024-04-04 19:52:27 +02:00
client->init();
client->connect();
}
2024-12-31 22:00:20 +01:00
log.init();
2024-02-28 20:49:18 +01:00
}
2024-03-19 01:29:50 +01:00
/**
* @brief runOnce need to be called periodically to process send/receive queues
*
*/
2024-03-08 11:40:39 +01:00
void ViewController::runOnce(void)
{
2024-04-04 19:52:27 +02:00
if (client) {
2025-02-18 12:16:30 +01:00
if (view->getState() == MeshtasticView::eEnterProgrammingMode ||
(view->getState() >= MeshtasticView::eBootScreenDone && requestConfigRequired))
requestConfig();
2024-12-31 22:00:20 +01:00
if (configCompleted && !messagesRestored)
restoreTextMessages();
2025-02-13 17:45:46 +01:00
else {
if (myNodeNum == 0 || view->getState() != MeshtasticView::eProgrammingMode)
2025-02-13 17:45:46 +01:00
receive();
}
2024-12-31 22:00:20 +01:00
2024-04-04 19:52:27 +02:00
// executed every 10s:
time_t curtime;
time(&curtime);
2024-03-19 01:29:50 +01:00
2024-04-04 19:52:27 +02:00
if (curtime - lastrun10 >= 10) {
lastrun10 = curtime;
if (!client->isConnected())
client->connect();
if (client->isConnected() && view->getState() == MeshtasticView::eBootScreenDone) {
2024-11-02 23:15:19 +01:00
requestConfigRequired = true;
requestConfig();
}
2024-04-04 19:52:27 +02:00
}
// executed every 1s:
if (curtime - lastrun1 >= 1) {
lastrun1 = curtime;
client->task_handler();
}
}
}
2024-04-05 20:38:05 +02:00
bool ViewController::sleep(int16_t pin)
{
if (client)
return client->sleep(pin);
else
return false;
}
bool ViewController::isStandalone(void)
{
if (client)
return client->isStandalone();
else
return false;
}
void ViewController::stop(void)
{
if (client) {
client->disconnect();
}
}
2024-03-19 01:29:50 +01:00
void ViewController::processEvent(void) {}
2024-10-11 16:40:19 +02:00
uint32_t ViewController::requestDeviceUIConfig(void)
{
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_get_ui_config_request_tag,
.get_ui_config_request = true},
myNodeNum);
2024-10-11 16:40:19 +02:00
}
2024-05-22 21:23:11 +02:00
uint32_t ViewController::requestDeviceConfig(uint32_t nodeId)
2024-03-19 01:29:50 +01:00
{
2024-06-18 23:04:42 +02:00
return requestConfig(meshtastic_AdminMessage_ConfigType_DEVICE_CONFIG, nodeId ? nodeId : myNodeNum);
2024-03-19 01:29:50 +01:00
}
2024-05-22 21:23:11 +02:00
uint32_t ViewController::requestPositionConfig(uint32_t nodeId)
{
2024-06-18 23:04:42 +02:00
return requestConfig(meshtastic_AdminMessage_ConfigType_POSITION_CONFIG, nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
uint32_t ViewController::requestPowerConfig(uint32_t nodeId)
{
2024-06-18 23:04:42 +02:00
return requestConfig(meshtastic_AdminMessage_ConfigType_POWER_CONFIG, nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
uint32_t ViewController::requestNetworkConfig(uint32_t nodeId)
{
2024-06-18 23:04:42 +02:00
return requestConfig(meshtastic_AdminMessage_ConfigType_NETWORK_CONFIG, nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
uint32_t ViewController::requestDisplayConfig(uint32_t nodeId)
{
2024-06-18 23:04:42 +02:00
return requestConfig(meshtastic_AdminMessage_ConfigType_DISPLAY_CONFIG, nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
uint32_t ViewController::requestLoRaConfig(uint32_t nodeId)
{
2024-06-18 23:04:42 +02:00
return requestConfig(meshtastic_AdminMessage_ConfigType_LORA_CONFIG, nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
uint32_t ViewController::requestBluetoothConfig(uint32_t nodeId)
{
2024-06-18 23:04:42 +02:00
return requestConfig(meshtastic_AdminMessage_ConfigType_BLUETOOTH_CONFIG, nodeId ? nodeId : myNodeNum);
}
uint32_t ViewController::requestRingtone(uint32_t nodeId)
{
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_get_ringtone_request_tag,
.get_ringtone_request = true},
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
/**
* Request specific device config block
*/
uint32_t ViewController::requestConfig(meshtastic_AdminMessage_ConfigType type, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_get_config_request_tag,
.get_config_request = type},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
}
2024-05-22 21:23:11 +02:00
bool ViewController::requestReboot(int32_t seconds, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_reboot_seconds_tag, .reboot_seconds = seconds},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
}
bool ViewController::requestRebootOTA(int32_t seconds, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_reboot_ota_seconds_tag,
.reboot_ota_seconds = seconds},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
}
bool ViewController::requestShutdown(int32_t seconds, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_shutdown_seconds_tag,
.shutdown_seconds = seconds},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
}
/**
* @brief request factory reset or nodedb reset
2024-06-06 09:38:45 +02:00
*
* @param factoryReset set to false if only nodeDB reset is desired
* @param nodeId
* @return true
* @return false
*/
bool ViewController::requestReset(bool factoryReset, uint32_t nodeId)
2024-06-06 09:38:45 +02:00
{
2024-07-05 08:23:32 +02:00
return sendAdminMessage(
2024-08-18 10:27:41 +02:00
meshtastic_AdminMessage{.which_payload_variant =
(pb_size_t)(factoryReset ? meshtastic_AdminMessage_factory_reset_config_tag
: meshtastic_AdminMessage_nodedb_reset_tag)},
2024-07-05 08:23:32 +02:00
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
2024-10-11 16:40:19 +02:00
bool ViewController::storeUIConfig(const meshtastic_DeviceUIConfig &config)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_store_ui_config_tag, .store_ui_config = config},
myNodeNum);
2024-10-11 16:40:19 +02:00
}
2024-05-22 21:23:11 +02:00
bool ViewController::sendConfig(const meshtastic_User &user, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(
2024-06-18 23:04:42 +02:00
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_owner_tag, .set_owner{user}},
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
bool ViewController::sendConfig(meshtastic_Config_DeviceConfig &&device, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_config_tag,
.set_config{.which_payload_variant = meshtastic_Config_device_tag,
.payload_variant{.device = device}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
bool ViewController::sendConfig(meshtastic_Config_PositionConfig &&position, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_config_tag,
.set_config{.which_payload_variant = meshtastic_Config_position_tag,
.payload_variant{.position = position}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
bool ViewController::sendConfig(meshtastic_Position &&position, uint32_t nodeId)
{
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_fixed_position_tag,
.set_fixed_position{position}},
nodeId ? nodeId : myNodeNum);
}
2024-05-22 21:23:11 +02:00
bool ViewController::sendConfig(meshtastic_Config_PowerConfig &&power, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_config_tag,
.set_config{.which_payload_variant = meshtastic_Config_power_tag,
.payload_variant{.power = power}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
bool ViewController::sendConfig(meshtastic_Config_NetworkConfig &&network, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_config_tag,
.set_config{.which_payload_variant = meshtastic_Config_network_tag,
.payload_variant{.network = network}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
bool ViewController::sendConfig(meshtastic_Config_DisplayConfig &&display, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_config_tag,
.set_config{.which_payload_variant = meshtastic_Config_display_tag,
.payload_variant{.display = display}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
bool ViewController::sendConfig(meshtastic_Config_LoRaConfig &&lora, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_config_tag,
.set_config{.which_payload_variant = meshtastic_Config_lora_tag, .payload_variant{.lora = lora}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-05-22 21:23:11 +02:00
}
bool ViewController::sendConfig(meshtastic_Config_BluetoothConfig &&bluetooth, uint32_t nodeId)
{
2024-06-06 09:38:45 +02:00
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_config_tag,
.set_config{.which_payload_variant = meshtastic_Config_bluetooth_tag,
.payload_variant{.bluetooth = bluetooth}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-06 09:38:45 +02:00
}
2024-09-02 16:20:44 +02:00
bool ViewController::sendConfig(meshtastic_Config_SecurityConfig &&security, uint32_t nodeId)
{
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_config_tag,
.set_config{.which_payload_variant = meshtastic_Config_security_tag,
.payload_variant{.security = security}}},
nodeId ? nodeId : myNodeNum);
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_Channel &channel, uint32_t nodeId)
{
return sendAdminMessage(
2024-06-18 23:04:42 +02:00
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_channel_tag, .set_channel{channel}},
nodeId ? nodeId : myNodeNum);
}
2024-06-02 18:28:34 +02:00
// module config
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_MQTTConfig &&mqtt, uint32_t nodeId)
{
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_mqtt_tag,
.payload_variant{.mqtt = mqtt}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_SerialConfig &&serial, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{
.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_serial_tag, .payload_variant{.serial = serial}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_ExternalNotificationConfig &&extNotif, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_external_notification_tag,
.payload_variant{.external_notification = extNotif}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
}
bool ViewController::sendConfig(const char ringtone[230], uint32_t nodeId)
{
meshtastic_AdminMessage adminMsg{.which_payload_variant = meshtastic_AdminMessage_set_ringtone_message_tag};
memcpy(adminMsg.set_ringtone_message, ringtone, std::min(strlen(ringtone), (size_t)230U));
return sendAdminMessage(adminMsg, nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_StoreForwardConfig &&storeForward, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_store_forward_tag,
.payload_variant{.store_forward = storeForward}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_RangeTestConfig &&rangeTest, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_range_test_tag,
.payload_variant{.range_test = rangeTest}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_TelemetryConfig &&telemetry, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_telemetry_tag,
.payload_variant{.telemetry = telemetry}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_CannedMessageConfig &&cannedMessage, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_canned_message_tag,
.payload_variant{.canned_message = cannedMessage}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_AudioConfig &&audio, uint32_t nodeId)
{
return sendAdminMessage(meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_audio_tag,
.payload_variant{.audio = audio}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_RemoteHardwareConfig &&remoteHW, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag,
.payload_variant{.remote_hardware = remoteHW}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_NeighborInfoConfig &&neighborInfo, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag,
.payload_variant{.neighbor_info = neighborInfo}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_AmbientLightingConfig &&ambientLighting, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag,
.payload_variant{.ambient_lighting = ambientLighting}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_DetectionSensorConfig &&detectionSensor, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag,
.payload_variant{.detection_sensor = detectionSensor}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
2024-06-06 09:38:45 +02:00
bool ViewController::sendConfig(meshtastic_ModuleConfig_PaxcounterConfig &&paxCounter, uint32_t nodeId)
{
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_set_module_config_tag,
.set_module_config{.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag,
.payload_variant{.paxcounter = paxCounter}}},
2024-06-18 23:04:42 +02:00
nodeId ? nodeId : myNodeNum);
2024-06-02 18:28:34 +02:00
}
/**
2024-10-03 17:59:58 +02:00
* @brief Generic admin message (takes lvalue)
2024-06-18 23:04:42 +02:00
*
*/
bool ViewController::sendAdminMessage(meshtastic_AdminMessage &config, uint32_t nodeId)
{
meshtastic_Data_payload_t payload;
payload.size = pb_encode_to_bytes(payload.bytes, DATA_PAYLOAD_LEN, &meshtastic_AdminMessage_msg, &config);
2024-10-16 21:13:53 +02:00
return send(nodeId, meshtastic_PortNum_ADMIN_APP, payload, true);
2024-06-18 23:04:42 +02:00
}
/**
* @brief Generic admin message (takes rvalue)
2024-06-06 09:38:45 +02:00
*
*/
bool ViewController::sendAdminMessage(meshtastic_AdminMessage &&config, uint32_t nodeId)
{
2024-05-22 21:23:11 +02:00
meshtastic_Data_payload_t payload;
2024-06-02 08:59:45 +02:00
payload.size = pb_encode_to_bytes(payload.bytes, DATA_PAYLOAD_LEN, &meshtastic_AdminMessage_msg, &config);
2024-10-16 21:13:53 +02:00
return send(nodeId, meshtastic_PortNum_ADMIN_APP, payload, true);
2024-05-22 21:23:11 +02:00
}
2024-03-19 01:29:50 +01:00
2024-04-20 23:22:03 +01:00
void ViewController::sendHeartbeat(void)
{
if (client->isConnected()) {
client->send(meshtastic_ToRadio{.which_payload_variant = meshtastic_ToRadio_heartbeat_tag});
} else {
ILOG_DEBUG("sendHeartbeat skipped, client not connected");
2024-04-20 23:22:03 +01:00
}
}
2024-09-04 18:37:30 +02:00
void ViewController::sendPing(void)
{
if (client->isConnected()) {
client->send(meshtastic_ToRadio{.which_payload_variant = meshtastic_ToRadio_heartbeat_tag,
2025-08-09 10:22:29 -05:00
.heartbeat{.nonce = 1}}); // tell packet server to send ping to all nodes
2024-09-04 18:37:30 +02:00
}
}
2024-04-04 19:52:27 +02:00
void ViewController::setConfigRequested(bool required)
{
2024-03-27 01:41:48 +01:00
requestConfigRequired = required;
}
2024-12-31 22:00:20 +01:00
void ViewController::sendTextMessage(uint32_t to, uint8_t ch, uint8_t hopLimit, uint32_t msgTime, uint32_t requestId, bool usePkc,
const char *textmsg)
2024-05-22 21:23:11 +02:00
{
2024-12-31 22:00:20 +01:00
size_t msgLen = strlen(textmsg);
assert(msgLen <= (size_t)DATA_PAYLOAD_LEN);
if (send(to, ch, hopLimit, requestId, meshtastic_PortNum_TEXT_MESSAGE_APP, false, usePkc, (const uint8_t *)textmsg, msgLen)) {
2025-08-07 23:34:09 +02:00
// ILOG_DEBUG("storing msg to:0x%08x, ch:%d, time:%d, size:%d, '%s'", to, ch, msgTime, msgLen, textmsg);
2024-12-31 22:00:20 +01:00
log.write(LogMessageEnv(myNodeNum, to, ch, msgTime, LogMessage::eDefault, false, msgLen, (const uint8_t *)textmsg));
}
2024-07-19 14:36:37 +02:00
}
2024-07-22 22:06:22 +02:00
bool ViewController::requestPosition(uint32_t to, uint8_t ch, uint32_t requestId)
{
2024-10-17 09:06:42 +02:00
ILOG_DEBUG("sending position request");
2024-07-22 22:06:22 +02:00
meshtastic_Position position{};
meshtastic_Data_payload_t payload;
payload.size = pb_encode_to_bytes(payload.bytes, DATA_PAYLOAD_LEN, &meshtastic_Position_msg, &position);
return client->send(
meshtastic_ToRadio{.which_payload_variant = meshtastic_ToRadio_packet_tag,
.packet{.to = to,
.channel = ch,
.which_payload_variant = meshtastic_MeshPacket_decoded_tag,
.decoded{.portnum = meshtastic_PortNum_POSITION_APP, .payload{payload}, .want_response = true},
.id = requestId,
.hop_limit = 0,
.want_ack = false}});
}
2024-10-03 17:59:58 +02:00
void ViewController::traceRoute(uint32_t to, uint8_t ch, uint8_t hopLimit, uint32_t requestId)
2024-07-19 14:36:37 +02:00
{
2024-10-18 14:48:50 +02:00
meshtastic_RouteDiscovery request{};
2024-07-19 14:36:37 +02:00
meshtastic_Data_payload_t payload;
2024-10-18 14:48:50 +02:00
payload.size = pb_encode_to_bytes(payload.bytes, DATA_PAYLOAD_LEN, &meshtastic_RouteDiscovery_msg, &request);
send(to, ch, hopLimit, requestId, meshtastic_PortNum_TRACEROUTE_APP, true, false, payload.bytes, payload.size);
2024-05-22 21:23:11 +02:00
}
/**
* @brief generic send message to configure or request config data
*
* @param to destination
* @param portnum app
* @param payload
* @return true
* @return false
*/
2024-10-11 16:40:19 +02:00
bool ViewController::send(uint32_t to, meshtastic_PortNum portnum, const meshtastic_Data_payload_t &payload, bool wantRsp)
2024-05-22 21:23:11 +02:00
{
ILOG_DEBUG("sending meshpacket to radio id=0x%08x, to=0x%08x(%u), portnum=%u, len=%u, wantRsp=%d", 0, to, to, portnum,
payload.size, wantRsp);
2024-05-22 21:23:11 +02:00
return client->send(meshtastic_ToRadio{.which_payload_variant = meshtastic_ToRadio_packet_tag,
.packet{.to = to,
.which_payload_variant = meshtastic_MeshPacket_decoded_tag,
2024-10-11 16:40:19 +02:00
.decoded{.portnum = portnum, .payload{payload}, .want_response = wantRsp},
2024-05-22 21:23:11 +02:00
.want_ack = (to != 0)}});
}
2024-03-19 01:29:50 +01:00
/**
* generic send method for sending meshpackets with encoded payload
*/
2024-10-03 17:59:58 +02:00
bool ViewController::send(uint32_t to, uint8_t ch, uint8_t hopLimit, uint32_t requestId, meshtastic_PortNum portnum, bool wantRsp,
2024-11-30 00:09:08 +00:00
bool usePkc, const unsigned char bytes[meshtastic_Constants_DATA_PAYLOAD_LEN], size_t len)
2024-03-19 01:29:50 +01:00
{
ILOG_DEBUG("sending meshpacket to radio id=0x%x, to=0x%08x(%u), ch=%u, portnum=%u, len=%u, wantRsp=%d", requestId, to, to,
(unsigned int)ch, portnum, len, wantRsp);
2024-03-19 01:29:50 +01:00
// send requires movable lvalue, i.e. a temporary object
return client->send(meshtastic_ToRadio{
.which_payload_variant = meshtastic_ToRadio_packet_tag,
.packet{
.to = to,
.channel = ch,
.which_payload_variant = meshtastic_MeshPacket_decoded_tag,
.decoded{
.portnum = portnum,
2024-03-19 21:08:28 +01:00
.payload{.size = (unsigned short)len,
.bytes = {bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31],
bytes[32], bytes[33], bytes[34], bytes[35], bytes[36], bytes[37], bytes[38], bytes[39],
bytes[40], bytes[41], bytes[42], bytes[43], bytes[44], bytes[45], bytes[46], bytes[47],
bytes[48], bytes[49], bytes[50], bytes[51], bytes[52], bytes[53], bytes[54], bytes[55],
bytes[56], bytes[57], bytes[58], bytes[59], bytes[60], bytes[61], bytes[62], bytes[63],
bytes[64], bytes[65], bytes[66], bytes[67], bytes[68], bytes[69], bytes[70], bytes[71],
bytes[72], bytes[73], bytes[74], bytes[75], bytes[76], bytes[77], bytes[78], bytes[79],
bytes[80], bytes[81], bytes[82], bytes[83], bytes[84], bytes[85], bytes[86], bytes[87],
bytes[88], bytes[89], bytes[90], bytes[91], bytes[92], bytes[93], bytes[94], bytes[95],
bytes[96], bytes[97], bytes[98], bytes[99], bytes[100], bytes[101], bytes[102], bytes[103],
bytes[104], bytes[105], bytes[106], bytes[107], bytes[108], bytes[109], bytes[110], bytes[111],
bytes[112], bytes[113], bytes[114], bytes[115], bytes[116], bytes[117], bytes[118], bytes[119],
bytes[120], bytes[121], bytes[122], bytes[123], bytes[124], bytes[125], bytes[126], bytes[127],
bytes[128], bytes[129], bytes[130], bytes[131], bytes[132], bytes[133], bytes[134], bytes[135],
bytes[136], bytes[137], bytes[138], bytes[139], bytes[140], bytes[141], bytes[142], bytes[143],
bytes[144], bytes[145], bytes[146], bytes[147], bytes[148], bytes[149], bytes[150], bytes[151],
bytes[152], bytes[153], bytes[154], bytes[155], bytes[156], bytes[157], bytes[158], bytes[159],
bytes[160], bytes[161], bytes[162], bytes[163], bytes[164], bytes[165], bytes[166], bytes[167],
bytes[168], bytes[169], bytes[170], bytes[171], bytes[172], bytes[173], bytes[174], bytes[175],
bytes[176], bytes[177], bytes[178], bytes[179], bytes[180], bytes[181], bytes[182], bytes[183],
bytes[184], bytes[185], bytes[186], bytes[187], bytes[188], bytes[189], bytes[190], bytes[191],
bytes[192], bytes[193], bytes[194], bytes[195], bytes[196], bytes[197], bytes[198], bytes[199],
bytes[200], bytes[201], bytes[202], bytes[203], bytes[204], bytes[205], bytes[206], bytes[207],
bytes[208], bytes[209], bytes[210], bytes[211], bytes[212], bytes[213], bytes[214], bytes[215],
bytes[216], bytes[217], bytes[218], bytes[219], bytes[220], bytes[221], bytes[222], bytes[223],
bytes[224], bytes[225], bytes[226], bytes[227], bytes[228], bytes[229], bytes[230], bytes[231],
2024-11-30 00:09:08 +00:00
bytes[232]}},
2024-07-19 14:36:37 +02:00
.want_response = wantRsp}, // FIXME: traceRoute, requestPosition, remote config: true
2024-05-30 16:51:37 +02:00
.id = requestId,
2024-10-03 17:59:58 +02:00
.hop_limit = hopLimit,
.want_ack = (to != 0),
.pki_encrypted = usePkc}});
2024-03-19 01:29:50 +01:00
}
bool ViewController::receive(void)
{
2024-03-19 23:27:05 +01:00
bool gotPacket = false;
2024-03-19 21:08:28 +01:00
if (client->isConnected()) {
uint16_t received = 0;
2024-03-19 23:27:05 +01:00
do {
meshtastic_FromRadio from = client->receive();
2024-03-27 01:41:48 +01:00
if (from.which_payload_variant) {
2024-03-19 23:27:05 +01:00
handleFromRadio(from);
}
2024-03-27 01:41:48 +01:00
gotPacket = from.which_payload_variant != 0;
} while (gotPacket && received++ < 7); // handle max 7 packets in one go
2024-03-19 23:27:05 +01:00
return true;
2024-03-19 01:29:50 +01:00
}
return false;
}
/**
* request full upload of all config data from the radio
*/
2024-03-08 11:40:39 +01:00
void ViewController::requestConfig(void)
{
2024-11-04 00:15:29 +01:00
static uint32_t configId = 1;
2024-03-27 01:41:48 +01:00
if (client->isConnected() && requestConfigRequired) {
client->send(
meshtastic_ToRadio{.which_payload_variant = meshtastic_ToRadio_want_config_id_tag, .want_config_id = configId++});
2024-03-27 01:41:48 +01:00
requestConfigRequired = false;
}
}
2024-06-18 23:04:42 +02:00
/**
* @brief request additional config after initial startup finished
*
*/
void ViewController::requestAdditionalConfig(void)
{
requestRingtone(myNodeNum);
}
2024-12-31 22:00:20 +01:00
/**
* recover all messages from persistent log (could take a while!)
*/
void ViewController::beginRestoreTextMessages(void)
{
configCompleted = true;
restoreTimer = millis();
2025-01-26 20:10:28 +01:00
ILOG_INFO("loading persistent messages...");
2024-12-31 22:00:20 +01:00
}
/**
* incrementally recover messages from persistent log (could take a while!)
*/
void ViewController::restoreTextMessages(void)
{
2025-01-26 20:10:28 +01:00
static uint32_t msgCounter = 0;
static uint32_t msgTotalSize = 0;
2024-12-31 22:00:20 +01:00
LogMessageEnv msg;
2024-12-31 22:00:20 +01:00
if (log.readNext(msg)) {
2025-01-26 20:10:28 +01:00
msgCounter++;
msgTotalSize += msg.size();
view->restoreMessage(msg);
view->notifyRestoreMessages(msgTotalSize * 100 / log.size());
2024-12-31 22:00:20 +01:00
} else {
2025-01-26 20:10:28 +01:00
ILOG_INFO("restoring %d messages completed in %dms.", msgCounter, millis() - restoreTimer);
msgCounter = 0;
msgTotalSize = 0;
2024-12-31 22:00:20 +01:00
messagesRestored = true;
view->notifyMessagesRestored();
}
}
2025-01-26 20:10:28 +01:00
2024-12-31 22:00:20 +01:00
/**
* write a flag into message log that chat has been deleted
* The call removeTextMessages(0,0,0) removes all logs.
*/
void ViewController::removeTextMessages(uint32_t from, uint32_t to, uint8_t ch)
{
if (!from && !to && !ch) {
log.clear();
} else {
log.write(LogMessageEnv(from, to, ch, 0L, LogMessage::eDefault, true, 0, nullptr));
}
}
2024-03-19 01:29:50 +01:00
/**
* request connection status of WLAN/BT/MQTT
*/
2024-06-20 19:31:28 +02:00
bool ViewController::requestDeviceConnectionStatus(void)
2024-03-08 11:40:39 +01:00
{
2024-06-20 19:31:28 +02:00
return sendAdminMessage(
meshtastic_AdminMessage{.which_payload_variant = meshtastic_AdminMessage_get_device_connection_status_request_tag,
.get_device_connection_status_request = true},
myNodeNum);
2024-03-19 01:29:50 +01:00
}
bool ViewController::handleFromRadio(const meshtastic_FromRadio &from)
{
2025-02-13 17:45:46 +01:00
if (view->getState() == MeshtasticView::eProgrammingMode)
return false;
ILOG_DEBUG("handleFromRadio variant %u, id=%d", from.which_payload_variant, from.id);
if (from.which_payload_variant == meshtastic_FromRadio_deviceuiConfig_tag) {
2025-02-13 17:45:46 +01:00
setupDone = view->setupUIConfig(from.deviceuiConfig);
} else if (from.which_payload_variant == meshtastic_FromRadio_my_info_tag) {
2024-03-08 11:40:39 +01:00
const meshtastic_MyNodeInfo &info = from.my_info;
view->setMyInfo(info.my_node_num);
2024-06-18 23:04:42 +02:00
myNodeNum = info.my_node_num;
} else {
2025-02-13 17:45:46 +01:00
if (setupDone || (from.which_payload_variant == meshtastic_FromRadio_config_tag &&
from.config.which_payload_variant == meshtastic_Config_bluetooth_tag)) {
switch (from.which_payload_variant) {
case meshtastic_FromRadio_packet_tag: {
const meshtastic_MeshPacket &p = from.packet;
if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
packetReceived(p);
} else {
// FIXME: needs implementation when not using PacketClient interface
ILOG_WARN("dropping encoded meshpacket id=%u from radio!", from.id);
}
break;
}
case meshtastic_FromRadio_node_info_tag: {
const meshtastic_NodeInfo &node = from.node_info;
if (node.has_user) {
2025-05-30 19:27:33 +02:00
view->addOrUpdateNode(node.num, node.channel, node.last_heard, node.user);
} else {
2025-05-30 19:27:33 +02:00
view->addOrUpdateNode(node.num, node.channel, node.last_heard, MeshtasticView::eRole::unknown, false,
node.via_mqtt);
}
if (node.has_position) {
view->updatePosition(node.num, node.position.latitude_i, node.position.longitude_i, node.position.altitude, 0,
node.position.precision_bits);
}
if (node.has_device_metrics) {
view->updateMetrics(node.num, node.device_metrics.battery_level, node.device_metrics.voltage,
node.device_metrics.channel_utilization, node.device_metrics.air_util_tx);
}
break;
}
case meshtastic_FromRadio_config_tag: {
const meshtastic_Config &config = from.config;
switch (config.which_payload_variant) {
case meshtastic_Config_device_tag: {
const meshtastic_Config_DeviceConfig &cfg = config.payload_variant.device;
view->updateDeviceConfig(cfg);
break;
}
case meshtastic_Config_position_tag: {
const meshtastic_Config_PositionConfig &cfg = config.payload_variant.position;
view->updatePositionConfig(cfg);
break;
}
case meshtastic_Config_power_tag: {
const meshtastic_Config_PowerConfig &cfg = config.payload_variant.power;
view->updatePowerConfig(cfg);
break;
}
case meshtastic_Config_network_tag: {
const meshtastic_Config_NetworkConfig &cfg = config.payload_variant.network;
view->updateNetworkConfig(cfg);
break;
}
case meshtastic_Config_display_tag: {
const meshtastic_Config_DisplayConfig &cfg = config.payload_variant.display;
view->updateDisplayConfig(cfg);
break;
}
case meshtastic_Config_lora_tag: {
const meshtastic_Config_LoRaConfig &cfg = config.payload_variant.lora;
view->updateLoRaConfig(cfg);
break;
}
case meshtastic_Config_bluetooth_tag: {
const meshtastic_Config_BluetoothConfig &cfg = config.payload_variant.bluetooth;
2025-02-13 17:45:46 +01:00
view->updateBluetoothConfig(cfg, from.id); // PacketAPI provides our nodeId here
break;
}
case meshtastic_Config_security_tag: {
const meshtastic_Config_SecurityConfig &cfg = config.payload_variant.security;
view->updateSecurityConfig(cfg);
break;
}
case meshtastic_Config_sessionkey_tag: {
const meshtastic_Config_SessionkeyConfig &cfg = config.payload_variant.sessionkey;
view->updateSessionKeyConfig(cfg);
break;
}
case meshtastic_Config_device_ui_tag: {
ILOG_DEBUG("skipping meshtastic_Config_device_ui_tag");
break;
}
default:
ILOG_ERROR("unsupported device config variant: %u", config.which_payload_variant);
return false;
}
break;
}
case meshtastic_FromRadio_moduleConfig_tag: {
const meshtastic_ModuleConfig &module = from.moduleConfig;
switch (module.which_payload_variant) {
case meshtastic_ModuleConfig_mqtt_tag: {
const meshtastic_ModuleConfig_MQTTConfig &cfg = module.payload_variant.mqtt;
view->updateMQTTModule(cfg);
break;
}
case meshtastic_ModuleConfig_serial_tag: {
const meshtastic_ModuleConfig_SerialConfig &cfg = module.payload_variant.serial;
view->updateSerialModule(cfg);
break;
}
case meshtastic_ModuleConfig_external_notification_tag: {
const meshtastic_ModuleConfig_ExternalNotificationConfig &cfg = module.payload_variant.external_notification;
view->updateExtNotificationModule(cfg);
break;
}
case meshtastic_ModuleConfig_store_forward_tag: {
const meshtastic_ModuleConfig_StoreForwardConfig &cfg = module.payload_variant.store_forward;
view->updateStoreForwardModule(cfg);
break;
}
case meshtastic_ModuleConfig_range_test_tag: {
const meshtastic_ModuleConfig_RangeTestConfig &cfg = module.payload_variant.range_test;
view->updateRangeTestModule(cfg);
break;
}
case meshtastic_ModuleConfig_telemetry_tag: {
const meshtastic_ModuleConfig_TelemetryConfig &cfg = module.payload_variant.telemetry;
view->updateTelemetryModule(cfg);
break;
}
case meshtastic_ModuleConfig_canned_message_tag: {
const meshtastic_ModuleConfig_CannedMessageConfig &cfg = module.payload_variant.canned_message;
view->updateCannedMessageModule(cfg);
break;
}
case meshtastic_ModuleConfig_audio_tag: {
const meshtastic_ModuleConfig_AudioConfig &cfg = module.payload_variant.audio;
view->updateAudioModule(cfg);
break;
}
case meshtastic_ModuleConfig_remote_hardware_tag: {
const meshtastic_ModuleConfig_RemoteHardwareConfig &cfg = module.payload_variant.remote_hardware;
view->updateRemoteHardwareModule(cfg);
break;
}
case meshtastic_ModuleConfig_neighbor_info_tag: {
const meshtastic_ModuleConfig_NeighborInfoConfig &cfg = module.payload_variant.neighbor_info;
view->updateNeighborInfoModule(cfg);
break;
}
case meshtastic_ModuleConfig_ambient_lighting_tag: {
const meshtastic_ModuleConfig_AmbientLightingConfig &cfg = module.payload_variant.ambient_lighting;
view->updateAmbientLightingModule(cfg);
break;
}
case meshtastic_ModuleConfig_detection_sensor_tag: {
const meshtastic_ModuleConfig_DetectionSensorConfig &cfg = module.payload_variant.detection_sensor;
view->updateDetectionSensorModule(cfg);
break;
}
case meshtastic_ModuleConfig_paxcounter_tag: {
const meshtastic_ModuleConfig_PaxcounterConfig &cfg = module.payload_variant.paxcounter;
view->updatePaxCounterModule(cfg);
break;
}
default:
ILOG_ERROR("unsupported module config variant: %u", module.which_payload_variant);
return false;
}
break;
}
case meshtastic_FromRadio_fileInfo_tag: {
const meshtastic_FileInfo &fileinfo = from.fileInfo;
view->updateFileinfo(fileinfo);
break;
}
case meshtastic_FromRadio_channel_tag: {
const meshtastic_Channel &ch = from.channel;
if (ch.has_settings) {
view->updateChannelConfig(ch);
}
break;
}
case meshtastic_FromRadio_metadata_tag: {
const meshtastic_DeviceMetadata &meta = from.metadata;
view->setDeviceMetaData(meta.hw_model, meta.firmware_version, meta.hasBluetooth, meta.hasWifi, meta.hasEthernet,
meta.canShutdown);
break;
}
case meshtastic_FromRadio_config_complete_id_tag: {
2024-12-31 22:00:20 +01:00
beginRestoreTextMessages();
view->configCompleted();
requestAdditionalConfig();
view->notifyResync(false);
break;
}
case meshtastic_FromRadio_queueStatus_tag: {
const meshtastic_QueueStatus &q = from.queueStatus;
if (q.free == 0) {
ILOG_CRIT("meshqueue full!?");
}
break;
}
case meshtastic_FromRadio_rebooted_tag: {
view->notifyResync(true);
setConfigRequested(true);
break;
}
default: {
ILOG_ERROR("unhandled fromRadio packet variant: %u", from.which_payload_variant);
return false;
}
}
} else {
2024-10-17 09:06:42 +02:00
ILOG_WARN("skipping packet while setup not finished: %u", from.which_payload_variant);
2024-03-19 01:29:50 +01:00
return false;
2024-03-08 11:40:39 +01:00
}
2024-03-19 01:29:50 +01:00
}
return true;
2024-03-08 11:40:39 +01:00
}
2024-03-19 23:27:05 +01:00
bool ViewController::packetReceived(const meshtastic_MeshPacket &p)
{
2024-10-20 15:27:25 +02:00
ILOG_DEBUG("received packet from 0x%08x, id=0x%08x, portnum=%u", p.from, p.id, p.decoded.portnum);
2024-03-19 23:27:05 +01:00
view->packetReceived(p);
// only for direct neighbors print rssi/snr
if (p.hop_limit == p.hop_start && p.hop_limit > 0) {
2024-03-19 23:27:05 +01:00
view->updateSignalStrength(p.from, p.rx_rssi, p.rx_snr);
2024-05-10 20:21:48 +02:00
} else if (p.hop_start > 0) {
2024-05-28 23:32:51 +02:00
view->updateHopsAway(p.from, p.hop_start - p.hop_limit);
2024-03-19 23:27:05 +01:00
}
view->updateLastHeard(p.from);
switch (p.decoded.portnum) {
2025-02-19 15:32:58 +01:00
case meshtastic_PortNum_ALERT_APP:
2025-09-02 21:19:58 +02:00
case meshtastic_PortNum_DETECTION_SENSOR_APP:
2025-12-15 22:42:42 +01:00
case meshtastic_PortNum_TEXT_MESSAGE_APP:
case meshtastic_PortNum_RANGE_TEST_APP: {
2024-10-20 15:27:25 +02:00
ILOG_INFO("received text message '%s'", (const char *)p.decoded.payload.bytes);
2024-12-31 22:00:20 +01:00
if (!messagesRestored && log.count() > 0) {
// houston we have a problem! Haven't finished restoring messages incrementally while new ones come in
if (!configCompleted) {
ILOG_ERROR("cannot handle received message NOW");
return false; // the only way out
2025-02-13 17:45:46 +01:00
} else {
// let's hope for the best...
ILOG_ERROR("WTF!? how did we get here??");
2024-12-31 22:00:20 +01:00
}
}
uint32_t time = p.rx_time;
view->newMessage(p.from, p.to, p.channel, (const char *)p.decoded.payload.bytes, time);
log.write(LogMessageEnv(p.from, p.to, p.channel, time, LogMessage::eDefault, false, p.decoded.payload.size,
(const uint8_t *)p.decoded.payload.bytes));
2024-03-19 23:27:05 +01:00
break;
}
case meshtastic_PortNum_POSITION_APP: {
meshtastic_Position position;
if (pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Position_msg, &position)) {
2024-07-22 22:06:22 +02:00
// if "to" is our node then this is a reply to a requestPosition request
if (p.to == myNodeNum) {
2024-08-18 10:27:41 +02:00
view->handlePositionResponse(p.from, p.decoded.request_id, p.rx_rssi, p.rx_snr, p.hop_limit == p.hop_start);
2024-07-22 22:06:22 +02:00
} else {
view->updatePosition(p.from, position.latitude_i, position.longitude_i, position.altitude, position.sats_in_view,
position.precision_bits);
}
view->updateTime(position.time);
2024-03-19 23:27:05 +01:00
} else {
2024-10-17 09:06:42 +02:00
ILOG_ERROR("Error decoding protobuf meshtastic_Position!");
2024-03-19 23:27:05 +01:00
return false;
}
break;
}
case meshtastic_PortNum_NODEINFO_APP: {
meshtastic_User user;
if (pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_User_msg, &user)) {
2025-05-30 19:27:33 +02:00
view->updateNode(p.from, -1, user);
2024-03-19 23:27:05 +01:00
} else {
2024-10-17 09:06:42 +02:00
ILOG_ERROR("Error decoding protobuf meshtastic_User (nodeinfo)!");
2024-03-19 23:27:05 +01:00
return false;
}
break;
}
case meshtastic_PortNum_TELEMETRY_APP: {
meshtastic_Telemetry telemetry;
if (pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Telemetry_msg, &telemetry)) {
switch (telemetry.which_variant) {
case meshtastic_Telemetry_device_metrics_tag: {
2024-07-14 08:01:43 +02:00
meshtastic_DeviceMetrics &metrics = telemetry.variant.device_metrics;
view->updateMetrics(p.from, metrics.battery_level, metrics.voltage, metrics.channel_utilization,
metrics.air_util_tx);
2024-03-19 23:27:05 +01:00
break;
}
case meshtastic_Telemetry_environment_metrics_tag: {
view->updateEnvironmentMetrics(p.from, telemetry.variant.environment_metrics);
break;
}
case meshtastic_Telemetry_air_quality_metrics_tag: {
view->updateAirQualityMetrics(p.from, telemetry.variant.air_quality_metrics);
2024-03-19 23:27:05 +01:00
return false;
}
case meshtastic_Telemetry_power_metrics_tag: {
view->updatePowerMetrics(p.from, telemetry.variant.power_metrics);
2024-03-19 23:27:05 +01:00
return false;
2024-10-17 20:27:34 +02:00
}
case meshtastic_Telemetry_local_stats_tag: {
ILOG_DEBUG("meshtastic_Telemetry_local_stats_tag not implemented!");
return false;
2024-03-19 23:27:05 +01:00
}
default:
2024-10-17 09:06:42 +02:00
ILOG_ERROR("unhandled telemetry variant: %u", telemetry.which_variant);
2024-03-19 23:27:05 +01:00
return false;
}
} else {
2024-10-17 09:06:42 +02:00
ILOG_ERROR("Error decoding protobuf meshtastic_Telemetry!");
2024-03-19 23:27:05 +01:00
return false;
}
break;
}
2024-07-19 14:36:37 +02:00
case meshtastic_PortNum_TRACEROUTE_APP: {
2024-10-17 09:06:42 +02:00
ILOG_DEBUG("PortNum_TRACEROUTE_APP");
2024-07-19 14:36:37 +02:00
meshtastic_RouteDiscovery route;
if (pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_RouteDiscovery_msg, &route)) {
view->handleResponse(p.from, p.decoded.request_id, route);
} else {
2024-10-17 09:06:42 +02:00
ILOG_ERROR("Error decoding protobuf meshtastic_RouteDiscovery!");
2024-07-19 14:36:37 +02:00
return false;
}
break;
}
case meshtastic_PortNum_ROUTING_APP: {
2024-05-30 16:51:37 +02:00
meshtastic_Routing routing;
2025-03-01 16:05:02 +01:00
ILOG_DEBUG(
"PortNum_ROUTING_APP: id:%08x, from:%08x, to:%08x, ch:%d, dest:%08x, source:%08x, requestId:%08x, replyId:%08x", p.id,
p.from, p.to, p.channel, p.decoded.dest, p.decoded.source, p.decoded.request_id, p.decoded.reply_id);
2024-05-30 16:51:37 +02:00
if (pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Routing_msg, &routing)) {
2024-05-31 18:23:12 +02:00
if (routing.which_variant == meshtastic_Routing_error_reason_tag) {
switch (routing.error_reason) {
2024-06-06 09:38:45 +02:00
case meshtastic_Routing_Error_NONE:
case meshtastic_Routing_Error_MAX_RETRANSMIT:
2024-07-22 22:06:22 +02:00
view->handleResponse(p.from, p.decoded.request_id, routing, p);
break;
case meshtastic_Routing_Error_NO_RESPONSE:
2024-10-17 09:06:42 +02:00
ILOG_DEBUG("Routing error: no response");
2024-07-22 22:06:22 +02:00
// this response is sent by the other node when position is not availble
// however, it contains valid rssi/snr, so use these
2024-08-18 10:27:41 +02:00
view->handlePositionResponse(p.from, p.decoded.request_id, p.rx_rssi, p.rx_snr, p.hop_limit == p.hop_start);
2024-06-06 09:38:45 +02:00
break;
2025-05-11 00:24:48 +02:00
case meshtastic_Routing_Error_NO_INTERFACE:
2024-12-08 22:57:47 +01:00
case meshtastic_Routing_Error_NO_CHANNEL:
2025-05-11 00:24:48 +02:00
// invalid channel or interface
case meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY:
2024-12-08 22:57:47 +01:00
// this response is sent by the other node when encryption keys differ (outdated)
view->handleResponse(p.from, p.decoded.request_id, routing, p);
break;
2024-05-31 18:23:12 +02:00
default:
2024-10-17 09:06:42 +02:00
ILOG_WARN("got unhandled Routing_Error: %d", routing.error_reason);
2024-05-31 18:23:12 +02:00
break;
}
2024-06-06 09:38:45 +02:00
} else {
2024-07-22 22:06:22 +02:00
view->handleResponse(p.from, p.decoded.request_id, routing, p);
2024-05-31 18:23:12 +02:00
}
2024-05-30 16:51:37 +02:00
} else {
2024-10-17 09:06:42 +02:00
ILOG_ERROR("Error decoding protobuf meshtastic_Routing!");
2024-05-30 16:51:37 +02:00
return false;
}
2024-03-19 23:27:05 +01:00
break;
2024-07-19 14:36:37 +02:00
}
2024-03-19 23:27:05 +01:00
case meshtastic_PortNum_ADMIN_APP: {
meshtastic_AdminMessage admin;
if (pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_AdminMessage_msg, &admin)) {
switch (admin.which_payload_variant) {
case meshtastic_AdminMessage_get_device_connection_status_response_tag: {
meshtastic_DeviceConnectionStatus &status = admin.get_device_connection_status_response;
view->updateConnectionStatus(status);
break;
}
2024-05-22 21:23:11 +02:00
case meshtastic_AdminMessage_get_config_response_tag: {
meshtastic_Config &config = admin.get_config_response;
switch (config.which_payload_variant) {
case meshtastic_Config_device_tag: {
const meshtastic_Config_DeviceConfig &cfg = config.payload_variant.device;
view->updateDeviceConfig(cfg);
break;
}
case meshtastic_Config_position_tag: {
const meshtastic_Config_PositionConfig &cfg = config.payload_variant.position;
view->updatePositionConfig(cfg);
break;
}
case meshtastic_Config_power_tag: {
const meshtastic_Config_PowerConfig &cfg = config.payload_variant.power;
view->updatePowerConfig(cfg);
break;
}
case meshtastic_Config_network_tag: {
const meshtastic_Config_NetworkConfig &cfg = config.payload_variant.network;
view->updateNetworkConfig(cfg);
break;
}
case meshtastic_Config_display_tag: {
const meshtastic_Config_DisplayConfig &cfg = config.payload_variant.display;
view->updateDisplayConfig(cfg);
break;
}
case meshtastic_Config_lora_tag: {
const meshtastic_Config_LoRaConfig &cfg = config.payload_variant.lora;
view->updateLoRaConfig(cfg);
break;
}
case meshtastic_Config_bluetooth_tag: {
const meshtastic_Config_BluetoothConfig &cfg = config.payload_variant.bluetooth;
view->updateBluetoothConfig(cfg);
break;
}
default:
2024-10-17 09:06:42 +02:00
ILOG_ERROR("unhandled meshtastic_Config variant: %u", config.which_payload_variant);
2024-07-28 19:44:01 +02:00
return false;
2024-05-22 21:23:11 +02:00
}
2024-03-19 23:27:05 +01:00
break;
}
2024-06-20 19:31:28 +02:00
case meshtastic_AdminMessage_get_module_config_response_tag: {
meshtastic_ModuleConfig &config = admin.get_module_config_response;
switch (config.which_payload_variant) {
case meshtastic_ModuleConfig_mqtt_tag: {
const meshtastic_ModuleConfig_MQTTConfig &cfg = config.payload_variant.mqtt;
view->updateMQTTModule(cfg);
break;
}
default:
2024-10-17 09:06:42 +02:00
ILOG_ERROR("unhandled meshtastic_ModuleConfig variant: %u", config.which_payload_variant);
2024-07-28 19:44:01 +02:00
return false;
2024-06-20 19:31:28 +02:00
}
break;
}
case meshtastic_AdminMessage_get_ringtone_response_tag: {
view->updateRingtone(admin.get_ringtone_response);
break;
}
2024-07-22 22:06:22 +02:00
case meshtastic_AdminMessage_set_channel_tag: {
// TODO
2024-10-17 09:06:42 +02:00
ILOG_WARN("meshtastic_AdminMessage_set_channel_tag not implemented");
2024-07-28 19:44:01 +02:00
return false;
2024-07-22 22:06:22 +02:00
}
2024-03-19 23:27:05 +01:00
default:
2024-10-17 09:06:42 +02:00
ILOG_ERROR("unhandled AdminMessage variant: %u", admin.which_payload_variant);
2024-03-19 23:27:05 +01:00
return false;
}
} else {
2024-10-17 09:06:42 +02:00
ILOG_ERROR("Error decoding protobuf meshtastic_AdminMessage!");
2024-03-19 23:27:05 +01:00
return false;
}
break;
}
case meshtastic_PortNum_SIMULATOR_APP:
break;
default:
2024-10-17 09:06:42 +02:00
ILOG_ERROR("unhandled meshpacket portnum: %u", p.decoded.portnum);
2024-03-19 23:27:05 +01:00
return false;
}
return true;
}
2024-03-07 16:21:28 +01:00
ViewController::~ViewController() {}