diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 1cac7479b..6500eb03d 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -83,6 +83,7 @@ jobs: include: - board: heltec-v3 - board: heltec-wsl-v3 + - board: heltec-wireless-tracker - board: tbeam-s3-core - board: tlora-t3s3-v1 uses: ./.github/workflows/build_esp32_s3.yml @@ -97,6 +98,7 @@ jobs: include: - board: rak4631 - board: rak4631_eink + - board: monteops_hw1 - board: t-echo - board: pca10059_diy_eink - board: feather_diy @@ -248,7 +250,7 @@ jobs: - name: Create request artifacts if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }} - uses: gavv/pull-request-artifacts@v1.0.0 + uses: gavv/pull-request-artifacts@v1.1.0 with: commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }} repo-token: ${{ secrets.GITHUB_TOKEN }} @@ -306,7 +308,7 @@ jobs: with: draft: true prerelease: true - release_name: Meshtastic Firmware ${{ steps.version.outputs.version }} + release_name: Meshtastic Firmware ${{ steps.version.outputs.version }} Alpha tag_name: v${{ steps.version.outputs.version }} body: | Autogenerated by github action, developer should edit as required before publishing... diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 62a943ece..f57ad549d 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -1,7 +1,7 @@ ; Common settings for ESP targes, mixin with extends = esp32_base [esp32_base] extends = arduino_base -platform = platformio/espressif32@^6.2.0 +platform = platformio/espressif32@^6.3.2 build_src_filter = ${arduino_base.build_src_filter} - - - - @@ -28,6 +28,7 @@ build_flags = -DCONFIG_BT_NIMBLE_ENABLED -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20 + -DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120 -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING ;-DDEBUG_HEAP diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index f44054f24..858dcdc9c 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -1,6 +1,6 @@ [nrf52_base] ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files -platform = platformio/nordicnrf52@^9.6.0 +platform = platformio/nordicnrf52@^10.0.0 extends = arduino_base build_type = debug ; I'm debugging with ICE a lot now @@ -9,7 +9,7 @@ build_flags = -Isrc/platform/nrf52 build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - lib_deps= ${arduino_base.lib_deps} diff --git a/arch/rp2040/rp2040.ini b/arch/rp2040/rp2040.ini index 52fba9cba..b6ac4f171 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 diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini index 819ecc31c..524edd6b9 100644 --- a/arch/stm32/stm32wl5e.ini +++ b/arch/stm32/stm32wl5e.ini @@ -13,7 +13,7 @@ build_flags = -DVECT_TAB_OFFSET=0x08000000 build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - - - - board_upload.offset_address = 0x08000000 upload_protocol = stlink diff --git a/boards/t-echo.json b/boards/t-echo.json index 9cb48b41a..957ba01e3 100644 --- a/boards/t-echo.json +++ b/boards/t-echo.json @@ -7,7 +7,10 @@ "cpu": "cortex-m4", "extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA", "f_cpu": "64000000L", - "hwids": [["0x239A", "0x4405"]], + "hwids": [ + ["0x239A", "0x4405"], + ["0x239A", "0x002A"] + ], "usb_product": "TTGO_eink", "mcu": "nrf52840", "variant": "t-echo", diff --git a/platformio.ini b/platformio.ini index b580d7160..e19175af7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,6 +9,7 @@ ;default_envs = heltec-v1 ;default_envs = heltec-v2_0 ;default_envs = heltec-v2_1 +;default_envs = heltec-wireless-tracker ;default_envs = tlora-v1 ;default_envs = tlora_v1_3 ;default_envs = tlora-v2 @@ -119,4 +120,4 @@ lib_deps = adafruit/Adafruit SHT31 Library@^2.2.0 adafruit/Adafruit PM25 AQI Sensor@^1.0.6 adafruit/Adafruit MPU6050@^2.2.4 - adafruit/Adafruit LIS3DH@^1.2.4 \ No newline at end of file + adafruit/Adafruit LIS3DH@^1.2.4 diff --git a/protobufs b/protobufs index 5f3daac5f..e0b136f5f 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 5f3daac5fabdfe2a0561395fed0ba11a38ba3e7e +Subproject commit e0b136f5f8e26094d02c28d1fdcacd61e087298c diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index 875ca2e22..307ca233e 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -43,7 +43,7 @@ class AccelerometerThread : public concurrency::OSThread } else if (accleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) { LOG_DEBUG("LIS3DH initializing\n"); lis.setRange(LIS3DH_RANGE_2_G); - // Adjust threshhold, higher numbers are less sensitive + // Adjust threshold, higher numbers are less sensitive lis.setClick(config.device.double_tap_as_button_press ? 2 : 1, ACCELEROMETER_CLICK_THRESHOLD); } } diff --git a/src/ButtonThread.h b/src/ButtonThread.h index 135d727c2..f03d2861a 100644 --- a/src/ButtonThread.h +++ b/src/ButtonThread.h @@ -98,7 +98,7 @@ class ButtonThread : public concurrency::OSThread userButtonTouch.tick(); canSleep &= userButtonTouch.isIdle(); #endif - // if (!canSleep) LOG_DEBUG("Supressing sleep!\n"); + // if (!canSleep) LOG_DEBUG("Suppressing sleep!\n"); // else LOG_DEBUG("sleep ok\n"); return 5; diff --git a/src/GPSStatus.h b/src/GPSStatus.h index ed3b3fc14..bcfb5f2eb 100644 --- a/src/GPSStatus.h +++ b/src/GPSStatus.h @@ -106,7 +106,7 @@ class GPSStatus : public Status bool matches(const GPSStatus *newStatus) const { #ifdef GPS_EXTRAVERBOSE - LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp); + LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.timestamp, p.timestamp); #endif return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->isPowerSaving != isPowerSaving || newStatus->p.latitude_i != p.latitude_i || diff --git a/src/OSTimer.cpp b/src/OSTimer.cpp index 0f7177a87..21744615f 100644 --- a/src/OSTimer.cpp +++ b/src/OSTimer.cpp @@ -5,7 +5,8 @@ * Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR) * * NOTE! xTimerPend... seems to ignore the time passed in on ESP32 and on NRF52 - * The reason this didn't work is bcause xTimerPednFunctCall really isn't a timer function at all - it just means run the callback + * The reason this didn't work is because xTimerPednFunctCall really isn't a timer function at all - it just means run the +callback * from the timer thread the next time you have spare cycles. * * @return true if successful, false if the timer fifo is too full. diff --git a/src/Power.cpp b/src/Power.cpp index 37d80a31f..ac1789cb0 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -50,7 +50,7 @@ XPowersLibInterface *PMU = NULL; #else // Copy of the base class defined in axp20x.h. -// I'd rather not inlude axp20x.h as it brings Wire dependency. +// I'd rather not include axp20x.h as it brings Wire dependency. class HasBatteryLevel { public: @@ -712,7 +712,7 @@ bool Power::axpChipInit() PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300); PMU->enablePowerOutput(XPOWERS_ALDO1); - // sdcard power channle + // sdcard power channel PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300); PMU->enablePowerOutput(XPOWERS_BLDO1); diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index e2cf94258..2d42ef655 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -352,5 +352,5 @@ void PowerFSM_setup() "mesh timeout"); #endif - powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state + powerFSM.run_machine(); // run one iteration of the state machine, so we run our on enter tasks for the initial DARK state } \ No newline at end of file diff --git a/src/airtime.h b/src/airtime.h index cb5f8bf6d..3ed7b6d7c 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -17,9 +17,9 @@ Example analytics: - TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel. + TX_LOG + RX_LOG = Total air time for a particular meshtastic channel. - TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including + TX_LOG + RX_LOG = Total air time for a particular meshtastic channel, including other lora radios. RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel. diff --git a/src/concurrency/InterruptableDelay.h b/src/concurrency/InterruptableDelay.h index 2b499073a..41bc40a21 100644 --- a/src/concurrency/InterruptableDelay.h +++ b/src/concurrency/InterruptableDelay.h @@ -18,7 +18,7 @@ namespace concurrency * * Useful for they top level loop() delay call to keep the CPU powered down until our next scheduled event or some external event. * - * This is implmented for FreeRTOS but should be easy to port to other operating systems. + * This is implemented for FreeRTOS but should be easy to port to other operating systems. */ class InterruptableDelay { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index a56ce86fe..4b6361cfd 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -33,7 +33,9 @@ class ScanI2C PMSA0031, MPU6050, LIS3DH, +#ifdef HAS_NCP5623 NCP5623, +#endif } DeviceType; // typedef uint8_t DeviceAddress; @@ -95,4 +97,4 @@ class ScanI2C private: bool shouldSuppressScreen = false; -}; +}; \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 7afb03ee2..7b5bb0a12 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -212,9 +212,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } break; - SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n") + SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n"); +#ifdef HAS_NCP5623 SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n"); - +#endif #ifdef HAS_PMU SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found\n") #endif @@ -305,4 +306,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); -} +} \ No newline at end of file diff --git a/src/detect/einkScan.h b/src/detect/einkScan.h index 8d82f4f81..6915709de 100644 --- a/src/detect/einkScan.h +++ b/src/detect/einkScan.h @@ -1,6 +1,6 @@ #include "../configuration.h" -#ifdef RAK4630 +#ifdef RAK_4631 #include "../main.h" #include @@ -64,4 +64,4 @@ void scanEInkDevice(void) LOG_DEBUG("EInk display not found\n"); SPI1.end(); } -#endif +#endif \ No newline at end of file diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 1b7c8511f..ed52ca70a 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -4,6 +4,10 @@ #include "configuration.h" #include "sleep.h" +#ifndef GPS_RESET_MODE +#define GPS_RESET_MODE HIGH +#endif + // If we have a serial GPS port it will not be null #ifdef GPS_SERIAL_NUM HardwareSerial _serial_gps_real(GPS_SERIAL_NUM); @@ -21,11 +25,26 @@ GPS *gps; /// only init that port once. static bool didSerialInit; -bool GPS::getACK(uint8_t c, uint8_t i) +void GPS::UBXChecksum(byte *message, size_t length) +{ + uint8_t CK_A = 0, CK_B = 0; + + // Calculate the checksum, starting from the CLASS field (which is message[2]) + for (size_t i = 2; i < length - 2; i++) { + CK_A = (CK_A + message[i]) & 0xFF; + CK_B = (CK_B + CK_A) & 0xFF; + } + + // Place the calculated checksum values in the message + message[length - 2] = CK_A; + message[length - 1] = CK_B; +} + +bool GPS::getACK(uint8_t class_id, uint8_t msg_id) { uint8_t b; uint8_t ack = 0; - const uint8_t ackP[2] = {c, i}; + const uint8_t ackP[2] = {class_id, msg_id}; uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned long startTime = millis(); @@ -42,17 +61,23 @@ bool GPS::getACK(uint8_t c, uint8_t i) while (1) { if (ack > 9) { - return true; + // LOG_INFO("Got ACK for class %02X message %02X\n", class_id, msg_id); + return true; // ACK received } - if (millis() - startTime > 1000) { - return false; + if (millis() - startTime > 3000) { + LOG_WARN("No response for class %02X message %02X\n", class_id, msg_id); + return false; // No response received within 3 seconds } if (_serial_gps->available()) { b = _serial_gps->read(); if (b == buf[ack]) { ack++; } else { - ack = 0; + ack = 0; // Reset the acknowledgement counter + if (buf[3] == 0x00) { // UBX-ACK-NAK message + LOG_WARN("Got NAK for class %02X message %02X\n", class_id, msg_id); + return false; // NAK received + } } } } @@ -108,12 +133,12 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t } break; case 4: - // Payload lenght lsb + // Payload length lsb needRead = c; ubxFrameCounter++; break; case 5: - // Payload lenght msb + // Payload length msb needRead |= (c << 8); ubxFrameCounter++; break; @@ -126,7 +151,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t if (_serial_gps->readBytes(buffer, needRead) != needRead) { ubxFrameCounter = 0; } else { - // return payload lenght + // return payload length return needRead; } break; @@ -160,10 +185,14 @@ bool GPS::setupGPS() config.position.tx_gpio = GPS_TX_PIN; #endif +//#define BAUD_RATE 115200 // ESP32 has a special set of parameters vs other arduino ports #if defined(ARCH_ESP32) - if (config.position.rx_gpio) + if (config.position.rx_gpio) { + LOG_DEBUG("Using GPIO%d for GPS RX\n", config.position.rx_gpio); + LOG_DEBUG("Using GPIO%d for GPS TX\n", config.position.tx_gpio); _serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, config.position.rx_gpio, config.position.tx_gpio); + } #else _serial_gps->begin(GPS_BAUDRATE); #endif @@ -190,8 +219,131 @@ bool GPS::setupGPS() // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g _serial_gps->write("$PCAS11,3*1E\r\n"); delay(250); + } else if (gnssModel == GNSS_MODEL_UC6850) { + + // use GPS + GLONASS + _serial_gps->write("$CFGSYS,h15\r\n"); + delay(250); } else if (gnssModel == GNSS_MODEL_UBLOX) { + // Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command) + // We need set it because by default it is GPS only, and we want to use GLONASS too + // Also we need SBAS for better accuracy and extra features + // ToDo: Dynamic configure GNSS systems depending of LoRa region + byte _message_GNSS[36] = { + 0xb5, 0x62, // Sync message for UBX protocol + 0x06, 0x3e, // Message class and ID (UBX-CFG-GNSS) + 0x1c, 0x00, // Length of payload (28 bytes) + 0x00, // msgVer (0 for this version) + 0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0) + 0xff, // numTrkChUse (max number of channels to use, 0xff = max available) + 0x03, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems + // GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags + 0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, // GPS + 0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS + 0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01, // GLONASS + 0x00, 0x00 // Checksum (to be calculated below) + }; + + // Calculate the checksum and update the message. + UBXChecksum(_message_GNSS, sizeof(_message_GNSS)); + + // Send the message to the module + _serial_gps->write(_message_GNSS, sizeof(_message_GNSS)); + + if (!getACK(0x06, 0x3e)) { + // It's not critical if the module doesn't acknowledge this configuration. + // The module should operate adequately with its factory or previously saved settings. + // It appears that there is a firmware bug in some GPS modules: When an attempt is made + // to overwrite a saved state with identical values, no ACK/NAK is received, contrary to + // what is specified in the Ublox documentation. + // There is also a possibility that the module may be GPS-only. + LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n"); + return true; + } else { + LOG_INFO("GNSS configured for GPS+SBAS+GLONASS. Pause for 0.75s before sending next command.\n"); + // Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next commands + delay(750); + return true; + } + + // Enable interference resistance, because we are using LoRa, WiFi and Bluetooth on same board, + // and we need to reduce interference from them + byte _message_JAM[16] = { + 0xB5, 0x62, // UBX protocol sync characters + 0x06, 0x39, // Message class and ID (UBX-CFG-ITFM) + 0x08, 0x00, // Length of payload (8 bytes) + // bbThreshold (Broadband jamming detection threshold) is set to 0x3F (63 in decimal) + // cwThreshold (CW jamming detection threshold) is set to 0x10 (16 in decimal) + // algorithmBits (Reserved algorithm settings) is set to 0x16B156 as recommended + // enable (Enable interference detection) is set to 1 (enabled) + 0x3F, 0x10, 0xB1, 0x56, // config: Interference config word + // generalBits (General settings) is set to 0x31E as recommended + // antSetting (Antenna setting, 0=unknown, 1=passive, 2=active) is set to 0 (unknown) + // ToDo: Set to 1 (passive) or 2 (active) if known, for example from UBX-MON-HW, or from board info + // enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1 + // (enabled) + 0x1E, 0x03, 0x00, 0x01, // config2: Extra settings for jamming/interference monitor + 0x00, 0x00 // Checksum (calculated below) + }; + + // Calculate the checksum and update the message. + UBXChecksum(_message_JAM, sizeof(_message_JAM)); + + // Send the message to the module + _serial_gps->write(_message_JAM, sizeof(_message_JAM)); + + if (!getACK(0x06, 0x39)) { + LOG_WARN("Unable to enable interference resistance.\n"); + return true; + } + + // Configure navigation engine expert settings: + byte _message_NAVX5[48] = { + 0xb5, 0x62, // UBX protocol sync characters + 0x06, 0x23, // Message class and ID (UBX-CFG-NAVX5) + 0x28, 0x00, // Length of payload (40 bytes) + 0x00, 0x00, // msgVer (0 for this version) + // minMax flag = 1: apply min/max SVs settings + // minCno flag = 1: apply minimum C/N0 setting + // initial3dfix flag = 0: apply initial 3D fix settings + // aop flag = 1: apply aopCfg (useAOP flag) settings (AssistNow Autonomous) + 0x1B, 0x00, // mask1 (First parameters bitmask) + // adr flag = 0: apply ADR sensor fusion on/off setting (useAdr flag) + // If firmware is not ADR/UDR, enabling this flag will fail configuration + // ToDo: check this with UBX-MON-VER + 0x00, 0x00, 0x00, 0x00, // mask2 (Second parameters bitmask) + 0x00, 0x00, // Reserved + 0x03, // minSVs (Minimum number of satellites for navigation) = 3 + 0x10, // maxSVs (Maximum number of satellites for navigation) = 16 + 0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz + 0x00, // Reserved + 0x00, // iniFix3D (Initial fix must be 3D) = 0 (disabled) + 0x00, 0x00, // Reserved + 0x00, // ackAiding (Issue acknowledgements for assistance message input) = 0 (disabled) + 0x00, 0x00, // Reserved + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved + 0x00, // Reserved + 0x01, // aopCfg (AssistNow Autonomous configuration) = 1 (enabled) + 0x00, 0x00, // Reserved + 0x00, 0x00, // Reserved + 0x00, 0x00, 0x00, 0x00, // Reserved + 0x00, 0x00, 0x00, // Reserved + 0x01, // useAdr (Enable/disable ADR sensor fusion) = 1 (enabled) + 0x00, 0x00 // Checksum (calculated below) + }; + + // Calculate the checksum and update the message. + UBXChecksum(_message_NAVX5, sizeof(_message_NAVX5)); + + // Send the message to the module + _serial_gps->write(_message_NAVX5, sizeof(_message_NAVX5)); + + if (!getACK(0x06, 0x23)) { + LOG_WARN("Unable to configure extra settings.\n"); + return true; + } + /* tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after setting will not output command messages in UART1, resulting in unrecognized module information @@ -208,57 +360,205 @@ bool GPS::setupGPS() // ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid - // disable GGL - byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A}; + // Set GPS update rate to 1Hz + // Lowering the update rate helps to save power. + // Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz + // is recommended to avoid a known issue with satellites disappearing. + byte _message_1Hz[] = { + 0xB5, 0x62, // UBX protocol sync characters + 0x06, 0x08, // Message class and ID (UBX-CFG-RATE) + 0x06, 0x00, // Length of payload (6 bytes) + 0xE8, 0x03, // Measurement Rate (1000ms for 1Hz) + 0x01, 0x00, // Navigation rate, always 1 in GPS mode + 0x01, 0x00, // Time reference + 0x00, 0x00 // Placeholder for checksum, will be calculated next + }; + + // Calculate the checksum and update the message. + UBXChecksum(_message_1Hz, sizeof(_message_1Hz)); + + // Send the message to the module + _serial_gps->write(_message_1Hz, sizeof(_message_1Hz)); + + if (!getACK(0x06, 0x08)) { + LOG_WARN("Unable to set GPS update rate.\n"); + return true; + } + + // Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical + // coordinates. + byte _message_GGL[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x01, // NMEA ID for GLL + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x00, // Disable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + + // Calculate the checksum and update the message. + UBXChecksum(_message_GGL, sizeof(_message_GGL)); + + // Send the message to the module _serial_gps->write(_message_GGL, sizeof(_message_GGL)); + if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA GGL.\n"); return true; } - // disable GSA - byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41}; + // Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and + // the DOP (Dilution of Precision) + byte _message_GSA[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x02, // NMEA ID for GSA + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x01, // Enable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_GSA, sizeof(_message_GSA)); _serial_gps->write(_message_GSA, sizeof(_message_GSA)); if (!getACK(0x06, 0x01)) { - LOG_WARN("Unable to disable NMEA GSA.\n"); + LOG_WARN("Unable to Enable NMEA GSA.\n"); return true; } - // disable GSV - byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48}; + // Disable GSV. GSV - Satellites in view, details the number and location of satellites in view. + byte _message_GSV[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x03, // NMEA ID for GSV + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x00, // Disable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_GSV, sizeof(_message_GSV)); _serial_gps->write(_message_GSV, sizeof(_message_GSV)); if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA GSV.\n"); return true; } - // disable VTG - byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56}; + // Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to + // the ground. + byte _message_VTG[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x05, // NMEA ID for VTG + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x00, // Disable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_VTG, sizeof(_message_VTG)); _serial_gps->write(_message_VTG, sizeof(_message_VTG)); if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA VTG.\n"); return true; } - // enable RMC - byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54}; + // Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data. + byte _message_RMC[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x04, // NMEA ID for RMC + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x01, // Enable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_RMC, sizeof(_message_RMC)); _serial_gps->write(_message_RMC, sizeof(_message_RMC)); if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to enable NMEA RMC.\n"); return true; } - // enable GGA - byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38}; + // Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data. + byte _message_GGA[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x00, // NMEA ID for GGA + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x01, // Enable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_GGA, sizeof(_message_GGA)); _serial_gps->write(_message_GGA, sizeof(_message_GGA)); if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to enable NMEA GGA.\n"); + return true; + } + + // The Power Management configuration allows the GPS module to operate in different power modes for optimized power + // consumption. + // The modes supported are: + // 0x00 = Full power: The module operates at full power with no power saving. + // 0x01 = Balanced: The module dynamically adjusts the tracking behavior to balance power consumption. + // 0x02 = Interval: The module operates in a periodic mode, cycling between tracking and power saving states. + // 0x03 = Aggressive with 1 Hz: The module operates in a power saving mode with a 1 Hz update rate. + // 0x04 = Aggressive with 2 Hz: The module operates in a power saving mode with a 2 Hz update rate. + // 0x05 = Aggressive with 4 Hz: The module operates in a power saving mode with a 4 Hz update rate. + // The 'period' field specifies the position update and search period. It is only valid when the powerSetupValue is + // set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase and + // must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise, it must + // be set to '0'. + byte UBX_CFG_PMS[14] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x86, // Message class and ID (UBX-CFG-PMS) + 0x06, 0x00, // Length of payload (6 bytes) + 0x00, // Version (0) + 0x03, // Power setup value + 0x00, 0x00, // period: not applicable, set to 0 + 0x00, 0x00, // onTime: not applicable, set to 0 + 0x00, 0x00 // Placeholder for checksum, will be calculated next + }; + + // Calculate the checksum and update the message + UBXChecksum(UBX_CFG_PMS, sizeof(UBX_CFG_PMS)); + + // Send the message to the module + _serial_gps->write(UBX_CFG_PMS, sizeof(UBX_CFG_PMS)); + if (!getACK(0x06, 0x86)) { + LOG_WARN("Unable to enable powersaving for GPS.\n"); + return true; + } + + // We need save configuration to flash to make our config changes persistent + byte _message_SAVE[21] = { + 0xB5, 0x62, // UBX protocol header + 0x06, 0x09, // UBX class ID (Configuration Input Messages), message ID (UBX-CFG-CFG) + 0x0D, 0x00, // Length of payload (13 bytes) + 0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared + 0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections + 0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded + 0x0F, // deviceMask: BBR, Flash, EEPROM, and SPI Flash + 0x00, 0x00 // Checksum (calculated below) + }; + + // Calculate the checksum and update the message. + UBXChecksum(_message_SAVE, sizeof(_message_SAVE)); + + // Send the message to the module + _serial_gps->write(_message_SAVE, sizeof(_message_SAVE)); + + if (!getACK(0x06, 0x09)) { + LOG_WARN("Unable to save GNSS module configuration.\n"); + return true; + } else { + LOG_INFO("GNSS module configuration saved!\n"); + return true; } } } @@ -269,22 +569,21 @@ bool GPS::setupGPS() bool GPS::setup() { // Master power for the GPS -#ifdef PIN_GPS_EN - digitalWrite(PIN_GPS_EN, 1); - pinMode(PIN_GPS_EN, OUTPUT); -#endif -#ifdef HAS_PMU +#if defined(HAS_PMU) || defined(PIN_GPS_EN) if (config.position.gps_enabled) { +#ifdef PIN_GPS_EN + pinMode(PIN_GPS_EN, OUTPUT); +#endif setGPSPower(true); } #endif #ifdef PIN_GPS_RESET - digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms + digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms pinMode(PIN_GPS_RESET, OUTPUT); delay(10); - digitalWrite(PIN_GPS_RESET, 0); + digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE); #endif setAwake(true); // Wake GPS power before doing any init bool ok = setupGPS(); @@ -384,7 +683,7 @@ void GPS::setAwake(bool on) } } -/** Get how long we should stay looking for each aquisition in msecs +/** Get how long we should stay looking for each acquisition in msecs */ uint32_t GPS::getWakeTime() const { @@ -560,6 +859,9 @@ GnssModel_t GPS::probe() return GNSS_MODEL_UBLOX; #elif defined(GPS_L76K) return GNSS_MODEL_MTK; +#elif defined(GPS_UC6580) + _serial_gps->updateBaudRate(115200); + return GNSS_MODEL_UC6850; #else // we use autodetect, only T-BEAM S3 for now... uint8_t buffer[256]; @@ -599,7 +901,7 @@ GnssModel_t GPS::probe() // Check that the returned response class and message ID are correct if (!getAck(buffer, 256, 0x06, 0x08)) { LOG_WARN("Failed to find UBlox & MTK GNSS Module\n"); - return GNSS_MODEL_UNKONW; + return GNSS_MODEL_UNKNOWN; } // Get Ublox gnss module hardware and software info @@ -675,8 +977,8 @@ GPS *createGps() LOG_DEBUG("Using MSL altitude model\n"); #endif if (GPS::_serial_gps) { - // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just - // assume NMEA at 9600 baud. + // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. + // Just assume NMEA at 9600 baud. GPS *new_gps = new NMEAGPS(); new_gps->setup(); return new_gps; @@ -688,4 +990,4 @@ GPS *createGps() } return nullptr; #endif -} +} \ No newline at end of file diff --git a/src/gps/GPS.h b/src/gps/GPS.h index a5f5f2ff4..847a60016 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -14,7 +14,8 @@ struct uBloxGnssModelInfo { typedef enum { GNSS_MODEL_MTK, GNSS_MODEL_UBLOX, - GNSS_MODEL_UNKONW, + GNSS_MODEL_UC6850, + GNSS_MODEL_UNKNOWN, } GnssModel_t; // Generate a string representation of DOP @@ -139,6 +140,9 @@ class GPS : private concurrency::OSThread /// always returns 0 to indicate okay to sleep int prepareDeepSleep(void *unused); + // Calculate checksum + void UBXChecksum(byte *message, size_t length); + /** * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode * @@ -164,6 +168,7 @@ class GPS : private concurrency::OSThread virtual int32_t runOnce() override; // Get GNSS model + String getNMEA(); GnssModel_t probe(); int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID); @@ -172,11 +177,11 @@ class GPS : private concurrency::OSThread uint8_t fixeddelayCtr = 0; protected: - GnssModel_t gnssModel = GNSS_MODEL_UNKONW; + GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; }; // Creates an instance of the GPS class. // Returns the new instance or null if the GPS is not present. GPS *createGps(); -extern GPS *gps; +extern GPS *gps; \ No newline at end of file diff --git a/src/gps/GeoCoord.cpp b/src/gps/GeoCoord.cpp index 9d5e6315e..19a753c02 100644 --- a/src/gps/GeoCoord.cpp +++ b/src/gps/GeoCoord.cpp @@ -12,7 +12,7 @@ GeoCoord::GeoCoord(int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _lon GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt) { - // Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000 + // Change decimial representation to int32_t. I.e., 12.345 becomes 123450000 _latitude = int32_t(lat * 1e+7); _longitude = int32_t(lon * 1e+7); GeoCoord::setCoords(); @@ -20,7 +20,7 @@ GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt) GeoCoord::GeoCoord(double lat, double lon, int32_t alt) : _altitude(alt) { - // Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000 + // Change decimial representation to int32_t. I.e., 12.345 becomes 123450000 _latitude = int32_t(lat * 1e+7); _longitude = int32_t(lon * 1e+7); GeoCoord::setCoords(); @@ -41,7 +41,7 @@ void GeoCoord::setCoords() void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt) { - // If marked dirty or new coordiantes + // If marked dirty or new coordinates if (_dirty || _latitude != lat || _longitude != lon || _altitude != alt) { _dirty = true; _latitude = lat; @@ -55,7 +55,7 @@ void GeoCoord::updateCoords(const double lat, const double lon, const int32_t al { int32_t iLat = lat * 1e+7; int32_t iLon = lon * 1e+7; - // If marked dirty or new coordiantes + // If marked dirty or new coordinates if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) { _dirty = true; _latitude = iLat; @@ -69,7 +69,7 @@ void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt) { int32_t iLat = lat * 1e+7; int32_t iLon = lon * 1e+7; - // If marked dirty or new coordiantes + // If marked dirty or new coordinates if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) { _dirty = true; _latitude = iLat; @@ -217,7 +217,7 @@ void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr) double eta2 = v / rho - 1; double mA = (1 + n + (5 / 4) * n * n + (5 / 4) * n * n * n) * (phi - phi0); double mB = (3 * n + 3 * n * n + (21 / 8) * n * n * n) * sin(phi - phi0) * cos(phi + phi0); - // loss of precision in mC & mD due to floating point rounding can cause innaccuracy of northing by a few meters + // loss of precision in mC & mD due to floating point rounding can cause inaccuracy of northing by a few meters double mC = (15 / 8 * n * n + 15 / 8 * n * n * n) * sin(2 * (phi - phi0)) * cos(2 * (phi + phi0)); double mD = (35 / 24) * n * n * n * sin(3 * (phi - phi0)) * cos(3 * (phi + phi0)); double m = b * f0 * (mA - mB + mC - mD); diff --git a/src/gps/GeoCoord.h b/src/gps/GeoCoord.h index 28e9e14e9..06b11c3de 100644 --- a/src/gps/GeoCoord.h +++ b/src/gps/GeoCoord.h @@ -65,7 +65,7 @@ struct MGRS { uint32_t northing; }; -// A struct to hold the data for a OSGR coordiante +// A struct to hold the data for a OSGR coordinate struct OSGR { char e100k; char n100k; diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index 118c2128c..b80fd04aa 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -19,7 +19,7 @@ static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only upda void readFromRTC() { - struct timeval tv; /* btw settimeofday() is helpfull here too*/ + struct timeval tv; /* btw settimeofday() is helpful here too*/ #ifdef RV3028_RTC if (rtc_found.address == RV3028_RTC) { uint32_t now = millis(); diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 048e8dd6e..61d0eea5a 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -7,6 +7,10 @@ #include "main.h" #include +// #ifdef HELTEC_WIRELESS_PAPER +// SPIClass *hspi = NULL; +// #endif + #define COLORED GxEPD_BLACK #define UNCOLORED GxEPD_WHITE @@ -19,13 +23,13 @@ #define TECHO_DISPLAY_MODEL GxEPD2_213_BN // 4.2 inch 300x400 - GxEPD2_420_M01 -//#define TECHO_DISPLAY_MODEL GxEPD2_420_M01 +// #define TECHO_DISPLAY_MODEL GxEPD2_420_M01 // 2.9 inch 296x128 - GxEPD2_290_T5D -//#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D +// #define TECHO_DISPLAY_MODEL GxEPD2_290_T5D // 1.54 inch 200x200 - GxEPD2_154_M09 -//#define TECHO_DISPLAY_MODEL GxEPD2_154_M09 +// #define TECHO_DISPLAY_MODEL GxEPD2_154_M09 #elif defined(MAKERPYTHON) // 2.9 inch 296x128 - GxEPD2_290_T5D @@ -41,6 +45,9 @@ // 1.54 inch 200x200 - GxEPD2_154_M09 #define TECHO_DISPLAY_MODEL GxEPD2_154_M09 +#elif defined(HELTEC_WIRELESS_PAPER) +//#define TECHO_DISPLAY_MODEL GxEPD2_213_T5D +#define TECHO_DISPLAY_MODEL GxEPD2_213_BN #endif GxEPD2_BW *adafruitDisplay; @@ -62,6 +69,10 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY // GxEPD2_154_M09 // setGeometry(GEOMETRY_RAWMODE, 200, 200); + +#elif defined(HELTEC_WIRELESS_PAPER) + // setGeometry(GEOMETRY_RAWMODE, 212, 104); + setGeometry(GEOMETRY_RAWMODE, 250, 122); #elif defined(MAKERPYTHON) // GxEPD2_290_T5D setGeometry(GEOMETRY_RAWMODE, 296, 128); @@ -109,7 +120,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit) for (uint32_t y = 0; y < displayHeight; y++) { for (uint32_t x = 0; x < displayWidth; x++) { - // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent + // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient auto b = buffer[x + (y / 8) * displayWidth]; auto isset = b & (1 << (y & 7)); adafruitDisplay->drawPixel(x, y, isset ? COLORED : UNCOLORED); @@ -218,6 +229,16 @@ bool EInkDisplay::connect() (void)adafruitDisplay; } } +#elif defined(HELTEC_WIRELESS_PAPER) + { + auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY); + adafruitDisplay = new GxEPD2_BW(*lowLevel); + // hspi = new SPIClass(HSPI); + // hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS + adafruitDisplay->init(115200, true, 10, false, SPI, SPISettings(6000000, MSBFIRST, SPI_MODE0)); + adafruitDisplay->setRotation(3); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + } #elif defined(PCA10059) { auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY); diff --git a/src/graphics/RAKled.h b/src/graphics/RAKled.h index 06e2a717f..2e36b874a 100644 --- a/src/graphics/RAKled.h +++ b/src/graphics/RAKled.h @@ -1,6 +1,6 @@ #include "main.h" -#ifdef RAK4630 +#ifdef HAS_NCP5623 #include extern NCP5623 rgb; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index f2c5da4e2..3105ee218 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -320,18 +320,18 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { + uint16_t x_offset = display->width() / 2; display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(FONT_MEDIUM); - display->drawString(64 + x, 26 + y, "Shutting down..."); + display->drawString(x_offset + x, 26 + y, "Shutting down..."); } static void drawFrameReboot(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { + uint16_t x_offset = display->width() / 2; display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(FONT_MEDIUM); - display->drawString(64 + x, 26 + y, "Rebooting..."); + display->drawString(x_offset + x, 26 + y, "Rebooting..."); } static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -360,7 +360,7 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org"); } -// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled +// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled static bool shouldDrawMessage(const meshtastic_MeshPacket *packet) { return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled; @@ -442,7 +442,7 @@ static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, i } } -/// Draw a series of fields in a column, wrapping to multiple colums if needed +/// Draw a series of fields in a column, wrapping to multiple columns if needed static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) { // The coordinates define the left starting point of the text @@ -1789,7 +1789,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat heartbeat = !heartbeat; #endif } -// adjust Brightness cycle trough 1 to 254 as long as attachDuringLongPress is true +// adjust Brightness cycle through 1 to 254 as long as attachDuringLongPress is true void Screen::adjustBrightness() { if (!useDisplay) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 8c07a4204..b54ac75cf 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -1,12 +1,112 @@ #include "configuration.h" +#ifndef TFT_BACKLIGHT_ON +#define TFT_BACKLIGHT_ON HIGH +#endif + +// convert 24-bit color to 16-bit (56K) +#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)) +#define TFT_MESH COLOR565(0x67, 0xEA, 0x94) + +#if defined(ST7735S) +#include // Graphics and font library for ST7735 driver chip + +#if defined(ST7735_BACKLIGHT_EN) && !defined(TFT_BL) +#define TFT_BL ST7735_BACKLIGHT_EN +#endif + +class LGFX : public lgfx::LGFX_Device +{ + lgfx::Panel_ST7735S _panel_instance; + lgfx::Bus_SPI _bus_instance; + lgfx::Light_PWM _light_instance; + + public: + LGFX(void) + { + { + auto cfg = _bus_instance.config(); + + // configure SPI + cfg.spi_host = ST7735_SPI_HOST; // ESP32-S2,S3,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST + cfg.spi_mode = 0; + cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing + // 80MHz by an integer) + cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving + cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin + cfg.use_lock = true; // Set to true to use transaction locking + cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch / + // SPI_DMA_CH_AUTO=auto setting) + cfg.pin_sclk = ST7735_SCK; // Set SPI SCLK pin number + cfg.pin_mosi = ST7735_SDA; // Set SPI MOSI pin number + cfg.pin_miso = ST7735_MISO; // Set SPI MISO pin number (-1 = disable) + cfg.pin_dc = ST7735_RS; // Set SPI DC pin number (-1 = disable) + + _bus_instance.config(cfg); // applies the set value to the bus. + _panel_instance.setBus(&_bus_instance); // set the bus on the panel. + } + + { // Set the display panel control. + auto cfg = _panel_instance.config(); // Gets a structure for display panel settings. + + cfg.pin_cs = ST7735_CS; // Pin number where CS is connected (-1 = disable) + cfg.pin_rst = ST7735_RESET; // Pin number where RST is connected (-1 = disable) + cfg.pin_busy = ST7735_BUSY; // Pin number where BUSY is connected (-1 = disable) + + // The following setting values ​​are general initial values ​​for each panel, so please comment out any + // unknown items and try them. + + cfg.panel_width = TFT_WIDTH; // actual displayable width + cfg.panel_height = TFT_HEIGHT; // actual displayable height + cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction + cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction + cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is upside down) + cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout + cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read + cfg.readable = true; // Set to true if data can be read + cfg.invert = true; // Set to true if the light/darkness of the panel is reversed + cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped + cfg.dlen_16bit = + false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI + cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.) + + // Set the following only when the display is shifted with a driver with a variable number of pixels, such as the + // ST7735 or ILI9163. + cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC + cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC + _panel_instance.config(cfg); + } + + // Set the backlight control + { + auto cfg = _light_instance.config(); // Gets a structure for backlight settings. + + cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected + cfg.invert = true; // true to invert the brightness of the backlight + // cfg.freq = 44100; // PWM frequency of backlight + // cfg.pwm_channel = 1; // PWM channel number to use + + _light_instance.config(cfg); + _panel_instance.setLight(&_light_instance); // Set the backlight on the panel. + } + + setPanel(&_panel_instance); + } +}; + +static LGFX tft; + +#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) +#include // Graphics and font library for ILI9341 driver chip + +static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h + +#endif + #if defined(ST7735_CS) || defined(ILI9341_DRIVER) #include "SPILock.h" #include "TFTDisplay.h" #include -#include // Graphics and font library for ST7735 driver chip - -static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus) { @@ -30,7 +130,7 @@ void TFTDisplay::display(void) auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7)); auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7)); if (isset != dblbuf_isset) { - tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK); + tft.drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK); } } } @@ -46,8 +146,31 @@ void TFTDisplay::display(void) // Send a command to the display (low level function) void TFTDisplay::sendCommand(uint8_t com) { - (void)com; - // Drop all commands to device (we just update the buffer) + // handle display on/off directly + switch (com) { + case DISPLAYON: { +#ifdef TFT_BL + digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); +#endif +#ifdef VTFT_CTRL + digitalWrite(VTFT_CTRL, LOW); +#endif + break; + } + case DISPLAYOFF: { +#ifdef TFT_BL + digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON); +#endif +#ifdef VTFT_CTRL + digitalWrite(VTFT_CTRL, HIGH); +#endif + break; + } + default: + break; + } + + // Drop all other commands to device (we just update the buffer) } void TFTDisplay::setDetected(uint8_t detected) @@ -62,14 +185,10 @@ bool TFTDisplay::connect() LOG_INFO("Doing TFT init\n"); #ifdef TFT_BL - digitalWrite(TFT_BL, HIGH); + digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); pinMode(TFT_BL, OUTPUT); #endif -#ifdef ST7735_BACKLIGHT_EN - digitalWrite(ST7735_BACKLIGHT_EN, HIGH); - pinMode(ST7735_BACKLIGHT_EN, OUTPUT); -#endif tft.init(); #ifdef M5STACK tft.setRotation(1); // M5Stack has the TFT in landscape @@ -77,7 +196,6 @@ bool TFTDisplay::connect() tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label #endif tft.fillScreen(TFT_BLACK); - // tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left return true; } diff --git a/src/graphics/TFTDisplay.h b/src/graphics/TFTDisplay.h index 013f4961e..46cfe85e7 100644 --- a/src/graphics/TFTDisplay.h +++ b/src/graphics/TFTDisplay.h @@ -7,7 +7,6 @@ * * Remaining TODO: * optimize display() to only draw changed pixels (see other OLED subclasses for examples) - * implement displayOn/displayOff to turn off the TFT device (and backlight) * Use the fast NRF52 SPI API rather than the slow standard arduino version * * turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted? diff --git a/src/main.cpp b/src/main.cpp index c867930d0..e503aadcf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,13 +47,12 @@ NRF52Bluetooth *nrf52Bluetooth; #if HAS_WIFI #include "mesh/api/WiFiServerAPI.h" -#include "mqtt/MQTT.h" #endif #if HAS_ETHERNET #include "mesh/api/ethServerAPI.h" -#include "mqtt/MQTT.h" #endif +#include "mqtt/MQTT.h" #include "LLCC68Interface.h" #include "RF95Interface.h" @@ -170,7 +169,7 @@ SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0); RadioInterface *rIf = NULL; /** - * Some platforms (nrf52) might provide an alterate version that supresses calling delay from sleep. + * Some platforms (nrf52) might provide an alterate version that suppresses calling delay from sleep. */ __attribute__((weak, noinline)) bool loopCanSleep() { @@ -215,6 +214,16 @@ void setup() digitalWrite(VEXT_ENABLE, 0); // turn on the display power #endif +#ifdef VGNSS_CTRL + pinMode(VGNSS_CTRL, OUTPUT); + digitalWrite(VGNSS_CTRL, LOW); +#endif + +#if defined(VTFT_CTRL) + pinMode(VTFT_CTRL, OUTPUT); + digitalWrite(VTFT_CTRL, LOW); +#endif + #ifdef RESET_OLED pinMode(RESET_OLED, OUTPUT); digitalWrite(RESET_OLED, 1); @@ -261,10 +270,11 @@ void setup() #endif #ifdef RAK4630 +#ifdef PIN_3V3_EN // We need to enable 3.3V periphery in order to scan it pinMode(PIN_3V3_EN, OUTPUT); digitalWrite(PIN_3V3_EN, HIGH); - +#endif #ifndef USE_EINK // RAK-12039 set pin for Air quality sensor pinMode(AQ_SET_PIN, OUTPUT); @@ -352,17 +362,18 @@ void setup() pmu_found = i2cScanner->exists(ScanI2C::DeviceType::PMU_AXP192_AXP2101); - /* - * There are a bunch of sensors that have no further logic than to be found and stuffed into the - * nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field - * "found". - */ +/* + * There are a bunch of sensors that have no further logic than to be found and stuffed into the + * nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field + * "found". + */ - // Only one supported RGB LED currently +// Only one supported RGB LED currently +#ifdef HAS_NCP5623 rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623); -// Start the RGB LED at 50% -#ifdef RAK4630 + // Start the RGB LED at 50% + if (rgb_found.type == ScanI2C::NCP5623) { rgb.begin(); rgb.setCurrent(10); @@ -654,9 +665,7 @@ void setup() } } -#if HAS_WIFI || HAS_ETHERNET mqttInit(); -#endif #ifndef ARCH_PORTDUINO // Initialize Wifi @@ -701,7 +710,7 @@ uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reb uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to shutdown from python or mobile client) // If a thread does something that might need for it to be rescheduled ASAP it can set this flag -// This will supress the current delay and instead try to run ASAP. +// This will suppress the current delay and instead try to run ASAP. bool runASAP; extern meshtastic_DeviceMetadata getDeviceMetadata() diff --git a/src/main.h b/src/main.h index 93baec590..c13c92bd4 100644 --- a/src/main.h +++ b/src/main.h @@ -59,7 +59,7 @@ extern uint32_t shutdownAtMsec; extern uint32_t serialSinceMsec; // If a thread does something that might need for it to be rescheduled ASAP it can set this flag -// This will supress the current delay and instead try to run ASAP. +// This will suppress the current delay and instead try to run ASAP. extern bool runASAP; void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), clearBonds(); diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index f3d696f90..b4bdcbd5c 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -20,7 +20,7 @@ class Channels /// The index of the primary channel ChannelIndex primaryIndex = 0; - /** The channel index that was requested for sending/receving. Note: if this channel is a secondary + /** The channel index that was requested for sending/receiving. Note: if this channel is a secondary channel and does not have a PSK, we will use the PSK from the primary channel. If this channel is disabled no sending or receiving will be allowed */ ChannelIndex activeChannelIndex = 0; diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index f412c0e1c..db3f3f35e 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -21,7 +21,12 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { if (wasSeenRecently(p)) { // Note: this will also add a recent packet record printPacket("Ignoring incoming msg, because we've already seen it", p); - Router::cancelSending(p->from, p->id); // cancel rebroadcast of this message *if* there was already one + if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && + config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT && + config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { + // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! + Router::cancelSending(p->from, p->id); + } return true; } diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index bf3e34c24..309035cb3 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -49,7 +49,7 @@ class FloodingRouter : public Router, protected PacketHistory /** * Should this incoming filter be dropped? * - * Called immedately on receiption, before any further processing. + * Called immediately on reception, before any further processing. * @return true to abandon the packet */ virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override; diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index 55948b33f..a1e719721 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -18,7 +18,7 @@ meshtastic_MeshPacket *MeshModule::currentReply; MeshModule::MeshModule(const char *_name) : name(_name) { - // Can't trust static initalizer order, so we check each time + // Can't trust static initializer order, so we check each time if (!modules) modules = new std::vector(); @@ -39,7 +39,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod c.error_reason = err; c.which_variant = meshtastic_Routing_error_reason_tag; - // Now that we have moded sendAckNak up one level into the class heirarchy we can no longer assume we are a RoutingPlugin + // Now that we have moded sendAckNak up one level into the class hierarchy we can no longer assume we are a RoutingPlugin // So we manually call pb_encode_to_bytes and specify routing port number // auto p = allocDataProtobuf(c); meshtastic_MeshPacket *p = router->allocForSending(); @@ -169,7 +169,7 @@ void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src) // Note: if the message started with the local node or a module asked to ignore the request, we don't want to send a // no response reply - // No one wanted to reply to this requst, tell the requster that happened + // No one wanted to reply to this request, tell the requster that happened LOG_DEBUG("No one responded, send a nak\n"); // SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded) diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h index 2eee04f5d..323cc8595 100644 --- a/src/mesh/MeshModule.h +++ b/src/mesh/MeshModule.h @@ -47,7 +47,7 @@ typedef struct _UIFrameEvent { * A key concept for this is that your module should use a particular "portnum" for each message type you want to receive * and handle. * - * Interally we use modules to implement the core meshtastic text messaging and gps position sharing features. You + * Internally we use modules to implement the core meshtastic text messaging and gps position sharing features. You * can use these classes as examples for how to write your own custom module. See here: (FIXME) */ class MeshModule diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 2ad46a6b7..32565cb29 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -34,7 +34,7 @@ arbitrating to select a node number and keeping the current nodedb. /* Broadcast when a newly powered mesh node wants to find a node num it can use -The algoritm is as follows: +The algorithm is as follows: * when a node starts up, it broadcasts their user and the normal flow is for all other nodes to reply with their User as well (so the new node can build its node db) * If a node ever receives a User (not just the first broadcast) message where the sender node number equals our node number, that @@ -52,13 +52,18 @@ FIXME in the initial proof of concept we just skip the entire want/deny flow and MeshService service; +static MemoryDynamic staticMqttClientProxyMessagePool; + static MemoryDynamic staticQueueStatusPool; +Allocator &mqttClientProxyMessagePool = staticMqttClientProxyMessagePool; + Allocator &queueStatusPool = staticQueueStatusPool; #include "Router.h" -MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE) +MeshService::MeshService() + : toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE), toPhoneMqttProxyQueue(MAX_RX_TOPHONE) { lastQueueStatus = {0, 0, 16, 0}; } @@ -269,6 +274,20 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p) fromNum++; } +void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m) +{ + LOG_DEBUG("Sending mqtt message on topic '%s' to client for proxying to server\n", m->topic); + if (toPhoneMqttProxyQueue.numFree() == 0) { + LOG_WARN("MqttClientProxyMessagePool queue is full, discarding oldest\n"); + meshtastic_MqttClientProxyMessage *d = toPhoneMqttProxyQueue.dequeuePtr(0); + if (d) + releaseMqttClientProxyMessageToPool(d); + } + + assert(toPhoneMqttProxyQueue.enqueue(m, 0)); + fromNum++; +} + meshtastic_NodeInfoLite *MeshService::refreshLocalMeshNode() { meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum()); diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index d14db7139..fa184b391 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -15,6 +15,7 @@ #endif extern Allocator &queueStatusPool; +extern Allocator &mqttClientProxyMessagePool; /** * Top level app for this service. keeps the mesh, the radio config and the queue of received packets. @@ -34,6 +35,9 @@ class MeshService // keep list of QueueStatus packets to be send to the phone PointerQueue toPhoneQueueStatusQueue; + // keep list of MqttClientProxyMessages to be send to the client for delivery + PointerQueue toPhoneMqttProxyQueue; + // This holds the last QueueStatus send meshtastic_QueueStatus lastQueueStatus; @@ -67,9 +71,15 @@ class MeshService /// Return the next QueueStatus packet destined to the phone. meshtastic_QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); } + /// Return the next MqttClientProxyMessage packet destined to the phone. + meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); } + // Release QueueStatus packet to pool void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); } + // Release MqttClientProxyMessage packet to pool + void releaseMqttClientProxyMessageToPool(meshtastic_MqttClientProxyMessage *p) { mqttClientProxyMessagePool.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 @@ -103,11 +113,14 @@ class MeshService /// Send a packet to the phone void sendToPhone(meshtastic_MeshPacket *p); + /// Send an MQTT message to the phone for client proxying + void sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m); + bool isToPhoneQueueEmpty(); private: /// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh - /// returns 0 to allow futher processing + /// returns 0 to allow further processing int onGPSChanged(const meshtastic::GPSStatus *arg); /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index ee23b9158..5b2cbd1b1 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -13,7 +13,7 @@ typedef uint32_t PacketId; // A packet sequence number #define ERRNO_OK 0 #define ERRNO_NO_INTERFACES 33 #define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER -#define ERRNO_DISABLED 34 // the itnerface is disabled +#define ERRNO_DISABLED 34 // the interface is disabled /* * Source of a received message diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index bb4bbdb2f..28820008c 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -141,7 +141,7 @@ bool NodeDB::factoryReset() // write NeighbourInfo neighborInfoModule->saveProtoForModule(); #ifdef ARCH_ESP32 - // This will erase what's in NVS including ssl keys, persistant variables and ble pairing + // This will erase what's in NVS including ssl keys, persistent variables and ble pairing nvs_flash_erase(); #endif #ifdef ARCH_NRF52 @@ -228,6 +228,15 @@ void NodeDB::installDefaultModuleConfig() moduleConfig.has_store_forward = true; moduleConfig.has_telemetry = true; moduleConfig.has_external_notification = true; +#if defined(RAK4630) || defined(RAK11310) + // Default to RAK led pin 2 (blue) + moduleConfig.external_notification.enabled = true; + moduleConfig.external_notification.output = PIN_LED2; + moduleConfig.external_notification.active = true; + moduleConfig.external_notification.alert_message = true; + moduleConfig.external_notification.output_ms = 1000; + moduleConfig.external_notification.nag_timeout = 60; +#endif moduleConfig.has_canned_message = true; strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address)); @@ -906,9 +915,9 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co error_code = code; error_address = address; - // Currently portuino is mostly used for simulation. Make sue the user notices something really bad happend + // Currently portuino is mostly used for simulation. Make sure the user notices something really bad happened #ifdef ARCH_PORTDUINO LOG_ERROR("A critical failure occurred, portduino is exiting..."); exit(2); #endif -} \ No newline at end of file +} diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 83d9e252f..9b0249dcd 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -56,7 +56,7 @@ class NodeDB meshtastic_NodeInfoLite *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI Observable newStatus; - /// don't do mesh based algoritm for node id assignment (initially) + /// don't do mesh based algorithm for node id assignment (initially) /// instead just store in flash - possibly even in the initial alpha release do this hack NodeDB(); @@ -252,4 +252,4 @@ extern uint32_t error_address; #define Module_Config_size \ (ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \ ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \ - ModuleConfig_TelemetryConfig_size + ModuleConfig_size) \ No newline at end of file + ModuleConfig_TelemetryConfig_size + ModuleConfig_size) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index ebc886301..6c6c70165 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -18,6 +18,8 @@ #error ToRadio is too big #endif +#include "mqtt/MQTT.h" + PhoneAPI::PhoneAPI() { lastContactMsec = millis(); @@ -54,6 +56,7 @@ void PhoneAPI::close() unobserve(&xModem.packetReady); releasePhonePacket(); // Don't leak phone packets on shutdown releaseQueueStatusPhonePacket(); + releaseMqttClientProxyPhonePacket(); onConnectionChanged(false); } @@ -98,6 +101,12 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) LOG_INFO("Got xmodem packet\n"); xModem.handlePacket(toRadioScratch.xmodemPacket); break; + case meshtastic_ToRadio_mqttClientProxyMessage_tag: + LOG_INFO("Got MqttClientProxy message\n"); + if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled) { + mqtt->onClientProxyReceive(toRadioScratch.mqttClientProxyMessage); + } + break; default: // Ignore nop messages // LOG_DEBUG("Error: unexpected ToRadio variant\n"); @@ -295,12 +304,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) break; case STATE_SEND_PACKETS: - // Do we have a message from the mesh? + // Do we have a message from the mesh or packet from the local device? LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n"); if (queueStatusPacketForPhone) { fromRadioScratch.which_payload_variant = meshtastic_FromRadio_queueStatus_tag; fromRadioScratch.queueStatus = *queueStatusPacketForPhone; releaseQueueStatusPhonePacket(); + } else if (mqttClientProxyMessageForPhone) { + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_mqttClientProxyMessage_tag; + fromRadioScratch.mqttClientProxyMessage = *mqttClientProxyMessageForPhone; + releaseMqttClientProxyPhonePacket(); } else if (xmodemPacketForPhone.control != meshtastic_XModem_Control_NUL) { fromRadioScratch.which_payload_variant = meshtastic_FromRadio_xmodemPacket_tag; fromRadioScratch.xmodemPacket = xmodemPacketForPhone; @@ -353,6 +366,14 @@ void PhoneAPI::releaseQueueStatusPhonePacket() } } +void PhoneAPI::releaseMqttClientProxyPhonePacket() +{ + if (mqttClientProxyMessageForPhone) { + service.releaseMqttClientProxyMessageToPool(mqttClientProxyMessageForPhone); + mqttClientProxyMessageForPhone = NULL; + } +} + /** * Return true if we have data available to send to the phone */ @@ -381,7 +402,9 @@ bool PhoneAPI::available() case STATE_SEND_PACKETS: { if (!queueStatusPacketForPhone) queueStatusPacketForPhone = service.getQueueStatusForPhone(); - bool hasPacket = !!queueStatusPacketForPhone; + if (!mqttClientProxyMessageForPhone) + mqttClientProxyMessageForPhone = service.getMqttClientProxyMessageForPhone(); + bool hasPacket = !!queueStatusPacketForPhone || !!mqttClientProxyMessageForPhone; if (hasPacket) return true; diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 8097ad34b..65a06bc6b 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -50,6 +50,9 @@ class PhoneAPI // Keep QueueStatus packet just as packetForPhone meshtastic_QueueStatus *queueStatusPacketForPhone = NULL; + // Keep MqttClientProxyMessage packet just as packetForPhone + meshtastic_MqttClientProxyMessage *mqttClientProxyMessageForPhone = NULL; + /// We temporarily keep the nodeInfo here between the call to available and getFromRadio meshtastic_NodeInfo nodeInfoForPhone = meshtastic_NodeInfo_init_default; @@ -126,6 +129,8 @@ class PhoneAPI void releaseQueueStatusPhonePacket(); + void releaseMqttClientProxyPhonePacket(); + /// begin a new connection void handleStartConfig(); diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index cf9cd9477..3102aa029 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -192,7 +192,7 @@ bool RF95Interface::isChannelActive() return false; } -/** Could we send right now (i.e. either not actively receving or transmitting)? */ +/** Could we send right now (i.e. either not actively receiving or transmitting)? */ bool RF95Interface::isActivelyReceiving() { return lora->isReceiving(); @@ -201,7 +201,7 @@ bool RF95Interface::isActivelyReceiving() bool RF95Interface::sleep() { // put chipset into sleep mode - setStandby(); // First cancel any active receving/sending + setStandby(); // First cancel any active receiving/sending lora->sleep(); return true; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 00af93e15..61b6b85d0 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -196,8 +196,9 @@ uint32_t RadioInterface::getRetransmissionMsec(const meshtastic_MeshPacket *p) // LOG_DEBUG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec); float channelUtil = airTime->channelUtilizationPercent(); uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax); - // Assuming we pick max. of CWsize and there will be a receiver with SNR at half the range - return 2 * packetAirtime + (pow(2, CWsize) + pow(2, int((CWmax + CWmin) / 2))) * slotTimeMsec + PROCESSING_TIME_MSEC; + // Assuming we pick max. of CWsize and there will be a client with SNR at half the range + return 2 * packetAirtime + (pow(2, CWsize) + 2 * CWmax + pow(2, int((CWmax + CWmin) / 2))) * slotTimeMsec + + PROCESSING_TIME_MSEC; } /** The delay to use when we want to send something */ @@ -307,7 +308,7 @@ bool RadioInterface::init() preflightSleepObserver.observe(&preflightSleep); notifyDeepSleepObserver.observe(¬ifyDeepSleep); - // we now expect interfaces to operate in promiscous mode + // we now expect interfaces to operate in promiscuous mode // radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor // time. diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index b5fb5fcd3..9c5d66293 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -15,7 +15,7 @@ /** * This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility - * wtih the old radiohead implementation. + * with the old radiohead implementation. */ typedef struct { NodeNum to, from; // can be 1 byte or four bytes @@ -75,7 +75,7 @@ class RadioInterface uint32_t lastTxStart = 0L; /** - * A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need + * A temporary buffer used for sending/receiving packets, sized to hold the biggest buffer we might need * */ uint8_t radiobuf[MAX_RHPACKETLEN]; @@ -198,7 +198,7 @@ class RadioInterface virtual void saveFreq(float savedFreq); /** - * Save the chanel we selected for later reuse. + * Save the channel we selected for later reuse. */ virtual void saveChannelNum(uint32_t savedChannelNum); @@ -206,7 +206,7 @@ class RadioInterface /** * Convert our modemConfig enum into wf, sf, etc... * - * These paramaters will be pull from the channelSettings global + * These parameters will be pull from the channelSettings global */ void applyModemConfig(); diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index a74d41090..4f0c52e67 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -68,7 +68,7 @@ void INTERRUPT_ATTR RadioLibInterface::isrTxLevel0() */ RadioLibInterface *RadioLibInterface::instance; -/** Could we send right now (i.e. either not actively receving or transmitting)? */ +/** Could we send right now (i.e. either not actively receiving or transmitting)? */ bool RadioLibInterface::canSendImmediately() { // We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one). diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 6f020d739..e605cfc94 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -12,9 +12,7 @@ extern "C" { #include "mesh/compression/unishox2.h" } -#if HAS_WIFI || HAS_ETHERNET #include "mqtt/MQTT.h" -#endif /** * Router todo @@ -248,7 +246,6 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) bool shouldActuallyEncrypt = true; -#if HAS_WIFI || HAS_ETHERNET if (moduleConfig.mqtt.enabled) { // check if we should send decrypted packets to mqtt @@ -272,7 +269,6 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) if (mqtt && !shouldActuallyEncrypt) mqtt->onSend(*p, chIndex); } -#endif auto encodeResult = perhapsEncode(p); if (encodeResult != meshtastic_Routing_Error_NONE) { @@ -280,14 +276,12 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) return encodeResult; // FIXME - this isn't a valid ErrorCode } -#if HAS_WIFI || HAS_ETHERNET if (moduleConfig.mqtt.enabled) { // the packet is now encrypted. // check if we should send encrypted packets to mqtt if (mqtt && shouldActuallyEncrypt) mqtt->onSend(*p, chIndex); } -#endif } assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside) @@ -405,7 +399,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) if (compressed_len >= p->decoded.payload.size) { LOG_DEBUG("Not using compressing message.\n"); - // Set the uncompressed payload varient anyway. Shouldn't hurt? + // Set the uncompressed payload variant anyway. Shouldn't hurt? // p->decoded.which_payloadVariant = Data_payload_tag; // Otherwise we use the compressor diff --git a/src/mesh/Router.h b/src/mesh/Router.h index f43f92158..db810e42e 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -90,7 +90,7 @@ class Router : protected concurrency::OSThread * * FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic * - * Called immedately on receiption, before any further processing. + * Called immediately on reception, before any further processing. * @return true to abandon the packet */ virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) { return false; } diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 495840d50..144b8847d 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -249,7 +249,7 @@ template bool SX126xInterface::isChannelActive() return false; } -/** Could we send right now (i.e. either not actively receving or transmitting)? */ +/** Could we send right now (i.e. either not actively receiving or transmitting)? */ template bool SX126xInterface::isActivelyReceiving() { // The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index 9c3ec3e91..f056f7369 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -242,7 +242,7 @@ template bool SX128xInterface::isChannelActive() return false; } -/** Could we send right now (i.e. either not actively receving or transmitting)? */ +/** Could we send right now (i.e. either not actively receiving or transmitting)? */ template bool SX128xInterface::isActivelyReceiving() { uint16_t irq = lora.getIrqStatus(); diff --git a/src/mesh/SinglePortModule.h b/src/mesh/SinglePortModule.h index 6fa69d964..a5aaa2582 100644 --- a/src/mesh/SinglePortModule.h +++ b/src/mesh/SinglePortModule.h @@ -3,7 +3,7 @@ #include "Router.h" /** - * Most modules are only interested in sending/receving one particular portnum. This baseclass simplifies that common + * Most modules are only interested in sending/receiving one particular portnum. This baseclass simplifies that common * case. */ class SinglePortModule : public MeshModule diff --git a/src/mesh/compression/unishox2.c b/src/mesh/compression/unishox2.c index 1632f970a..99c62f659 100644 --- a/src/mesh/compression/unishox2.c +++ b/src/mesh/compression/unishox2.c @@ -57,7 +57,7 @@ uint8_t usx_code_94[94]; 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 +/// Length of each vertical code 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) @@ -188,7 +188,7 @@ int append_switch_code(char *out, int olen, int ol, uint8_t state) return ol; } -/// Appends given horizontal and veritical code bits to out +/// Appends given horizontal and vertical code bits to out 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[]) { @@ -888,7 +888,7 @@ int read8bitCode(const char *in, int len, int bit_no) return code; } -/// The list of veritical codes is split into 5 sections. Used by readVCodeIdx() +/// The list of vertical 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 uint8_t usx_vsections[] = {0x7F, 0xBF, 0xDF, 0xEF, 0xFF}; @@ -915,7 +915,7 @@ uint8_t usx_vcode_lookup[36] = {(1 << 5) + 0, (1 << 5) + 0, (2 << 5) + 1, (2 /// 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 +/// Returns the vertical 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) { diff --git a/src/mesh/compression/unishox2.h b/src/mesh/compression/unishox2.h index e3674fb7c..a5117a5de 100644 --- a/src/mesh/compression/unishox2.h +++ b/src/mesh/compression/unishox2.h @@ -198,45 +198,45 @@ 2, 2, 2, 2, 0 \ } -/// Default frequently occuring sequences. When composition of text is know beforehand, the other sequences in this section can be -/// used to achieve more compression. +/// Default frequently occurring sequences. When composition of text is know beforehand, the other sequences in this section can +/// be used to achieve more compression. #define USX_FREQ_SEQ_DFLT \ (const char *[]) \ { \ "\": \"", "\": ", "" \ } -/// Frequently occuring sequences in XML content +/// Frequently occurring sequences in XML content #define USX_FREQ_SEQ_XML \ (const char *[]) \ { \ "", "connected()) { + if (mqtt && !moduleConfig.mqtt.proxy_to_client_enabled && !mqtt->isConnectedDirectly()) { mqtt->reconnect(); } } @@ -87,7 +87,6 @@ static int32_t reconnectETH() perhapsSetRTC(RTCQualityNTP, &tv); ntp_renew = millis() + 43200 * 1000; // success, refresh every 12 hours - } else { LOG_ERROR("NTP Update failed\n"); ntp_renew = millis() + 300 * 1000; // failure, retry every 5 minutes @@ -170,7 +169,6 @@ bool initEthernet() ethEvent = new Periodic("ethConnect", reconnectETH); return true; - } else { LOG_INFO("Not using Ethernet\n"); return false; diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 535962ae6..f5ee79308 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -81,7 +81,7 @@ typedef struct _meshtastic_ChannelSettings { a table of well known IDs. (see Well Known Channels FIXME) */ uint32_t id; - /* If true, messages on the mesh will be sent to the *public* internet by any gateway ndoe */ + /* If true, messages on the mesh will be sent to the *public* internet by any gateway node */ bool uplink_enabled; /* If true, messages seen on the internet will be forwarded to the local mesh. */ bool downlink_enabled; diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 99314aef5..0101845dc 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -215,7 +215,7 @@ typedef enum _meshtastic_Config_BluetoothConfig_PairingMode { typedef struct _meshtastic_Config_DeviceConfig { /* Sets the role of node */ meshtastic_Config_DeviceConfig_Role role; - /* Disabling this will disable the SerialConsole by not initilizing the StreamAPI */ + /* Disabling this will disable the SerialConsole by not initializing the StreamAPI */ bool serial_enabled; /* By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). Set this to true to leave the debug log outputting even when API is active. */ @@ -269,7 +269,7 @@ typedef struct _meshtastic_Config_PositionConfig { uint32_t tx_gpio; /* The minimum distance in meters traveled (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */ uint32_t broadcast_smart_minimum_distance; - /* The minumum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */ + /* The minimum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */ uint32_t broadcast_smart_minimum_interval_secs; } meshtastic_Config_PositionConfig; @@ -363,7 +363,7 @@ typedef struct _meshtastic_Config_DisplayConfig { bool compass_north_top; /* Flip screen vertically, for cases that mount the screen upside down */ bool flip_screen; - /* Perferred display units */ + /* Preferred display units */ meshtastic_Config_DisplayConfig_DisplayUnits units; /* Override auto-detect in screen */ meshtastic_Config_DisplayConfig_OledType oled; diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 48f93da5e..a093c9fe2 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -153,7 +153,7 @@ typedef struct _meshtastic_DeviceState { /* The mesh's nodes with their available gpio pins for RemoteHardware module */ pb_size_t node_remote_hardware_pins_count; meshtastic_NodeRemoteHardwarePin node_remote_hardware_pins[12]; - /* New lite version of NodeDB to decrease */ + /* New lite version of NodeDB to decrease memory footprint */ pb_size_t node_db_lite_count; meshtastic_NodeInfoLite node_db_lite[80]; } meshtastic_DeviceState; @@ -323,7 +323,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg; #define meshtastic_DeviceState_size 35056 #define meshtastic_NodeInfoLite_size 151 #define meshtastic_NodeRemoteHardwarePin_size 29 -#define meshtastic_OEMStore_size 3152 +#define meshtastic_OEMStore_size 3154 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index d70acc7fc..b7199a001 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -163,7 +163,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define meshtastic_LocalConfig_size 461 -#define meshtastic_LocalModuleConfig_size 545 +#define meshtastic_LocalModuleConfig_size 547 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/mesh.pb.c b/src/mesh/generated/meshtastic/mesh.pb.c index ce7d48b14..790f8be2d 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.c +++ b/src/mesh/generated/meshtastic/mesh.pb.c @@ -24,6 +24,9 @@ PB_BIND(meshtastic_Data, meshtastic_Data, 2) PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO) +PB_BIND(meshtastic_MqttClientProxyMessage, meshtastic_MqttClientProxyMessage, 2) + + PB_BIND(meshtastic_MeshPacket, meshtastic_MeshPacket, 2) diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 0ed2f8e68..659dd6c0b 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -97,6 +97,14 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_BETAFPV_900_NANO_TX = 46, /* Raspberry Pi Pico (W) with Waveshare SX1262 LoRa Node Module */ meshtastic_HardwareModel_RPI_PICO = 47, + /* Heltec Wireless Tracker with ESP32-S3 CPU, built-in GPS, and TFT */ + meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER = 48, + /* Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display */ + meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER = 49, + /* LilyGo T-Deck with ESP32-S3 CPU, Keyboard, and IPS display */ + meshtastic_HardwareModel_T_DECK = 50, + /* LilyGo T-Watch S3 with ESP32-S3 CPU and IPS display */ + meshtastic_HardwareModel_T_WATCH_S3 = 51, /* ------------------------------------------------------------------------------------------------------------------------------------------ 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. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -139,7 +147,7 @@ typedef enum _meshtastic_CriticalErrorCode { /* Radio transmit hardware failure. We sent data to the radio chip, but it didn't reply with an interrupt. */ meshtastic_CriticalErrorCode_TRANSMIT_FAILED = 8, - /* We detected that the main CPU voltage dropped below the minumum acceptable value */ + /* We detected that the main CPU voltage dropped below the minimum acceptable value */ meshtastic_CriticalErrorCode_BROWNOUT = 9, /* Selftest of SX1262 radio chip failed */ meshtastic_CriticalErrorCode_SX1262_FAILURE = 10, @@ -363,7 +371,7 @@ typedef struct _meshtastic_Position { 0 through 3 - for future use */ typedef struct _meshtastic_User { /* A globally unique ID string for this user. - In the case of Signal that would mean +16504442323, for the default macaddr derived id it would be !<8 hexidecimal bytes>. + In the case of Signal that would mean +16504442323, for the default macaddr derived id it would be !<8 hexadecimal bytes>. Note: app developers are encouraged to also use the following standard node IDs "^all" (for broadcast), "^local" (for the locally connected node) */ char id[16]; @@ -410,7 +418,7 @@ typedef struct _meshtastic_Routing { typedef PB_BYTES_ARRAY_T(237) meshtastic_Data_payload_t; /* (Formerly called SubPacket) - The payload portion fo a packet, this is the actual bytes that are sent + The payload portion for a packet, this is the actual bytes that are sent inside a radio packet (because from/to are broken out by the comms library) */ typedef struct _meshtastic_Data { /* Formerly named typ and of type Type */ @@ -462,6 +470,22 @@ typedef struct _meshtastic_Waypoint { uint32_t icon; } meshtastic_Waypoint; +typedef PB_BYTES_ARRAY_T(435) meshtastic_MqttClientProxyMessage_data_t; +/* This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server */ +typedef struct _meshtastic_MqttClientProxyMessage { + /* The MQTT topic this message will be sent /received on */ + char topic[60]; + pb_size_t which_payload_variant; + union { + /* Bytes */ + meshtastic_MqttClientProxyMessage_data_t data; + /* Text */ + char text[435]; + } payload_variant; + /* Whether the message should be retained (or not) */ + bool retained; +} meshtastic_MqttClientProxyMessage; + typedef PB_BYTES_ARRAY_T(256) meshtastic_MeshPacket_encrypted_t; /* A packet envelope sent/received over the mesh only payload_variant is sent in the payload portion of the LORA packet. @@ -528,7 +552,7 @@ typedef struct _meshtastic_MeshPacket { /* The priority of this message for sending. See MeshPacket.Priority description for more details. */ meshtastic_MeshPacket_Priority priority; - /* rssi of received packet. Only sent to phone for dispay purposes. */ + /* rssi of received packet. Only sent to phone for display purposes. */ int32_t rx_rssi; /* Describe if this message is delayed */ meshtastic_MeshPacket_Delayed delayed; @@ -683,6 +707,8 @@ typedef struct _meshtastic_ToRadio { (Sending this message is optional for clients) */ bool disconnect; meshtastic_XModem xmodemPacket; + /* MQTT Client Proxy Message */ + meshtastic_MqttClientProxyMessage mqttClientProxyMessage; }; } meshtastic_ToRadio; @@ -780,6 +806,8 @@ typedef struct _meshtastic_FromRadio { meshtastic_XModem xmodemPacket; /* Device metadata message */ meshtastic_DeviceMetadata metadata; + /* MQTT Client Proxy Message */ + meshtastic_MqttClientProxyMessage mqttClientProxyMessage; }; } meshtastic_FromRadio; @@ -836,6 +864,7 @@ extern "C" { #define meshtastic_Data_portnum_ENUMTYPE meshtastic_PortNum + #define meshtastic_MeshPacket_priority_ENUMTYPE meshtastic_MeshPacket_Priority #define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed @@ -862,6 +891,7 @@ extern "C" { #define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}} #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_default {0, 0, 0, 0, 0, "", "", 0} +#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} #define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN} #define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0} #define meshtastic_MyNodeInfo_init_default {0, 0, 0, "", _meshtastic_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} @@ -879,6 +909,7 @@ extern "C" { #define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}} #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_zero {0, 0, 0, 0, 0, "", "", 0} +#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} #define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN} #define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0, "", _meshtastic_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} @@ -940,6 +971,10 @@ extern "C" { #define meshtastic_Waypoint_name_tag 6 #define meshtastic_Waypoint_description_tag 7 #define meshtastic_Waypoint_icon_tag 8 +#define meshtastic_MqttClientProxyMessage_topic_tag 1 +#define meshtastic_MqttClientProxyMessage_data_tag 2 +#define meshtastic_MqttClientProxyMessage_text_tag 3 +#define meshtastic_MqttClientProxyMessage_retained_tag 4 #define meshtastic_MeshPacket_from_tag 1 #define meshtastic_MeshPacket_to_tag 2 #define meshtastic_MeshPacket_channel_tag 3 @@ -988,6 +1023,7 @@ extern "C" { #define meshtastic_ToRadio_want_config_id_tag 3 #define meshtastic_ToRadio_disconnect_tag 4 #define meshtastic_ToRadio_xmodemPacket_tag 5 +#define meshtastic_ToRadio_mqttClientProxyMessage_tag 6 #define meshtastic_Compressed_portnum_tag 1 #define meshtastic_Compressed_data_tag 2 #define meshtastic_Neighbor_node_id_tag 1 @@ -1018,6 +1054,7 @@ extern "C" { #define meshtastic_FromRadio_queueStatus_tag 11 #define meshtastic_FromRadio_xmodemPacket_tag 12 #define meshtastic_FromRadio_metadata_tag 13 +#define meshtastic_FromRadio_mqttClientProxyMessage_tag 14 /* Struct field encoding specification for nanopb */ #define meshtastic_Position_FIELDLIST(X, a) \ @@ -1094,6 +1131,14 @@ X(a, STATIC, SINGULAR, FIXED32, icon, 8) #define meshtastic_Waypoint_CALLBACK NULL #define meshtastic_Waypoint_DEFAULT NULL +#define meshtastic_MqttClientProxyMessage_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, topic, 1) \ +X(a, STATIC, ONEOF, BYTES, (payload_variant,data,payload_variant.data), 2) \ +X(a, STATIC, ONEOF, STRING, (payload_variant,text,payload_variant.text), 3) \ +X(a, STATIC, SINGULAR, BOOL, retained, 4) +#define meshtastic_MqttClientProxyMessage_CALLBACK NULL +#define meshtastic_MqttClientProxyMessage_DEFAULT NULL + #define meshtastic_MeshPacket_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, FIXED32, from, 1) \ X(a, STATIC, SINGULAR, FIXED32, to, 2) \ @@ -1175,7 +1220,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig), X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,queueStatus,queueStatus), 11) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 12) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) #define meshtastic_FromRadio_CALLBACK NULL #define meshtastic_FromRadio_DEFAULT NULL #define meshtastic_FromRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket @@ -1188,16 +1234,19 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13) #define meshtastic_FromRadio_payload_variant_queueStatus_MSGTYPE meshtastic_QueueStatus #define meshtastic_FromRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem #define meshtastic_FromRadio_payload_variant_metadata_MSGTYPE meshtastic_DeviceMetadata +#define meshtastic_FromRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage #define meshtastic_ToRadio_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,want_config_id,want_config_id), 3) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,disconnect,disconnect), 4) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 5) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 5) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 6) #define meshtastic_ToRadio_CALLBACK NULL #define meshtastic_ToRadio_DEFAULT NULL #define meshtastic_ToRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket #define meshtastic_ToRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem +#define meshtastic_ToRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage #define meshtastic_Compressed_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, portnum, 1) \ @@ -1239,6 +1288,7 @@ extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg; extern const pb_msgdesc_t meshtastic_Routing_msg; extern const pb_msgdesc_t meshtastic_Data_msg; extern const pb_msgdesc_t meshtastic_Waypoint_msg; +extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg; extern const pb_msgdesc_t meshtastic_MeshPacket_msg; extern const pb_msgdesc_t meshtastic_NodeInfo_msg; extern const pb_msgdesc_t meshtastic_MyNodeInfo_msg; @@ -1258,6 +1308,7 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg; #define meshtastic_Routing_fields &meshtastic_Routing_msg #define meshtastic_Data_fields &meshtastic_Data_msg #define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg +#define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg #define meshtastic_MeshPacket_fields &meshtastic_MeshPacket_msg #define meshtastic_NodeInfo_fields &meshtastic_NodeInfo_msg #define meshtastic_MyNodeInfo_fields &meshtastic_MyNodeInfo_msg @@ -1274,9 +1325,10 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg; #define meshtastic_Compressed_size 243 #define meshtastic_Data_size 270 #define meshtastic_DeviceMetadata_size 46 -#define meshtastic_FromRadio_size 330 +#define meshtastic_FromRadio_size 510 #define meshtastic_LogRecord_size 81 #define meshtastic_MeshPacket_size 321 +#define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 179 #define meshtastic_NeighborInfo_size 142 #define meshtastic_Neighbor_size 11 @@ -1285,7 +1337,7 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg; #define meshtastic_QueueStatus_size 23 #define meshtastic_RouteDiscovery_size 40 #define meshtastic_Routing_size 42 -#define meshtastic_ToRadio_size 324 +#define meshtastic_ToRadio_size 504 #define meshtastic_User_size 77 #define meshtastic_Waypoint_size 165 diff --git a/src/mesh/generated/meshtastic/module_config.pb.c b/src/mesh/generated/meshtastic/module_config.pb.c index 9352feb17..86614d18c 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.c +++ b/src/mesh/generated/meshtastic/module_config.pb.c @@ -39,6 +39,9 @@ PB_BIND(meshtastic_ModuleConfig_TelemetryConfig, meshtastic_ModuleConfig_Telemet PB_BIND(meshtastic_ModuleConfig_CannedMessageConfig, meshtastic_ModuleConfig_CannedMessageConfig, AUTO) +PB_BIND(meshtastic_ModuleConfig_AmbientLightingConfig, meshtastic_ModuleConfig_AmbientLightingConfig, AUTO) + + PB_BIND(meshtastic_RemoteHardwarePin, meshtastic_RemoteHardwarePin, AUTO) diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 6273a89ae..43b330b04 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -112,6 +112,8 @@ typedef struct _meshtastic_ModuleConfig_MQTTConfig { /* The root topic to use for MQTT messages. Default is "msh". This is useful if you want to use a single MQTT server for multiple meshtastic networks and separate them via ACLs */ char root[16]; + /* If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection */ + bool proxy_to_client_enabled; } meshtastic_ModuleConfig_MQTTConfig; /* NeighborInfoModule Config */ @@ -279,6 +281,20 @@ typedef struct _meshtastic_ModuleConfig_CannedMessageConfig { bool send_bell; } meshtastic_ModuleConfig_CannedMessageConfig; +/* Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels. +Initially created for the RAK14001 RGB LED module. */ +typedef struct _meshtastic_ModuleConfig_AmbientLightingConfig { + /* Sets LED to on or off. */ + bool led_state; + /* Sets the overall current for the LED, firmware side range for the RAK14001 is 1-31, but users should be given a range of 0-100% */ + uint8_t current; + uint8_t red; /* Red level */ + /* Sets the green level of the LED, firmware side values are 0-255, but users should be given a range of 0-100% */ + uint8_t green; /* Green level */ + /* Sets the blue level of the LED, firmware side values are 0-255, but users should be given a range of 0-100% */ + uint8_t blue; /* Blue level */ +} meshtastic_ModuleConfig_AmbientLightingConfig; + /* A GPIO pin definition for remote hardware module */ typedef struct _meshtastic_RemoteHardwarePin { /* GPIO Pin number (must match Arduino) */ @@ -324,6 +340,8 @@ typedef struct _meshtastic_ModuleConfig { meshtastic_ModuleConfig_RemoteHardwareConfig remote_hardware; /* TODO: REPLACE */ meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info; + /* TODO: REPLACE */ + meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting; } payload_variant; } meshtastic_ModuleConfig; @@ -370,12 +388,13 @@ extern "C" { #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_event_ccw_ENUMTYPE meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_event_press_ENUMTYPE meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar + #define meshtastic_RemoteHardwarePin_type_ENUMTYPE meshtastic_RemoteHardwarePinType /* Initializer values for message structs */ #define meshtastic_ModuleConfig_init_default {0, {meshtastic_ModuleConfig_MQTTConfig_init_default}} -#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, ""} +#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, "", 0} #define meshtastic_ModuleConfig_RemoteHardwareConfig_init_default {0, 0, 0, {meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default}} #define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0} #define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} @@ -385,9 +404,10 @@ extern "C" { #define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} +#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0} #define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN} #define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}} -#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, ""} +#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0} #define meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero {0, 0, 0, {meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero}} #define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0} #define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} @@ -397,6 +417,7 @@ extern "C" { #define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} +#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0} #define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN} /* Field tags (for use in manual encoding/decoding) */ @@ -408,6 +429,7 @@ extern "C" { #define meshtastic_ModuleConfig_MQTTConfig_json_enabled_tag 6 #define meshtastic_ModuleConfig_MQTTConfig_tls_enabled_tag 7 #define meshtastic_ModuleConfig_MQTTConfig_root_tag 8 +#define meshtastic_ModuleConfig_MQTTConfig_proxy_to_client_enabled_tag 9 #define meshtastic_ModuleConfig_NeighborInfoConfig_enabled_tag 1 #define meshtastic_ModuleConfig_NeighborInfoConfig_update_interval_tag 2 #define meshtastic_ModuleConfig_AudioConfig_codec2_enabled_tag 1 @@ -465,6 +487,11 @@ extern "C" { #define meshtastic_ModuleConfig_CannedMessageConfig_enabled_tag 9 #define meshtastic_ModuleConfig_CannedMessageConfig_allow_input_source_tag 10 #define meshtastic_ModuleConfig_CannedMessageConfig_send_bell_tag 11 +#define meshtastic_ModuleConfig_AmbientLightingConfig_led_state_tag 1 +#define meshtastic_ModuleConfig_AmbientLightingConfig_current_tag 2 +#define meshtastic_ModuleConfig_AmbientLightingConfig_red_tag 3 +#define meshtastic_ModuleConfig_AmbientLightingConfig_green_tag 4 +#define meshtastic_ModuleConfig_AmbientLightingConfig_blue_tag 5 #define meshtastic_RemoteHardwarePin_gpio_pin_tag 1 #define meshtastic_RemoteHardwarePin_name_tag 2 #define meshtastic_RemoteHardwarePin_type_tag 3 @@ -481,6 +508,7 @@ extern "C" { #define meshtastic_ModuleConfig_audio_tag 8 #define meshtastic_ModuleConfig_remote_hardware_tag 9 #define meshtastic_ModuleConfig_neighbor_info_tag 10 +#define meshtastic_ModuleConfig_ambient_lighting_tag 11 /* Struct field encoding specification for nanopb */ #define meshtastic_ModuleConfig_FIELDLIST(X, a) \ @@ -493,7 +521,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,telemetry,payload_variant.te X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_variant.canned_message), 7) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,audio,payload_variant.audio), 8) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_variant.remote_hardware), 9) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11) #define meshtastic_ModuleConfig_CALLBACK NULL #define meshtastic_ModuleConfig_DEFAULT NULL #define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig @@ -506,6 +535,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_varian #define meshtastic_ModuleConfig_payload_variant_audio_MSGTYPE meshtastic_ModuleConfig_AudioConfig #define meshtastic_ModuleConfig_payload_variant_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig #define meshtastic_ModuleConfig_payload_variant_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig +#define meshtastic_ModuleConfig_payload_variant_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig #define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ @@ -515,7 +545,8 @@ X(a, STATIC, SINGULAR, STRING, password, 4) \ X(a, STATIC, SINGULAR, BOOL, encryption_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, json_enabled, 6) \ X(a, STATIC, SINGULAR, BOOL, tls_enabled, 7) \ -X(a, STATIC, SINGULAR, STRING, root, 8) +X(a, STATIC, SINGULAR, STRING, root, 8) \ +X(a, STATIC, SINGULAR, BOOL, proxy_to_client_enabled, 9) #define meshtastic_ModuleConfig_MQTTConfig_CALLBACK NULL #define meshtastic_ModuleConfig_MQTTConfig_DEFAULT NULL @@ -616,6 +647,15 @@ X(a, STATIC, SINGULAR, BOOL, send_bell, 11) #define meshtastic_ModuleConfig_CannedMessageConfig_CALLBACK NULL #define meshtastic_ModuleConfig_CannedMessageConfig_DEFAULT NULL +#define meshtastic_ModuleConfig_AmbientLightingConfig_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BOOL, led_state, 1) \ +X(a, STATIC, SINGULAR, UINT32, current, 2) \ +X(a, STATIC, SINGULAR, UINT32, red, 3) \ +X(a, STATIC, SINGULAR, UINT32, green, 4) \ +X(a, STATIC, SINGULAR, UINT32, blue, 5) +#define meshtastic_ModuleConfig_AmbientLightingConfig_CALLBACK NULL +#define meshtastic_ModuleConfig_AmbientLightingConfig_DEFAULT NULL + #define meshtastic_RemoteHardwarePin_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, gpio_pin, 1) \ X(a, STATIC, SINGULAR, STRING, name, 2) \ @@ -634,6 +674,7 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_StoreForwardConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_RangeTestConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_TelemetryConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_CannedMessageConfig_msg; +extern const pb_msgdesc_t meshtastic_ModuleConfig_AmbientLightingConfig_msg; extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ @@ -648,20 +689,22 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_RangeTestConfig_fields &meshtastic_ModuleConfig_RangeTestConfig_msg #define meshtastic_ModuleConfig_TelemetryConfig_fields &meshtastic_ModuleConfig_TelemetryConfig_msg #define meshtastic_ModuleConfig_CannedMessageConfig_fields &meshtastic_ModuleConfig_CannedMessageConfig_msg +#define meshtastic_ModuleConfig_AmbientLightingConfig_fields &meshtastic_ModuleConfig_AmbientLightingConfig_msg #define meshtastic_RemoteHardwarePin_fields &meshtastic_RemoteHardwarePin_msg /* Maximum encoded size of messages (where known) */ +#define meshtastic_ModuleConfig_AmbientLightingConfig_size 14 #define meshtastic_ModuleConfig_AudioConfig_size 19 #define meshtastic_ModuleConfig_CannedMessageConfig_size 49 #define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40 -#define meshtastic_ModuleConfig_MQTTConfig_size 220 +#define meshtastic_ModuleConfig_MQTTConfig_size 222 #define meshtastic_ModuleConfig_NeighborInfoConfig_size 8 #define meshtastic_ModuleConfig_RangeTestConfig_size 10 #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 #define meshtastic_ModuleConfig_StoreForwardConfig_size 22 #define meshtastic_ModuleConfig_TelemetryConfig_size 26 -#define meshtastic_ModuleConfig_size 223 +#define meshtastic_ModuleConfig_size 225 #define meshtastic_RemoteHardwarePin_size 21 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 089d7b59f..e089f9182 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -17,7 +17,7 @@ PortNums should be assigned in the following range: 0-63 Core Meshtastic use, do not use for third party apps 64-127 Registered 3rd party apps, send in a pull request that adds a new entry to portnums.proto to register your application - 256-511 Use one of these portnums for your private applications that you don't want to register publically + 256-511 Use one of these portnums for your private applications that you don't want to register publicly All other values are reserved. Note: This was formerly a Type enum named 'typ' with the same id # We have change to this 'portnum' based scheme for specifying app handlers for particular payloads. @@ -54,6 +54,8 @@ typedef enum _meshtastic_PortNum { /* Audio Payloads. Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now */ meshtastic_PortNum_AUDIO_APP = 9, + /* Payloads for clients with a network connection proxying MQTT pub/sub to the device */ + meshtastic_PortNum_MQTT_CLIENT_PROXY_APP = 10, /* Provides a 'ping' service that replies to any packet it receives. Also serves as a small example module. */ meshtastic_PortNum_REPLY_APP = 32, diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 9ddb5ca3a..acee9be0d 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -165,7 +165,7 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) if (params->getQueryParameter("all", valueAll)) { - // If all is ture, return all the buffers we have available + // If all is true, return all the buffers we have available // to us at this point in time. if (valueAll == "true") { while (len) { @@ -179,7 +179,7 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) res->write(txBuf, len); } - // the param "all" was not spcified. Return just one protobuf + // the param "all" was not specified. Return just one protobuf } else { len = webAPI.getFromRadio(txBuf); res->write(txBuf, len); @@ -460,7 +460,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res) HTTPBodyParser *parser; std::string contentType = req->getHeader("Content-Type"); - // The content type may have additional properties after a semicolon, for exampel: + // The content type may have additional properties after a semicolon, for example: // Content-Type: text/html;charset=utf-8 // Content-Type: multipart/form-data;boundary=------s0m3w31rdch4r4c73rs // As we're interested only in the actual mime _type_, we strip everything after the diff --git a/src/mesh/http/WebServer.cpp b/src/mesh/http/WebServer.cpp index 289f1429b..2b045c0be 100644 --- a/src/mesh/http/WebServer.cpp +++ b/src/mesh/http/WebServer.cpp @@ -15,7 +15,7 @@ #include "esp_task_wdt.h" #endif -// Persistant Data Storage +// Persistent Data Storage #include Preferences prefs; diff --git a/src/mesh/mesh-pb-constants.cpp b/src/mesh/mesh-pb-constants.cpp index f9fa02251..994fab61f 100644 --- a/src/mesh/mesh-pb-constants.cpp +++ b/src/mesh/mesh-pb-constants.cpp @@ -14,7 +14,7 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc if (!pb_encode(&stream, fields, src_struct)) { LOG_ERROR("Panic: can't encode protobuf reason='%s'\n", PB_GET_ERROR(&stream)); assert( - 0); // If this asser fails it probably means you made a field too large for the max limits specified in mesh.options + 0); // If this assert fails it probably means you made a field too large for the max limits specified in mesh.options } else { return stream.bytes_written; } diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index de7870340..afe26f5a3 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -16,9 +16,7 @@ #include "unistd.h" #endif -#if HAS_WIFI || HAS_ETHERNET #include "mqtt/MQTT.h" -#endif #define DEFAULT_REBOOT_SECONDS 7 @@ -572,7 +570,7 @@ void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &r if (conn.wifi.status.is_connected) { conn.wifi.rssi = WiFi.RSSI(); conn.wifi.status.ip_address = WiFi.localIP(); - conn.wifi.status.is_mqtt_connected = mqtt && mqtt->connected(); + conn.wifi.status.is_mqtt_connected = mqtt && mqtt->isConnectedDirectly(); conn.wifi.status.is_syslog_connected = false; // FIXME wire this up } #endif @@ -583,7 +581,7 @@ void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &r if (Ethernet.linkStatus() == LinkON) { conn.ethernet.status.is_connected = true; conn.ethernet.status.ip_address = Ethernet.localIP(); - conn.ethernet.status.is_mqtt_connected = mqtt && mqtt->connected(); + conn.ethernet.status.is_mqtt_connected = mqtt && mqtt->isConnectedDirectly(); conn.ethernet.status.is_syslog_connected = false; // FIXME wire this up } else { conn.ethernet.status.is_connected = false; diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index bbd39f696..5e8cdcbf5 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -4,7 +4,7 @@ #include "FSCommon.h" #include "MeshService.h" #include "NodeDB.h" -#include "PowerFSM.h" // neede for button bypass +#include "PowerFSM.h" // needed for button bypass #include "detect/ScanI2C.h" #include "mesh/generated/meshtastic/cannedmessages.pb.h" @@ -123,8 +123,8 @@ int CannedMessageModule::splitConfiguredMessages() int CannedMessageModule::handleInputEvent(const InputEvent *event) { if ((strlen(moduleConfig.canned_message.allow_input_source) > 0) && - (strcmp(moduleConfig.canned_message.allow_input_source, event->source) != 0) && - (strcmp(moduleConfig.canned_message.allow_input_source, "_any") != 0)) { + (strcasecmp(moduleConfig.canned_message.allow_input_source, event->source) != 0) && + (strcasecmp(moduleConfig.canned_message.allow_input_source, "_any") != 0)) { // Event source is not accepted. // Event only accepted if source matches the configured one, or // the configured one is "_any" (or if there is no configured diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 82701cdc0..79bbb4028 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -10,7 +10,7 @@ #include "main.h" -#ifdef RAK4630 +#ifdef HAS_NCP5623 #include NCP5623 rgb; @@ -84,7 +84,7 @@ int32_t ExternalNotificationModule::runOnce() millis()) { getExternal(2) ? setExternalOff(2) : setExternalOn(2); } -#ifdef RAK4630 +#ifdef HAS_NCP5623 if (rgb_found.type == ScanI2C::NCP5623) { green = (green + 50) % 255; red = abs(red - green) % 255; @@ -127,7 +127,7 @@ void ExternalNotificationModule::setExternalOn(uint8_t index) digitalWrite(output, (moduleConfig.external_notification.active ? true : false)); break; } -#ifdef RAK4630 +#ifdef HAS_NCP5623 if (rgb_found.type == ScanI2C::NCP5623) { rgb.setColor(red, green, blue); } @@ -153,7 +153,7 @@ void ExternalNotificationModule::setExternalOff(uint8_t index) break; } -#ifdef RAK4630 +#ifdef HAS_NCP5623 if (rgb_found.type == ScanI2C::NCP5623) { red = 0; green = 0; @@ -235,7 +235,7 @@ ExternalNotificationModule::ExternalNotificationModule() LOG_INFO("Using Pin %i in PWM mode\n", config.device.buzzer_gpio); } } -#ifdef RAK4630 +#ifdef HAS_NCP5623 if (rgb_found.type == ScanI2C::NCP5623) { rgb.begin(); rgb.setCurrent(10); diff --git a/src/modules/RangeTestModule.cpp b/src/modules/RangeTestModule.cpp index 783fbd758..28835406d 100644 --- a/src/modules/RangeTestModule.cpp +++ b/src/modules/RangeTestModule.cpp @@ -54,7 +54,7 @@ int32_t RangeTestModule::runOnce() if (moduleConfig.range_test.sender) { LOG_INFO("Initializing Range Test Module -- Sender\n"); started = millis(); // make a note of when we started - return (5000); // Sending first message 5 seconds after initilization. + return (5000); // Sending first message 5 seconds after initialization. } else { LOG_INFO("Initializing Range Test Module -- Receiver\n"); return disable(); @@ -147,8 +147,8 @@ ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket LOG_DEBUG("mp.from %d\n", mp.from); LOG_DEBUG("mp.rx_snr %f\n", mp.rx_snr); LOG_DEBUG("mp.hop_limit %d\n", mp.hop_limit); - // LOG_DEBUG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated - // LOG_DEBUG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated + // LOG_DEBUG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Deprecated + // LOG_DEBUG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Deprecated LOG_DEBUG("---- Node Information of Received Packet (mp.from):\n"); LOG_DEBUG("n->user.long_name %s\n", n->user.long_name); LOG_DEBUG("n->user.short_name %s\n", n->user.short_name); @@ -186,8 +186,8 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp) LOG_DEBUG("mp.from %d\n", mp.from); LOG_DEBUG("mp.rx_snr %f\n", mp.rx_snr); LOG_DEBUG("mp.hop_limit %d\n", mp.hop_limit); - // LOG_DEBUG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated - // LOG_DEBUG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated + // LOG_DEBUG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Deprecated + // LOG_DEBUG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Deprecated LOG_DEBUG("---- Node Information of Received Packet (mp.from):\n"); LOG_DEBUG("n->user.long_name %s\n", n->user.long_name); LOG_DEBUG("n->user.short_name %s\n", n->user.short_name); diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index af7ba1381..a3cac53b1 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -33,11 +33,11 @@ to your device. TODO (in this order): - * Define a verbose RX mode to report on mesh and packet infomration. + * Define a verbose RX mode to report on mesh and packet information. - This won't happen any time soon. KNOWN PROBLEMS - * Until the module is initilized by the startup sequence, the TX pin is in a floating + * Until the module is initialized by the startup sequence, the TX pin is in a floating state. Device connected to that pin may see this as "noise". * Will not work on Linux device targets. diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 5cdc4bf4d..8a4747114 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -86,6 +86,10 @@ int32_t EnvironmentTelemetryModule::runOnce() result = lps22hbSensor.runOnce(); if (sht31Sensor.hasSensor()) result = sht31Sensor.runOnce(); + if (ina219Sensor.hasSensor() && !ina219Sensor.isInitialized()) + result = ina219Sensor.runOnce(); + if (ina260Sensor.hasSensor() && !ina260Sensor.isInitialized()) + result = ina260Sensor.runOnce(); } return result; } else { diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index 767e1fb2b..fccbd7199 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -62,7 +62,7 @@ void StoreForwardModule::populatePSRAM() https://learn.upesy.com/en/programmation/psram.html#psram-tab */ - LOG_DEBUG("*** Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", memGet.getFreeHeap(), memGet.getHeapSize(), + LOG_DEBUG("*** Before PSRAM initialization: heap %d/%d PSRAM %d/%d\n", memGet.getFreeHeap(), memGet.getHeapSize(), memGet.getFreePsram(), memGet.getPsramSize()); this->packetHistoryTXQueue = @@ -77,7 +77,7 @@ void StoreForwardModule::populatePSRAM() this->packetHistory = static_cast(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct))); - LOG_DEBUG("*** After PSRAM initilization: heap %d/%d PSRAM %d/%d\n", memGet.getFreeHeap(), memGet.getHeapSize(), + LOG_DEBUG("*** After PSRAM initialization: heap %d/%d PSRAM %d/%d\n", memGet.getFreeHeap(), memGet.getHeapSize(), memGet.getFreePsram(), memGet.getPsramSize()); LOG_DEBUG("*** numberOfPackets for packetHistory - %u\n", numberOfPackets); } diff --git a/src/mqtt/JSONValue.cpp b/src/mqtt/JSONValue.cpp index 10d79a4df..1990a13b6 100644 --- a/src/mqtt/JSONValue.cpp +++ b/src/mqtt/JSONValue.cpp @@ -282,7 +282,7 @@ JSONValue *JSONValue::Parse(const char **data) return NULL; } - // Ran out of possibilites, it's bad! + // Ran out of possibilities, it's bad! else { return NULL; } diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 5e6b4ac1d..28eb70fe7 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -25,12 +25,16 @@ Allocator &mqttPool = staticMqttPool; void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length) { - mqtt->onPublish(topic, payload, length); + mqtt->onReceive(topic, payload, length); } -void MQTT::onPublish(char *topic, byte *payload, unsigned int length) +void MQTT::onClientProxyReceive(meshtastic_MqttClientProxyMessage msg) +{ + onReceive(msg.topic, msg.payload_variant.data.bytes, msg.payload_variant.data.size); +} + +void MQTT::onReceive(char *topic, byte *payload, size_t length) { - // parsing ServiceEnvelope meshtastic_ServiceEnvelope e = meshtastic_ServiceEnvelope_init_default; if (moduleConfig.mqtt.json_enabled && (strncmp(topic, jsonTopic.c_str(), jsonTopic.length()) == 0)) { @@ -153,10 +157,13 @@ void mqttInit() new MQTT(); } +#ifdef HAS_NETWORKING MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE) +#else +MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) +#endif { if (moduleConfig.mqtt.enabled) { - assert(!mqtt); mqtt = this; @@ -170,22 +177,77 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_ jsonTopic = "msh" + jsonTopic; } - pubSub.setCallback(mqttCallback); - +#ifdef HAS_NETWORKING + if (!moduleConfig.mqtt.proxy_to_client_enabled) + pubSub.setCallback(mqttCallback); +#endif // preflightSleepObserver.observe(&preflightSleep); } else { disable(); } } -bool MQTT::connected() +bool MQTT::isConnectedDirectly() { +#ifdef HAS_NETWORKING return pubSub.connected(); +#else + return false; +#endif +} + +bool MQTT::publish(const char *topic, const char *payload, bool retained) +{ + if (moduleConfig.mqtt.proxy_to_client_enabled) { + meshtastic_MqttClientProxyMessage *msg = mqttClientProxyMessagePool.allocZeroed(); + msg->which_payload_variant = meshtastic_MqttClientProxyMessage_text_tag; + strcpy(msg->topic, topic); + strcpy(msg->payload_variant.text, payload); + msg->retained = retained; + service.sendMqttMessageToClientProxy(msg); + return true; + } +#ifdef HAS_NETWORKING + else if (isConnectedDirectly()) { + return pubSub.publish(topic, payload, retained); + } +#endif + return false; +} + +bool MQTT::publish(const char *topic, const uint8_t *payload, size_t length, bool retained) +{ + if (moduleConfig.mqtt.proxy_to_client_enabled) { + meshtastic_MqttClientProxyMessage *msg = mqttClientProxyMessagePool.allocZeroed(); + msg->which_payload_variant = meshtastic_MqttClientProxyMessage_data_tag; + strcpy(msg->topic, topic); + msg->payload_variant.data.size = length; + memcpy(msg->payload_variant.data.bytes, payload, length); + msg->retained = retained; + service.sendMqttMessageToClientProxy(msg); + return true; + } +#ifdef HAS_NETWORKING + else if (isConnectedDirectly()) { + return pubSub.publish(topic, payload, length, retained); + } +#endif + return false; } void MQTT::reconnect() { if (wantsLink()) { + if (moduleConfig.mqtt.proxy_to_client_enabled) { + LOG_INFO("MQTT connecting via client proxy instead...\n"); + enabled = true; + runASAP = true; + reconnectCount = 0; + + publishStatus(); + return; // Don't try to connect directly to the server + } +#ifdef HAS_NETWORKING // Defaults int serverPort = 1883; const char *serverAddr = default_mqtt_address; @@ -197,7 +259,6 @@ void MQTT::reconnect() mqttUsername = moduleConfig.mqtt.username; mqttPassword = moduleConfig.mqtt.password; } - #if HAS_WIFI && !defined(ARCH_PORTDUINO) if (moduleConfig.mqtt.tls_enabled) { // change default for encrypted to 8883 @@ -214,7 +275,7 @@ void MQTT::reconnect() LOG_INFO("Using non-TLS-encrypted session\n"); pubSub.setClient(mqttClient); } -#else +#elif HAS_NETWORKING pubSub.setClient(mqttClient); #endif @@ -229,8 +290,9 @@ void MQTT::reconnect() pubSub.setServer(serverAddr, serverPort); pubSub.setBufferSize(512); - LOG_INFO("Connecting to MQTT server %s, port: %d, username: %s, password: %s\n", serverAddr, serverPort, mqttUsername, - mqttPassword); + LOG_INFO("Attempting to connect directly to MQTT server %s, port: %d, username: %s, password: %s\n", serverAddr, + serverPort, mqttUsername, mqttPassword); + auto myStatus = (statusTopic + owner.id); bool connected = pubSub.connect(owner.id, mqttUsername, mqttPassword, myStatus.c_str(), 1, true, "offline"); if (connected) { @@ -239,15 +301,12 @@ void MQTT::reconnect() runASAP = true; reconnectCount = 0; - /// FIXME, include more information in the status text - bool ok = pubSub.publish(myStatus.c_str(), "online", true); - LOG_INFO("published %d\n", ok); - + publishStatus(); sendSubscriptions(); } else { #if HAS_WIFI && !defined(ARCH_PORTDUINO) reconnectCount++; - LOG_ERROR("Failed to contact MQTT server (%d/%d)...\n", reconnectCount, reconnectMax); + LOG_ERROR("Failed to contact MQTT server directly (%d/%d)...\n", reconnectCount, reconnectMax); if (reconnectCount >= reconnectMax) { needReconnect = true; wifiReconnect->setIntervalFromNow(0); @@ -255,11 +314,13 @@ void MQTT::reconnect() } #endif } +#endif } } void MQTT::sendSubscriptions() { +#ifdef HAS_NETWORKING size_t numChan = channels.getNumChannels(); for (size_t i = 0; i < numChan; i++) { auto &ch = channels.getByIndex(i); @@ -274,6 +335,7 @@ void MQTT::sendSubscriptions() } } } +#endif } bool MQTT::wantsLink() const @@ -291,60 +353,44 @@ bool MQTT::wantsLink() const } } } + if (hasChannel && moduleConfig.mqtt.proxy_to_client_enabled) + return true; #if HAS_WIFI return hasChannel && WiFi.isConnected(); #endif #if HAS_ETHERNET - return hasChannel && (Ethernet.linkStatus() == LinkON); + return hasChannel && Ethernet.linkStatus() == LinkON; #endif return false; } int32_t MQTT::runOnce() { - if (!moduleConfig.mqtt.enabled) { + if (!moduleConfig.mqtt.enabled) return disable(); - } + bool wantConnection = wantsLink(); // If connected poll rapidly, otherwise only occasionally check for a wifi connection change and ability to contact server - if (!pubSub.loop()) { - if (wantConnection) { + if (moduleConfig.mqtt.proxy_to_client_enabled) { + publishQueuedMessages(); + return 200; + } +#ifdef HAS_NETWORKING + else if (!pubSub.loop()) { + if (!wantConnection) + return 5000; // If we don't want connection now, check again in 5 secs + else { 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 - meshtastic_ServiceEnvelope *env = mqttQueue.dequeuePtr(0); - static uint8_t bytes[meshtastic_MeshPacket_size + 64]; - size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env); - - std::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) { - std::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); - } + if (isConnectedDirectly()) { + publishQueuedMessages(); return 200; - } else { + } else return 30000; - } - } else - return 5000; // If we don't want connection now, check again in 5 secs + } } else { // we are connected to server, check often for new requests on the TCP port if (!wantConnection) { @@ -355,6 +401,44 @@ int32_t MQTT::runOnce() powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // Suppress entering light sleep (because that would turn off bluetooth) return 20; } +#endif + return 30000; +} + +/// FIXME, include more information in the status text +void MQTT::publishStatus() +{ + auto myStatus = (statusTopic + owner.id); + bool ok = publish(myStatus.c_str(), "online", true); + LOG_INFO("published online=%d\n", ok); +} + +void MQTT::publishQueuedMessages() +{ + if (!mqttQueue.isEmpty()) { + LOG_DEBUG("Publishing enqueued MQTT message\n"); + // FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets + meshtastic_ServiceEnvelope *env = mqttQueue.dequeuePtr(0); + static uint8_t bytes[meshtastic_MeshPacket_size + 64]; + size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env); + + std::string topic = cryptTopic + env->channel_id + "/" + owner.id; + LOG_INFO("publish %s, %u bytes from queue\n", topic.c_str(), numBytes); + + publish(topic.c_str(), bytes, numBytes, false); + + if (moduleConfig.mqtt.json_enabled) { + // handle json topic + auto jsonString = this->meshPacketToJson(env->packet); + if (jsonString.length() != 0) { + std::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()); + publish(topicJson.c_str(), jsonString.c_str(), false); + } + } + mqttPool.release(env); + } } void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex) @@ -368,27 +452,26 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex) env->channel_id = (char *)channelId; env->gateway_id = owner.id; env->packet = (meshtastic_MeshPacket *)∓ + LOG_DEBUG("MQTT onSend - Publishing portnum %i message\n", env->packet->decoded.portnum); - // don't bother sending if not connected... - if (pubSub.connected()) { - + if (moduleConfig.mqtt.proxy_to_client_enabled || this->isConnectedDirectly()) { // FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets static uint8_t bytes[meshtastic_MeshPacket_size + 64]; size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env); std::string topic = cryptTopic + channelId + "/" + owner.id; - LOG_DEBUG("publish %s, %u bytes\n", topic.c_str(), numBytes); + LOG_DEBUG("MQTT Publish %s, %u bytes\n", topic.c_str(), numBytes); - pubSub.publish(topic.c_str(), bytes, numBytes, false); + publish(topic.c_str(), bytes, numBytes, false); if (moduleConfig.mqtt.json_enabled) { // handle json topic - auto jsonString = this->downstreamPacketToJson((meshtastic_MeshPacket *)&mp); + auto jsonString = this->meshPacketToJson((meshtastic_MeshPacket *)&mp); if (jsonString.length() != 0) { std::string topicJson = jsonTopic + channelId + "/" + 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); + publish(topicJson.c_str(), jsonString.c_str(), false); } } } else { @@ -408,7 +491,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex) } // converts a downstream packet into a json message -std::string MQTT::downstreamPacketToJson(meshtastic_MeshPacket *mp) +std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) { // the created jsonObj is immutable after creation, so // we need to do the heavy lifting before assembling it. diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index 1e626c3e0..565f46ecf 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -5,15 +5,20 @@ #include "concurrency/OSThread.h" #include "mesh/Channels.h" #include "mesh/generated/meshtastic/mqtt.pb.h" -#include #if HAS_WIFI #include +#define HAS_NETWORKING 1 #if !defined(ARCH_PORTDUINO) #include #endif #endif #if HAS_ETHERNET #include +#define HAS_NETWORKING 1 +#endif + +#ifdef HAS_NETWORKING +#include #endif #define MAX_MQTT_QUEUE 16 @@ -35,12 +40,9 @@ class MQTT : private concurrency::OSThread #if HAS_ETHERNET EthernetClient mqttClient; #endif -#if !defined(DEBUG_HEAP_MQTT) - PubSubClient pubSub; public: -#else - public: +#ifdef HAS_NETWORKING PubSubClient pubSub; #endif MQTT(); @@ -51,7 +53,7 @@ class MQTT : private concurrency::OSThread * @param chIndex the index of the channel for this message * * Note: for messages we are forwarding on the mesh that we can't find the channel for (because we don't have the keys), we - * can not forward those messages to the cloud - becuase no way to find a global channel ID. + * can not forward those messages to the cloud - because no way to find a global channel ID. */ void onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex); @@ -59,7 +61,13 @@ class MQTT : private concurrency::OSThread */ void reconnect(); - bool connected(); + bool isConnectedDirectly(); + + bool publish(const char *topic, const char *payload, bool retained); + + bool publish(const char *topic, const uint8_t *payload, size_t length, const bool retained); + + void onClientProxyReceive(meshtastic_MqttClientProxyMessage msg); protected: PointerQueue mqttQueue; @@ -80,14 +88,17 @@ class MQTT : private concurrency::OSThread */ void sendSubscriptions(); - /// Just C glue to call onPublish + /// Callback for direct mqtt subscription messages static void mqttCallback(char *topic, byte *payload, unsigned int length); /// Called when a new publish arrives from the MQTT server - void onPublish(char *topic, byte *payload, unsigned int length); + void onReceive(char *topic, byte *payload, size_t length); /// Called when a new publish arrives from the MQTT server - std::string downstreamPacketToJson(meshtastic_MeshPacket *mp); + std::string meshPacketToJson(meshtastic_MeshPacket *mp); + + void publishStatus(); + void publishQueuedMessages(); /// Return 0 if sleep is okay, veto sleep if we are connected to pubsub server // int preflightSleepCb(void *unused = NULL) { return pubSub.connected() ? 1 : 0; } diff --git a/src/platform/esp32/CallbackCharacteristic.h b/src/platform/esp32/CallbackCharacteristic.h index 9c4f59a05..cd3bc6f51 100644 --- a/src/platform/esp32/CallbackCharacteristic.h +++ b/src/platform/esp32/CallbackCharacteristic.h @@ -3,7 +3,7 @@ #include "PowerFSM.h" // FIXME - someday I want to make this OTA thing a separate lb at at that point it can't touch this /** - * A characterstic with a set of overridable callbacks + * A characteristic with a set of overridable callbacks */ class CallbackCharacteristic : public BLECharacteristic, public BLECharacteristicCallbacks { diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 7a1e9ba49..23346d493 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -97,6 +97,10 @@ #define HW_VENDOR meshtastic_HardwareModel_HELTEC_V3 #elif defined(HELTEC_WSL_V3) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_WSL_V3 +#elif defined(HELTEC_WIRELESS_TRACKER) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER +#elif defined(HELTEC_WIRELESS_PAPER) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER #elif defined(TLORA_T3S3_V1) #define HW_VENDOR meshtastic_HardwareModel_TLORA_T3_S3 #elif defined(BETAFPV_2400_TX) diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 4cb7f4443..8abe6d56d 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -99,7 +99,7 @@ void esp32Setup() LOG_DEBUG("Setup Preferences in Flash Storage\n"); - // Create object to store our persistant data + // Create object to store our persistent data Preferences preferences; preferences.begin("meshtastic", false); diff --git a/src/platform/nrf52/JLINK_MONITOR_ISR_SES.S b/src/platform/nrf52/JLINK_MONITOR_ISR_SES.S index b513ea07d..cda4b1a50 100644 --- a/src/platform/nrf52/JLINK_MONITOR_ISR_SES.S +++ b/src/platform/nrf52/JLINK_MONITOR_ISR_SES.S @@ -136,7 +136,7 @@ Purpose : Implementation of debug monitor for J-Link monitor mode * This handler is also responsible for handling commands that are sent by the debugger. * * Notes -* This is actually the ISR for the debug inerrupt (exception no. 12) +* This is actually the ISR for the debug interrupt (exception no. 12) */ .thumb_func diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 044b57ae6..c29739542 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -17,7 +17,7 @@ static BLEBas blebas; // BAS (Battery Service) helper class instance static BLEDfu bledfu; // DFU software update helper service // This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in -// proccess at once +// process at once // static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; static uint8_t fromRadioBytes[meshtastic_FromRadio_size]; static uint8_t toRadioBytes[meshtastic_ToRadio_size]; diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index c630aa13b..fd6fe2cc2 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -170,8 +170,11 @@ void cpuDeepSleep(uint32_t msecToWake) Serial1.end(); #endif setBluetoothEnable(false); + #ifdef RAK4630 +#ifdef PIN_3V3_EN digitalWrite(PIN_3V3_EN, LOW); +#endif #ifndef USE_EINK // RAK-12039 set pin for Air quality sensor digitalWrite(AQ_SET_PIN, LOW); diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp index f71113ab4..e3d56554a 100644 --- a/src/platform/portduino/SimRadio.cpp +++ b/src/platform/portduino/SimRadio.cpp @@ -92,7 +92,7 @@ void SimRadio::completeSending() } } -/** Could we send right now (i.e. either not actively receving or transmitting)? */ +/** Could we send right now (i.e. either not actively receiving or transmitting)? */ bool SimRadio::canSendImmediately() { // We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one). diff --git a/src/platform/rp2040/architecture.h b/src/platform/rp2040/architecture.h index 772e4b1af..762a2dc83 100644 --- a/src/platform/rp2040/architecture.h +++ b/src/platform/rp2040/architecture.h @@ -2,9 +2,18 @@ #define ARCH_RP2040 +#ifndef HAS_BUTTON +#define HAS_BUTTON 1 +#endif #ifndef HAS_TELEMETRY #define HAS_TELEMETRY 1 #endif +#ifndef HAS_SCREEN +#define HAS_SCREEN 1 +#endif +#ifndef HAS_WIRE +#define HAS_WIRE 1 +#endif #ifndef HAS_SENSOR #define HAS_SENSOR 1 #endif diff --git a/src/platform/stm32wl/InternalFileSystem.cpp b/src/platform/stm32wl/InternalFileSystem.cpp index 950ceb0cd..d42a646a5 100644 --- a/src/platform/stm32wl/InternalFileSystem.cpp +++ b/src/platform/stm32wl/InternalFileSystem.cpp @@ -49,7 +49,7 @@ static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, l } // Program a region in a block. The block must have previously -// been erased. Negative error codes are propogated to the user. +// been erased. Negative error codes are propagated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { @@ -67,7 +67,7 @@ static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, l // Erase a block. A block must be erased before being programmed. // The state of an erased block is undefined. Negative error codes -// are propogated to the user. +// are propagated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block) { @@ -84,7 +84,7 @@ static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block) } // Sync the state of the underlying block device. Negative error codes -// are propogated to the user. +// are propagated to the user. static int _internal_flash_sync(const struct lfs_config *c) { // we don't use a ram cache, this is a noop diff --git a/src/shutdown.h b/src/shutdown.h index ee63422dd..d9077151c 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -12,6 +12,8 @@ void powerCommandsCheck() ESP.restart(); #elif defined(ARCH_NRF52) NVIC_SystemReset(); +#elif defined(ARCH_RP2040) + rp2040.reboot(); #else rebootAtMsec = -1; LOG_WARN("FIXME implement reboot for this platform. Skipping for now.\n"); @@ -33,4 +35,4 @@ void powerCommandsCheck() LOG_WARN("FIXME implement shutdown for this platform"); #endif } -} +} \ No newline at end of file diff --git a/src/sleep.cpp b/src/sleep.cpp index 5331eaf75..0b8fbb782 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -99,6 +99,10 @@ void setGPSPower(bool on) { LOG_INFO("Setting GPS power=%d\n", on); +#ifdef PIN_GPS_EN + digitalWrite(PIN_GPS_EN, on ? 1 : 0); +#endif + #ifdef HAS_PMU if (pmu_found && PMU) { uint8_t model = PMU->getChipModel(); @@ -185,7 +189,7 @@ static void waitEnterSleep() void doGPSpowersave(bool on) { -#ifdef HAS_PMU +#if defined(HAS_PMU) || defined(PIN_GPS_EN) if (on) { LOG_INFO("Turning GPS back on\n"); gps->forceWake(1); @@ -246,7 +250,7 @@ void doDeepSleep(uint32_t msecToWake) // // No need to turn this off if the power draw in sleep mode really is just 0.2uA and turning it off would // leave floating input for the IRQ line - // If we want to leave the radio receving in would be 11.5mA current draw, but most of the time it is just waiting + // If we want to leave the radio receiving in would be 11.5mA current draw, but most of the time it is just waiting // in its sequencer (true?) so the average power draw should be much lower even if we were listinging for packets // all the time. diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 3e0ace39c..58ee0b5ba 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -4,3 +4,4 @@ board = heltec_wifi_lora_32_V3 # Temporary until espressif creates a release with this new target build_flags = ${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3 + -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. \ No newline at end of file diff --git a/variants/heltec_v3/variant.h b/variants/heltec_v3/variant.h index d9fc0b4c2..aedfbe677 100644 --- a/variants/heltec_v3/variant.h +++ b/variants/heltec_v3/variant.h @@ -7,6 +7,8 @@ #define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost #define BUTTON_PIN 0 +#define PIN_GPS_EN 46 // GPS power enable pin + #define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO1_CHANNEL #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider @@ -29,4 +31,4 @@ #define SX126X_DIO1 LORA_DIO1 #define SX126X_BUSY LORA_DIO2 #define SX126X_RESET LORA_RESET -#define SX126X_E22 \ No newline at end of file +#define SX126X_E22 diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini new file mode 100644 index 000000000..0bc7f14d1 --- /dev/null +++ b/variants/heltec_wireless_paper/platformio.ini @@ -0,0 +1,8 @@ +[env:heltec-wireless-paper] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +build_flags = + ${esp32s3_base.build_flags} -D HELTEC_WIRELESS_PAPER -I variants/heltec_wireless_paper +lib_deps = + ${esp32s3_base.lib_deps} + zinggjm/GxEPD2@^1.5.2 diff --git a/variants/heltec_wireless_paper/variant.h b/variants/heltec_wireless_paper/variant.h new file mode 100644 index 000000000..84c16c884 --- /dev/null +++ b/variants/heltec_wireless_paper/variant.h @@ -0,0 +1,39 @@ +#define LED_PIN 18 + +#define USE_EINK +/* + * eink display pins + */ +#define PIN_EINK_CS 4 +#define PIN_EINK_BUSY 7 +#define PIN_EINK_DC 5 +#define PIN_EINK_RES 6 +#define PIN_EINK_SCLK 3 +#define PIN_EINK_MOSI 2 + +#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost +#define BUTTON_PIN 0 + +#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO1_CHANNEL +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider +#define ADC_MULTIPLIER 4.9 + +#define USE_SX1262 + +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define RF95_SCK 9 +#define RF95_MISO 11 +#define RF95_MOSI 10 +#define RF95_NSS 8 + +#define SX126X_CS RF95_NSS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET +#define SX126X_E22 \ No newline at end of file diff --git a/variants/heltec_wireless_tracker/platformio.ini b/variants/heltec_wireless_tracker/platformio.ini new file mode 100644 index 000000000..43f80687d --- /dev/null +++ b/variants/heltec_wireless_tracker/platformio.ini @@ -0,0 +1,12 @@ +[env:heltec-wireless-tracker] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +upload_protocol = esp-builtin + +build_flags = + ${esp32s3_base.build_flags} -D HELTEC_WIRELESS_TRACKER -I variants/heltec_wireless_tracker + -DARDUINO_USB_CDC_ON_BOOT=1 + +lib_deps = + ${esp32s3_base.lib_deps} + lovyan03/LovyanGFX@^1.1.7 \ No newline at end of file diff --git a/variants/heltec_wireless_tracker/variant.h b/variants/heltec_wireless_tracker/variant.h new file mode 100644 index 000000000..318454522 --- /dev/null +++ b/variants/heltec_wireless_tracker/variant.h @@ -0,0 +1,59 @@ +#define LED_PIN 18 + +// ST7735S TFT LCD +#define ST7735S 1 // there are different (sub-)versions of ST7735 +#define ST7735_CS 38 +#define ST7735_RS 40 // DC +#define ST7735_SDA 42 // MOSI +#define ST7735_SCK 41 +#define ST7735_RESET 39 +#define ST7735_MISO -1 +#define ST7735_BUSY -1 +#define ST7735_BL 45 +#define ST7735_SPI_HOST SPI3_HOST +#define ST7735_BACKLIGHT_EN 45 +#define SPI_FREQUENCY 40000000 +#define SPI_READ_FREQUENCY 16000000 +#define SCREEN_ROTATE +#define TFT_HEIGHT 160 +#define TFT_WIDTH 80 +#define TFT_OFFSET_X 26 +#define TFT_OFFSET_Y 0 +#define VTFT_CTRL 46 // Heltec Tracker needs this pulled low for TFT +#define SCREEN_TRANSITION_FRAMERATE 1 // fps + +#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost +#define BUTTON_PIN 0 + +#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO1_CHANNEL +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider +#define ADC_MULTIPLIER 4.9 + +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN 33 +#define GPS_TX_PIN 34 +#define PIN_GPS_RESET 35 +#define PIN_GPS_PPS 36 +#define VGNSS_CTRL 37 // Heltec Tracker needs this pulled low for GPS +#define GPS_RESET_MODE LOW +#define GPS_UC6580 + +#define USE_SX1262 +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define RF95_SCK 9 +#define RF95_MISO 11 +#define RF95_MOSI 10 +#define RF95_NSS 8 + +#define SX126X_CS RF95_NSS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET +#define SX126X_E22 \ No newline at end of file diff --git a/variants/heltec_wsl_v3/platformio.ini b/variants/heltec_wsl_v3/platformio.ini index 5f89a7466..c95659156 100644 --- a/variants/heltec_wsl_v3/platformio.ini +++ b/variants/heltec_wsl_v3/platformio.ini @@ -4,3 +4,4 @@ board = heltec_wifi_lora_32_V3 # Temporary until espressif creates a release with this new target build_flags = ${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/heltec_wsl_v3 + -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. \ No newline at end of file diff --git a/variants/heltec_wsl_v3/variant.h b/variants/heltec_wsl_v3/variant.h index 0ecc5bea7..ec5796313 100644 --- a/variants/heltec_wsl_v3/variant.h +++ b/variants/heltec_wsl_v3/variant.h @@ -8,6 +8,8 @@ #define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost #define BUTTON_PIN 0 +#define PIN_GPS_EN 46 // GPS power enable pin + #define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO1_CHANNEL #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider @@ -30,4 +32,4 @@ #define SX126X_DIO1 LORA_DIO1 #define SX126X_BUSY LORA_DIO2 #define SX126X_RESET LORA_RESET -#define SX126X_E22 \ No newline at end of file +#define SX126X_E22 diff --git a/variants/m5stack_coreink/variant.h b/variants/m5stack_coreink/variant.h index 37131caca..3abf16be7 100644 --- a/variants/m5stack_coreink/variant.h +++ b/variants/m5stack_coreink/variant.h @@ -1,7 +1,19 @@ +// Primary I2C Bus includes PCF8563 RTC Module #define I2C_SDA 21 #define I2C_SCL 22 -// LED? +// 7-07-2023 Or enable Secondary I2C Bus +//#define I2C_SDA1 32 +//#define I2C_SCL1 33 + +#define HAS_GPS 1 +#undef GPS_RX_PIN +#undef GPS_TX_PIN +// Use Secondary I2C Bus as GPS Serial +#define GPS_RX_PIN 33 +#define GPS_TX_PIN 32 + +// Green LED #define LED_INVERTED 0 #define LED_PIN 10 @@ -37,10 +49,6 @@ #define LORA_DIO1 RADIOLIB_NC #define LORA_DIO2 RADIOLIB_NC -// This board has no GPS for now -#undef GPS_RX_PIN -#undef GPS_TX_PIN - #define USE_EINK // https://docs.m5stack.com/en/core/coreink // https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/schematic/Core/coreink/coreink_sch.pdf diff --git a/variants/monteops_hw1/platformio.ini b/variants/monteops_hw1/platformio.ini new file mode 100644 index 000000000..f9d260e74 --- /dev/null +++ b/variants/monteops_hw1/platformio.ini @@ -0,0 +1,14 @@ +; MonteOps M.Node/M.Backbone/M.Eagle hardware based on hardware variant #1 (RAK4630 based) +[env:monteops_hw1] +extends = nrf52840_base +board = wiscore_rak4631 +build_flags = ${nrf52840_base.build_flags} -Ivariants/monteops_hw1 -D MONTEOPS_HW1 + -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard" +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/monteops_hw1> + + + +lib_deps = + ${nrf52840_base.lib_deps} + ${networking_base.lib_deps} + https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 +debug_tool = jlink +; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) +;upload_protocol = jlink \ No newline at end of file diff --git a/variants/monteops_hw1/variant.cpp b/variants/monteops_hw1/variant.cpp new file mode 100644 index 000000000..75cca1dc3 --- /dev/null +++ b/variants/monteops_hw1/variant.cpp @@ -0,0 +1,41 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); +} diff --git a/variants/monteops_hw1/variant.h b/variants/monteops_hw1/variant.h new file mode 100644 index 000000000..866ddf471 --- /dev/null +++ b/variants/monteops_hw1/variant.h @@ -0,0 +1,240 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library 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 Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_MOPS_HW1_ +#define _VARIANT_MOPS_HW1_ + +#define RAK4630 + +// MonteOps hardware design variant +#ifndef MONTEOPS_HW1 +#define MONTEOPS_HW1 +#endif + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (6) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (35) +#define PIN_LED2 (36) // Connected to WWAN host LED (if present) + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_GREEN PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +/* + * Buttons + */ + +//#define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion +#define BUTTON_NEED_PULLUP +#define PIN_BUTTON2 12 +#define PIN_BUTTON3 24 +#define PIN_BUTTON4 25 + +/* + * Analog pins + */ +#define PIN_A0 (5) +#define PIN_A1 (31) +#define PIN_A2 (28) +#define PIN_A3 (29) +#define PIN_A4 (30) +#define PIN_A5 (31) +#define PIN_A6 (0xff) +#define PIN_A7 (0xff) + +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; +static const uint8_t A4 = PIN_A4; +static const uint8_t A5 = PIN_A5; +static const uint8_t A6 = PIN_A6; +static const uint8_t A7 = PIN_A7; +#define ADC_RESOLUTION 14 + +// Other pins +#define PIN_AREF (2) +#define PIN_NFC1 (9) +#define PIN_NFC2 (10) + +static const uint8_t AREF = PIN_AREF; + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (15) +#define PIN_SERIAL1_TX (16) + +// Connected to Jlink CDC +#define PIN_SERIAL2_RX (8) +#define PIN_SERIAL2_TX (6) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO (45) +#define PIN_SPI_MOSI (44) +#define PIN_SPI_SCK (43) + +#define PIN_SPI1_MISO (29) // (0 + 29) +#define PIN_SPI1_MOSI (30) // (0 + 30) +#define PIN_SPI1_SCK (3) // (0 + 3) + +static const uint8_t SS = 42; +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (13) +#define PIN_WIRE_SCL (14) + +// QSPI Pins +#define PIN_QSPI_SCK 3 +#define PIN_QSPI_CS 26 +#define PIN_QSPI_IO0 30 +#define PIN_QSPI_IO1 29 +#define PIN_QSPI_IO2 28 +#define PIN_QSPI_IO3 2 + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES IS25LP080D +#define EXTERNAL_FLASH_USE_QSPI + +/* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports + RAK5005-O <-> nRF52840 + IO1 <-> P0.17 (Arduino GPIO number 17) + IO2 <-> P1.02 (Arduino GPIO number 34) + IO3 <-> P0.21 (Arduino GPIO number 21) + IO4 <-> P0.04 (Arduino GPIO number 4) + IO5 <-> P0.09 (Arduino GPIO number 9) + IO6 <-> P0.10 (Arduino GPIO number 10) + IO7 <-> P0.28 (Arduino GPIO number 28) + SW1 <-> P0.01 (Arduino GPIO number 1) + A0 <-> P0.04/AIN2 (Arduino Analog A2) + A1 <-> P0.31/AIN7 (Arduino Analog A7) + SPI_CS <-> P0.26 (Arduino GPIO number 26) + */ + +// RAK4630 LoRa module + +/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) + +P1.10 NSS SPI NSS (Arduino GPIO number 42) +P1.11 SCK SPI CLK (Arduino GPIO number 43) +P1.12 MOSI SPI MOSI (Arduino GPIO number 44) +P1.13 MISO SPI MISO (Arduino GPIO number 45) +P1.14 BUSY BUSY signal (Arduino GPIO number 46) +P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) +P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) + +Important for successful SX1262 initialization: + +* Setup DIO2 to control the antenna switch +* Setup DIO3 to control the TCXO power supply +* Setup the SX1262 to use it's DCDC regulator and not the LDO +* RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the +control of the antenna switch + +SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG + +*/ + +#define USE_SX1262 +#define SX126X_CS (42) +#define SX126X_DIO1 (47) +#define SX126X_BUSY (46) +#define SX126X_RESET (38) +// #define SX126X_TXEN (39) +// #define SX126X_RXEN (37) +#define SX126X_POWER_EN (37) +#define SX126X_E22 // DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 + +#define PIN_GPS_RESET (34) // Must be P1.02 +// #define PIN_GPS_EN +// #define PIN_GPS_PPS (17) // Pulse per second input from the GPS + +#define GPS_RX_PIN PIN_SERIAL1_RX +#define GPS_TX_PIN PIN_SERIAL1_TX + +// Battery +// The battery sense is hooked to pin A0 (5) +#define BATTERY_PIN PIN_A0 +// and has 12 bit resolution +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +// Definition of milliVolt per LSB => 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096 +#define VBAT_MV_PER_LSB (0.73242188F) +// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M)) +#define VBAT_DIVIDER (0.4F) +// Compensation factor for the VBAT divider +#define VBAT_DIVIDER_COMP (1.73) +// Fixed calculation of milliVolt from compensation value +#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB) +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER VBAT_DIVIDER_COMP // REAL_VBAT_MV_PER_LSB +#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x) + +//#define HAS_RTC 1 + +#define HAS_ETHERNET 1 + +#define PIN_ETHERNET_RESET 21 +#define PIN_ETHERNET_SS 26 // P0.26 QSPI_CS +#define ETH_SPI_PORT SPI1 +#define AQ_SET_PIN 10 + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif \ No newline at end of file diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index fe9f062c8..258e4eb3c 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -139,6 +139,9 @@ static const uint8_t SCK = PIN_SPI_SCK; // #define USE_EINK +// RAKRGB +#define HAS_NCP5623 + /* * Wire Interfaces */ @@ -255,6 +258,8 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG #define HAS_ETHERNET 1 +#define RAK_4631 1 + #define PIN_ETHERNET_RESET 21 #define PIN_ETHERNET_SS PIN_EINK_CS #define ETH_SPI_PORT SPI1 diff --git a/variants/rak4631_epaper/variant.h b/variants/rak4631_epaper/variant.h index a43229088..ad3e4b87f 100644 --- a/variants/rak4631_epaper/variant.h +++ b/variants/rak4631_epaper/variant.h @@ -139,6 +139,9 @@ static const uint8_t SCK = PIN_SPI_SCK; #define USE_EINK +// RAKRGB +#define HAS_NCP5623 + /* * Wire Interfaces */ @@ -226,6 +229,8 @@ static const uint8_t SCK = PIN_SPI_SCK; #define HAS_RTC 1 +#define RAK_4631 1 + #ifdef __cplusplus } #endif @@ -234,4 +239,4 @@ static const uint8_t SCK = PIN_SPI_SCK; * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif +#endif \ No newline at end of file diff --git a/variants/rak4631_epaper_onrxtx/variant.h b/variants/rak4631_epaper_onrxtx/variant.h index 44db0b7f0..e4d7c7d45 100644 --- a/variants/rak4631_epaper_onrxtx/variant.h +++ b/variants/rak4631_epaper_onrxtx/variant.h @@ -120,6 +120,9 @@ static const uint8_t SCK = PIN_SPI_SCK; // FIXME - I think this is actually just the board power enable - it enables power to the CPU also // #define PIN_EINK_PWR_ON (-1) +// RAKRGB +#define HAS_NCP5623 + /* * Wire Interfaces */ @@ -207,4 +210,4 @@ static const uint8_t SCK = PIN_SPI_SCK; * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif +#endif \ No newline at end of file diff --git a/variants/rpipico/variant.h b/variants/rpipico/variant.h index 7e2660aa6..fb4b9bd75 100644 --- a/variants/rpipico/variant.h +++ b/variants/rpipico/variant.h @@ -15,11 +15,11 @@ #define USE_SH1106 1 #undef GPS_SERIAL_NUM -// #define I2C_SDA 6 -// #define I2C_SCL 7 +// default I2C pins: +// SDA = 4 +// SCL = 5 #define BUTTON_PIN 17 -#define EXT_NOTIFY_OUT 4 #define LED_PIN PIN_LED diff --git a/variants/rpipicow/variant.h b/variants/rpipicow/variant.h index 4741fd130..59f8d2ec2 100644 --- a/variants/rpipicow/variant.h +++ b/variants/rpipicow/variant.h @@ -15,11 +15,11 @@ #define USE_SH1106 1 #undef GPS_SERIAL_NUM -// #define I2C_SDA 6 -// #define I2C_SCL 7 +// default I2C pins: +// SDA = 4 +// SCL = 5 #define BUTTON_PIN 17 -#define EXT_NOTIFY_OUT 4 #define BATTERY_PIN 26 // ratio of voltage divider = 3.0 (R17=200k, R18=100k) diff --git a/version.properties b/version.properties index 1b9a7da4f..e279aa749 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 1 -build = 17 +build = 19