diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 6c338c81..69f22591 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,6 +4,7 @@ You probably don't care about this section - skip to the next one. For app cleanup: +* use structured logging to kep logs in ram. Also send logs as packets to api clients * DONE writeup nice python options docs (common cases, link to protobuf docs) * have android app link to user manual * DONE only do wantReplies once per packet type, if we change network settings force it again diff --git a/docs/software/mqtt.md b/docs/software/mqtt.md index 0d3f7745..06ec7bb0 100644 --- a/docs/software/mqtt.md +++ b/docs/software/mqtt.md @@ -30,6 +30,17 @@ ## 1.1. Abstract +FIXME: + +- add channels as security + - have a uplinkPolicy enum (none, up only, down only, updown, stay encrypted) +- add simpler mapping of channels/nodes/messages/portnums to mqtt topics +- leave payloads as raw packets/protobufs +- explain why not UDP + - need to have a server anyways so that nodes can reach each other from anywhere + - raw UDP is dropped **very** agressively by many cellular providers + - mqtt provides a nice/documented/standard security model to build upon + This is a mini-doc/RFC sketching out a development plan to satisfy a number of 1.1 goals. - [MQTT](https://opensource.com/article/18/6/mqtt) internet accessible API. Issue #[369](https://github.com/meshtastic/Meshtastic-device/issues/169) @@ -80,12 +91,24 @@ A sample [topic](https://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics- | MESHID/USERID/msg/text/DESTCLASS/DESTID | A text message from USERID to DESTCLASS/DESTID | | MESHID/NODEID/msg/bin/DESTCLASS/DESTID | A binary message from NODEID to DESTCLASS/DESTCLASS | | MESHID/NODEID/gpio/set/GPIONUM | Set a GPIO output | -| MESHID/NODEID/gpio/get/GPIONUM | Try to read a GPIO | -| MESHID/NODEID/gpio/upd/GPIONUM | Contains the read GPIO value | | MESHID/NODEID/attr/ATTRNAME/req | Request a current attribute value | | MESHID/NODEID/attr/ATTRNAME/set | Set an attribute value | | MESHID/NODEID/app/APPNUM/# | An topic from an unregistered/unknown app | +for encrypted packets (consumer would need to have access to the specified channel to be able to parse) + +encrypted/CHANNELID/MESHID/NODEID/PORTID + +If the channelid 'well known'/public it can be decrypted by a web service, in which case it will be decrypted by a web service and appear at: + +clear/MESHID/NODEID/PORTID + +FIXME, the payload published on the topic, will include the message, and full information about arrival time, who forwarded it, source channel etc... + +FIXME, figure out how channelids work +FIXME, figure out rules for store and forward + + #### 1.6.1.1. MESHID A unique ID for this mesh. There will be some sort of key exchange process so that the mesh ID can not be impersonated by other meshes. diff --git a/proto b/proto index 020ef9ee..9a7d8a03 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 020ef9eea8129756a0b45be5a3900b0355be4451 +Subproject commit 9a7d8a03cb051eb42787d4a06836b109677d8ef1 diff --git a/src/error.h b/src/error.h index b3926c9d..e290c403 100644 --- a/src/error.h +++ b/src/error.h @@ -2,32 +2,7 @@ #include -/** Error codes for critical errors - * - * The device might report these fault codes on the screen. If you encounter a fault code, please - * post on the meshtastic.discourse.group and we'll try to help. - */ -enum CriticalErrorCode { - NoError = 0, - - /// A software bug was detected while trying to send lora packets - ErrTxWatchdog = 1, - - /// A software bug was detected on entry to sleep - ErrSleepEnterWait = 2, - - /// No Lora radio hardware could be found - ErrNoRadio = 3, - - /// Not normally used - ErrUnspecified = 4, - - /// We failed while configuring a UBlox GPS - ErrUBloxInitFailed = 5, - - /// This board was expected to have a power management chip and it is missing or broken - ErrNoAXP192 = 6 - }; +#include "mesh/mesh.pb.h" // For CriticalErrorCode /// Record an error that should be reported via analytics -void recordCriticalError(CriticalErrorCode code, uint32_t address = 0); +void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_Unspecified, uint32_t address = 0); diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index 7aa29b01..8fda6bc4 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -43,7 +43,7 @@ bool UBloxGPS::setupGPS() DEBUG_MSG("Connected to UBLOX GPS successfully\n"); if (!setUBXMode()) - recordCriticalError(ErrUBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug + recordCriticalError(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug return true; } else { diff --git a/src/main.cpp b/src/main.cpp index 7d27ad63..64851022 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -428,7 +428,7 @@ void setup() // Do this after service.init (because that clears error_code) #ifdef AXP192_SLAVE_ADDRESS if(!axp192_found) - recordCriticalError(ErrNoAXP192); // Record a hardware fault for missing hardware + recordCriticalError(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware #endif // Don't call screen setup until after nodedb is setup (because we need @@ -497,7 +497,7 @@ void setup() initWifi(forceSoftAP); if (!rIf) - recordCriticalError(ErrNoRadio); + recordCriticalError(CriticalErrorCode_NoRadio); else router->addInterface(rIf); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 9f4c144d..16ea5c16 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -271,7 +271,7 @@ void NodeDB::init() myNodeInfo.node_num_bits = sizeof(NodeNum) * 8; myNodeInfo.packet_id_bits = sizeof(PacketId) * 8; - myNodeInfo.error_code = NoError; // For the error code, only show values from this boot (discard value from flash) + myNodeInfo.error_code = CriticalErrorCode_None; // For the error code, only show values from this boot (discard value from flash) myNodeInfo.error_address = 0; // likewise - we always want the app requirements to come from the running appload diff --git a/src/mesh/mesh.pb.c b/src/mesh/mesh.pb.c index ca17e720..1fae4453 100644 --- a/src/mesh/mesh.pb.c +++ b/src/mesh/mesh.pb.c @@ -42,7 +42,7 @@ PB_BIND(MyNodeInfo, MyNodeInfo, AUTO) PB_BIND(DeviceState, DeviceState, 2) -PB_BIND(DebugString, DebugString, 2) +PB_BIND(LogRecord, LogRecord, AUTO) PB_BIND(FromRadio, FromRadio, 2) @@ -58,3 +58,5 @@ PB_BIND(ToRadio, ToRadio, 2) + + diff --git a/src/mesh/mesh.pb.h b/src/mesh/mesh.pb.h index 92bab3ae..fd382765 100644 --- a/src/mesh/mesh.pb.h +++ b/src/mesh/mesh.pb.h @@ -48,6 +48,16 @@ typedef enum _LocationSharing { LocationSharing_LocDisabled = 2 } LocationSharing; +typedef enum _CriticalErrorCode { + CriticalErrorCode_None = 0, + CriticalErrorCode_TxWatchdog = 1, + CriticalErrorCode_SleepEnterWait = 2, + CriticalErrorCode_NoRadio = 3, + CriticalErrorCode_Unspecified = 4, + CriticalErrorCode_UBloxInitFailed = 5, + CriticalErrorCode_NoAXP192 = 6 +} CriticalErrorCode; + typedef enum _ChannelSettings_ModemConfig { ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0, ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1, @@ -55,6 +65,16 @@ typedef enum _ChannelSettings_ModemConfig { ChannelSettings_ModemConfig_Bw125Cr48Sf4096 = 3 } ChannelSettings_ModemConfig; +typedef enum _LogRecord_Level { + LogRecord_Level_UNSET = 0, + LogRecord_Level_CRITICAL = 50, + LogRecord_Level_ERROR = 40, + LogRecord_Level_WARNING = 30, + LogRecord_Level_INFO = 20, + LogRecord_Level_DEBUG = 10, + LogRecord_Level_TRACE = 5 +} LogRecord_Level; + /* Struct definitions */ typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t; typedef struct _ChannelSettings { @@ -74,9 +94,12 @@ typedef struct _Data { Data_payload_t payload; } Data; -typedef struct _DebugString { - char message[256]; -} DebugString; +typedef struct _LogRecord { + char message[64]; + uint32_t time; + char source[8]; + LogRecord_Level level; +} LogRecord; typedef struct _MyNodeInfo { uint32_t my_node_num; @@ -85,7 +108,7 @@ typedef struct _MyNodeInfo { char region[12]; char hw_model[16]; char firmware_version[12]; - uint32_t error_code; + CriticalErrorCode error_code; uint32_t error_address; uint32_t error_count; uint32_t packet_id_bits; @@ -226,7 +249,7 @@ typedef struct _FromRadio { MyNodeInfo my_info; NodeInfo node_info; RadioConfig radio; - DebugString debug_string; + LogRecord log_record; uint32_t config_complete_id; bool rebooted; ChannelSettings secondary_channel; @@ -265,10 +288,18 @@ typedef struct _ToRadio { #define _LocationSharing_MAX LocationSharing_LocDisabled #define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1)) +#define _CriticalErrorCode_MIN CriticalErrorCode_None +#define _CriticalErrorCode_MAX CriticalErrorCode_NoAXP192 +#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_NoAXP192+1)) + #define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128 #define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096 #define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1)) +#define _LogRecord_Level_MIN LogRecord_Level_UNSET +#define _LogRecord_Level_MAX LogRecord_Level_CRITICAL +#define _LogRecord_Level_ARRAYSIZE ((LogRecord_Level)(LogRecord_Level_CRITICAL+1)) + #ifdef __cplusplus extern "C" { @@ -285,9 +316,9 @@ extern "C" { #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} #define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} -#define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0} +#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default}} -#define DebugString_init_default {""} +#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_default {0, 0, {MeshPacket_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}} #define Position_init_zero {0, 0, 0, 0, 0} @@ -300,9 +331,9 @@ extern "C" { #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} #define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} -#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0} +#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero}} -#define DebugString_init_zero {""} +#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}} #define ToRadio_init_zero {0, {MeshPacket_init_zero}} @@ -317,7 +348,10 @@ extern "C" { #define ChannelSettings_channel_num_tag 9 #define Data_portnum_tag 1 #define Data_payload_tag 2 -#define DebugString_message_tag 1 +#define LogRecord_message_tag 1 +#define LogRecord_time_tag 2 +#define LogRecord_source_tag 3 +#define LogRecord_level_tag 4 #define MyNodeInfo_my_node_num_tag 1 #define MyNodeInfo_has_gps_tag 2 #define MyNodeInfo_num_channels_tag 3 @@ -410,7 +444,7 @@ extern "C" { #define FromRadio_my_info_tag 3 #define FromRadio_node_info_tag 4 #define FromRadio_radio_tag 6 -#define FromRadio_debug_string_tag 7 +#define FromRadio_log_record_tag 7 #define FromRadio_config_complete_id_tag 8 #define FromRadio_rebooted_tag 9 #define FromRadio_secondary_channel_tag 10 @@ -550,7 +584,7 @@ X(a, STATIC, SINGULAR, INT32, num_channels, 3) \ X(a, STATIC, SINGULAR, STRING, region, 4) \ X(a, STATIC, SINGULAR, STRING, hw_model, 5) \ X(a, STATIC, SINGULAR, STRING, firmware_version, 6) \ -X(a, STATIC, SINGULAR, UINT32, error_code, 7) \ +X(a, STATIC, SINGULAR, UENUM, error_code, 7) \ X(a, STATIC, SINGULAR, UINT32, error_address, 8) \ X(a, STATIC, SINGULAR, UINT32, error_count, 9) \ X(a, STATIC, SINGULAR, UINT32, packet_id_bits, 10) \ @@ -582,10 +616,13 @@ X(a, STATIC, REPEATED, MESSAGE, secondary_channels, 12) #define DeviceState_rx_text_message_MSGTYPE MeshPacket #define DeviceState_secondary_channels_MSGTYPE ChannelSettings -#define DebugString_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, STRING, message, 1) -#define DebugString_CALLBACK NULL -#define DebugString_DEFAULT NULL +#define LogRecord_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, message, 1) \ +X(a, STATIC, SINGULAR, FIXED32, time, 2) \ +X(a, STATIC, SINGULAR, STRING, source, 3) \ +X(a, STATIC, SINGULAR, UENUM, level, 4) +#define LogRecord_CALLBACK NULL +#define LogRecord_DEFAULT NULL #define FromRadio_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, num, 1) \ @@ -593,7 +630,7 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 2) \ X(a, STATIC, ONEOF, MESSAGE, (variant,my_info,variant.my_info), 3) \ X(a, STATIC, ONEOF, MESSAGE, (variant,node_info,variant.node_info), 4) \ X(a, STATIC, ONEOF, MESSAGE, (variant,radio,variant.radio), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,debug_string,variant.debug_string), 7) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,log_record,variant.log_record), 7) \ X(a, STATIC, ONEOF, UINT32, (variant,config_complete_id,variant.config_complete_id), 8) \ X(a, STATIC, ONEOF, BOOL, (variant,rebooted,variant.rebooted), 9) \ X(a, STATIC, ONEOF, MESSAGE, (variant,secondary_channel,variant.secondary_channel), 10) @@ -603,7 +640,7 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,secondary_channel,variant.secondary_ #define FromRadio_variant_my_info_MSGTYPE MyNodeInfo #define FromRadio_variant_node_info_MSGTYPE NodeInfo #define FromRadio_variant_radio_MSGTYPE RadioConfig -#define FromRadio_variant_debug_string_MSGTYPE DebugString +#define FromRadio_variant_log_record_MSGTYPE LogRecord #define FromRadio_variant_secondary_channel_MSGTYPE ChannelSettings #define ToRadio_FIELDLIST(X, a) \ @@ -629,7 +666,7 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg; extern const pb_msgdesc_t NodeInfo_msg; extern const pb_msgdesc_t MyNodeInfo_msg; extern const pb_msgdesc_t DeviceState_msg; -extern const pb_msgdesc_t DebugString_msg; +extern const pb_msgdesc_t LogRecord_msg; extern const pb_msgdesc_t FromRadio_msg; extern const pb_msgdesc_t ToRadio_msg; @@ -646,7 +683,7 @@ extern const pb_msgdesc_t ToRadio_msg; #define NodeInfo_fields &NodeInfo_msg #define MyNodeInfo_fields &MyNodeInfo_msg #define DeviceState_fields &DeviceState_msg -#define DebugString_fields &DebugString_msg +#define LogRecord_fields &LogRecord_msg #define FromRadio_fields &FromRadio_msg #define ToRadio_fields &ToRadio_msg @@ -661,9 +698,9 @@ extern const pb_msgdesc_t ToRadio_msg; #define RadioConfig_size 308 #define RadioConfig_UserPreferences_size 219 #define NodeInfo_size 132 -#define MyNodeInfo_size 110 -#define DeviceState_size 5818 -#define DebugString_size 258 +#define MyNodeInfo_size 106 +#define DeviceState_size 5814 +#define LogRecord_size 81 #define FromRadio_size 329 #define ToRadio_size 323 diff --git a/src/mesh/portnums.pb.h b/src/mesh/portnums.pb.h index 703daa91..bef19c12 100644 --- a/src/mesh/portnums.pb.h +++ b/src/mesh/portnums.pb.h @@ -17,14 +17,14 @@ typedef enum _PortNum { PortNum_POSITION_APP = 3, PortNum_NODEINFO_APP = 4, PortNum_REPLY_APP = 32, - PortNum_PRIVATE_APP = 256, - PortNum_IP_TUNNEL_APP = 1024 + PortNum_IP_TUNNEL_APP = 33, + PortNum_PRIVATE_APP = 256 } PortNum; /* Helper constants for enums */ #define _PortNum_MIN PortNum_UNKNOWN_APP -#define _PortNum_MAX PortNum_IP_TUNNEL_APP -#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_IP_TUNNEL_APP+1)) +#define _PortNum_MAX PortNum_PRIVATE_APP +#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_PRIVATE_APP+1)) #ifdef __cplusplus diff --git a/src/sleep.cpp b/src/sleep.cpp index 60bf911f..ae175eed 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -127,7 +127,7 @@ static void waitEnterSleep() delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives) if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep - recordCriticalError(ErrSleepEnterWait); + recordCriticalError(CriticalErrorCode_SleepEnterWait); assert(0); // FIXME - for now we just restart, need to fix bug #167 break; }