From 41f9636ba39ba1ac326a045f59192ef35203d7bd Mon Sep 17 00:00:00 2001 From: thebentern Date: Tue, 3 Jan 2023 22:34:34 +0000 Subject: [PATCH 01/43] [create-pull-request] automated change --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 5c253336e..816f7c2ac 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 0 -build = 11 +build = 12 From 4f26a2a74a5ce53bc743d0953391663953925733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 4 Jan 2023 10:35:52 +0100 Subject: [PATCH 02/43] Update Unishox to latest V2 code, change is only cosmetic --- src/mesh/compression/unishox2.c | 108 ++++++++++++++++---------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/mesh/compression/unishox2.c b/src/mesh/compression/unishox2.c index e1f32ae05..2d6c60d75 100644 --- a/src/mesh/compression/unishox2.c +++ b/src/mesh/compression/unishox2.c @@ -33,14 +33,14 @@ #include "unishox2.h" -/// byte is unsigned char -typedef unsigned char byte; +/// uint8_t is unsigned char +typedef unsigned char uint8_t; /// possible horizontal sets and states enum {USX_ALPHA = 0, USX_SYM, USX_NUM, USX_DICT, USX_DELTA, USX_NUM_TEMP}; -/// This 2D array has the characters for the sets USX_ALPHA, USX_SYM and USX_NUM. Where a character cannot fit into a byte, 0 is used and handled in code. -byte usx_sets[][28] = {{ 0, ' ', 'e', 't', 'a', 'o', 'i', 'n', +/// This 2D array has the characters for the sets USX_ALPHA, USX_SYM and USX_NUM. Where a character cannot fit into a uint8_t, 0 is used and handled in code. +uint8_t usx_sets[][28] = {{ 0, ' ', 'e', 't', 'a', 'o', 'i', 'n', 's', 'r', 'l', 'c', 'd', 'h', 'u', 'p', 'm', 'b', 'g', 'w', 'f', 'y', 'v', 'k', 'q', 'j', 'x', 'z'}, {'"', '{', '}', '_', '<', '>', ':', '\n', @@ -53,22 +53,22 @@ byte usx_sets[][28] = {{ 0, ' ', 'e', 't', 'a', 'o', 'i', 'n', /// Stores position of letter in usx_sets. /// First 3 bits - position in usx_hcodes /// Next 5 bits - position in usx_vcodes -byte usx_code_94[94]; +uint8_t usx_code_94[94]; /// Vertical codes starting from the MSB -byte usx_vcodes[] = { 0x00, 0x40, 0x60, 0x80, 0x90, 0xA0, 0xB0, +uint8_t usx_vcodes[] = { 0x00, 0x40, 0x60, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE4, 0xE8, 0xEC, 0xEE, 0xF0, 0xF2, 0xF4, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; /// Length of each veritical code -byte usx_vcode_lens[] = { 2, 3, 3, 4, 4, 4, 4, +uint8_t usx_vcode_lens[] = { 2, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; /// Vertical Codes and Set number for frequent sequences in sets USX_SYM and USX_NUM. First 3 bits indicate set (USX_SYM/USX_NUM) and rest are vcode positions -byte usx_freq_codes[] = {(1 << 5) + 25, (1 << 5) + 26, (1 << 5) + 27, (2 << 5) + 23, (2 << 5) + 24, (2 << 5) + 25}; +uint8_t usx_freq_codes[] = {(1 << 5) + 25, (1 << 5) + 26, (1 << 5) + 27, (2 << 5) + 23, (2 << 5) + 24, (2 << 5) + 25}; /// Not used const int UTF8_MASK[] = {0xE0, 0xF0, 0xF8}; @@ -117,7 +117,7 @@ const int UTF8_PREFIX[] = {0xC0, 0xE0, 0xF0}; #define USX_OFFSET_94 33 /// global to indicate whether initialization is complete or not -byte is_inited = 0; +uint8_t is_inited = 0; /// Fills the usx_code_94 94 letter array based on sets of characters at usx_sets \n /// For each element in usx_code_94, first 3 msb bits is set (USX_ALPHA / USX_SYM / USX_NUM) \n @@ -128,7 +128,7 @@ void init_coder() { memset(usx_code_94, '\0', sizeof(usx_code_94)); for (int i = 0; i < 3; i++) { for (int j = 0; j < 28; j++) { - byte c = usx_sets[i][j]; + uint8_t c = usx_sets[i][j]; if (c > 32) { usx_code_94[c - USX_OFFSET_94] = (i << 5) + j; if (c >= 'a' && c <= 'z') @@ -145,7 +145,7 @@ unsigned int usx_mask[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF}; /// Appends specified number of bits to the output (out) \n /// If maximum limit (olen) is reached, -1 is returned \n /// Otherwise clen bits in code are appended to out starting with MSB -int append_bits(char *out, int olen, int ol, byte code, int clen) { +int append_bits(char *out, int olen, int ol, uint8_t code, int clen) { //printf("%d,%x,%d,%d\n", ol, code, clen, state); @@ -154,8 +154,8 @@ int append_bits(char *out, int olen, int ol, byte code, int clen) { int oidx; unsigned char a_byte; - byte cur_bit = ol % 8; - byte blen = clen; + uint8_t cur_bit = ol % 8; + uint8_t blen = clen; a_byte = code & usx_mask[blen - 1]; a_byte >>= cur_bit; if (blen + cur_bit > 8) @@ -181,7 +181,7 @@ int append_bits(char *out, int olen, int ol, byte code, int clen) { } while (0) /// Appends switch code to out depending on the state (USX_DELTA or other) -int append_switch_code(char *out, int olen, int ol, byte state) { +int append_switch_code(char *out, int olen, int ol, uint8_t state) { if (state == USX_DELTA) { SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, UNI_STATE_SPL_CODE, UNI_STATE_SPL_CODE_LEN)); SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, UNI_STATE_SW_CODE, UNI_STATE_SW_CODE_LEN)); @@ -191,9 +191,9 @@ int append_switch_code(char *out, int olen, int ol, byte state) { } /// Appends given horizontal and veritical code bits to out -int append_code(char *out, int olen, int ol, byte code, byte *state, const byte usx_hcodes[], const byte usx_hcode_lens[]) { - byte hcode = code >> 5; - byte vcode = code & 0x1F; +int append_code(char *out, int olen, int ol, uint8_t code, uint8_t *state, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) { + uint8_t hcode = code >> 5; + uint8_t vcode = code & 0x1F; if (!usx_hcode_lens[hcode] && hcode != USX_ALPHA) return ol; switch (hcode) { @@ -221,11 +221,11 @@ int append_code(char *out, int olen, int ol, byte code, byte *state, const byte } /// Length of bits used to represent count for each level -const byte count_bit_lens[5] = {2, 4, 7, 11, 16}; +const uint8_t count_bit_lens[5] = {2, 4, 7, 11, 16}; /// Cumulative counts represented at each level const int32_t count_adder[5] = {4, 20, 148, 2196, 67732}; /// Codes used to specify the level that the count belongs to -const byte count_codes[] = {0x01, 0x82, 0xC3, 0xE4, 0xF4}; +const uint8_t count_codes[] = {0x01, 0x82, 0xC3, 0xE4, 0xF4}; /// Encodes given count to out int encodeCount(char *out, int olen, int ol, int count) { // First five bits are code and Last three bits of codes represent length @@ -245,15 +245,15 @@ int encodeCount(char *out, int olen, int ol, int count) { } /// Length of bits used to represent delta code for each level -const byte uni_bit_len[5] = {6, 12, 14, 16, 21}; +const uint8_t uni_bit_len[5] = {6, 12, 14, 16, 21}; /// Cumulative delta codes represented at each level const int32_t uni_adder[5] = {0, 64, 4160, 20544, 86080}; /// Encodes the unicode code point given by code to out. prev_code is used to calculate the delta int encodeUnicode(char *out, int olen, int ol, int32_t code, int32_t prev_code) { // First five bits are code and Last three bits of codes represent length - //const byte codes[8] = {0x00, 0x42, 0x83, 0xA3, 0xC3, 0xE4, 0xF5, 0xFD}; - const byte codes[6] = {0x01, 0x82, 0xC3, 0xE4, 0xF5, 0xFD}; + //const uint8_t codes[8] = {0x00, 0x42, 0x83, 0xA3, 0xC3, 0xE4, 0xF5, 0xFD}; + const uint8_t codes[6] = {0x01, 0x82, 0xC3, 0xE4, 0xF5, 0xFD}; int32_t till = 0; int32_t diff = code - prev_code; if (diff < 0) @@ -331,7 +331,7 @@ int32_t readUTF8(const char *in, int len, int l, int *utf8len) { /// This is also used for Unicode strings \n /// This is a crude implementation that is not optimized. Assuming only short strings \n /// are encoded, this is not much of an issue. -int matchOccurance(const char *in, int len, int l, char *out, int olen, int *ol, byte *state, const byte usx_hcodes[], const byte usx_hcode_lens[]) { +int matchOccurance(const char *in, int len, int l, char *out, int olen, int *ol, uint8_t *state, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) { int j, k; int longest_dist = 0; int longest_len = 0; @@ -372,7 +372,7 @@ int matchOccurance(const char *in, int len, int l, char *out, int olen, int *ol, /// This is also used for Unicode strings \n /// This is a crude implementation that is not optimized. Assuming only short strings \n /// are encoded, this is not much of an issue. -int matchLine(const char *in, int len, int l, char *out, int olen, int *ol, struct us_lnk_lst *prev_lines, byte *state, const byte usx_hcodes[], const byte usx_hcode_lens[]) { +int matchLine(const char *in, int len, int l, char *out, int olen, int *ol, struct us_lnk_lst *prev_lines, uint8_t *state, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) { int last_ol = *ol; int last_len = 0; int last_dist = 0; @@ -431,7 +431,7 @@ int matchLine(const char *in, int len, int l, char *out, int olen, int *ol, stru /// Returns 4 bit code assuming ch falls between '0' to '9', \n /// 'A' to 'F' or 'a' to 'f' -byte getBaseCode(char ch) { +uint8_t getBaseCode(char ch) { if (ch >= '0' && ch <= '9') return (ch - '0') << 4; else if (ch >= 'A' && ch <= 'F') @@ -458,7 +458,7 @@ char getNibbleType(char ch) { } /// Starts coding of nibble sets -int append_nibble_escape(char *out, int olen, int ol, byte state, const byte usx_hcodes[], const byte usx_hcode_lens[]) { +int append_nibble_escape(char *out, int olen, int ol, uint8_t state, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) { SAFE_APPEND_BITS(ol = append_switch_code(out, olen, ol, state)); SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, usx_hcodes[USX_NUM], usx_hcode_lens[USX_NUM])); SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, 0, 2)); @@ -471,7 +471,7 @@ long min_of(long c, long i) { } /// Appends the terminator code depending on the state, preset and whether full terminator needs to be encoded to out or not \n -int append_final_bits(char *const out, const int olen, int ol, const byte state, const byte is_all_upper, const byte usx_hcodes[], const byte usx_hcode_lens[]) { +int append_final_bits(char *const out, const int olen, int ol, const uint8_t state, const uint8_t is_all_upper, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) { if (usx_hcode_lens[USX_ALPHA]) { if (USX_NUM != state) { // for num state, append TERM_CODE directly @@ -486,7 +486,7 @@ int append_final_bits(char *const out, const int olen, int ol, const byte state, SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, TERM_BYTE_PRESET_1, is_all_upper ? TERM_BYTE_PRESET_1_LEN_UPPER : TERM_BYTE_PRESET_1_LEN_LOWER)); } - // fill byte with the last bit + // fill uint8_t with the last bit SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, (ol == 0 || out[(ol-1)/8] << ((ol-1)&7) >= 0) ? 0 : 0xFF, (8 - ol % 8) & 7)); return ol; @@ -500,21 +500,21 @@ int append_final_bits(char *const out, const int olen, int ol, const byte state, } while (0) // Main API function. See unishox2.h for documentation -int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) { +int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) { - byte state; + uint8_t state; int l, ll, ol; char c_in, c_next; int prev_uni; - byte is_upper, is_all_upper; + uint8_t is_upper, is_all_upper; #if (UNISHOX_API_OUT_AND_LEN(0,1)) == 0 const int olen = INT_MAX - 1; const int rawolen = olen; - const byte need_full_term_codes = 0; + const uint8_t need_full_term_codes = 0; #else const int rawolen = olen; - byte need_full_term_codes = 0; + uint8_t need_full_term_codes = 0; if (olen < 0) { need_full_term_codes = 1; olen *= -1; @@ -735,9 +735,9 @@ int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(cha } } if (state == USX_DELTA && (c_in == ' ' || c_in == '.' || c_in == ',')) { - byte spl_code = (c_in == ',' ? 0xC0 : (c_in == '.' ? 0xE0 : (c_in == ' ' ? 0 : 0xFF))); + uint8_t spl_code = (c_in == ',' ? 0xC0 : (c_in == '.' ? 0xE0 : (c_in == ' ' ? 0 : 0xFF))); if (spl_code != 0xFF) { - byte spl_code_len = (c_in == ',' ? 3 : (c_in == '.' ? 4 : (c_in == ' ' ? 1 : 4))); + uint8_t spl_code_len = (c_in == ',' ? 3 : (c_in == '.' ? 4 : (c_in == ' ' ? 1 : 4))); SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, UNI_STATE_SPL_CODE, UNI_STATE_SPL_CODE_LEN)); SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, spl_code, spl_code_len)); continue; @@ -833,7 +833,7 @@ int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(cha } // Main API function. See unishox2.h for documentation -int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) { +int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) { return unishox2_compress_lines(in, len, UNISHOX_API_OUT_AND_LEN(out, olen), usx_hcodes, usx_hcode_lens, usx_freq_seq, usx_templates, NULL); } @@ -852,10 +852,10 @@ int read8bitCode(const char *in, int len, int bit_no) { int bit_pos = bit_no & 0x07; int char_pos = bit_no >> 3; len >>= 3; - byte code = (((byte)in[char_pos]) << bit_pos); + uint8_t code = (((uint8_t)in[char_pos]) << bit_pos); char_pos++; if (char_pos < len) { - code |= ((byte)in[char_pos]) >> (8 - bit_pos); + code |= ((uint8_t)in[char_pos]) >> (8 - bit_pos); } else code |= (0xFF >> (8 - bit_pos)); return code; @@ -864,17 +864,17 @@ int read8bitCode(const char *in, int len, int bit_no) { /// The list of veritical codes is split into 5 sections. Used by readVCodeIdx() #define SECTION_COUNT 5 /// Used by readVCodeIdx() for finding the section under which the code read using read8bitCode() falls -byte usx_vsections[] = {0x7F, 0xBF, 0xDF, 0xEF, 0xFF}; +uint8_t usx_vsections[] = {0x7F, 0xBF, 0xDF, 0xEF, 0xFF}; /// Used by readVCodeIdx() for finding the section vertical position offset -byte usx_vsection_pos[] = {0, 4, 8, 12, 20}; +uint8_t usx_vsection_pos[] = {0, 4, 8, 12, 20}; /// Used by readVCodeIdx() for masking the code read by read8bitCode() -byte usx_vsection_mask[] = {0x7F, 0x3F, 0x1F, 0x0F, 0x0F}; +uint8_t usx_vsection_mask[] = {0x7F, 0x3F, 0x1F, 0x0F, 0x0F}; /// Used by readVCodeIdx() for shifting the code read by read8bitCode() to obtain the vpos -byte usx_vsection_shift[] = {5, 4, 3, 1, 0}; +uint8_t usx_vsection_shift[] = {5, 4, 3, 1, 0}; /// Vertical decoder lookup table - 3 bits code len, 5 bytes vertical pos /// code len is one less as 8 cannot be accommodated in 3 bits -byte usx_vcode_lookup[36] = { +uint8_t usx_vcode_lookup[36] = { (1 << 5) + 0, (1 << 5) + 0, (2 << 5) + 1, (2 << 5) + 2, // Section 1 (3 << 5) + 3, (3 << 5) + 4, (3 << 5) + 5, (3 << 5) + 6, // Section 2 (3 << 5) + 7, (3 << 5) + 7, (4 << 5) + 8, (4 << 5) + 9, // Section 3 @@ -887,19 +887,19 @@ byte usx_vcode_lookup[36] = { }; /// Decodes the vertical code from the given bitstream at in \n -/// This is designed to use less memory using a 36 byte buffer \n -/// compared to using a 256 byte buffer to decode the next 8 bits read by read8bitCode() \n +/// This is designed to use less memory using a 36 uint8_t buffer \n +/// compared to using a 256 uint8_t buffer to decode the next 8 bits read by read8bitCode() \n /// by splitting the list of vertical codes. \n /// Decoder is designed for using less memory, not speed. \n /// Returns the veritical code index or 99 if match could not be found. \n /// Also updates bit_no_p with how many ever bits used by the vertical code. int readVCodeIdx(const char *in, int len, int *bit_no_p) { if (*bit_no_p < len) { - byte code = read8bitCode(in, len, *bit_no_p); + uint8_t code = read8bitCode(in, len, *bit_no_p); int i = 0; do { if (code <= usx_vsections[i]) { - byte vcode = usx_vcode_lookup[usx_vsection_pos[i] + ((code & usx_vsection_mask[i]) >> usx_vsection_shift[i])]; + uint8_t vcode = usx_vcode_lookup[usx_vsection_pos[i] + ((code & usx_vsection_mask[i]) >> usx_vsection_shift[i])]; (*bit_no_p) += ((vcode >> 5) + 1); if (*bit_no_p > len) return 99; @@ -912,16 +912,16 @@ int readVCodeIdx(const char *in, int len, int *bit_no_p) { /// Mask for retrieving each code to be decoded according to its length \n /// Same as usx_mask so redundant -byte len_masks[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF}; +uint8_t len_masks[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF}; /// Decodes the horizontal code from the given bitstream at in \n /// depending on the hcodes defined using usx_hcodes and usx_hcode_lens \n /// Returns the horizontal code index or 99 if match could not be found. \n /// Also updates bit_no_p with how many ever bits used by the horizontal code. -int readHCodeIdx(const char *in, int len, int *bit_no_p, const byte usx_hcodes[], const byte usx_hcode_lens[]) { +int readHCodeIdx(const char *in, int len, int *bit_no_p, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) { if (!usx_hcode_lens[USX_ALPHA]) return USX_ALPHA; if (*bit_no_p < len) { - byte code = read8bitCode(in, len, *bit_no_p); + uint8_t code = read8bitCode(in, len, *bit_no_p); for (int code_pos = 0; code_pos < 5; code_pos++) { if (usx_hcode_lens[code_pos] && (code & len_masks[usx_hcode_lens[code_pos] - 1]) == usx_hcodes[code_pos]) { *bit_no_p += usx_hcode_lens[code_pos]; @@ -1083,12 +1083,12 @@ char getHexChar(int32_t nibble, int hex_type) { } // Main API function. See unishox2.h for documentation -int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) { +int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) { int dstate; int bit_no; int h, v; - byte is_all_upper; + uint8_t is_all_upper; #if (UNISHOX_API_OUT_AND_LEN(0,1)) == 0 const int olen = INT_MAX - 1; #endif @@ -1155,7 +1155,7 @@ int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(c } else h = dstate; char c = 0; - byte is_upper = is_all_upper; + uint8_t is_upper = is_all_upper; v = readVCodeIdx(in, len, &bit_no); if (v == 99 || h == 99) { bit_no = orig_bit_no; @@ -1357,7 +1357,7 @@ int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(c } // Main API function. See unishox2.h for documentation -int unishox2_decompress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) { +int unishox2_decompress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) { return unishox2_decompress_lines(in, len, UNISHOX_API_OUT_AND_LEN(out, olen), usx_hcodes, usx_hcode_lens, usx_freq_seq, usx_templates, NULL); } From d077be1496a467e4cbc75d0ca10207387569326b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 4 Jan 2023 10:37:27 +0100 Subject: [PATCH 03/43] add a possibility to flush the serial TX buffer on the console. --- src/SerialConsole.cpp | 6 ++++-- src/SerialConsole.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 0b6b9ee24..b66eae455 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -20,9 +20,7 @@ void consolePrintf(const char *format, ...) va_start(arg, format); console->vprintf(format, arg); va_end(arg); -#ifdef ARCH_ESP32 console->flush(); -#endif } SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole") @@ -51,6 +49,10 @@ int32_t SerialConsole::runOnce() return runOncePart(); } +void SerialConsole::flush() { + Port.flush(); +} + // For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages bool SerialConsole::checkIsConnected() { diff --git a/src/SerialConsole.h b/src/SerialConsole.h index d1f2abac8..f5e2077ba 100644 --- a/src/SerialConsole.h +++ b/src/SerialConsole.h @@ -26,6 +26,8 @@ class SerialConsole : public StreamAPI, public RedirectablePrint, private concur virtual int32_t runOnce() override; + void flush(); + protected: /// Check the current underlying physical link to see if the client is currently connected From 30ae4c2a38abb376a2bf61acc5184ec5cff5176f Mon Sep 17 00:00:00 2001 From: pavelb-techspark <107929268+pavelb-techspark@users.noreply.github.com> Date: Wed, 4 Jan 2023 14:56:52 +0200 Subject: [PATCH 04/43] Add QueueStatus sending to the firmware (#1820) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Yank mqtt service envelope queue * trybuildfix mqtt system * removed too much * no excessive heap debugging on release builds * send QueueStatus messages The QueueStatus message is sent as a response to the attempt to queue an outgoing MeshPacket and contains statuses of the last queue attempt, TX Queue space and capacity and MeshPacket.id that was queued. When TX Queue changes status from completely full to at least a single slot free a QueueStatus message is also sent to notify that user can queue more messages. Signed-off-by: Pavel Boldin * WIP: update protobufs Signed-off-by: Pavel Boldin * update protobufs * regen protos Signed-off-by: Pavel Boldin Co-authored-by: Ben Meadors Co-authored-by: Thomas Göttgens Co-authored-by: Sacha Weatherstone --- arch/esp32/esp32.ini | 1 - arch/esp32/esp32s2.ini | 1 - arch/esp32/esp32s3.ini | 1 - protobufs | 2 +- src/mesh/MeshPacketQueue.h | 6 +++ src/mesh/MeshService.cpp | 45 +++++++++++++++++++- src/mesh/MeshService.h | 16 +++++++ src/mesh/PhoneAPI.cpp | 26 ++++++++++-- src/mesh/PhoneAPI.h | 5 +++ src/mesh/RadioInterface.h | 7 +++ src/mesh/RadioLibInterface.cpp | 11 +++++ src/mesh/RadioLibInterface.h | 2 + src/mesh/Router.cpp | 5 +++ src/mesh/Router.h | 3 ++ src/mesh/generated/mesh.pb.c | 3 ++ src/mesh/generated/mesh.pb.h | 36 +++++++++++++++- src/mesh/generated/module_config.pb.h | 1 + src/mqtt/MQTT.cpp | 61 ++++----------------------- src/mqtt/MQTT.h | 5 +-- src/platform/portduino/SimRadio.cpp | 10 +++++ src/platform/portduino/SimRadio.h | 3 ++ 21 files changed, 184 insertions(+), 66 deletions(-) diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 0011cc39f..70654e8ec 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -26,7 +26,6 @@ build_flags = -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING - -DDEBUG_HEAP lib_deps = ${arduino_base.lib_deps} diff --git a/arch/esp32/esp32s2.ini b/arch/esp32/esp32s2.ini index ca4f576d6..cd47c4ca1 100644 --- a/arch/esp32/esp32s2.ini +++ b/arch/esp32/esp32s2.ini @@ -27,7 +27,6 @@ build_flags = -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING -DHAS_BLUETOOTH=0 - -DDEBUG_HEAP lib_deps = ${arduino_base.lib_deps} diff --git a/arch/esp32/esp32s3.ini b/arch/esp32/esp32s3.ini index b276ceff9..ce64fdbe2 100644 --- a/arch/esp32/esp32s3.ini +++ b/arch/esp32/esp32s3.ini @@ -26,7 +26,6 @@ build_flags = -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING - -DDEBUG_HEAP lib_deps = ${arduino_base.lib_deps} diff --git a/protobufs b/protobufs index 6048ecd2f..3b0d871ca 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 6048ecd2f8433005bb73ab4505386a7bbdb78c86 +Subproject commit 3b0d871ca1e0f8a2ed823f0696e2d7cf31ed2ebd diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index 8c93b452e..ee6c6954a 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -26,6 +26,12 @@ class MeshPacketQueue /** return true if the queue is empty */ bool empty(); + /** return amount of free packets in Queue */ + size_t getFree() { return maxLen - queue.size(); } + + /** return total size of the Queue */ + size_t getMaxLen() { return maxLen; } + MeshPacket *dequeue(); MeshPacket *getFront(); diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index c300104a4..208b1b9ea 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -52,10 +52,15 @@ FIXME in the initial proof of concept we just skip the entire want/deny flow and MeshService service; +static MemoryDynamic staticQueueStatusPool; + +Allocator &queueStatusPool = staticQueueStatusPool; + #include "Router.h" -MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE) +MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE) { + lastQueueStatus = { 0, 0, 16, 0 }; // assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro } @@ -83,6 +88,11 @@ int MeshService::handleFromRadio(const MeshPacket *mp) /// Do idle processing (mostly processing messages which have been queued from the radio) void MeshService::loop() { + if (lastQueueStatus.free == 0) { // check if there is now free space in TX queue + QueueStatus qs = router->getQueueStatus(); + if (qs.free != lastQueueStatus.free) + (void)sendQueueStatusToPhone(qs, 0, 0); + } if (oldFromNum != fromNum) { // We don't want to generate extra notifies for multiple new packets fromNumChanged.notifyObservers(fromNum); oldFromNum = fromNum; @@ -179,12 +189,43 @@ bool MeshService::cancelSending(PacketId id) return router->cancelSending(nodeDB.getNodeNum(), id); } +ErrorCode MeshService::sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id) +{ + QueueStatus *copied = queueStatusPool.allocCopy(qs); + + copied->res = res; + copied->mesh_packet_id = mesh_packet_id; + + if (toPhoneQueueStatusQueue.numFree() == 0) { + LOG_DEBUG("NOTE: tophone queue status queue is full, discarding oldest\n"); + QueueStatus *d = toPhoneQueueStatusQueue.dequeuePtr(0); + if (d) + releaseQueueStatusToPool(d); + } + + lastQueueStatus = *copied; + + res = toPhoneQueueStatusQueue.enqueue(copied, 0); + fromNum++; + + return res ? ERRNO_OK : ERRNO_UNKNOWN; +} + void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone) { + uint32_t mesh_packet_id = p->id; nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...) // Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it - router->sendLocal(p, src); + ErrorCode res = router->sendLocal(p, src); + + /* NOTE(pboldin): Prepare and send QueueStatus message to the phone as a + * high-priority message. */ + QueueStatus qs = router->getQueueStatus(); + ErrorCode r = sendQueueStatusToPhone(qs, res, mesh_packet_id); + if (r != ERRNO_OK) { + LOG_DEBUG("Can't send status to phone"); + } if (ccToPhone) { sendToPhone(p); diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index c3b3c95d9..31b63bd3f 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -14,6 +14,8 @@ #include "../platform/portduino/SimRadio.h" #endif +extern Allocator &queueStatusPool; + /** * Top level app for this service. keeps the mesh, the radio config and the queue of received packets. * @@ -29,6 +31,12 @@ class MeshService /// FIXME - save this to flash on deep sleep PointerQueue toPhoneQueue; + // keep list of QueueStatus packets to be send to the phone + PointerQueue toPhoneQueueStatusQueue; + + // This holds the last QueueStatus send + QueueStatus lastQueueStatus; + /// The current nonce for the newest packet which has been queued for the phone uint32_t fromNum = 0; @@ -56,6 +64,12 @@ class MeshService /// Allows the bluetooth handler to free packets after they have been sent void releaseToPool(MeshPacket *p) { packetPool.release(p); } + /// Return the next QueueStatus packet destined to the phone. + QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); } + + // Release QueueStatus packet to pool + void releaseQueueStatusToPool(QueueStatus *p) { queueStatusPool.release(p); } + /** * Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh) * Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep @@ -100,6 +114,8 @@ class MeshService /// needs to keep the packet around it makes a copy int handleFromRadio(const MeshPacket *p); friend class RoutingModule; + + ErrorCode sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id); }; extern MeshService service; diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 897ddfe8a..c1d56b7ec 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -50,6 +50,7 @@ void PhoneAPI::close() unobserve(&service.fromNumChanged); releasePhonePacket(); // Don't leak phone packets on shutdown + releaseQueueStatusPhonePacket(); onConnectionChanged(false); } @@ -282,14 +283,19 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) case STATE_SEND_PACKETS: // Do we have a message from the mesh? LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n"); - if (packetForPhone) { + if (queueStatusPacketForPhone) { + + fromRadioScratch.which_payload_variant = FromRadio_queueStatus_tag; + fromRadioScratch.queueStatus = *queueStatusPacketForPhone; + releaseQueueStatusPhonePacket(); + } else if (packetForPhone) { printPacket("phone downloaded packet", packetForPhone); // Encapsulate as a FromRadio packet fromRadioScratch.which_payload_variant = FromRadio_packet_tag; fromRadioScratch.packet = *packetForPhone; + releasePhonePacket(); } - releasePhonePacket(); break; default: @@ -322,6 +328,14 @@ void PhoneAPI::releasePhonePacket() } } +void PhoneAPI::releaseQueueStatusPhonePacket() +{ + if (queueStatusPacketForPhone) { + service.releaseQueueStatusToPool(queueStatusPacketForPhone); + queueStatusPacketForPhone = NULL; + } +} + /** * Return true if we have data available to send to the phone */ @@ -342,9 +356,15 @@ bool PhoneAPI::available() return true; // Always say we have something, because we might need to advance our state machine case STATE_SEND_PACKETS: { + if (!queueStatusPacketForPhone) + queueStatusPacketForPhone = service.getQueueStatusForPhone(); + bool hasPacket = !!queueStatusPacketForPhone; + if (hasPacket) + return true; + if (!packetForPhone) packetForPhone = service.getForPhone(); - bool hasPacket = !!packetForPhone; + hasPacket = !!packetForPhone; // LOG_DEBUG("available hasPacket=%d\n", hasPacket); return hasPacket; } diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index cbac5f688..2f2695807 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -42,6 +42,9 @@ class PhoneAPI : public Observer // FIXME, we shouldn't be inheriting /// downloads it MeshPacket *packetForPhone = NULL; + // Keep QueueStatus packet just as packetForPhone + QueueStatus *queueStatusPacketForPhone = NULL; + /// We temporarily keep the nodeInfo here between the call to available and getFromRadio const NodeInfo *nodeInfoForPhone = NULL; @@ -115,6 +118,8 @@ class PhoneAPI : public Observer // FIXME, we shouldn't be inheriting private: void releasePhonePacket(); + void releaseQueueStatusPhonePacket(); + /// begin a new connection void handleStartConfig(); diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index f50c0ae77..59c63add2 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -115,6 +115,13 @@ class RadioInterface */ virtual ErrorCode send(MeshPacket *p) = 0; + /** Return TX queue status */ + virtual QueueStatus getQueueStatus() { + QueueStatus qs; + qs.res = qs.mesh_packet_id = qs.free = qs.maxlen = 0; + return qs; + } + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ virtual bool cancelSending(NodeNum from, PacketId id) { return false; } diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 53eaeca60..81a4d803e 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -158,6 +158,17 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) #endif } +QueueStatus RadioLibInterface::getQueueStatus() +{ + QueueStatus qs; + + qs.res = qs.mesh_packet_id = 0; + qs.free = txQueue.getFree(); + qs.maxlen = txQueue.getMaxLen(); + + return qs; +} + bool RadioLibInterface::canSleep() { bool res = txQueue.empty(); diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 16495c2f4..628ea863f 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -153,6 +153,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual void startSend(MeshPacket *txp); + QueueStatus getQueueStatus(); + protected: /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 0a8497463..0f34010ec 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -148,6 +148,11 @@ void Router::setReceivedMessage() runASAP = true; } +QueueStatus Router::getQueueStatus() +{ + return iface->getQueueStatus(); +} + ErrorCode Router::sendLocal(MeshPacket *p, RxSource src) { // No need to deliver externally if the destination is the local node diff --git a/src/mesh/Router.h b/src/mesh/Router.h index f7748bb2b..5a9cc0702 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -55,6 +55,9 @@ class Router : protected concurrency::OSThread */ MeshPacket *allocForSending(); + /** Return Underlying interface's TX queue status */ + QueueStatus getQueueStatus(); + /** * @return our local nodenum */ NodeNum getNodeNum(); diff --git a/src/mesh/generated/mesh.pb.c b/src/mesh/generated/mesh.pb.c index bd749b6cb..29594c612 100644 --- a/src/mesh/generated/mesh.pb.c +++ b/src/mesh/generated/mesh.pb.c @@ -36,6 +36,9 @@ PB_BIND(MyNodeInfo, MyNodeInfo, AUTO) PB_BIND(LogRecord, LogRecord, AUTO) +PB_BIND(QueueStatus, QueueStatus, AUTO) + + PB_BIND(FromRadio, FromRadio, 2) diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 31e7817a0..d1f3e5bf5 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -621,6 +621,17 @@ typedef struct _LogRecord { LogRecord_Level level; } LogRecord; +typedef struct _QueueStatus { + /* Last attempt to queue status, ErrorCode */ + int8_t res; + /* Free entries in the outgoing queue */ + uint8_t free; + /* Maximum entries in the outgoing queue */ + uint8_t maxlen; + /* What was mesh packet id that generated this response? */ + uint32_t mesh_packet_id; +} QueueStatus; + /* Packets from the radio to the phone will appear on the fromRadio characteristic. It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? It will sit in that descriptor until consumed by the phone, @@ -657,6 +668,8 @@ typedef struct _FromRadio { ModuleConfig moduleConfig; /* One packet is sent for each channel */ Channel channel; + /* Queue status info */ + QueueStatus queueStatus; }; } FromRadio; @@ -755,6 +768,7 @@ extern "C" { + #define Compressed_portnum_ENUMTYPE PortNum @@ -769,6 +783,7 @@ extern "C" { #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0, false, DeviceMetrics_init_default} #define MyNodeInfo_init_default {0, 0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} +#define QueueStatus_init_default {0, 0, 0, 0} #define FromRadio_init_default {0, 0, {MeshPacket_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}} #define Compressed_init_default {_PortNum_MIN, {0, {0}}} @@ -782,6 +797,7 @@ extern "C" { #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0, false, DeviceMetrics_init_zero} #define MyNodeInfo_init_zero {0, 0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} +#define QueueStatus_init_zero {0, 0, 0, 0} #define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}} #define ToRadio_init_zero {0, {MeshPacket_init_zero}} #define Compressed_init_zero {_PortNum_MIN, {0, {0}}} @@ -873,6 +889,10 @@ extern "C" { #define LogRecord_time_tag 2 #define LogRecord_source_tag 3 #define LogRecord_level_tag 4 +#define QueueStatus_res_tag 1 +#define QueueStatus_free_tag 2 +#define QueueStatus_maxlen_tag 3 +#define QueueStatus_mesh_packet_id_tag 4 #define FromRadio_id_tag 1 #define FromRadio_packet_tag 2 #define FromRadio_my_info_tag 3 @@ -883,6 +903,7 @@ extern "C" { #define FromRadio_rebooted_tag 8 #define FromRadio_moduleConfig_tag 9 #define FromRadio_channel_tag 10 +#define FromRadio_queueStatus_tag 11 #define ToRadio_packet_tag 1 #define ToRadio_want_config_id_tag 3 #define ToRadio_disconnect_tag 4 @@ -1022,6 +1043,14 @@ X(a, STATIC, SINGULAR, UENUM, level, 4) #define LogRecord_CALLBACK NULL #define LogRecord_DEFAULT NULL +#define QueueStatus_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT32, res, 1) \ +X(a, STATIC, SINGULAR, UINT32, free, 2) \ +X(a, STATIC, SINGULAR, UINT32, maxlen, 3) \ +X(a, STATIC, SINGULAR, UINT32, mesh_packet_id, 4) +#define QueueStatus_CALLBACK NULL +#define QueueStatus_DEFAULT NULL + #define FromRadio_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, id, 1) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 2) \ @@ -1032,7 +1061,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,log_record,log_record), 6) X(a, STATIC, ONEOF, UINT32, (payload_variant,config_complete_id,config_complete_id), 7) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,rebooted,rebooted), 8) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig), 9) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,queueStatus,queueStatus), 11) #define FromRadio_CALLBACK NULL #define FromRadio_DEFAULT NULL #define FromRadio_payload_variant_packet_MSGTYPE MeshPacket @@ -1042,6 +1072,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) #define FromRadio_payload_variant_log_record_MSGTYPE LogRecord #define FromRadio_payload_variant_moduleConfig_MSGTYPE ModuleConfig #define FromRadio_payload_variant_channel_MSGTYPE Channel +#define FromRadio_payload_variant_queueStatus_MSGTYPE QueueStatus #define ToRadio_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \ @@ -1067,6 +1098,7 @@ extern const pb_msgdesc_t MeshPacket_msg; extern const pb_msgdesc_t NodeInfo_msg; extern const pb_msgdesc_t MyNodeInfo_msg; extern const pb_msgdesc_t LogRecord_msg; +extern const pb_msgdesc_t QueueStatus_msg; extern const pb_msgdesc_t FromRadio_msg; extern const pb_msgdesc_t ToRadio_msg; extern const pb_msgdesc_t Compressed_msg; @@ -1082,6 +1114,7 @@ extern const pb_msgdesc_t Compressed_msg; #define NodeInfo_fields &NodeInfo_msg #define MyNodeInfo_fields &MyNodeInfo_msg #define LogRecord_fields &LogRecord_msg +#define QueueStatus_fields &QueueStatus_msg #define FromRadio_fields &FromRadio_msg #define ToRadio_fields &ToRadio_msg #define Compressed_fields &Compressed_msg @@ -1095,6 +1128,7 @@ extern const pb_msgdesc_t Compressed_msg; #define MyNodeInfo_size 179 #define NodeInfo_size 258 #define Position_size 137 +#define QueueStatus_size 23 #define RouteDiscovery_size 40 #define Routing_size 42 #define ToRadio_size 324 diff --git a/src/mesh/generated/module_config.pb.h b/src/mesh/generated/module_config.pb.h index 52b551590..da13ac706 100644 --- a/src/mesh/generated/module_config.pb.h +++ b/src/mesh/generated/module_config.pb.h @@ -301,6 +301,7 @@ extern "C" { + #define ModuleConfig_AudioConfig_bitrate_ENUMTYPE ModuleConfig_AudioConfig_Audio_Baud #define ModuleConfig_SerialConfig_baud_ENUMTYPE ModuleConfig_SerialConfig_Serial_Baud diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index f4004139a..49ad586dd 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -21,10 +21,6 @@ String statusTopic = "msh/2/stat/"; String cryptTopic = "msh/2/c/"; // msh/2/c/CHANNELID/NODEID String jsonTopic = "msh/2/json/"; // msh/2/json/CHANNELID/NODEID -static MemoryDynamic staticMqttPool; - -Allocator &mqttPool = staticMqttPool; - void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length) { mqtt->onPublish(topic, payload, length); @@ -126,7 +122,7 @@ void mqttInit() new MQTT(); } -MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE) +MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient) { if(moduleConfig.mqtt.enabled) { @@ -253,36 +249,9 @@ int32_t MQTT::runOnce() if (!pubSub.loop()) { if (wantConnection) { reconnect(); - - // If we succeeded, empty the queue one by one and start reading rapidly, else try again in 30 seconds (TCP connections are EXPENSIVE so try rarely) - if (pubSub.connected()) { - if (!mqttQueue.isEmpty()) { - // FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets - ServiceEnvelope *env = mqttQueue.dequeuePtr(0); - static uint8_t bytes[MeshPacket_size + 64]; - size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &ServiceEnvelope_msg, env); - - String topic = cryptTopic + env->channel_id + "/" + owner.id; - LOG_INFO("publish %s, %u bytes from queue\n", topic.c_str(), numBytes); - - - pubSub.publish(topic.c_str(), bytes, numBytes, false); - - if (moduleConfig.mqtt.json_enabled) { - // handle json topic - auto jsonString = this->downstreamPacketToJson(env->packet); - if (jsonString.length() != 0) { - String topicJson = jsonTopic + env->channel_id + "/" + owner.id; - LOG_INFO("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str()); - pubSub.publish(topicJson.c_str(), jsonString.c_str(), false); - } - } - mqttPool.release(env); - } - return 20; - } else { - return 30000; - } + + // If we succeeded, start reading rapidly, else try again in 30 seconds (TCP connections are EXPENSIVE so try rarely) + return pubSub.connected() ? 20 : 30000; } else return 5000; // If we don't want connection now, check again in 5 secs } else { @@ -304,17 +273,17 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex) if (ch.settings.uplink_enabled) { const char *channelId = channels.getGlobalId(chIndex); // FIXME, for now we just use the human name for the channel - ServiceEnvelope *env = mqttPool.allocZeroed(); - env->channel_id = (char *)channelId; - env->gateway_id = owner.id; - env->packet = (MeshPacket *)∓ + ServiceEnvelope env = ServiceEnvelope_init_default; + env.channel_id = (char *)channelId; + env.gateway_id = owner.id; + env.packet = (MeshPacket *)∓ // don't bother sending if not connected... if (pubSub.connected()) { // FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets static uint8_t bytes[MeshPacket_size + 64]; - size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &ServiceEnvelope_msg, env); + size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &ServiceEnvelope_msg, &env); String topic = cryptTopic + channelId + "/" + owner.id; LOG_DEBUG("publish %s, %u bytes\n", topic.c_str(), numBytes); @@ -330,19 +299,7 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex) pubSub.publish(topicJson.c_str(), jsonString.c_str(), false); } } - } else { - LOG_INFO("MQTT not connected, queueing packet\n"); - if (mqttQueue.numFree() == 0) { - LOG_WARN("NOTE: MQTT queue is full, discarding oldest\n"); - ServiceEnvelope *d = mqttQueue.dequeuePtr(0); - if (d) - mqttPool.release(d); - } - // make a copy of serviceEnvelope and queue it - ServiceEnvelope *copied = mqttPool.allocCopy(*env); - assert(mqttQueue.enqueue(copied, 0)); } - mqttPool.release(env); } } diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index ddbacbcc4..33fbbb8eb 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -13,8 +13,6 @@ #include #endif -#define MAX_MQTT_QUEUE 32 - /** * Our wrapper/singleton for sending/receiving MQTT "udp" packets. This object isolates the MQTT protocol implementation from * the two components that use it: MQTTPlugin and MQTTSimInterface. @@ -55,10 +53,9 @@ class MQTT : private concurrency::OSThread bool connected(); protected: - PointerQueue mqttQueue; int reconnectCount = 0; - + virtual int32_t runOnce() override; private: diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp index 87800de22..a2611a464 100644 --- a/src/platform/portduino/SimRadio.cpp +++ b/src/platform/portduino/SimRadio.cpp @@ -215,6 +215,16 @@ void SimRadio::startReceive(MeshPacket *p) { handleReceiveInterrupt(p); } +QueueStatus SimRadio::getQueueStatus() +{ + QueueStatus qs; + + qs.res = qs.mesh_packet_id = 0; + qs.free = txQueue.getFree(); + qs.maxlen = txQueue.getMaxLen(); + + return qs; +} void SimRadio::handleReceiveInterrupt(MeshPacket *p) { diff --git a/src/platform/portduino/SimRadio.h b/src/platform/portduino/SimRadio.h index a71cf22f8..d2a36c81e 100644 --- a/src/platform/portduino/SimRadio.h +++ b/src/platform/portduino/SimRadio.h @@ -45,6 +45,9 @@ class SimRadio : public RadioInterface */ virtual void startReceive(MeshPacket *p); + QueueStatus getQueueStatus() override; + + protected: /// are _trying_ to receive a packet currently (note - we might just be waiting for one) bool isReceiving = false; From d9f0dc7ea41766842cfd8204b1fdedd139390c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 4 Jan 2023 14:41:58 +0100 Subject: [PATCH 05/43] add MQTT outqueue back in (still broken) --- src/mqtt/MQTT.cpp | 61 ++++++++++++++++++++++++++++++++++++++++------- src/mqtt/MQTT.h | 5 +++- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 49ad586dd..f4004139a 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -21,6 +21,10 @@ String statusTopic = "msh/2/stat/"; String cryptTopic = "msh/2/c/"; // msh/2/c/CHANNELID/NODEID String jsonTopic = "msh/2/json/"; // msh/2/json/CHANNELID/NODEID +static MemoryDynamic staticMqttPool; + +Allocator &mqttPool = staticMqttPool; + void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length) { mqtt->onPublish(topic, payload, length); @@ -122,7 +126,7 @@ void mqttInit() new MQTT(); } -MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient) +MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE) { if(moduleConfig.mqtt.enabled) { @@ -249,9 +253,36 @@ int32_t MQTT::runOnce() if (!pubSub.loop()) { if (wantConnection) { reconnect(); - - // If we succeeded, start reading rapidly, else try again in 30 seconds (TCP connections are EXPENSIVE so try rarely) - return pubSub.connected() ? 20 : 30000; + + // If we succeeded, empty the queue one by one and start reading rapidly, else try again in 30 seconds (TCP connections are EXPENSIVE so try rarely) + if (pubSub.connected()) { + if (!mqttQueue.isEmpty()) { + // FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets + ServiceEnvelope *env = mqttQueue.dequeuePtr(0); + static uint8_t bytes[MeshPacket_size + 64]; + size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &ServiceEnvelope_msg, env); + + String topic = cryptTopic + env->channel_id + "/" + owner.id; + LOG_INFO("publish %s, %u bytes from queue\n", topic.c_str(), numBytes); + + + pubSub.publish(topic.c_str(), bytes, numBytes, false); + + if (moduleConfig.mqtt.json_enabled) { + // handle json topic + auto jsonString = this->downstreamPacketToJson(env->packet); + if (jsonString.length() != 0) { + String topicJson = jsonTopic + env->channel_id + "/" + owner.id; + LOG_INFO("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str()); + pubSub.publish(topicJson.c_str(), jsonString.c_str(), false); + } + } + mqttPool.release(env); + } + return 20; + } else { + return 30000; + } } else return 5000; // If we don't want connection now, check again in 5 secs } else { @@ -273,17 +304,17 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex) if (ch.settings.uplink_enabled) { const char *channelId = channels.getGlobalId(chIndex); // FIXME, for now we just use the human name for the channel - ServiceEnvelope env = ServiceEnvelope_init_default; - env.channel_id = (char *)channelId; - env.gateway_id = owner.id; - env.packet = (MeshPacket *)∓ + ServiceEnvelope *env = mqttPool.allocZeroed(); + env->channel_id = (char *)channelId; + env->gateway_id = owner.id; + env->packet = (MeshPacket *)∓ // don't bother sending if not connected... if (pubSub.connected()) { // FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets static uint8_t bytes[MeshPacket_size + 64]; - size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &ServiceEnvelope_msg, &env); + size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &ServiceEnvelope_msg, env); String topic = cryptTopic + channelId + "/" + owner.id; LOG_DEBUG("publish %s, %u bytes\n", topic.c_str(), numBytes); @@ -299,7 +330,19 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex) pubSub.publish(topicJson.c_str(), jsonString.c_str(), false); } } + } else { + LOG_INFO("MQTT not connected, queueing packet\n"); + if (mqttQueue.numFree() == 0) { + LOG_WARN("NOTE: MQTT queue is full, discarding oldest\n"); + ServiceEnvelope *d = mqttQueue.dequeuePtr(0); + if (d) + mqttPool.release(d); + } + // make a copy of serviceEnvelope and queue it + ServiceEnvelope *copied = mqttPool.allocCopy(*env); + assert(mqttQueue.enqueue(copied, 0)); } + mqttPool.release(env); } } diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index 33fbbb8eb..ddbacbcc4 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -13,6 +13,8 @@ #include #endif +#define MAX_MQTT_QUEUE 32 + /** * Our wrapper/singleton for sending/receiving MQTT "udp" packets. This object isolates the MQTT protocol implementation from * the two components that use it: MQTTPlugin and MQTTSimInterface. @@ -53,9 +55,10 @@ class MQTT : private concurrency::OSThread bool connected(); protected: + PointerQueue mqttQueue; int reconnectCount = 0; - + virtual int32_t runOnce() override; private: From b64a74c0c5aa94d6ae7e93786f3b4f4e8aa8eb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 4 Jan 2023 14:43:23 +0100 Subject: [PATCH 06/43] add heap debugging back in too --- arch/esp32/esp32.ini | 1 + arch/esp32/esp32s2.ini | 1 + arch/esp32/esp32s3.ini | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 70654e8ec..0011cc39f 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -26,6 +26,7 @@ build_flags = -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING + -DDEBUG_HEAP lib_deps = ${arduino_base.lib_deps} diff --git a/arch/esp32/esp32s2.ini b/arch/esp32/esp32s2.ini index cd47c4ca1..ca4f576d6 100644 --- a/arch/esp32/esp32s2.ini +++ b/arch/esp32/esp32s2.ini @@ -27,6 +27,7 @@ build_flags = -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING -DHAS_BLUETOOTH=0 + -DDEBUG_HEAP lib_deps = ${arduino_base.lib_deps} diff --git a/arch/esp32/esp32s3.ini b/arch/esp32/esp32s3.ini index ce64fdbe2..b276ceff9 100644 --- a/arch/esp32/esp32s3.ini +++ b/arch/esp32/esp32s3.ini @@ -26,6 +26,7 @@ build_flags = -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING + -DDEBUG_HEAP lib_deps = ${arduino_base.lib_deps} From 9740f0a5059f6b6ffc72516f2f0cc5d9b08c83fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 4 Jan 2023 14:45:28 +0100 Subject: [PATCH 07/43] External Notification Hotfix --- src/modules/ExternalNotificationModule.cpp | 79 ++++++++++------------ src/modules/ExternalNotificationModule.h | 14 ++++ 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index b24b0bbc0..e0014f98c 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -42,26 +42,22 @@ int32_t ExternalNotificationModule::runOnce() if (!moduleConfig.external_notification.enabled) { return INT32_MAX; // we don't need this thread here... } else { -#ifndef ARCH_PORTDUINO if ((nagCycleCutoff < millis()) && !rtttl::isPlaying()) { -#else - if (nagCycleCutoff < millis()) { -#endif + // let the song finish if we reach timeout nagCycleCutoff = UINT32_MAX; LOG_INFO("Turning off external notification: "); for (int i = 0; i < 2; i++) { - if (getExternal(i)) { - setExternalOff(i); - externalTurnedOn[i] = 0; - LOG_INFO("%d ", i); - } + setExternalOff(i); + externalTurnedOn[i] = 0; + LOG_INFO("%d ", i); } LOG_INFO("\n"); + isNagging = false; return INT32_MAX; // save cycles till we're needed again } // If the output is turned on, turn it back off after the given period of time. - if (nagCycleCutoff != UINT32_MAX) { + if (isNagging) { if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) { @@ -80,16 +76,14 @@ int32_t ExternalNotificationModule::runOnce() } // now let the PWM buzzer play -#ifndef ARCH_PORTDUINO if (moduleConfig.external_notification.use_pwm) { if (rtttl::isPlaying()) { rtttl::play(); - } else if (nagCycleCutoff >= millis()) { + } else if (isNagging && (nagCycleCutoff >= millis())) { // start the song again if we have time left rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); } } -#endif return 25; } } @@ -140,10 +134,9 @@ bool ExternalNotificationModule::getExternal(uint8_t index) } void ExternalNotificationModule::stopNow() { -#ifndef ARCH_PORTDUINO rtttl::stop(); -#endif nagCycleCutoff = 1; // small value + isNagging = false; setIntervalFromNow(0); } @@ -230,6 +223,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) if (moduleConfig.external_notification.alert_bell) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell\n"); + isNagging = true; setExternalOn(0); if (moduleConfig.external_notification.nag_timeout) { nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; @@ -242,6 +236,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) if (moduleConfig.external_notification.alert_bell_vibra) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell (Vibra)\n"); + isNagging = true; setExternalOn(1); if (moduleConfig.external_notification.nag_timeout) { nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; @@ -254,12 +249,11 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) if (moduleConfig.external_notification.alert_bell_buzzer) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell (Buzzer)\n"); + isNagging = true; if (!moduleConfig.external_notification.use_pwm) { setExternalOn(2); } else { -#ifndef ARCH_PORTDUINO rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); -#endif } if (moduleConfig.external_notification.nag_timeout) { nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; @@ -271,6 +265,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) if (moduleConfig.external_notification.alert_message) { LOG_INFO("externalNotificationModule - Notification Module\n"); + isNagging = true; setExternalOn(0); if (moduleConfig.external_notification.nag_timeout) { nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; @@ -279,33 +274,33 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) } } - if (!moduleConfig.external_notification.use_pwm) { - if (moduleConfig.external_notification.alert_message_vibra) { - LOG_INFO("externalNotificationModule - Notification Module (Vibra)\n"); - setExternalOn(1); - if (moduleConfig.external_notification.nag_timeout) { - nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; - } else { - nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms; - } - } - - if (moduleConfig.external_notification.alert_message_buzzer) { - LOG_INFO("externalNotificationModule - Notification Module (Buzzer)\n"); - if (!moduleConfig.external_notification.use_pwm) { - setExternalOn(2); - } else { -#ifndef ARCH_PORTDUINO - rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); -#endif - } - if (moduleConfig.external_notification.nag_timeout) { - nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; - } else { - nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms; - } + + if (moduleConfig.external_notification.alert_message_vibra) { + LOG_INFO("externalNotificationModule - Notification Module (Vibra)\n"); + isNagging = true; + setExternalOn(1); + if (moduleConfig.external_notification.nag_timeout) { + nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; + } else { + nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms; } } + + if (moduleConfig.external_notification.alert_message_buzzer) { + LOG_INFO("externalNotificationModule - Notification Module (Buzzer)\n"); + isNagging = true; + if (!moduleConfig.external_notification.use_pwm) { + setExternalOn(2); + } else { + rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); + } + if (moduleConfig.external_notification.nag_timeout) { + nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000; + } else { + nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms; + } + } + setIntervalFromNow(0); // run once so we know if we should do something } diff --git a/src/modules/ExternalNotificationModule.h b/src/modules/ExternalNotificationModule.h index 50af360c1..097ae96b3 100644 --- a/src/modules/ExternalNotificationModule.h +++ b/src/modules/ExternalNotificationModule.h @@ -5,6 +5,18 @@ #include "configuration.h" #ifndef ARCH_PORTDUINO #include +#else +// Noop class for portduino. +class rtttl +{ + public: + explicit rtttl() {} + static bool isPlaying() { return false; } + static void play() {} + static void begin(byte a, const char * b) {}; + static void stop() {} + static bool done() { return true; } +}; #endif #include #include @@ -39,6 +51,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency: virtual int32_t runOnce() override; + bool isNagging = false; + virtual AdminMessageHandleResult handleAdminMessageForModule(const MeshPacket &mp, AdminMessage *request, AdminMessage *response) override; }; From 0b9c8e62eac9da68693e93a99c425623c507edbe Mon Sep 17 00:00:00 2001 From: Tim Wilkinson Date: Thu, 5 Jan 2023 22:31:57 -0800 Subject: [PATCH 08/43] Make sure we dont use a multicast MAC for ethernet --- src/mesh/eth/ethClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 29f55ebee..4ac9bd9ad 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -94,6 +94,7 @@ bool initEthernet() // createSSLCert(); getMacAddr(mac); // FIXME use the BLE MAC for now... + mac[0] &= 0xfe; // Make sure this is not a multicast MAC if (config.network.address_mode == Config_NetworkConfig_AddressMode_DHCP) { LOG_INFO("starting Ethernet DHCP\n"); From f4099261dfe157314c18d95b56d2e9ce2a4a47bb Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 6 Jan 2023 15:04:11 -0600 Subject: [PATCH 09/43] Hydra gps troubleshooting --- variants/diy/v1/variant.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/variants/diy/v1/variant.h b/variants/diy/v1/variant.h index 3c0878cd1..456daa708 100644 --- a/variants/diy/v1/variant.h +++ b/variants/diy/v1/variant.h @@ -4,9 +4,10 @@ // GPS #undef GPS_RX_PIN -#define GPS_RX_PIN 15 -//#undef GPS_TX_PIN -//#define GPS_TX_PIN 12 // not connected +#undef GPS_TX_PIN +#define GPS_RX_PIN 12 +#define GPS_TX_PIN 15 +#define GPS_UBLOX #define BUTTON_PIN 39 // The middle button GPIO on the T-Beam #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage From 7c1c49b8abefd91c328ff772a9458e5d627a215d Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 7 Jan 2023 13:00:50 +0200 Subject: [PATCH 10/43] Create platformio.ini --- variants/betafpv_2400_tx_micro/platformio.ini | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 variants/betafpv_2400_tx_micro/platformio.ini diff --git a/variants/betafpv_2400_tx_micro/platformio.ini b/variants/betafpv_2400_tx_micro/platformio.ini new file mode 100644 index 000000000..1968413c1 --- /dev/null +++ b/variants/betafpv_2400_tx_micro/platformio.ini @@ -0,0 +1,19 @@ +[env:betafpv_2400_tx_micro] +extends = esp32_base +board = esp32doit-devkit-v1 +build_flags = + ${esp32_base.build_flags} + -D DIY_V1 + ;-D EBYTE_E22 + ;-D OLED_RU + -D VTABLES_IN_FLASH=1 + -D CONFIG_DISABLE_HAL_LOCKS=1 + -O2 + -I variants/betafpv_2400_tx_micro +board_build.f_cpu = 240000000L +upload_protocol = esptool +upload_port = /dev/ttyUSB0 +upload_speed = 460800 +lib_deps = + ${esp32_base.lib_deps} + makuna/NeoPixelBus@^2.7.1 From 9f1c77da763c4872831cbc9e79dad309aeed975b Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 7 Jan 2023 13:01:14 +0200 Subject: [PATCH 11/43] Create variant.h --- variants/betafpv_2400_tx_micro/variant.h | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 variants/betafpv_2400_tx_micro/variant.h diff --git a/variants/betafpv_2400_tx_micro/variant.h b/variants/betafpv_2400_tx_micro/variant.h new file mode 100644 index 000000000..6a124b68e --- /dev/null +++ b/variants/betafpv_2400_tx_micro/variant.h @@ -0,0 +1,37 @@ +#include + +// For OLED LCD +#define I2C_SDA 22 +#define I2C_SCL 32 + +//#undef I2C_SDA +//#undef I2C_SCL +//#define HAS_SCREEN 0 + +// NO GPS +#undef GPS_RX_PIN +#undef GPS_TX_PIN + +#define RF95_SCK 18 +#define RF95_MISO 19 +#define RF95_MOSI 23 +#define RF95_NSS 5 +#define RF95_FAN_EN 17 + +#define LED_PIN 16 // This is a LED_WS2812 not a standard LED + +#define BUTTON_PIN 25 +#define BUTTON_NEED_PULLUP + +#undef EXT_NOTIFY_OUT + +// SX128X 2.4 Ghz LoRa module +#define USE_SX1280 +#define LORA_RESET 14 +#define SX128X_CS 5 +#define SX128X_DIO1 4 +#define SX128X_BUSY 21 +#define SX128X_TXEN 26 +#define SX128X_RXEN 27 +#define SX128X_RESET LORA_RESET +#define SX128X_MAX_POWER 13 From 0e0ccad4896987001ec0217d7dd2f61ef0efe02a Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 7 Jan 2023 13:22:32 +0200 Subject: [PATCH 12/43] Update variant.h --- variants/betafpv_2400_tx_micro/variant.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/variants/betafpv_2400_tx_micro/variant.h b/variants/betafpv_2400_tx_micro/variant.h index 6a124b68e..777c91ec7 100644 --- a/variants/betafpv_2400_tx_micro/variant.h +++ b/variants/betafpv_2400_tx_micro/variant.h @@ -1,13 +1,9 @@ #include -// For OLED LCD +// 0.96" OLED #define I2C_SDA 22 #define I2C_SCL 32 -//#undef I2C_SDA -//#undef I2C_SCL -//#define HAS_SCREEN 0 - // NO GPS #undef GPS_RX_PIN #undef GPS_TX_PIN From f21212dd3e3bdc2c8a17b4242811a588fae9a3b2 Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 7 Jan 2023 13:23:33 +0200 Subject: [PATCH 13/43] Update platformio.ini --- variants/betafpv_2400_tx_micro/platformio.ini | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/variants/betafpv_2400_tx_micro/platformio.ini b/variants/betafpv_2400_tx_micro/platformio.ini index 1968413c1..88fcfda98 100644 --- a/variants/betafpv_2400_tx_micro/platformio.ini +++ b/variants/betafpv_2400_tx_micro/platformio.ini @@ -4,11 +4,9 @@ board = esp32doit-devkit-v1 build_flags = ${esp32_base.build_flags} -D DIY_V1 - ;-D EBYTE_E22 - ;-D OLED_RU - -D VTABLES_IN_FLASH=1 - -D CONFIG_DISABLE_HAL_LOCKS=1 - -O2 + -D VTABLES_IN_FLASH=1 + -D CONFIG_DISABLE_HAL_LOCKS=1 + -O2 -I variants/betafpv_2400_tx_micro board_build.f_cpu = 240000000L upload_protocol = esptool From c98dc4cae09c977e98fb126f77c71470ac8e59a7 Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 7 Jan 2023 13:48:35 +0200 Subject: [PATCH 14/43] Update variant.h --- variants/betafpv_2400_tx_micro/variant.h | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/betafpv_2400_tx_micro/variant.h b/variants/betafpv_2400_tx_micro/variant.h index 777c91ec7..d4af5dac4 100644 --- a/variants/betafpv_2400_tx_micro/variant.h +++ b/variants/betafpv_2400_tx_micro/variant.h @@ -1,3 +1,4 @@ +//https://betafpv.com/products/elrs-micro-tx-module #include // 0.96" OLED From 52cfd620311f1ef8f9c467d7c01aa0753715148c Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 7 Jan 2023 14:05:16 +0200 Subject: [PATCH 15/43] Update SX128xInterface.cpp --- src/mesh/SX128xInterface.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index cc6d299c8..0fa77575f 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -25,7 +25,12 @@ bool SX128xInterface::init() digitalWrite(SX128X_POWER_EN, HIGH); pinMode(SX128X_POWER_EN, OUTPUT); #endif - + +#ifdef RF95_FAN_EN + pinMode(RF95_FAN_EN, OUTPUT); + digitalWrite(RF95_FAN_EN, 1); +#endif + #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output pinMode(SX128X_RXEN, OUTPUT); From 03c5dfc7a858307c48f1a0d42ec02686e9e2494e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 13:16:58 +0100 Subject: [PATCH 16/43] initial cleanup work --- src/FSCommon.cpp | 2 +- src/FSCommon.h | 6 +- src/Observer.h | 1 - src/concurrency/NotifiedWorkerThread.cpp | 1 - src/gps/GPS.cpp | 1 - src/memtest.cpp | 318 ----------------------- src/mesh/Channels.cpp | 17 +- src/mesh/MeshPacketQueue.cpp | 1 + src/mesh/MeshPacketQueue.h | 1 - src/mesh/MeshService.cpp | 4 +- src/mesh/NodeDB.cpp | 1 - src/mesh/PhoneAPI.cpp | 9 +- src/mesh/RadioInterface.cpp | 1 - src/modules/SerialModule.cpp | 2 - src/modules/esp32/AudioModule.cpp | 2 - src/modules/esp32/RangeTestModule.cpp | 1 - 16 files changed, 26 insertions(+), 342 deletions(-) delete mode 100644 src/memtest.cpp diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index 73d5d92b3..1bf355056 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -170,7 +170,7 @@ void fsInit() #ifdef FSCom if (!FSBegin()) { - LOG_ERROR("Filesystem mount Failed. Formatting...\n"); + LOG_ERROR("Filesystem mount Failed.\n"); assert(0); // FIXME - report failure to phone } #ifdef ARCH_ESP32 diff --git a/src/FSCommon.h b/src/FSCommon.h index e304a455b..f4c1372a1 100644 --- a/src/FSCommon.h +++ b/src/FSCommon.h @@ -17,7 +17,7 @@ // RP2040 #include "LittleFS.h" #define FSCom LittleFS -#define FSBegin() FSCom.begin() +#define FSBegin() FSCom.begin() // set autoformat #define FILE_O_WRITE "w" #define FILE_O_READ "r" #endif @@ -26,7 +26,7 @@ // ESP32 version #include "LittleFS.h" #define FSCom LittleFS -#define FSBegin() FSCom.begin(true) +#define FSBegin() FSCom.begin(true) // format on failure #define FILE_O_WRITE "w" #define FILE_O_READ "r" #endif @@ -35,7 +35,7 @@ // NRF52 version #include "InternalFileSystem.h" #define FSCom InternalFS -#define FSBegin() FSCom.begin() +#define FSBegin() FSCom.begin() // InternalFS formats on failure using namespace Adafruit_LittleFS_Namespace; #endif diff --git a/src/Observer.h b/src/Observer.h index ccc7f37b6..4c09101fb 100644 --- a/src/Observer.h +++ b/src/Observer.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include template class Observable; diff --git a/src/concurrency/NotifiedWorkerThread.cpp b/src/concurrency/NotifiedWorkerThread.cpp index ac6428f07..ccdc8fa2b 100644 --- a/src/concurrency/NotifiedWorkerThread.cpp +++ b/src/concurrency/NotifiedWorkerThread.cpp @@ -1,7 +1,6 @@ #include "configuration.h" #include "NotifiedWorkerThread.h" #include "main.h" -#include namespace concurrency { diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 7eec13228..e5791223d 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -3,7 +3,6 @@ #include "RTC.h" #include "configuration.h" #include "sleep.h" -#include // If we have a serial GPS port it will not be null #ifdef GPS_SERIAL_NUM diff --git a/src/memtest.cpp b/src/memtest.cpp deleted file mode 100644 index 20a4bfa53..000000000 --- a/src/memtest.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* - * mtest - Perform a memory test - * - * (C) Copyright 2000 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include "configuration.h" - -/* - * Perform a memory test. A more complete alternative test can be - * configured using CONFIG_CMD_MTEST_ALTERNATIVE. The complete test - * loops until interrupted by ctrl-c or by a failure of one of the - * sub-tests. - */ -#ifdef CONFIG_CMD_MTEST_ALTERNATIVE -static int mem_test(uint32_t _start, uint32_t _end, uint32_t pattern_unused) -{ - volatile uint32_t *start = (volatile uint32_t *)_start; - volatile uint32_t *end = (volatile uint32_t *)_end; - volatile uint32_t *addr; - uint32_t val; - uint32_t readback; - vu_long addr_mask; - vu_long offset; - vu_long test_offset; - vu_long pattern; - vu_long temp; - vu_long anti_pattern; - vu_long num_words; -#ifdef CFG_MEMTEST_SCRATCH - volatile uint32_t *dummy = (vu_long *)CFG_MEMTEST_SCRATCH; -#else - volatile uint32_t *dummy = start; -#endif - int j; - int iterations = 1; - static const uint32_t bitpattern[] = { - 0x00000001, /* single bit */ - 0x00000003, /* two adjacent bits */ - 0x00000007, /* three adjacent bits */ - 0x0000000F, /* four adjacent bits */ - 0x00000005, /* two non-adjacent bits */ - 0x00000015, /* three non-adjacent bits */ - 0x00000055, /* four non-adjacent bits */ - 0xaaaaaaaa, /* alternating 1/0 */ - }; - /* XXX: enforce alignment of start and end? */ - for (;;) { - if (ctrlc()) { - putchar('\n'); - return 1; - } - printf("Iteration: %6d\r", iterations); - iterations++; - /* - * Data line test: write a pattern to the first - * location, write the 1's complement to a 'parking' - * address (changes the state of the data bus so a - * floating bus doen't give a false OK), and then - * read the value back. Note that we read it back - * into a variable because the next time we read it, - * it might be right (been there, tough to explain to - * the quality guys why it prints a failure when the - * "is" and "should be" are obviously the same in the - * error message). - * - * Rather than exhaustively testing, we test some - * patterns by shifting '1' bits through a field of - * '0's and '0' bits through a field of '1's (i.e. - * pattern and ~pattern). - */ - addr = start; - /* XXX */ - if (addr == dummy) - ++addr; - for (j = 0; j < sizeof(bitpattern) / sizeof(bitpattern[0]); j++) { - val = bitpattern[j]; - for (; val != 0; val <<= 1) { - *addr = val; - *dummy = ~val; /* clear the test data off of the bus */ - readback = *addr; - if (readback != val) { - printf("FAILURE (data line): " - "expected 0x%08lx, actual 0x%08lx at address 0x%p\n", - val, readback, addr); - } - *addr = ~val; - *dummy = val; - readback = *addr; - if (readback != ~val) { - printf("FAILURE (data line): " - "Is 0x%08lx, should be 0x%08lx at address 0x%p\n", - readback, ~val, addr); - } - } - } - /* - * Based on code whose Original Author and Copyright - * information follows: Copyright (c) 1998 by Michael - * Barr. This software is placed into the public - * domain and may be used for any purpose. However, - * this notice must not be changed or removed and no - * warranty is either expressed or implied by its - * publication or distribution. - */ - /* - * Address line test - * - * Description: Test the address bus wiring in a - * memory region by performing a walking - * 1's test on the relevant bits of the - * address and checking for aliasing. - * This test will find single-bit - * address failures such as stuck -high, - * stuck-low, and shorted pins. The base - * address and size of the region are - * selected by the caller. - * - * Notes: For best results, the selected base - * address should have enough LSB 0's to - * guarantee single address bit changes. - * For example, to test a 64-Kbyte - * region, select a base address on a - * 64-Kbyte boundary. Also, select the - * region size as a power-of-two if at - * all possible. - * - * Returns: 0 if the test succeeds, 1 if the test fails. - * - * ## NOTE ## Be sure to specify start and end - * addresses such that addr_mask has - * lots of bits set. For example an - * address range of 01000000 02000000 is - * bad while a range of 01000000 - * 01ffffff is perfect. - */ - addr_mask = ((uint32_t)end - (uint32_t)start) / sizeof(vu_long); - pattern = (vu_long)0xaaaaaaaa; - anti_pattern = (vu_long)0x55555555; - debug("%s:%d: addr mask = 0x%.8lx\n", __FUNCTION__, __LINE__, addr_mask); - /* - * Write the default pattern at each of the - * power-of-two offsets. - */ - for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) - start[offset] = pattern; - /* - * Check for address bits stuck high. - */ - test_offset = 0; - start[test_offset] = anti_pattern; - for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { - temp = start[offset]; - if (temp != pattern) { - printf("\nFAILURE: Address bit stuck high @ 0x%.8lx:" - " expected 0x%.8lx, actual 0x%.8lx\n", - (uint32_t)&start[offset], pattern, temp); - return 1; - } - } - start[test_offset] = pattern; - /* - * Check for addr bits stuck low or shorted. - */ - for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) { - start[test_offset] = anti_pattern; - for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { - temp = start[offset]; - if ((temp != pattern) && (offset != test_offset)) { - printf("\nFAILURE: Address bit stuck low or shorted @" - " 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n", - (uint32_t)&start[offset], pattern, temp); - return 1; - } - } - start[test_offset] = pattern; - } - /* - * Description: Test the integrity of a physical - * memory device by performing an - * increment/decrement test over the - * entire region. In the process every - * storage bit in the device is tested - * as a zero and a one. The base address - * and the size of the region are - * selected by the caller. - * - * Returns: 0 if the test succeeds, 1 if the test fails. - */ - num_words = ((uint32_t)end - (uint32_t)start) / sizeof(vu_long) + 1; - /* - * Fill memory with a known pattern. - */ - for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { - start[offset] = pattern; - } - /* - * Check each location and invert it for the second pass. - */ - for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { - temp = start[offset]; - if (temp != pattern) { - printf("\nFAILURE (read/write) @ 0x%.8lx:" - " expected 0x%.8lx, actual 0x%.8lx)\n", - (uint32_t)&start[offset], pattern, temp); - return 1; - } - anti_pattern = ~pattern; - start[offset] = anti_pattern; - } - /* - * Check each location for the inverted pattern and zero it. - */ - for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { - anti_pattern = ~pattern; - temp = start[offset]; - if (temp != anti_pattern) { - printf("\nFAILURE (read/write): @ 0x%.8lx:" - " expected 0x%.8lx, actual 0x%.8lx)\n", - (uint32_t)&start[offset], anti_pattern, temp); - return 1; - } - start[offset] = 0; - } - } -} -#else -static int mem_test(uint32_t *_start, size_t len, bool doRead = true, bool doWrite = true) -{ - volatile uint32_t *addr; - volatile uint32_t *start = (volatile uint32_t *)_start; - const volatile uint32_t *end = start + len / sizeof(uint32_t); - uint32_t pattern = 0; - uint32_t val; - uint32_t readback; - uint32_t incr; - int rcode = 0; - incr = 1; - - //LOG_DEBUG("memtest read=%d, write=%d\n", doRead, doWrite); - - if (doWrite) { - //LOG_DEBUG("writing\n"); - for (addr = start, val = pattern; addr < end; addr++) { - *addr = val; - val += incr; - } - } - - if (doRead) { - //LOG_DEBUG("reading\n"); - for (addr = start, val = pattern; addr < end; addr++) { - readback = *addr; - if (readback != val) { - LOG_ERROR("Mem error @ 0x%08X: " - "found 0x%08lX, expected 0x%08lX\n", - addr, readback, val); - rcode++; - } - val += incr; - } - } - -#if 0 - /* - * Flip the pattern each time to make lots of zeros and - * then, the next time, lots of ones. We decrement - * the "negative" patterns and increment the "positive" - * patterns to preserve this feature. - */ - if(pattern & 0x80000000) { - pattern = -pattern; /* complement & increment */ - } - else { - pattern = ~pattern; - } -#endif - - return rcode; -} -#endif - -#define TESTBUF_LEN 16384 - -#include - -void doMemTest() -{ - static uint32_t *testBuf; - static int iter; - - if (!testBuf) - testBuf = (uint32_t *)malloc(TESTBUF_LEN); - - assert(testBuf); - if (mem_test(testBuf, TESTBUF_LEN, iter % 2 == 1, iter % 2 == 0) > 0) - assert(0); // FIXME report error better - - iter++; -} diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 97f2c1448..3d88bb49a 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -191,9 +191,20 @@ void Channels::onConfigChanged() Channel &Channels::getByIndex(ChannelIndex chIndex) { - assert(chIndex < channelFile.channels_count); // This should be equal to MAX_NUM_CHANNELS - Channel *ch = channelFile.channels + chIndex; - return *ch; + // remove this assert cause malformed packets can make our firmware reboot here. + if (chIndex < channelFile.channels_count) { // This should be equal to MAX_NUM_CHANNELS + Channel *ch = channelFile.channels + chIndex; + return *ch; + } else { + LOG_ERROR("Invalid channel index %d > %d, malformed packet received?\n", chIndex , channelFile.channels_count); + + Channel *ch = (Channel *)malloc(sizeof(Channel)); + memset(ch, 0, sizeof(Channel)); + // ch.index -1 means we don't know the channel locally and need to look it up by settings.name + // not sure this is handled right everywhere + ch->index = -1; + return *ch; + } } Channel &Channels::getByName(const char* chName) diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 51af89df8..9af381a0e 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -1,5 +1,6 @@ #include "configuration.h" #include "MeshPacketQueue.h" +#include #include diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index ee6c6954a..51dc34cb5 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -2,7 +2,6 @@ #include "MeshTypes.h" -#include #include diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 208b1b9ea..f881f4d40 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -3,7 +3,6 @@ #include #include "GPS.h" -//#include "MeshBluetoothService.h" #include "../concurrency/Periodic.h" #include "BluetoothCommon.h" // needed for updateBatteryLevel, FIXME, eventually when we pull mesh out into a lib we shouldn't be whacking bluetooth from here #include "MeshService.h" @@ -61,7 +60,6 @@ Allocator &queueStatusPool = staticQueueStatusPool; MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE) { lastQueueStatus = { 0, 0, 16, 0 }; - // assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro } void MeshService::init() @@ -261,7 +259,7 @@ void MeshService::sendToPhone(MeshPacket *p) MeshPacket *copied = packetPool.allocCopy(*p); perhapsDecode(copied); - assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages + assert(toPhoneQueue.enqueue(copied, 0)); fromNum++; } diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index e995e0b22..c19beadca 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1,5 +1,4 @@ #include "configuration.h" -#include #include "Channels.h" #include "CryptoEngine.h" diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index c1d56b7ec..3f74e672d 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -6,7 +6,6 @@ #include "PowerFSM.h" #include "RadioInterface.h" #include "configuration.h" -#include #if FromRadio_size > MAX_TO_FROM_RADIO_SIZE #error FromRadio is too big @@ -209,6 +208,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) fromRadioScratch.config.which_payload_variant = Config_bluetooth_tag; fromRadioScratch.config.payload_variant.bluetooth = config.bluetooth; break; + default: + LOG_ERROR("Unknown config type %d\n", config_state); } // NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior. // So even if we internally use 0 to represent 'use default' we still need to send the value we are @@ -262,6 +263,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_remote_hardware_tag; fromRadioScratch.moduleConfig.payload_variant.remote_hardware = moduleConfig.remote_hardware; break; + default: + LOG_ERROR("Unknown module config type %d\n", config_state); } config_state++; @@ -299,7 +302,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) break; default: - assert(0); // unexpected state - FIXME, make an error code and reboot + LOG_ERROR("getFromRadio unexpected state %d\n", state); } // Do we have a message from the mesh? @@ -369,7 +372,7 @@ bool PhoneAPI::available() return hasPacket; } default: - assert(0); // unexpected state - FIXME, make an error code and reboot + LOG_ERROR("PhoneAPI::available unexpected state %d\n", state); } return false; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 7c0f238a0..4b31b319a 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -4,7 +4,6 @@ #include "MeshService.h" #include "NodeDB.h" #include "Router.h" -#include "assert.h" #include "configuration.h" #include "main.h" #include "sleep.h" diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index c02b7219b..5d02e3ba8 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -7,8 +7,6 @@ #include "configuration.h" #include -#include - /* SerialModule A simple interface to send messages over the mesh network by sending strings diff --git a/src/modules/esp32/AudioModule.cpp b/src/modules/esp32/AudioModule.cpp index b38644340..bdef12e08 100644 --- a/src/modules/esp32/AudioModule.cpp +++ b/src/modules/esp32/AudioModule.cpp @@ -8,8 +8,6 @@ #include "Router.h" #include "FSCommon.h" -#include - #ifdef OLED_RU #include "graphics/fonts/OLEDDisplayFontsRU.h" #endif diff --git a/src/modules/esp32/RangeTestModule.cpp b/src/modules/esp32/RangeTestModule.cpp index 398af9071..1624a972b 100644 --- a/src/modules/esp32/RangeTestModule.cpp +++ b/src/modules/esp32/RangeTestModule.cpp @@ -9,7 +9,6 @@ #include "gps/GeoCoord.h" #include #include -//#include /* As a sender, I can send packets every n seconds. These packets include an incremented PacketID. From b283e526bf0bf56be6c137823a335444409c53eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 13:25:29 +0100 Subject: [PATCH 17/43] fix for nRF52 and Portduino --- src/FSCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index 1bf355056..2541aa8b5 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -171,7 +171,7 @@ void fsInit() if (!FSBegin()) { LOG_ERROR("Filesystem mount Failed.\n"); - assert(0); // FIXME - report failure to phone + // assert(0); This auto-formats the partition, so no need to fail here. } #ifdef ARCH_ESP32 LOG_DEBUG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes()); From be2d3f7769d317b1d07b779a5fed2fe01a3a3de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 13:28:36 +0100 Subject: [PATCH 18/43] fix leak --- src/mesh/Channels.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 3d88bb49a..85db38403 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -198,7 +198,7 @@ Channel &Channels::getByIndex(ChannelIndex chIndex) } else { LOG_ERROR("Invalid channel index %d > %d, malformed packet received?\n", chIndex , channelFile.channels_count); - Channel *ch = (Channel *)malloc(sizeof(Channel)); + static Channel *ch = (Channel *)malloc(sizeof(Channel)); memset(ch, 0, sizeof(Channel)); // ch.index -1 means we don't know the channel locally and need to look it up by settings.name // not sure this is handled right everywhere From 96fa5dafb8f1eef8206041e01f17295e879e9210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 13:36:02 +0100 Subject: [PATCH 19/43] fixing portduino --- .../portduino/CrossPlatformCryptoEngine.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/platform/portduino/CrossPlatformCryptoEngine.cpp b/src/platform/portduino/CrossPlatformCryptoEngine.cpp index 7bd021a42..208c60a5f 100644 --- a/src/platform/portduino/CrossPlatformCryptoEngine.cpp +++ b/src/platform/portduino/CrossPlatformCryptoEngine.cpp @@ -54,16 +54,18 @@ class CrossPlatformCryptoEngine : public CryptoEngine static uint8_t scratch[MAX_BLOCKSIZE]; //size_t nc_off = 0; - // LOG_DEBUG("ESP32 encrypt!\n"); initNonce(fromNode, packetId); - assert(numBytes <= MAX_BLOCKSIZE); - memcpy(scratch, bytes, numBytes); - memset(scratch + numBytes, 0, + if (numBytes <= MAX_BLOCKSIZE) { + memcpy(scratch, bytes, numBytes); + memset(scratch + numBytes, 0, sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it) - ctr->setIV(nonce, sizeof(nonce)); - ctr->setCounterSize(4); - ctr->encrypt(bytes, scratch, numBytes); + ctr->setIV(nonce, sizeof(nonce)); + ctr->setCounterSize(4); + ctr->encrypt(bytes, scratch, numBytes); + } else { + LOG_ERROR("Packet too large for crypto engine: %d. noop encryption!\n", numBytes); + } } } From 2a0b8093ea345e04b7a0aad44eb06c7925461f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 13:59:40 +0100 Subject: [PATCH 20/43] freakin' nitpickin' cpp_check --- src/platform/portduino/CrossPlatformCryptoEngine.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/platform/portduino/CrossPlatformCryptoEngine.cpp b/src/platform/portduino/CrossPlatformCryptoEngine.cpp index 208c60a5f..4c6d5f178 100644 --- a/src/platform/portduino/CrossPlatformCryptoEngine.cpp +++ b/src/platform/portduino/CrossPlatformCryptoEngine.cpp @@ -50,12 +50,9 @@ class CrossPlatformCryptoEngine : public CryptoEngine virtual void encrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override { if (key.length > 0) { - //uint8_t stream_block[16]; - static uint8_t scratch[MAX_BLOCKSIZE]; - //size_t nc_off = 0; - initNonce(fromNode, packetId); if (numBytes <= MAX_BLOCKSIZE) { + static uint8_t scratch[MAX_BLOCKSIZE]; memcpy(scratch, bytes, numBytes); memset(scratch + numBytes, 0, sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it) From 8465467aa81ac942b623c2c4659694f8cc60c780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 14:57:00 +0100 Subject: [PATCH 21/43] 2nd batch --- src/mesh/RadioInterface.cpp | 27 ++++++++++++++------------- src/mesh/RadioLibInterface.cpp | 1 - src/mesh/Router.cpp | 22 ++++++++-------------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 4b31b319a..2e44b0ada 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -110,6 +110,8 @@ const RegionInfo regions[] = { const RegionInfo *myRegion; +static uint8_t bytes[MAX_RHPACKETLEN]; + void initRegion() { const RegionInfo *r = regions; @@ -163,17 +165,19 @@ uint32_t RadioInterface::getPacketTime(uint32_t pl) uint32_t RadioInterface::getPacketTime(MeshPacket *p) { - assert(p->which_payload_variant == MeshPacket_encrypted_tag); // It should have already been encoded by now - uint32_t pl = p->encrypted.size + sizeof(PacketHeader); - + uint32_t pl = 0; + if(p->which_payload_variant == MeshPacket_encrypted_tag) { + pl = p->encrypted.size + sizeof(PacketHeader); + } else { + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded); + pl = numbytes + sizeof(PacketHeader); + } return getPacketTime(pl); } /** The delay to use for retransmitting dropped packets */ uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p) { - assert(slotTimeMsec); // Better be non zero - static uint8_t bytes[MAX_RHPACKETLEN]; size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded); uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader)); // Make sure enough time has elapsed for this packet to be sent and an ACK is received. @@ -270,9 +274,6 @@ void printPacket(const char *prefix, const MeshPacket *p) RadioInterface::RadioInterface() { assert(sizeof(PacketHeader) == 16); // make sure the compiler did what we expected - - // Can't print strings this early - serial not setup yet - // LOG_DEBUG("Set meshradio defaults name=%s\n", channelSettings.name); } bool RadioInterface::reconfigure() @@ -383,7 +384,7 @@ void RadioInterface::applyModemConfig() cr = 8; sf = 10; break; - case Config_LoRaConfig_ModemPreset_LONG_FAST: + default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal. bw = (myRegion->wideLora) ? 812.5 : 250; cr = 8; sf = 11; @@ -398,8 +399,6 @@ void RadioInterface::applyModemConfig() cr = 8; sf = 12; break; - default: - assert(0); // Unknown enum } } else { sf = loraConfig.spread_factor; @@ -421,7 +420,6 @@ void RadioInterface::applyModemConfig() } power = loraConfig.tx_power; - assert(myRegion); // Should have been found in init if ((power == 0) || ((power > myRegion->powerLimit) && !devicestate.owner.is_licensed)) power = myRegion->powerLimit; @@ -501,7 +499,10 @@ size_t RadioInterface::beginSending(MeshPacket *p) h->to = p->to; h->id = p->id; h->channel = p->channel; - assert(p->hop_limit <= HOP_MAX); + if (p->hop_limit > HOP_MAX) { + LOG_WARN("hop limit %d is too high, setting to %d\n", p->hop_limit, HOP_MAX); + p->hop_limit = HOP_MAX; + } h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0); // if the sender nodenum is zero, that means uninitialized diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 81a4d803e..eb17dbe37 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -372,7 +372,6 @@ QueueStatus RadioLibInterface::getQueueStatus() printPacket("Lora RX", mp); - // xmitMsec = getPacketTime(mp); airTime->logAirtime(RX_LOG, xmitMsec); deliverToReceiver(mp); diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 0f34010ec..69ac1d5c9 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -39,6 +39,8 @@ static MemoryDynamic staticPool; Allocator &packetPool = staticPool; +static uint8_t bytes[MAX_RHPACKETLEN]; + /** * Constructor * @@ -94,8 +96,7 @@ PacketId generatePacketId() static uint32_t i; // Note: trying to keep this in noinit didn't help for working across reboots static bool didInit = false; - assert(sizeof(PacketId) == 4 || sizeof(PacketId) == 1); // only supported values - uint32_t numPacketId = sizeof(PacketId) == 1 ? UINT8_MAX : UINT32_MAX; // 0 is consider invalid + uint32_t numPacketId = UINT32_MAX; if (!didInit) { didInit = true; @@ -191,7 +192,11 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes) */ ErrorCode Router::send(MeshPacket *p) { - assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal + if (p->to == nodeDB.getNodeNum()) { + LOG_ERROR("BUG! send() called with packet destined for local node!\n"); + packetPool.release(p); + return Routing_Error_BAD_REQUEST; + } // should have already been handled by sendLocal // Abort sending if we are violating the duty cycle if (!config.lora.override_duty_cycle && myRegion->dutyCycle != 100) { @@ -286,7 +291,6 @@ bool Router::cancelSending(NodeNum from, PacketId id) */ void Router::sniffReceived(const MeshPacket *p, const Routing *c) { - LOG_DEBUG("FIXME-update-db Sniffing packet\n"); // FIXME, update nodedb here for any packet that passes through us } @@ -305,7 +309,6 @@ bool perhapsDecode(MeshPacket *p) // Try to use this hash/channel pair if (channels.decryptForHash(chIndex, p->channel)) { // Try to decrypt the packet if we can - static uint8_t bytes[MAX_RHPACKETLEN]; size_t rawSize = p->encrypted.size; assert(rawSize <= sizeof(bytes)); memcpy(bytes, p->encrypted.bytes, @@ -325,14 +328,6 @@ bool perhapsDecode(MeshPacket *p) p->which_payload_variant = MeshPacket_decoded_tag; // change type to decoded p->channel = chIndex; // change to store the index instead of the hash - /* - if (p->decoded.portnum == PortNum_TEXT_MESSAGE_APP) { - LOG_DEBUG("\n\n** TEXT_MESSAGE_APP\n"); - } else if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) { - LOG_DEBUG("\n\n** PortNum_TEXT_MESSAGE_COMPRESSED_APP\n"); - } - */ - // Decompress if needed. jm if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) { // Decompress the payload @@ -368,7 +363,6 @@ Routing_Error perhapsEncode(MeshPacket *p) { // If the packet is not yet encrypted, do so now if (p->which_payload_variant == MeshPacket_decoded_tag) { - static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded); From 4d7402839e6e6dab048ce5e858a54b52c60553b4 Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 7 Jan 2023 16:00:27 +0200 Subject: [PATCH 22/43] Update platformio.ini --- variants/betafpv_2400_tx_micro/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/betafpv_2400_tx_micro/platformio.ini b/variants/betafpv_2400_tx_micro/platformio.ini index 88fcfda98..e04f4efc2 100644 --- a/variants/betafpv_2400_tx_micro/platformio.ini +++ b/variants/betafpv_2400_tx_micro/platformio.ini @@ -3,7 +3,7 @@ extends = esp32_base board = esp32doit-devkit-v1 build_flags = ${esp32_base.build_flags} - -D DIY_V1 + -D BETAFPV_2400_TX -D VTABLES_IN_FLASH=1 -D CONFIG_DISABLE_HAL_LOCKS=1 -O2 From d8b85f9a096df61101bd847bf9c410acffa47ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 15:24:46 +0100 Subject: [PATCH 23/43] fingers crossed --- src/modules/CannedMessageModule.cpp | 8 ++++---- src/modules/ExternalNotificationModule.cpp | 8 ++++---- src/modules/esp32/StoreForwardModule.cpp | 2 +- src/platform/esp32/ESP32CryptoEngine.cpp | 15 +++++++++------ src/platform/portduino/SimRadio.cpp | 7 ++++++- src/sleep.cpp | 2 +- 6 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index c2f4f1b13..f1cbc576d 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -549,10 +549,10 @@ AdminMessageHandleResult CannedMessageModule::handleAdminMessageForModule(const void CannedMessageModule::handleGetCannedMessageModuleMessages(const MeshPacket &req, AdminMessage *response) { LOG_DEBUG("*** handleGetCannedMessageModuleMessages\n"); - assert(req.decoded.want_response); - - response->which_payload_variant = AdminMessage_get_canned_message_module_messages_response_tag; - strcpy(response->get_canned_message_module_messages_response, cannedMessageModuleConfig.messages); + if(req.decoded.want_response) { + response->which_payload_variant = AdminMessage_get_canned_message_module_messages_response_tag; + strcpy(response->get_canned_message_module_messages_response, cannedMessageModuleConfig.messages); + } // Don't send anything if not instructed to. Better than asserting. } diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index e0014f98c..a8f112c94 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -347,10 +347,10 @@ AdminMessageHandleResult ExternalNotificationModule::handleAdminMessageForModule void ExternalNotificationModule::handleGetRingtone(const MeshPacket &req, AdminMessage *response) { LOG_INFO("*** handleGetRingtone\n"); - assert(req.decoded.want_response); - - response->which_payload_variant = AdminMessage_get_ringtone_response_tag; - strcpy(response->get_ringtone_response, rtttlConfig.ringtone); + if(req.decoded.want_response) { + response->which_payload_variant = AdminMessage_get_ringtone_response_tag; + strcpy(response->get_ringtone_response, rtttlConfig.ringtone); + } // Don't send anything if not instructed to. Better than asserting. } diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index ecb2ab978..bf0421a9a 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -392,7 +392,7 @@ bool StoreForwardModule::handleReceivedProtobuf(const MeshPacket &mp, StoreAndFo break; default: - assert(0); // unexpected state - FIXME, make an error code and reboot + assert(0); // unexpected state } return true; // There's no need for others to look at this message. } diff --git a/src/platform/esp32/ESP32CryptoEngine.cpp b/src/platform/esp32/ESP32CryptoEngine.cpp index 93eb76dbd..a7589b2bf 100644 --- a/src/platform/esp32/ESP32CryptoEngine.cpp +++ b/src/platform/esp32/ESP32CryptoEngine.cpp @@ -43,18 +43,21 @@ class ESP32CryptoEngine : public CryptoEngine { if (key.length > 0) { uint8_t stream_block[16]; - static uint8_t scratch[MAX_BLOCKSIZE]; size_t nc_off = 0; LOG_DEBUG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetId, numBytes); initNonce(fromNode, packetId); - assert(numBytes <= MAX_BLOCKSIZE); - memcpy(scratch, bytes, numBytes); - memset(scratch + numBytes, 0, + if (numBytes <= MAX_BLOCKSIZE) { + static uint8_t scratch[MAX_BLOCKSIZE]; + memcpy(scratch, bytes, numBytes); + memset(scratch + numBytes, 0, sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it) - auto res = mbedtls_aes_crypt_ctr(&aes, numBytes, &nc_off, nonce, stream_block, scratch, bytes); - assert(!res); + auto res = mbedtls_aes_crypt_ctr(&aes, numBytes, &nc_off, nonce, stream_block, scratch, bytes); + assert(!res); + } else { + LOG_ERROR("Packet too large for crypto engine: %d. noop encryption!\n", numBytes); + } } } diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp index a2611a464..ce96d02cc 100644 --- a/src/platform/portduino/SimRadio.cpp +++ b/src/platform/portduino/SimRadio.cpp @@ -230,7 +230,12 @@ void SimRadio::handleReceiveInterrupt(MeshPacket *p) { LOG_DEBUG("HANDLE RECEIVE INTERRUPT\n"); uint32_t xmitMsec; - assert(isReceiving); + + if (!isReceiving) { + LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode\n"); + return; + } + isReceiving = false; // read the number of actually received bytes diff --git a/src/sleep.cpp b/src/sleep.cpp index c85eec3ff..5eb62a1c5 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -163,7 +163,7 @@ static void waitEnterSleep() } // Code that still needs to be moved into notifyObservers - Serial.flush(); // send all our characters before we stop cpu clock + console->flush(); // send all our characters before we stop cpu clock setBluetoothEnable(false); // has to be off before calling light sleep notifySleep.notifyObservers(NULL); From 3a8ffe7ac2c6da87d96e2f5a45ee68ad9b5bbdc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 15:43:17 +0100 Subject: [PATCH 24/43] ah feck --- src/platform/esp32/ESP32CryptoEngine.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/platform/esp32/ESP32CryptoEngine.cpp b/src/platform/esp32/ESP32CryptoEngine.cpp index a7589b2bf..f8cb04704 100644 --- a/src/platform/esp32/ESP32CryptoEngine.cpp +++ b/src/platform/esp32/ESP32CryptoEngine.cpp @@ -42,13 +42,12 @@ class ESP32CryptoEngine : public CryptoEngine virtual void encrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override { if (key.length > 0) { - uint8_t stream_block[16]; - size_t nc_off = 0; - LOG_DEBUG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetId, numBytes); initNonce(fromNode, packetId); if (numBytes <= MAX_BLOCKSIZE) { static uint8_t scratch[MAX_BLOCKSIZE]; + uint8_t stream_block[16]; + size_t nc_off = 0; memcpy(scratch, bytes, numBytes); memset(scratch + numBytes, 0, sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it) From 81ee6dd79911c70c3782514d77ab7e25ef5f7021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 7 Jan 2023 23:40:47 +0100 Subject: [PATCH 25/43] first crash from stress test --- src/mesh/http/WiFiAPClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp index ec34f9927..82ca7a52d 100644 --- a/src/mesh/http/WiFiAPClient.cpp +++ b/src/mesh/http/WiFiAPClient.cpp @@ -182,7 +182,7 @@ bool initWifi() WiFi.onEvent( [](WiFiEvent_t event, WiFiEventInfo_t info) { - LOG_WARN("WiFi lost connection. Reason: %s", info.wifi_sta_disconnected.reason); + LOG_WARN("WiFi lost connection. Reason: %d", info.wifi_sta_disconnected.reason); /* If we are disconnected from the AP for some reason, From 5cec370cf5ac667811c1aff1b666adb2f45feb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 9 Jan 2023 11:28:21 +0100 Subject: [PATCH 26/43] getByName was not used anywhere in the code so that change is safe. Please TEST this as i don't have a working Json setup in mqtt at the moment. --- src/mesh/Channels.cpp | 2 +- src/mqtt/MQTT.cpp | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 97f2c1448..bfd46091f 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -199,7 +199,7 @@ Channel &Channels::getByIndex(ChannelIndex chIndex) Channel &Channels::getByName(const char* chName) { for (ChannelIndex i = 0; i < getNumChannels(); i++) { - if (strcasecmp(channelFile.channels[i].settings.name, chName) == 0) { + if (strcasecmp(getGlobalId(i), chName) == 0) { return channelFile.channels[i]; } } diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index f4004139a..e66b942e9 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -43,9 +43,20 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length) JSONValue *json_value = JSON::Parse(payloadStr); if (json_value != NULL) { LOG_INFO("JSON Received on MQTT, parsing..\n"); + // check if it is a valid envelope JSONObject json; json = json_value->AsObject(); + + // parse the channel name from the topic string + char *ptr = strtok(topic, "/"); + for (int i = 0; i < 3; i++) { + ptr = strtok(NULL, "/"); + } + LOG_DEBUG("Looking for Channel name: %s\n", ptr); + Channel sendChannel = channels.getByName(ptr); + LOG_DEBUG("Found Channel name: %s (Index %d)\n", channels.getGlobalId(sendChannel.settings.channel_num), sendChannel.settings.channel_num); + if ((json.find("sender") != json.end()) && (json.find("payload") != json.end()) && (json.find("type") != json.end()) && json["type"]->IsString() && (json["type"]->AsString().compare("sendtext") == 0)) { // this is a valid envelope if (json["payload"]->IsString() && json["type"]->IsString() && (json["sender"]->AsString().compare(owner.id) != 0)) { @@ -55,13 +66,18 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length) // construct protobuf data packet using TEXT_MESSAGE, send it to the mesh MeshPacket *p = router->allocForSending(); p->decoded.portnum = PortNum_TEXT_MESSAGE_APP; - if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) { - memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length()); - p->decoded.payload.size = jsonPayloadStr.length(); - MeshPacket *packet = packetPool.allocCopy(*p); - service.sendToMesh(packet, RX_SRC_LOCAL); + p->channel = sendChannel.settings.channel_num; + if (sendChannel.settings.downlink_enabled) { + if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) { + memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length()); + p->decoded.payload.size = jsonPayloadStr.length(); + MeshPacket *packet = packetPool.allocCopy(*p); + service.sendToMesh(packet, RX_SRC_LOCAL); + } else { + LOG_WARN("Received MQTT json payload too long, dropping\n"); + } } else { - LOG_WARN("Received MQTT json payload too long, dropping\n"); + LOG_WARN("Received MQTT json payload on channel %s, but downlink is disabled, dropping\n", sendChannel.settings.name); } } else { LOG_DEBUG("JSON Ignoring downlink message we originally sent.\n"); @@ -80,9 +96,13 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length) // construct protobuf data packet using POSITION, send it to the mesh MeshPacket *p = router->allocForSending(); p->decoded.portnum = PortNum_POSITION_APP; - p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Position_msg, &pos); //make the Data protobuf from position - service.sendToMesh(p, RX_SRC_LOCAL); - + p->channel = sendChannel.settings.channel_num; + if (sendChannel.settings.downlink_enabled) { + p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Position_msg, &pos); //make the Data protobuf from position + service.sendToMesh(p, RX_SRC_LOCAL); + } else { + LOG_WARN("Received MQTT json payload on channel %s, but downlink is disabled, dropping\n", sendChannel.settings.name); + } } else { LOG_DEBUG("JSON Ignoring downlink message we originally sent.\n"); } From 5fd00b253849791b3758e37465bc6737c0b9f16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 9 Jan 2023 17:03:52 +0100 Subject: [PATCH 27/43] - make a template class for API Server - Skip a lot of duplicate code - add a hexDump output - might come in handy - refactor directory names - remove unused debugOut that was generating template errors --- arch/nrf52/nrf52.ini | 2 +- arch/rp2040/rp2040.ini | 2 +- arch/stm32/stm32wl5e.ini | 2 +- src/RedirectablePrint.cpp | 33 ++++++-- src/RedirectablePrint.h | 2 + src/main.cpp | 4 +- src/mesh/InterfacesTemplates.cpp | 14 ++++ src/mesh/PhoneAPI.h | 3 - src/mesh/api/ServerAPI.cpp | 67 +++++++++++++++ .../{wifi/WiFiServerAPI.h => api/ServerAPI.h} | 22 ++--- src/mesh/api/WiFiServerAPI.cpp | 25 ++++++ src/mesh/api/WiFiServerAPI.h | 25 ++++++ src/mesh/api/ethServerAPI.cpp | 27 ++++++ src/mesh/api/ethServerAPI.h | 25 ++++++ src/mesh/eth/ethClient.cpp | 2 +- src/mesh/eth/ethServerAPI.cpp | 82 ------------------- src/mesh/eth/ethServerAPI.h | 58 ------------- src/mesh/http/WiFiAPClient.cpp | 2 +- src/mesh/wifi/WiFiServerAPI.cpp | 82 ------------------- variants/rak4631/platformio.ini | 2 +- 20 files changed, 230 insertions(+), 251 deletions(-) create mode 100644 src/mesh/api/ServerAPI.cpp rename src/mesh/{wifi/WiFiServerAPI.h => api/ServerAPI.h} (72%) create mode 100644 src/mesh/api/WiFiServerAPI.cpp create mode 100644 src/mesh/api/WiFiServerAPI.h create mode 100644 src/mesh/api/ethServerAPI.cpp create mode 100644 src/mesh/api/ethServerAPI.h delete mode 100644 src/mesh/eth/ethServerAPI.cpp delete mode 100644 src/mesh/eth/ethServerAPI.h delete mode 100644 src/mesh/wifi/WiFiServerAPI.cpp diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 46f946530..9ee2c37b5 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -8,7 +8,7 @@ build_flags = ${arduino_base.build_flags} -Wno-unused-variable -Isrc/platform/nrf52 build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - lib_ignore = BluetoothOTA diff --git a/arch/rp2040/rp2040.ini b/arch/rp2040/rp2040.ini index cf898a60f..f30a94d3d 100644 --- a/arch/rp2040/rp2040.ini +++ b/arch/rp2040/rp2040.ini @@ -12,7 +12,7 @@ build_flags = -D__PLAT_RP2040__ # -D _POSIX_THREADS build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - lib_ignore = BluetoothOTA lib_deps = diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini index 3fc7583ad..a38fb65e8 100644 --- a/arch/stm32/stm32wl5e.ini +++ b/arch/stm32/stm32wl5e.ini @@ -10,7 +10,7 @@ build_flags = # Arduino/PlatformIO framework-arduinoststm32 package does not presently have SUBGHZSPI support # -DPIN_SPI_MOSI=PINSUBGHZSPIMOSI -DPIN_SPI_MISO=PINSUBGHZSPIMISO -DPIN_SPI_SCK=PINSUBGHZSPISCK build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - - - - - - lib_deps = ${env.lib_deps} https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index e7f305e19..28ae3e635 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -3,7 +3,6 @@ #include "RTC.h" #include "NodeDB.h" #include "concurrency/OSThread.h" -// #include "wifi/WiFiServerAPI.h" #include #include #include @@ -27,10 +26,6 @@ size_t RedirectablePrint::write(uint8_t c) SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c); #endif - // FIXME - clean this up, the whole relationship of this class to SerialConsole to TCP/bluetooth debug log output is kinda messed up. But for now, just have this hack to - // optionally send chars to TCP also - //WiFiServerPort::debugOut(c); - if (!config.has_lora || config.device.serial_enabled) dest->write(c); @@ -108,3 +103,31 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) return r; } + +void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) { + char alphabet[17] = "0123456789abcdef"; + log(logLevel, " +------------------------------------------------+ +----------------+\n"); + log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n"); + for (uint16_t i = 0; i < len; i += 16) { + if (i % 128 == 0) + log(logLevel, " +------------------------------------------------+ +----------------+\n"); + char s[] = "| | | |\n"; + uint8_t ix = 1, iy = 52; + for (uint8_t j = 0; j < 16; j++) { + if (i + j < len) { + uint8_t c = buf[i + j]; + s[ix++] = alphabet[(c >> 4) & 0x0F]; + s[ix++] = alphabet[c & 0x0F]; + ix++; + if (c > 31 && c < 128) s[iy++] = c; + else s[iy++] = '.'; + } + } + uint8_t index = i / 16; + if (i < 256) log(logLevel, " "); + log(logLevel, "%02x",index); + log(logLevel, "."); + log(logLevel, s); + } + log(logLevel, " +------------------------------------------------+ +----------------+\n"); +} diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index 8fabd4a72..7aaeb4a47 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -38,6 +38,8 @@ class RedirectablePrint : public Print /** like printf but va_list based */ size_t vprintf(const char *format, va_list arg); + + void hexDump(const char *logLevel, unsigned char *buf, uint16_t len); }; class NoopPrint : public Print diff --git a/src/main.cpp b/src/main.cpp index af7f28b50..47236bf7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,12 +36,12 @@ #endif #if HAS_WIFI -#include "mesh/wifi/WiFiServerAPI.h" +#include "mesh/api/WiFiServerAPI.h" #include "mqtt/MQTT.h" #endif #if HAS_ETHERNET -#include "mesh/eth/ethServerAPI.h" +#include "mesh/api/ethServerAPI.h" #include "mqtt/MQTT.h" #endif diff --git a/src/mesh/InterfacesTemplates.cpp b/src/mesh/InterfacesTemplates.cpp index 0d2246428..d8f84c487 100644 --- a/src/mesh/InterfacesTemplates.cpp +++ b/src/mesh/InterfacesTemplates.cpp @@ -2,9 +2,23 @@ #include "SX126xInterface.cpp" #include "SX128xInterface.h" #include "SX128xInterface.cpp" +#include "api/ServerAPI.h" +#include "api/ServerAPI.cpp" // We need this declaration for proper linking in derived classes template class SX126xInterface; template class SX126xInterface; template class SX126xInterface; template class SX128xInterface; + +#if HAS_ETHERNET +#include "api/ethServerAPI.h" +template class ServerAPI; +template class APIServerPort; +#endif + +#if HAS_WIFI +#include "api/WiFiServerAPI.h" +template class ServerAPI; +template class APIServerPort; +#endif \ No newline at end of file diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 2f2695807..aa190ae37 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -86,9 +86,6 @@ class PhoneAPI : public Observer // FIXME, we shouldn't be inheriting void setInitialState() { state = STATE_SEND_MY_INFO; } - /// emit a debugging log character, FIXME - implement - void debugOut(char c) { } - protected: /// Our fromradio packet while it is being assembled FromRadio fromRadioScratch = {}; diff --git a/src/mesh/api/ServerAPI.cpp b/src/mesh/api/ServerAPI.cpp new file mode 100644 index 000000000..e35455063 --- /dev/null +++ b/src/mesh/api/ServerAPI.cpp @@ -0,0 +1,67 @@ +#include "ServerAPI.h" +#include "configuration.h" +#include + +template +ServerAPI::ServerAPI(T &_client) : StreamAPI(&client), concurrency::OSThread("ServerAPI"), client(_client) +{ + LOG_INFO("Incoming wifi connection\n"); +} + +template +ServerAPI::~ServerAPI() +{ + client.stop(); +} + +template +void ServerAPI::close() +{ + client.stop(); // drop tcp connection + StreamAPI::close(); +} + +/// Check the current underlying physical link to see if the client is currently connected +template +bool ServerAPI::checkIsConnected() +{ + return client.connected(); +} + +template +int32_t ServerAPI::runOnce() +{ + if (client.connected()) { + return StreamAPI::runOncePart(); + } else { + LOG_INFO("Client dropped connection, suspending API service\n"); + enabled = false; // we no longer need to run + return 0; + } +} + +template +APIServerPort::APIServerPort(int port) : U(port), concurrency::OSThread("ApiServer") {} + +template +void APIServerPort::init() +{ + U::begin(); +} + +template +int32_t APIServerPort::runOnce() +{ + auto client = U::available(); + if (client) { + // Close any previous connection (see FIXME in header file) + if (openAPI) { + LOG_INFO("Force closing previous TCP connection\n"); + delete openAPI; + } + + openAPI = new T(client); + } + + return 100; // only check occasionally for incoming connections +} diff --git a/src/mesh/wifi/WiFiServerAPI.h b/src/mesh/api/ServerAPI.h similarity index 72% rename from src/mesh/wifi/WiFiServerAPI.h rename to src/mesh/api/ServerAPI.h index 812408818..174aa774f 100644 --- a/src/mesh/wifi/WiFiServerAPI.h +++ b/src/mesh/api/ServerAPI.h @@ -1,21 +1,21 @@ #pragma once #include "StreamAPI.h" -#include /** * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). */ -class WiFiServerAPI : public StreamAPI, private concurrency::OSThread +template +class ServerAPI : public StreamAPI, private concurrency::OSThread { private: - WiFiClient client; + T client; public: - explicit WiFiServerAPI(WiFiClient &_client); + explicit ServerAPI(T &_client); - virtual ~WiFiServerAPI(); + virtual ~ServerAPI(); /// override close to also shutdown the TCP link virtual void close(); @@ -34,25 +34,21 @@ class WiFiServerAPI : public StreamAPI, private concurrency::OSThread /** * Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed */ -class WiFiServerPort : public WiFiServer, private concurrency::OSThread +template +class APIServerPort : public U, private concurrency::OSThread { /** The currently open port * * FIXME: We currently only allow one open TCP connection at a time, because we depend on the loop() call in this class to * delegate to the worker. Once coroutines are implemented we can relax this restriction. */ - WiFiServerAPI *openAPI = NULL; + T *openAPI = NULL; public: - explicit WiFiServerPort(int port); + explicit APIServerPort(int port); void init(); - /// If an api server is running, we try to spit out debug 'serial' characters there - static void debugOut(char c); - protected: int32_t runOnce() override; }; - -void initApiServer(int port=4403); diff --git a/src/mesh/api/WiFiServerAPI.cpp b/src/mesh/api/WiFiServerAPI.cpp new file mode 100644 index 000000000..5f86dbe85 --- /dev/null +++ b/src/mesh/api/WiFiServerAPI.cpp @@ -0,0 +1,25 @@ +#include "configuration.h" +#include + +#if HAS_WIFI +#include "WiFiServerAPI.h" + +static WiFiServerPort *apiPort; + +void initApiServer(int port) +{ + // Start API server on port 4403 + if (!apiPort) { + apiPort = new WiFiServerPort(port); + LOG_INFO("API server listening on TCP port %d\n", port); + apiPort->init(); + } +} + +WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client) +{ + LOG_INFO("Incoming wifi connection\n"); +} + +WiFiServerPort::WiFiServerPort(int port) : APIServerPort(port) {} +#endif diff --git a/src/mesh/api/WiFiServerAPI.h b/src/mesh/api/WiFiServerAPI.h new file mode 100644 index 000000000..279ee0f3f --- /dev/null +++ b/src/mesh/api/WiFiServerAPI.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ServerAPI.h" +#include + +/** + * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs + * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). + */ +class WiFiServerAPI : public ServerAPI +{ + public: + explicit WiFiServerAPI(WiFiClient &_client); +}; + +/** + * Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed + */ +class WiFiServerPort : public APIServerPort +{ + public: + explicit WiFiServerPort(int port); +}; + +void initApiServer(int port=4403); diff --git a/src/mesh/api/ethServerAPI.cpp b/src/mesh/api/ethServerAPI.cpp new file mode 100644 index 000000000..3badcdfde --- /dev/null +++ b/src/mesh/api/ethServerAPI.cpp @@ -0,0 +1,27 @@ +#include "configuration.h" +#include + +#if HAS_ETHERNET + +#include "ethServerAPI.h" + +static ethServerPort *apiPort; + +void initApiServer(int port) +{ + // Start API server on port 4403 + if (!apiPort) { + apiPort = new ethServerPort(port); + LOG_INFO("API server listening on TCP port %d\n", port); + apiPort->init(); + } +} + +ethServerAPI::ethServerAPI(EthernetClient &_client) : ServerAPI(_client) +{ + LOG_INFO("Incoming ethernet connection\n"); +} + +ethServerPort::ethServerPort(int port) : APIServerPort(port) {} + +#endif \ No newline at end of file diff --git a/src/mesh/api/ethServerAPI.h b/src/mesh/api/ethServerAPI.h new file mode 100644 index 000000000..36f363f70 --- /dev/null +++ b/src/mesh/api/ethServerAPI.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ServerAPI.h" +#include + +/** + * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs + * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). + */ +class ethServerAPI : public ServerAPI +{ + public: + explicit ethServerAPI(EthernetClient &_client); +}; + +/** + * Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed + */ +class ethServerPort : public APIServerPort +{ + public: + explicit ethServerPort(int port); +}; + +void initApiServer(int port=4403); diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 4ac9bd9ad..dce04b191 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -5,7 +5,7 @@ #include #include #include "target_specific.h" -#include "mesh/eth/ethServerAPI.h" +#include "mesh/api/ethServerAPI.h" #include "mqtt/MQTT.h" #ifndef DISABLE_NTP diff --git a/src/mesh/eth/ethServerAPI.cpp b/src/mesh/eth/ethServerAPI.cpp deleted file mode 100644 index d91b798a0..000000000 --- a/src/mesh/eth/ethServerAPI.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "ethServerAPI.h" -#include "configuration.h" -#include - -static ethServerPort *apiPort; - -void initApiServer(int port) -{ - // Start API server on port 4403 - if (!apiPort) { - apiPort = new ethServerPort(port); - LOG_INFO("API server listening on TCP port %d\n", port); - apiPort->init(); - } -} - -ethServerAPI::ethServerAPI(EthernetClient &_client) : StreamAPI(&client), concurrency::OSThread("ethServerAPI"), client(_client) -{ - LOG_INFO("Incoming ethernet connection\n"); -} - -ethServerAPI::~ethServerAPI() -{ - client.stop(); - - // FIXME - delete this if the client dropps the connection! -} - -/// override close to also shutdown the TCP link -void ethServerAPI::close() -{ - client.stop(); // drop tcp connection - StreamAPI::close(); -} - -/// Check the current underlying physical link to see if the client is currently connected -bool ethServerAPI::checkIsConnected() -{ - return client.connected(); -} - -int32_t ethServerAPI::runOnce() -{ - if (client.connected()) { - return StreamAPI::runOncePart(); - } else { - LOG_INFO("Client dropped connection, suspending API service\n"); - enabled = false; // we no longer need to run - return 0; - } -} - -/// If an api server is running, we try to spit out debug 'serial' characters there -void ethServerPort::debugOut(char c) -{ - if (apiPort && apiPort->openAPI) - apiPort->openAPI->debugOut(c); -} - - -ethServerPort::ethServerPort(int port) : EthernetServer(port), concurrency::OSThread("ApiServer") {} - -void ethServerPort::init() -{ - begin(); -} - -int32_t ethServerPort::runOnce() -{ - auto client = available(); - if (client) { - // Close any previous connection (see FIXME in header file) - if (openAPI) { - LOG_WARN("Force closing previous TCP connection\n"); - delete openAPI; - } - - openAPI = new ethServerAPI(client); - } - - return 100; // only check occasionally for incoming connections -} diff --git a/src/mesh/eth/ethServerAPI.h b/src/mesh/eth/ethServerAPI.h deleted file mode 100644 index 962841c80..000000000 --- a/src/mesh/eth/ethServerAPI.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "StreamAPI.h" -#include - -/** - * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs - * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). - */ -class ethServerAPI : public StreamAPI, private concurrency::OSThread -{ - private: - EthernetClient client; - - public: - explicit ethServerAPI(EthernetClient &_client); - - virtual ~ethServerAPI(); - - /// override close to also shutdown the TCP link - virtual void close(); - - protected: - /// We override this method to prevent publishing EVENT_SERIAL_CONNECTED/DISCONNECTED for wifi links (we want the board to - /// stay in the POWERED state to prevent disabling wifi) - virtual void onConnectionChanged(bool connected) override {} - - virtual int32_t runOnce() override; // Check for dropped client connections - - /// Check the current underlying physical link to see if the client is currently connected - virtual bool checkIsConnected() override; -}; - -/** - * Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed - */ -class ethServerPort : public EthernetServer, private concurrency::OSThread -{ - /** The currently open port - * - * FIXME: We currently only allow one open TCP connection at a time, because we depend on the loop() call in this class to - * delegate to the worker. Once coroutines are implemented we can relax this restriction. - */ - ethServerAPI *openAPI = NULL; - - public: - explicit ethServerPort(int port); - - void init(); - - /// If an api server is running, we try to spit out debug 'serial' characters there - static void debugOut(char c); - - protected: - int32_t runOnce() override; -}; - -void initApiServer(int port=4403); diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp index ec34f9927..d8f3570c2 100644 --- a/src/mesh/http/WiFiAPClient.cpp +++ b/src/mesh/http/WiFiAPClient.cpp @@ -5,7 +5,7 @@ #include "configuration.h" #include "main.h" #include "mesh/http/WebServer.h" -#include "mesh/wifi/WiFiServerAPI.h" +#include "mesh/api/WiFiServerAPI.h" #include "mqtt/MQTT.h" #include "target_specific.h" #include diff --git a/src/mesh/wifi/WiFiServerAPI.cpp b/src/mesh/wifi/WiFiServerAPI.cpp deleted file mode 100644 index 136dfadb7..000000000 --- a/src/mesh/wifi/WiFiServerAPI.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "WiFiServerAPI.h" -#include "configuration.h" -#include - -static WiFiServerPort *apiPort; - -void initApiServer(int port) -{ - // Start API server on port 4403 - if (!apiPort) { - apiPort = new WiFiServerPort(port); - LOG_INFO("API server listening on TCP port %d\n", port); - apiPort->init(); - } -} - -WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), concurrency::OSThread("WiFiServerAPI"), client(_client) -{ - LOG_INFO("Incoming wifi connection\n"); -} - -WiFiServerAPI::~WiFiServerAPI() -{ - client.stop(); - - // FIXME - delete this if the client dropps the connection! -} - -/// override close to also shutdown the TCP link -void WiFiServerAPI::close() -{ - client.stop(); // drop tcp connection - StreamAPI::close(); -} - -/// Check the current underlying physical link to see if the client is currently connected -bool WiFiServerAPI::checkIsConnected() -{ - return client.connected(); -} - -int32_t WiFiServerAPI::runOnce() -{ - if (client.connected()) { - return StreamAPI::runOncePart(); - } else { - LOG_INFO("Client dropped connection, suspending API service\n"); - enabled = false; // we no longer need to run - return 0; - } -} - -/// If an api server is running, we try to spit out debug 'serial' characters there -void WiFiServerPort::debugOut(char c) -{ - if (apiPort && apiPort->openAPI) - apiPort->openAPI->debugOut(c); -} - - -WiFiServerPort::WiFiServerPort(int port) : WiFiServer(port), concurrency::OSThread("ApiServer") {} - -void WiFiServerPort::init() -{ - begin(); -} - -int32_t WiFiServerPort::runOnce() -{ - auto client = available(); - if (client) { - // Close any previous connection (see FIXME in header file) - if (openAPI) { - LOG_INFO("Force closing previous TCP connection\n"); - delete openAPI; - } - - openAPI = new WiFiServerAPI(client); - } - - return 100; // only check occasionally for incoming connections -} diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index e08b54dae..a0928605f 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -3,7 +3,7 @@ extends = nrf52840_base board = wiscore_rak4631 build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631 -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> + + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> + + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} From 86748bf88ec447653606ec53a86fd5bf2bb8a6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 9 Jan 2023 19:23:41 +0100 Subject: [PATCH 28/43] fix building portduino and make cppcheck happy --- src/RedirectablePrint.cpp | 2 +- src/platform/portduino/SimRadio.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 28ae3e635..74b44dd86 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -105,7 +105,7 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) } void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) { - char alphabet[17] = "0123456789abcdef"; + const char alphabet[17] = "0123456789abcdef"; log(logLevel, " +------------------------------------------------+ +----------------+\n"); log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n"); for (uint16_t i = 0; i < len; i += 16) { diff --git a/src/platform/portduino/SimRadio.h b/src/platform/portduino/SimRadio.h index d2a36c81e..c4336a22b 100644 --- a/src/platform/portduino/SimRadio.h +++ b/src/platform/portduino/SimRadio.h @@ -2,7 +2,7 @@ #include "RadioInterface.h" #include "MeshPacketQueue.h" -#include "wifi/WiFiServerAPI.h" +#include "api/WiFiServerAPI.h" #include From e7d425ef6e1aab694906e3af9c97e3f367cc1ce4 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 9 Jan 2023 16:19:42 -0600 Subject: [PATCH 29/43] Until we figure out what's going on --- src/mesh/SX126xInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 15b808852..0e033eeb6 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -70,7 +70,7 @@ bool SX126xInterface::init() #if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC) // lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX if (res == RADIOLIB_ERR_NONE) - res = lora.setDio2AsRfSwitch(false); + res = lora.setDio2AsRfSwitch(true); #endif #if 0 From 1fc5d70221e85728b0acbe6d1c374e6840493329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 9 Jan 2023 23:26:47 +0100 Subject: [PATCH 30/43] let the library handle the reconnect, manually do it after 5 seconds --- src/mesh/http/WiFiAPClient.cpp | 14 ++++++++------ src/mqtt/MQTT.cpp | 14 ++++++++------ src/mqtt/MQTT.h | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp index ec34f9927..0a6a1b8df 100644 --- a/src/mesh/http/WiFiAPClient.cpp +++ b/src/mesh/http/WiFiAPClient.cpp @@ -5,7 +5,7 @@ #include "configuration.h" #include "main.h" #include "mesh/http/WebServer.h" -#include "mesh/wifi/WiFiServerAPI.h" +#include "mesh/api/WiFiServerAPI.h" #include "mqtt/MQTT.h" #include "target_specific.h" #include @@ -55,11 +55,13 @@ static int32_t reconnectWiFi() // Make sure we clear old connection credentials WiFi.disconnect(false, true); - LOG_INFO("Reconnecting to WiFi access point %s\n",wifiName); - WiFi.mode(WIFI_MODE_STA); - WiFi.begin(wifiName, wifiPsw); + delay(5000); + + if (!WiFi.isConnected()) { + WiFi.begin(wifiName, wifiPsw); + } } #ifndef DISABLE_NTP @@ -167,7 +169,7 @@ bool initWifi() WiFi.mode(WIFI_MODE_STA); WiFi.setHostname(ourHost); WiFi.onEvent(WiFiEvent); - WiFi.setAutoReconnect(false); + WiFi.setAutoReconnect(true); WiFi.setSleep(false); if (config.network.address_mode == Config_NetworkConfig_AddressMode_STATIC && config.network.ipv4_config.ip != 0) { WiFi.config(config.network.ipv4_config.ip, @@ -182,7 +184,7 @@ bool initWifi() WiFi.onEvent( [](WiFiEvent_t event, WiFiEventInfo_t info) { - LOG_WARN("WiFi lost connection. Reason: %s", info.wifi_sta_disconnected.reason); + LOG_WARN("WiFi lost connection. Reason: %d\n", info.wifi_sta_disconnected.reason); /* If we are disconnected from the AP for some reason, diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index e66b942e9..cc091bcff 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -207,14 +207,17 @@ void MQTT::reconnect() sendSubscriptions(); } else { - LOG_ERROR("Failed to contact MQTT server (%d/10)...\n",reconnectCount); #if HAS_WIFI && !defined(ARCH_PORTDUINO) - if (reconnectCount > 9) { + LOG_ERROR("Failed to contact MQTT server (%d/5)...\n",reconnectCount + 1); + if (reconnectCount >= 4) { needReconnect = true; - wifiReconnect->setIntervalFromNow(1000); + wifiReconnect->setIntervalFromNow(0); + reconnectCount = 0; + } else { + reconnectCount++; } + #endif - reconnectCount++; } } } @@ -284,7 +287,6 @@ int32_t MQTT::runOnce() String topic = cryptTopic + env->channel_id + "/" + owner.id; LOG_INFO("publish %s, %u bytes from queue\n", topic.c_str(), numBytes); - pubSub.publish(topic.c_str(), bytes, numBytes, false); @@ -299,7 +301,7 @@ int32_t MQTT::runOnce() } mqttPool.release(env); } - return 20; + return 200; } else { return 30000; } diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index ddbacbcc4..16ce4c37a 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -13,7 +13,7 @@ #include #endif -#define MAX_MQTT_QUEUE 32 +#define MAX_MQTT_QUEUE 16 /** * Our wrapper/singleton for sending/receiving MQTT "udp" packets. This object isolates the MQTT protocol implementation from From 713f7d5996183895cb1b89a4ed4e4f50676ea288 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 10 Jan 2023 07:36:19 -0600 Subject: [PATCH 31/43] Turn of 3.3v rail on RAK-4631 on shutdown --- src/main.cpp | 2 +- src/platform/nrf52/main-nrf52.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 47236bf7d..2631e68df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -239,7 +239,7 @@ void setup() #ifdef RAK4630 // We need to enable 3.3V periphery in order to scan it pinMode(PIN_3V3_EN, OUTPUT); - digitalWrite(PIN_3V3_EN, 1); + digitalWrite(PIN_3V3_EN, HIGH); #endif // Currently only the tbeam has a PMU diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 9a942a606..e3096b0ce 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -172,6 +172,9 @@ void cpuDeepSleep(uint64_t msecToWake) Serial1.end(); #endif setBluetoothEnable(false); +#ifdef RAK4630 + digitalWrite(PIN_3V3_EN, LOW); +#endif // FIXME, use system off mode with ram retention for key state? // FIXME, use non-init RAM per // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled From a3b93a4dcfa8e7281cc9d0ef88d8a742c417dddc Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 10 Jan 2023 21:10:09 +0100 Subject: [PATCH 32/43] Better not to compare float directly --- src/mesh/Router.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 69ac1d5c9..b5965f25f 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -199,7 +199,7 @@ ErrorCode Router::send(MeshPacket *p) } // should have already been handled by sendLocal // Abort sending if we are violating the duty cycle - if (!config.lora.override_duty_cycle && myRegion->dutyCycle != 100) { + if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { float hourlyTxPercent = airTime->utilizationTXPercent(); if (hourlyTxPercent > myRegion->dutyCycle) { uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); From e13fb9919e20e640fe309944ca1fd5f4528d24e0 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 10 Jan 2023 21:12:17 +0100 Subject: [PATCH 33/43] Send NAK only to the API upon duty cycle limit --- src/mesh/Router.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index b5965f25f..b3d43cf09 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -200,14 +200,18 @@ ErrorCode Router::send(MeshPacket *p) // Abort sending if we are violating the duty cycle if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { - float hourlyTxPercent = airTime->utilizationTXPercent(); - if (hourlyTxPercent > myRegion->dutyCycle) { - uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); - LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes); - Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT; - abortSendAndNak(err, p); - return err; - } + float hourlyTxPercent = airTime->utilizationTXPercent(); + if (hourlyTxPercent > myRegion->dutyCycle) { + uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); + LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes); + Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT; + if (getFrom(p) == nodeDB.getNodeNum()) { // only send NAK to API, not to the mesh + abortSendAndNak(err, p); + } else { + packetPool.release(p); + } + return err; + } } // PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; From ab9d0ba543be246ad7f52280550613a109661fb5 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 10 Jan 2023 21:12:40 +0100 Subject: [PATCH 34/43] Report actual RoutingError --- src/mesh/Router.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index b3d43cf09..74487588b 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -138,7 +138,7 @@ void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelI void Router::abortSendAndNak(Routing_Error err, MeshPacket *p) { LOG_ERROR("Error=%d, returning NAK and dropping packet.\n", err); - sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id, p->channel); + sendAckNak(err, getFrom(p), p->id, p->channel); packetPool.release(p); } From 4f71ab07c96bb08a6fc2a16500e0cbe96fa8415e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 11 Jan 2023 14:33:54 +0100 Subject: [PATCH 35/43] 2.0.12 is out already. Bump develop too. --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 816f7c2ac..40e7926a9 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 0 -build = 12 +build = 13 From 17a2589b352fe5474c02ccc90cecd17cf0e2b9ac Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 11 Jan 2023 07:50:07 -0600 Subject: [PATCH 36/43] Allow time from phone to be sent to the mesh --- src/mesh/MeshService.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index f881f4d40..9a6fa984c 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -280,8 +280,7 @@ NodeInfo *MeshService::refreshMyNodeInfo() node->last_heard = getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid - // For the time in the position field, only set that if we have a real GPS clock - position.time = getValidTime(RTCQualityGPS); + position.time = getValidTime(RTCQualityFromNet); updateBatteryLevel(powerStatus->getBatteryChargePercent()); @@ -327,4 +326,4 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus) bool MeshService::isToPhoneQueueEmpty() { return toPhoneQueue.isEmpty(); -} \ No newline at end of file +} From a354cebd8801b616529246df0fba1d4f77414824 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 11 Jan 2023 14:28:10 -0600 Subject: [PATCH 37/43] Update protos ref --- protobufs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 3b0d871ca..570cee3f3 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 3b0d871ca1e0f8a2ed823f0696e2d7cf31ed2ebd +Subproject commit 570cee3f31c8a1acfb31e0f3f434bf25b8451a52 From 721f87af7ef38c6959511d7e773f63f446268b3f Mon Sep 17 00:00:00 2001 From: thebentern Date: Wed, 11 Jan 2023 20:35:13 +0000 Subject: [PATCH 38/43] [create-pull-request] automated change --- src/mesh/generated/localonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 17 +++++++++++------ src/mesh/generated/module_config.pb.h | 6 +++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/mesh/generated/localonly.pb.h b/src/mesh/generated/localonly.pb.h index d2b9dfcae..1e4aa633c 100644 --- a/src/mesh/generated/localonly.pb.h +++ b/src/mesh/generated/localonly.pb.h @@ -157,7 +157,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define LocalConfig_size 391 -#define LocalModuleConfig_size 380 +#define LocalModuleConfig_size 412 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index d1f3e5bf5..5ff84a223 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -84,6 +84,8 @@ typedef enum _HardwareModel { HardwareModel_HELTEC_V3 = 43, /* New Heltec Wireless Stick Lite with ESP32-S3 CPU */ HardwareModel_HELTEC_WSL_V3 = 44, + /* New BETAFPV ELRS Micro TX Module 2.4G with ESP32 CPU */ + HardwareModel_BETAFPV_2400_TX = 45, /* Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. */ HardwareModel_PRIVATE_HW = 255 } HardwareModel; @@ -439,9 +441,10 @@ typedef struct _Waypoint { bool locked; /* Name of the waypoint - max 30 chars */ char name[30]; - /* * - Description of the waypoint - max 100 chars */ + /* Description of the waypoint - max 100 chars */ char description[100]; + /* Designator icon for the waypoint in the form of a unicode emoji */ + uint32_t emoji; } Waypoint; typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; @@ -778,7 +781,7 @@ extern "C" { #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_default {0, {RouteDiscovery_init_default}} #define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} -#define Waypoint_init_default {0, 0, 0, 0, 0, "", ""} +#define Waypoint_init_default {0, 0, 0, 0, 0, "", "", 0} #define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0, false, DeviceMetrics_init_default} #define MyNodeInfo_init_default {0, 0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0} @@ -792,7 +795,7 @@ extern "C" { #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_zero {0, {RouteDiscovery_init_zero}} #define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} -#define Waypoint_init_zero {0, 0, 0, 0, 0, "", ""} +#define Waypoint_init_zero {0, 0, 0, 0, 0, "", "", 0} #define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0, false, DeviceMetrics_init_zero} #define MyNodeInfo_init_zero {0, 0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0} @@ -850,6 +853,7 @@ extern "C" { #define Waypoint_locked_tag 5 #define Waypoint_name_tag 6 #define Waypoint_description_tag 7 +#define Waypoint_emoji_tag 8 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 #define MeshPacket_channel_tag 3 @@ -980,7 +984,8 @@ X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 3) \ X(a, STATIC, SINGULAR, UINT32, expire, 4) \ X(a, STATIC, SINGULAR, BOOL, locked, 5) \ X(a, STATIC, SINGULAR, STRING, name, 6) \ -X(a, STATIC, SINGULAR, STRING, description, 7) +X(a, STATIC, SINGULAR, STRING, description, 7) \ +X(a, STATIC, SINGULAR, FIXED32, emoji, 8) #define Waypoint_CALLBACK NULL #define Waypoint_DEFAULT NULL @@ -1133,7 +1138,7 @@ extern const pb_msgdesc_t Compressed_msg; #define Routing_size 42 #define ToRadio_size 324 #define User_size 77 -#define Waypoint_size 156 +#define Waypoint_size 161 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/module_config.pb.h b/src/mesh/generated/module_config.pb.h index da13ac706..bd4e90832 100644 --- a/src/mesh/generated/module_config.pb.h +++ b/src/mesh/generated/module_config.pb.h @@ -80,7 +80,7 @@ typedef struct _ModuleConfig_MQTTConfig { bool enabled; /* The server to use for our MQTT global message gateway feature. If not set, the default server will be used */ - char address[32]; + char address[64]; /* MQTT username to use (most useful for a custom MQTT server). If using a custom server, this will be honoured even if empty. If using the default server, this will only be honoured if set, otherwise the device will use the default username */ @@ -553,13 +553,13 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg; #define ModuleConfig_AudioConfig_size 19 #define ModuleConfig_CannedMessageConfig_size 49 #define ModuleConfig_ExternalNotificationConfig_size 40 -#define ModuleConfig_MQTTConfig_size 169 +#define ModuleConfig_MQTTConfig_size 201 #define ModuleConfig_RangeTestConfig_size 10 #define ModuleConfig_RemoteHardwareConfig_size 2 #define ModuleConfig_SerialConfig_size 26 #define ModuleConfig_StoreForwardConfig_size 22 #define ModuleConfig_TelemetryConfig_size 18 -#define ModuleConfig_size 172 +#define ModuleConfig_size 204 #ifdef __cplusplus } /* extern "C" */ From fc775012eac7a208fa611d088675625f13b967c7 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Wed, 11 Jan 2023 21:52:19 +0100 Subject: [PATCH 39/43] Don't send NodeInfo and DeviceTelemetry at high Tx air util Also move airtime checking to airtime class --- src/airtime.cpp | 25 +++++++++++++++++++ src/airtime.h | 6 +++++ src/mesh/SinglePortModule.h | 3 --- src/modules/NodeInfoModule.cpp | 8 +++--- src/modules/PositionModule.cpp | 8 ++---- src/modules/Telemetry/DeviceTelemetry.cpp | 2 +- .../Telemetry/EnvironmentTelemetry.cpp | 2 +- src/modules/esp32/RangeTestModule.cpp | 4 +-- src/modules/esp32/StoreForwardModule.cpp | 6 ++--- 9 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index c72a21d54..ae3b30811 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -117,6 +117,31 @@ float AirTime::utilizationTXPercent() return (float(sum) / float(MS_IN_HOUR)) * 100; } +bool AirTime::isTxAllowedChannelUtil(bool polite) +{ + uint8_t percentage = (polite ? polite_channel_util_percent : max_channel_util_percent); + if (channelUtilizationPercent() < percentage) { + return true; + } else { + LOG_WARN("Channel utilization is >%d percent. Skipping this opportunity to send.\n", percentage); + return false; + } +} + + +bool AirTime::isTxAllowedAirUtil() +{ + if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { + if (utilizationTXPercent() < polite_tx_util_percent) { + return true; + } else { + LOG_WARN("Tx air utilization is >%d percent. Skipping this opportunity to send.\n", polite_tx_util_percent); + return false; + } + } + return true; +} + // Get the amount of minutes we have to be silent before we can send again uint8_t AirTime::getSilentMinutes(float txPercent, float dutyCycle) { diff --git a/src/airtime.h b/src/airtime.h index 3f38f39f8..2d1f1e2d9 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -4,6 +4,7 @@ #include "configuration.h" #include #include +#include "MeshRadio.h" /* TX_LOG - Time on air this device has transmitted @@ -59,12 +60,17 @@ class AirTime : private concurrency::OSThread uint32_t getSecondsSinceBoot(); uint32_t *airtimeReport(reportTypes reportType); uint8_t getSilentMinutes(float txPercent, float dutyCycle); + bool isTxAllowedChannelUtil(bool polite=false); + bool isTxAllowedAirUtil(); private: bool firstTime = true; uint8_t lastUtilPeriod = 0; uint8_t lastUtilPeriodTX = 0; uint32_t secSinceBoot = 0; + uint8_t max_channel_util_percent = 40; + uint8_t polite_channel_util_percent = 25; + uint8_t polite_tx_util_percent = 5; struct airtimeStruct { uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted diff --git a/src/mesh/SinglePortModule.h b/src/mesh/SinglePortModule.h index 57db73221..2e587cb89 100644 --- a/src/mesh/SinglePortModule.h +++ b/src/mesh/SinglePortModule.h @@ -18,9 +18,6 @@ class SinglePortModule : public MeshModule SinglePortModule(const char *_name, PortNum _ourPortNum) : MeshModule(_name), ourPortNum(_ourPortNum) {} protected: - uint32_t max_channel_util_percent = 40; - uint32_t polite_channel_util_percent = 25; - /** * @return true if you want to receive the specified portnum */ diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index d8047c5f0..5dc05cd95 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -65,8 +65,10 @@ int32_t NodeInfoModule::runOnce() bool requestReplies = currentGeneration != radioGeneration; currentGeneration = radioGeneration; - LOG_INFO("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); - sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) + if (airTime->isTxAllowedAirUtil()) { + LOG_INFO("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); + sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) + } return default_broadcast_interval_secs * 1000; -} \ No newline at end of file +} diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 6680eaba5..4d119043c 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -144,7 +144,7 @@ int32_t PositionModule::runOnce() if (lastGpsSend == 0 || (now - lastGpsSend) >= intervalMs) { // Only send packets if the channel is less than 40% utilized. - if (airTime->channelUtilizationPercent() < max_channel_util_percent) { + if (airTime->isTxAllowedChannelUtil()) { if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) { lastGpsSend = now; @@ -158,14 +158,12 @@ int32_t PositionModule::runOnce() LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", node->position.timestamp, requestReplies); sendOurPosition(NODENUM_BROADCAST, requestReplies); } - } else { - LOG_WARN("Channel utilization is >40 percent. Skipping this opportunity to send.\n"); } } else if (config.position.position_broadcast_smart_enabled) { // Only send packets if the channel is less than 25% utilized. - if (airTime->channelUtilizationPercent() < polite_channel_util_percent) { + if (airTime->isTxAllowedChannelUtil(true)) { NodeInfo *node2 = service.refreshMyNodeInfo(); // should guarantee there is now a position @@ -208,8 +206,6 @@ int32_t PositionModule::runOnce() lastGpsSend = now; } } - } else { - LOG_WARN("Channel utilization is >25 percent. Skipping this opportunity to send.\n"); } } diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 109d8b5b1..dda7ab84d 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -17,7 +17,7 @@ int32_t DeviceTelemetryModule::runOnce() uint32_t now = millis(); if ((lastSentToMesh == 0 || (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval)) && - airTime->channelUtilizationPercent() < max_channel_util_percent) { + airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; } else if (service.isToPhoneQueueEmpty()) { diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 3bf303157..2a29405d3 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -107,7 +107,7 @@ int32_t EnvironmentTelemetryModule::runOnce() uint32_t now = millis(); if ((lastSentToMesh == 0 || (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval)) && - airTime->channelUtilizationPercent() < max_channel_util_percent) { + airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; } else if (service.isToPhoneQueueEmpty()) { diff --git a/src/modules/esp32/RangeTestModule.cpp b/src/modules/esp32/RangeTestModule.cpp index 1624a972b..52a18def5 100644 --- a/src/modules/esp32/RangeTestModule.cpp +++ b/src/modules/esp32/RangeTestModule.cpp @@ -73,10 +73,8 @@ int32_t RangeTestModule::runOnce() LOG_INFO("fixed_position() %d\n", config.position.fixed_position); // Only send packets if the channel is less than 25% utilized. - if (airTime->channelUtilizationPercent() < 25) { + if (airTime->isTxAllowedChannelUtil(true)) { rangeTestModuleRadio->sendPayload(); - } else { - LOG_WARN("RangeTest - Channel utilization is >25 percent. Skipping this opportunity to send.\n"); } return (senderHeartbeat); diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index bf0421a9a..b5e0b1e65 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -21,7 +21,7 @@ int32_t StoreForwardModule::runOnce() // Send out the message queue. if (this->busy) { // Only send packets if the channel is less than 25% utilized. - if (airTime->channelUtilizationPercent() < polite_channel_util_percent) { + if (airTime->isTxAllowedChannelUtil(true)) { storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index); if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) { // Tell the client we're done sending @@ -34,12 +34,10 @@ int32_t StoreForwardModule::runOnce() } else { this->packetHistoryTXQueue_index++; } - } else { - LOG_WARN("*** Channel utilization is too high. Retrying later.\n"); } LOG_DEBUG("*** SF bitrate = %f bytes / sec\n", myNodeInfo.bitrate); - } else if ((millis() - lastHeartbeat > (heartbeatInterval * 1000)) && (airTime->channelUtilizationPercent() < polite_channel_util_percent)) { + } else if ((millis() - lastHeartbeat > (heartbeatInterval * 1000)) && airTime->isTxAllowedChannelUtil(true)) { lastHeartbeat = millis(); LOG_INFO("*** Sending heartbeat\n"); StoreAndForward sf = StoreAndForward_init_zero; From c0166773e852619adcdb7f56b5dca4cf0238ef98 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Wed, 11 Jan 2023 21:53:23 +0100 Subject: [PATCH 40/43] Portduino can handle this --- src/modules/Telemetry/DeviceTelemetry.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index dda7ab84d..5f96661e5 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -13,7 +13,6 @@ int32_t DeviceTelemetryModule::runOnce() { -#ifndef ARCH_PORTDUINO uint32_t now = millis(); if ((lastSentToMesh == 0 || (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval)) && @@ -26,7 +25,6 @@ int32_t DeviceTelemetryModule::runOnce() sendTelemetry(NODENUM_BROADCAST, true); } return sendToPhoneIntervalMs; -#endif } bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemetry *t) From 440b965e710a6d4475f26c53d6e6ea89f14e2f30 Mon Sep 17 00:00:00 2001 From: thebentern Date: Thu, 12 Jan 2023 01:38:21 +0000 Subject: [PATCH 41/43] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/mesh.pb.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/protobufs b/protobufs index 570cee3f3..e00b5ba7d 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 570cee3f31c8a1acfb31e0f3f434bf25b8451a52 +Subproject commit e00b5ba7d06053d820f1123351881fc4fa9270d1 diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 5ff84a223..984ae33ee 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -444,7 +444,7 @@ typedef struct _Waypoint { /* Description of the waypoint - max 100 chars */ char description[100]; /* Designator icon for the waypoint in the form of a unicode emoji */ - uint32_t emoji; + uint32_t icon; } Waypoint; typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; @@ -853,7 +853,7 @@ extern "C" { #define Waypoint_locked_tag 5 #define Waypoint_name_tag 6 #define Waypoint_description_tag 7 -#define Waypoint_emoji_tag 8 +#define Waypoint_icon_tag 8 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 #define MeshPacket_channel_tag 3 @@ -985,7 +985,7 @@ X(a, STATIC, SINGULAR, UINT32, expire, 4) \ X(a, STATIC, SINGULAR, BOOL, locked, 5) \ X(a, STATIC, SINGULAR, STRING, name, 6) \ X(a, STATIC, SINGULAR, STRING, description, 7) \ -X(a, STATIC, SINGULAR, FIXED32, emoji, 8) +X(a, STATIC, SINGULAR, FIXED32, icon, 8) #define Waypoint_CALLBACK NULL #define Waypoint_DEFAULT NULL From bd51cbd721cd987265a501976d9134926aca96b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 12 Jan 2023 09:15:54 +0000 Subject: [PATCH 42/43] Chance calculation for Nice TX. Still same value but dynamically based on duty cycle. --- src/airtime.cpp | 2 +- src/airtime.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index ae3b30811..94ef6d5b2 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -132,7 +132,7 @@ bool AirTime::isTxAllowedChannelUtil(bool polite) bool AirTime::isTxAllowedAirUtil() { if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { - if (utilizationTXPercent() < polite_tx_util_percent) { + if (utilizationTXPercent() < myRegion->dutyCycle * polite_tx_util_percent / 100) { return true; } else { LOG_WARN("Tx air utilization is >%d percent. Skipping this opportunity to send.\n", polite_tx_util_percent); diff --git a/src/airtime.h b/src/airtime.h index 2d1f1e2d9..5ba6f676a 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -70,7 +70,7 @@ class AirTime : private concurrency::OSThread uint32_t secSinceBoot = 0; uint8_t max_channel_util_percent = 40; uint8_t polite_channel_util_percent = 25; - uint8_t polite_tx_util_percent = 5; + uint8_t polite_tx_util_percent = 50; // half of Duty Cycle allowance struct airtimeStruct { uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted From bd2b766a369f5782da87f8c63fc134fa1cf9ca01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 12 Jan 2023 14:03:06 +0100 Subject: [PATCH 43/43] Rename to make function clearer --- src/airtime.cpp | 4 ++-- src/airtime.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index 94ef6d5b2..0c3fe81fc 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -132,10 +132,10 @@ bool AirTime::isTxAllowedChannelUtil(bool polite) bool AirTime::isTxAllowedAirUtil() { if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { - if (utilizationTXPercent() < myRegion->dutyCycle * polite_tx_util_percent / 100) { + if (utilizationTXPercent() < myRegion->dutyCycle * polite_duty_cycle_percent / 100) { return true; } else { - LOG_WARN("Tx air utilization is >%d percent. Skipping this opportunity to send.\n", polite_tx_util_percent); + LOG_WARN("Tx air utilization is >%d percent. Skipping this opportunity to send.\n", myRegion->dutyCycle * polite_duty_cycle_percent / 100); return false; } } diff --git a/src/airtime.h b/src/airtime.h index 5ba6f676a..e454b35ad 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -70,7 +70,7 @@ class AirTime : private concurrency::OSThread uint32_t secSinceBoot = 0; uint8_t max_channel_util_percent = 40; uint8_t polite_channel_util_percent = 25; - uint8_t polite_tx_util_percent = 50; // half of Duty Cycle allowance + uint8_t polite_duty_cycle_percent = 50; // half of Duty Cycle allowance is ok for metadata struct airtimeStruct { uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted