diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 40fcd7109..b527c2fd9 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -143,7 +143,7 @@ jobs: merge-multiple: true - name: Test Report - uses: dorny/test-reporter@v2.4.0 + uses: dorny/test-reporter@v2.5.0 with: name: PlatformIO Tests path: testreport.xml diff --git a/.github/workflows/trunk_format_pr.yml b/.github/workflows/trunk_format_pr.yml deleted file mode 100644 index 8fa0cc1eb..000000000 --- a/.github/workflows/trunk_format_pr.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Run Trunk Fmt on PR Comment - -on: - issue_comment: - types: [created] - -permissions: read-all - -jobs: - trunk-fmt: - if: github.event.issue.pull_request != null && contains(github.event.comment.body, 'trunk fmt') - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - ref: ${{github.event.pull_request.head.ref}} - repository: ${{github.event.pull_request.head.repo.full_name}} - - - name: Install trunk - run: curl https://get.trunk.io -fsSL | bash - - - name: Run Trunk Fmt - run: trunk fmt - - - name: Get release version string - run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT - id: version - - - name: Commit and push changes - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git add . - git commit -m "Add firmware version ${{ steps.version.outputs.long }}" - git push - - - name: Comment on PR - uses: actions/github-script@v8 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: '`trunk fmt` has been run on this PR.' - }) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 705f0177c..fb2d93563 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -8,8 +8,8 @@ plugins: uri: https://github.com/trunk-io/plugins lint: enabled: - - checkov@3.2.496 - - renovate@42.66.14 + - checkov@3.2.497 + - renovate@42.74.2 - prettier@3.7.4 - trufflehog@3.92.4 - yamllint@1.37.1 @@ -21,7 +21,7 @@ lint: - markdownlint@0.47.0 - oxipng@10.0.0 - svgo@4.0.0 - - actionlint@1.7.9 + - actionlint@1.7.10 - flake8@7.3.0 - hadolint@2.14.0 - shfmt@3.6.0 diff --git a/platformio.ini b/platformio.ini index 11ef72b21..eed7d7728 100644 --- a/platformio.ini +++ b/platformio.ini @@ -119,7 +119,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/a8e2f947f7abaf0c5ac8e6dd189a22156335beaa.zip + https://github.com/meshtastic/device-ui/archive/272defcb35651461830ebfd1b39c9167c8f49317.zip ; Common libs for environmental measurements in telemetry module [environmental_base] diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 83acfdc18..2be9212cf 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -68,7 +68,7 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const if (r == 0x08 || r == 0x00) { logFoundDevice("SH1106", (uint8_t)addr.address); o_probe = SCREEN_SH1106; // SH1106 - } else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) { + } else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07 || r == 0x05) { logFoundDevice("SSD1306", (uint8_t)addr.address); o_probe = SCREEN_SSD1306; // SSD1306 } diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 4209baf5d..1678da793 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -148,7 +148,7 @@ bool EInkDisplay::connect() #endif #endif -#if defined(TTGO_T_ECHO) || defined(ELECROW_ThinkNode_M1) || defined(T_ECHO_LITE) +#if defined(TTGO_T_ECHO) || defined(ELECROW_ThinkNode_M1) || defined(T_ECHO_LITE) || defined(TTGO_T_ECHO_PLUS) { auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1); diff --git a/src/input/ButtonThread.cpp b/src/input/ButtonThread.cpp index 502959288..0d835a3a9 100644 --- a/src/input/ButtonThread.cpp +++ b/src/input/ButtonThread.cpp @@ -37,6 +37,9 @@ bool ButtonThread::initButton(const ButtonConfig &config) _activeLow = config.activeLow; _touchQuirk = config.touchQuirk; _intRoutine = config.intRoutine; + _pressHandler = config.onPress; + _releaseHandler = config.onRelease; + _suppressLeadUp = config.suppressLeadUpSound; _longLongPress = config.longLongPress; userButton = OneButton(config.pinNumber, config.activeLow, config.activePullup); @@ -133,6 +136,8 @@ int32_t ButtonThread::runOnce() // Detect start of button press if (buttonCurrentlyPressed && !buttonWasPressed) { + if (_pressHandler) + _pressHandler(); buttonPressStartTime = millis(); leadUpPlayed = false; leadUpSequenceActive = false; @@ -140,7 +145,7 @@ int32_t ButtonThread::runOnce() } // Progressive lead-up sound system - if (buttonCurrentlyPressed && (millis() - buttonPressStartTime) >= BUTTON_LEADUP_MS) { + if (!_suppressLeadUp && buttonCurrentlyPressed && (millis() - buttonPressStartTime) >= BUTTON_LEADUP_MS) { // Start the progressive sequence if not already active if (!leadUpSequenceActive) { @@ -160,6 +165,8 @@ int32_t ButtonThread::runOnce() // Reset when button is released if (!buttonCurrentlyPressed && buttonWasPressed) { + if (_releaseHandler) + _releaseHandler(); leadUpSequenceActive = false; resetLeadUpSequence(); } diff --git a/src/input/ButtonThread.h b/src/input/ButtonThread.h index 7de38341c..e724c3596 100644 --- a/src/input/ButtonThread.h +++ b/src/input/ButtonThread.h @@ -13,6 +13,9 @@ struct ButtonConfig { bool activePullup = true; uint32_t pullupSense = 0; voidFuncPtr intRoutine = nullptr; + voidFuncPtr onPress = nullptr; // Optional edge callbacks + voidFuncPtr onRelease = nullptr; // Optional edge callbacks + bool suppressLeadUpSound = false; input_broker_event singlePress = INPUT_BROKER_NONE; input_broker_event longPress = INPUT_BROKER_NONE; uint16_t longPressTime = 500; @@ -94,6 +97,9 @@ class ButtonThread : public Observable, public concurrency:: input_broker_event _shortLong = INPUT_BROKER_NONE; voidFuncPtr _intRoutine = nullptr; + voidFuncPtr _pressHandler = nullptr; + voidFuncPtr _releaseHandler = nullptr; + bool _suppressLeadUp = false; uint16_t _longPressTime = 500; uint16_t _longLongPressTime = 3900; int _pinNum = 0; diff --git a/src/main.cpp b/src/main.cpp index 9ac060d37..a9ed73bd7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -107,6 +107,10 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr; #if defined(BUTTON_PIN_TOUCH) ButtonThread *TouchButtonThread = nullptr; +#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN) +static bool touchBacklightWasOn = false; +static bool touchBacklightActive = false; +#endif #endif #if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) @@ -205,7 +209,7 @@ ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, /// The I2C address of our Air Quality Indicator (if found) ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE; -#if defined(T_WATCH_S3) || defined(T_LORA_PAGER) +#ifdef HAS_DRV2605 Adafruit_DRV2605 drv; #endif @@ -795,7 +799,6 @@ void setup() // We do this as early as possible because this loads preferences from flash // but we need to do this after main cpu init (esp32setup), because we need the random seed set nodeDB = new NodeDB; - #if HAS_TFT if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { tftSetup(); @@ -841,7 +844,12 @@ void setup() #endif #endif -#if defined(T_WATCH_S3) || defined(T_LORA_PAGER) +#ifdef HAS_DRV2605 +#if defined(PIN_DRV_EN) + pinMode(PIN_DRV_EN, OUTPUT); + digitalWrite(PIN_DRV_EN, HIGH); + delay(10); +#endif drv.begin(); drv.selectLibrary(1); // I2C trigger by sending 'go' command @@ -877,7 +885,7 @@ void setup() SPI.begin(); #endif #else - // ESP32 +// ESP32 #if defined(HW_SPI1_DEVICE) SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); LOG_DEBUG("SPI1.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); @@ -1046,6 +1054,24 @@ void setup() }; touchConfig.singlePress = INPUT_BROKER_NONE; touchConfig.longPress = INPUT_BROKER_BACK; +#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN) + // On T-Echo Plus the touch pad should only drive the backlight, not UI navigation/sounds + touchConfig.longPress = INPUT_BROKER_NONE; + touchConfig.suppressLeadUpSound = true; + touchConfig.onPress = []() { + touchBacklightWasOn = uiconfig.screen_brightness == 1; + if (!touchBacklightWasOn) { + digitalWrite(PIN_EINK_EN, HIGH); + } + touchBacklightActive = true; + }; + touchConfig.onRelease = []() { + if (touchBacklightActive && !touchBacklightWasOn) { + digitalWrite(PIN_EINK_EN, LOW); + } + touchBacklightActive = false; + }; +#endif TouchButtonThread->initButton(touchConfig); #endif diff --git a/src/main.h b/src/main.h index 414752b5c..7ca14d825 100644 --- a/src/main.h +++ b/src/main.h @@ -42,7 +42,7 @@ extern bool eink_found; extern bool pmu_found; extern bool isUSBPowered; -#if defined(T_WATCH_S3) || defined(T_LORA_PAGER) +#ifdef HAS_DRV2605 #include extern Adafruit_DRV2605 drv; #endif diff --git a/src/mesh/generated/meshtastic/admin.pb.cpp b/src/mesh/generated/meshtastic/admin.pb.cpp index ccece50d3..e358bc96d 100644 --- a/src/mesh/generated/meshtastic/admin.pb.cpp +++ b/src/mesh/generated/meshtastic/admin.pb.cpp @@ -12,6 +12,9 @@ PB_BIND(meshtastic_AdminMessage, meshtastic_AdminMessage, 2) PB_BIND(meshtastic_AdminMessage_InputEvent, meshtastic_AdminMessage_InputEvent, AUTO) +PB_BIND(meshtastic_AdminMessage_OTAEvent, meshtastic_AdminMessage_OTAEvent, AUTO) + + PB_BIND(meshtastic_HamParameters, meshtastic_HamParameters, AUTO) diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index b3edf7d43..785558f1b 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -113,6 +113,17 @@ typedef struct _meshtastic_AdminMessage_InputEvent { uint16_t touch_y; } meshtastic_AdminMessage_InputEvent; +typedef PB_BYTES_ARRAY_T(32) meshtastic_AdminMessage_OTAEvent_ota_hash_t; +/* User is requesting an over the air update. + Node will reboot into the OTA loader */ +typedef struct _meshtastic_AdminMessage_OTAEvent { + /* Tell the node to reboot into OTA mode for firmware update via BLE or WiFi (ESP32 only for now) */ + meshtastic_OTAMode reboot_ota_mode; + /* A 32 byte hash of the OTA firmware. + Used to verify the integrity of the firmware before applying an update. */ + meshtastic_AdminMessage_OTAEvent_ota_hash_t ota_hash; +} meshtastic_AdminMessage_OTAEvent; + /* Parameters for setting up Meshtastic for ameteur radio usage */ typedef struct _meshtastic_HamParameters { /* Amateur radio call sign, eg. KD2ABC */ @@ -288,6 +299,8 @@ typedef struct _meshtastic_AdminMessage { /* Tell the node to reset the nodedb. When true, favorites are preserved through reset. */ bool nodedb_reset; + /* Tell the node to reset into the OTA Loader */ + meshtastic_AdminMessage_OTAEvent ota_request; }; /* The node generates this key and sends it with any get_x_response packets. The client MUST include the same key with any set_x commands. Key expires after 300 seconds. @@ -329,6 +342,8 @@ extern "C" { #define meshtastic_AdminMessage_payload_variant_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode +#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode + @@ -338,12 +353,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_AdminMessage_init_default {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0} +#define meshtastic_AdminMessage_OTAEvent_init_default {_meshtastic_OTAMode_MIN, {0, {0}}} #define meshtastic_HamParameters_init_default {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0} #define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0} #define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0} +#define meshtastic_AdminMessage_OTAEvent_init_zero {_meshtastic_OTAMode_MIN, {0, {0}}} #define meshtastic_HamParameters_init_zero {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0} @@ -354,6 +371,8 @@ extern "C" { #define meshtastic_AdminMessage_InputEvent_kb_char_tag 2 #define meshtastic_AdminMessage_InputEvent_touch_x_tag 3 #define meshtastic_AdminMessage_InputEvent_touch_y_tag 4 +#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_tag 1 +#define meshtastic_AdminMessage_OTAEvent_ota_hash_tag 2 #define meshtastic_HamParameters_call_sign_tag 1 #define meshtastic_HamParameters_tx_power_tag 2 #define meshtastic_HamParameters_frequency_tag 3 @@ -422,6 +441,7 @@ extern "C" { #define meshtastic_AdminMessage_shutdown_seconds_tag 98 #define meshtastic_AdminMessage_factory_reset_config_tag 99 #define meshtastic_AdminMessage_nodedb_reset_tag 100 +#define meshtastic_AdminMessage_ota_request_tag 102 #define meshtastic_AdminMessage_session_passkey_tag 101 /* Struct field encoding specification for nanopb */ @@ -481,7 +501,8 @@ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_second X(a, STATIC, ONEOF, INT32, (payload_variant,shutdown_seconds,shutdown_seconds), 98) \ X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_config,factory_reset_config), 99) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,nodedb_reset,nodedb_reset), 100) \ -X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) +X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ota_request,ota_request), 102) #define meshtastic_AdminMessage_CALLBACK NULL #define meshtastic_AdminMessage_DEFAULT NULL #define meshtastic_AdminMessage_payload_variant_get_channel_response_MSGTYPE meshtastic_Channel @@ -502,6 +523,7 @@ X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) #define meshtastic_AdminMessage_payload_variant_store_ui_config_MSGTYPE meshtastic_DeviceUIConfig #define meshtastic_AdminMessage_payload_variant_add_contact_MSGTYPE meshtastic_SharedContact #define meshtastic_AdminMessage_payload_variant_key_verification_MSGTYPE meshtastic_KeyVerificationAdmin +#define meshtastic_AdminMessage_payload_variant_ota_request_MSGTYPE meshtastic_AdminMessage_OTAEvent #define meshtastic_AdminMessage_InputEvent_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, event_code, 1) \ @@ -511,6 +533,12 @@ X(a, STATIC, SINGULAR, UINT32, touch_y, 4) #define meshtastic_AdminMessage_InputEvent_CALLBACK NULL #define meshtastic_AdminMessage_InputEvent_DEFAULT NULL +#define meshtastic_AdminMessage_OTAEvent_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, reboot_ota_mode, 1) \ +X(a, STATIC, SINGULAR, BYTES, ota_hash, 2) +#define meshtastic_AdminMessage_OTAEvent_CALLBACK NULL +#define meshtastic_AdminMessage_OTAEvent_DEFAULT NULL + #define meshtastic_HamParameters_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, STRING, call_sign, 1) \ X(a, STATIC, SINGULAR, INT32, tx_power, 2) \ @@ -544,6 +572,7 @@ X(a, STATIC, OPTIONAL, UINT32, security_number, 4) extern const pb_msgdesc_t meshtastic_AdminMessage_msg; extern const pb_msgdesc_t meshtastic_AdminMessage_InputEvent_msg; +extern const pb_msgdesc_t meshtastic_AdminMessage_OTAEvent_msg; extern const pb_msgdesc_t meshtastic_HamParameters_msg; extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg; extern const pb_msgdesc_t meshtastic_SharedContact_msg; @@ -552,6 +581,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_AdminMessage_fields &meshtastic_AdminMessage_msg #define meshtastic_AdminMessage_InputEvent_fields &meshtastic_AdminMessage_InputEvent_msg +#define meshtastic_AdminMessage_OTAEvent_fields &meshtastic_AdminMessage_OTAEvent_msg #define meshtastic_HamParameters_fields &meshtastic_HamParameters_msg #define meshtastic_NodeRemoteHardwarePinsResponse_fields &meshtastic_NodeRemoteHardwarePinsResponse_msg #define meshtastic_SharedContact_fields &meshtastic_SharedContact_msg @@ -560,6 +590,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_ADMIN_PB_H_MAX_SIZE meshtastic_AdminMessage_size #define meshtastic_AdminMessage_InputEvent_size 14 +#define meshtastic_AdminMessage_OTAEvent_size 36 #define meshtastic_AdminMessage_size 511 #define meshtastic_HamParameters_size 31 #define meshtastic_KeyVerificationAdmin_size 25 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 75a490550..2ba592a12 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -92,8 +92,8 @@ typedef enum _meshtastic_HardwareModel { Less common/prototype boards listed here (needs one more byte over the air) --------------------------------------------------------------------------- */ meshtastic_HardwareModel_LORA_RELAY_V1 = 32, - /* TODO: REPLACE */ - meshtastic_HardwareModel_NRF52840DK = 33, + /* T-Echo Plus device from LilyGo */ + meshtastic_HardwareModel_T_ECHO_PLUS = 33, /* TODO: REPLACE */ meshtastic_HardwareModel_PPR = 34, /* TODO: REPLACE */ @@ -475,7 +475,10 @@ typedef enum _meshtastic_Routing_Error { meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37, /* Airtime fairness rate limit exceeded for a packet This typically enforced per portnum and is used to prevent a single node from monopolizing airtime */ - meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38 + meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38, + /* PKI encryption failed, due to no public key for the remote node + This is different from PKI_UNKNOWN_PUBKEY which indicates a failure upon receiving a packet */ + meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY = 39 } meshtastic_Routing_Error; /* Enum of message types */ @@ -1351,8 +1354,12 @@ extern "C" { #define _meshtastic_Position_AltSource_ARRAYSIZE ((meshtastic_Position_AltSource)(meshtastic_Position_AltSource_ALT_BAROMETRIC+1)) #define _meshtastic_Routing_Error_MIN meshtastic_Routing_Error_NONE -#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED -#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED+1)) +#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY +#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY+1)) + +#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE +#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF +#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_ARRAYSIZE ((meshtastic_StoreForwardPlusPlus_SFPP_message_type)(meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF+1)) #define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE #define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 6d52a3e46..3f6375a65 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -168,7 +168,7 @@ int32_t ExternalNotificationModule::runOnce() delay = EXT_NOTIFICATION_FAST_THREAD_MS; #endif -#if defined(T_WATCH_S3) || defined(T_LORA_PAGER) +#ifdef HAS_DRV2605 drv.go(); #endif } @@ -283,7 +283,7 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on) #ifdef UNPHONE unphone.rgb(red, green, blue); #endif -#if defined(T_WATCH_S3) || defined(T_LORA_PAGER) +#ifdef HAS_DRV2605 if (on) { drv.go(); } else { @@ -319,7 +319,7 @@ void ExternalNotificationModule::stopNow() externalTurnedOn[i] = 0; } setIntervalFromNow(0); -#if defined(T_WATCH_S3) || defined(T_LORA_PAGER) +#ifdef HAS_DRV2605 drv.stop(); #endif diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 719e342b1..f6007a565 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -63,9 +63,9 @@ SerialModule *serialModule; SerialModuleRadio *serialModuleRadio; -#if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1) || \ - defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || defined(ELECROW_ThinkNode_M3) || \ - defined(MUZI_BASE) +#if defined(TTGO_T_ECHO) || defined(TTGO_T_ECHO_PLUS) || defined(CANARYONE) || defined(MESHLINK) || \ + defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || \ + defined(ELECROW_ThinkNode_M3) || defined(MUZI_BASE) SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") { api_type = TYPE_SERIAL; @@ -204,8 +204,9 @@ int32_t SerialModule::runOnce() Serial.begin(baud); Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT); } -#elif !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \ - !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE) +#elif !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \ + !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \ + !defined(MUZI_BASE) if (moduleConfig.serial.rxd && moduleConfig.serial.txd) { #ifdef ARCH_RP2040 Serial2.setFIFOSize(RX_BUFFER); @@ -261,7 +262,7 @@ int32_t SerialModule::runOnce() } } -#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \ +#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \ !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE) else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) { processWXSerial(); @@ -536,9 +537,9 @@ ParsedLine parseLine(const char *line) */ void SerialModule::processWXSerial() { -#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \ - !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \ - !defined(ARCH_STM32WL) && !defined(MUZI_BASE) +#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \ + !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && \ + !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL) && !defined(MUZI_BASE) static unsigned int lastAveraged = 0; static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded. static double dir_sum_sin = 0; diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index d4699cd8c..afe96963d 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -66,6 +66,8 @@ #define HW_VENDOR meshtastic_HardwareModel_T_ECHO #elif defined(T_ECHO_LITE) #define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE +#elif defined(TTGO_T_ECHO_PLUS) +#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_PLUS #elif defined(ELECROW_ThinkNode_M1) #define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M1 #elif defined(ELECROW_ThinkNode_M3) diff --git a/variants/esp32s3/t-watch-s3/variant.h b/variants/esp32s3/t-watch-s3/variant.h index 923ac86ce..7a302f978 100644 --- a/variants/esp32s3/t-watch-s3/variant.h +++ b/variants/esp32s3/t-watch-s3/variant.h @@ -20,6 +20,8 @@ #define SCREEN_TRANSITION_FRAMERATE 5 // fps #define USE_TFTDISPLAY 1 +#define HAS_DRV2605 1 + #define HAS_TOUCHSCREEN 1 #define SCREEN_TOUCH_INT 16 #define SCREEN_TOUCH_USE_I2C1 diff --git a/variants/esp32s3/tlora-pager/variant.h b/variants/esp32s3/tlora-pager/variant.h index e6ac2c57e..565f4f580 100644 --- a/variants/esp32s3/tlora-pager/variant.h +++ b/variants/esp32s3/tlora-pager/variant.h @@ -26,6 +26,8 @@ #define I2C_SDA SDA #define I2C_SCL SCL +#define HAS_DRV2605 1 + #define USE_POWERSAVE #define SLEEP_TIME 120 diff --git a/variants/nrf52840/t-echo-plus/nicheGraphics.h b/variants/nrf52840/t-echo-plus/nicheGraphics.h new file mode 100644 index 000000000..483e16ea4 --- /dev/null +++ b/variants/nrf52840/t-echo-plus/nicheGraphics.h @@ -0,0 +1,70 @@ +#pragma once + +#include "configuration.h" + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +#include "graphics/niche/Drivers/Backlight/LatchingBacklight.h" +#include "graphics/niche/Drivers/EInk/GDEY0154D67.h" +#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h" +#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h" +#include "graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.h" +#include "graphics/niche/InkHUD/Applets/User/Positions/PositionsApplet.h" +#include "graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.h" +#include "graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.h" +#include "graphics/niche/InkHUD/InkHUD.h" +#include "graphics/niche/Inputs/TwoButton.h" + +void setupNicheGraphics() +{ + using namespace NicheGraphics; + + SPI1.begin(); + + Drivers::EInk *driver = new Drivers::GDEY0154D67; + driver->begin(&SPI1, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES); + + InkHUD::InkHUD *inkhud = InkHUD::InkHUD::getInstance(); + inkhud->setDriver(driver); + inkhud->setDisplayResilience(20, 1.5); + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; + inkhud->persistence->settings.userTiles.maxCount = 2; + inkhud->persistence->settings.rotation = 3; + inkhud->persistence->settings.optionalFeatures.batteryIcon = true; + inkhud->persistence->settings.optionalMenuItems.backlight = true; + + Drivers::LatchingBacklight *backlight = Drivers::LatchingBacklight::getInstance(); + backlight->setPin(PIN_EINK_BL); + + inkhud->addApplet("All Messages", new InkHUD::AllMessageApplet, true, true); + inkhud->addApplet("DMs", new InkHUD::DMApplet); + inkhud->addApplet("Channel 0", new InkHUD::ThreadedMessageApplet(0)); + inkhud->addApplet("Channel 1", new InkHUD::ThreadedMessageApplet(1)); + inkhud->addApplet("Positions", new InkHUD::PositionsApplet, true); + inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet); + inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); + + inkhud->begin(); + + Inputs::TwoButton *buttons = Inputs::TwoButton::getInstance(); + + buttons->setWiring(0, Inputs::TwoButton::getUserButtonPin()); + buttons->setTiming(0, 75, 500); + buttons->setHandlerShortPress(0, [inkhud]() { inkhud->shortpress(); }); + buttons->setHandlerLongPress(0, [inkhud]() { inkhud->longpress(); }); + + buttons->setWiring(1, PIN_BUTTON_TOUCH); + buttons->setTiming(1, 50, 5000); + buttons->setHandlerDown(1, [inkhud, backlight]() { + backlight->peek(); + inkhud->persistence->settings.optionalMenuItems.backlight = false; + }); + buttons->setHandlerLongPress(1, [backlight]() { backlight->latch(); }); + buttons->setHandlerShortPress(1, [backlight]() { backlight->off(); }); + + buttons->start(); +} + +#endif diff --git a/variants/nrf52840/t-echo-plus/platformio.ini b/variants/nrf52840/t-echo-plus/platformio.ini new file mode 100644 index 000000000..b77d54748 --- /dev/null +++ b/variants/nrf52840/t-echo-plus/platformio.ini @@ -0,0 +1,26 @@ +[env:t-echo-plus] +extends = nrf52840_base +board = t-echo +board_level = pr +board_check = true +debug_tool = jlink + +build_flags = ${nrf52840_base.build_flags} + -DTTGO_T_ECHO_PLUS + -Ivariants/nrf52840/t-echo-plus + -DEINK_DISPLAY_MODEL=GxEPD2_154_D67 + -DEINK_WIDTH=200 + -DEINK_HEIGHT=200 + -DUSE_EINK + -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -DEINK_LIMIT_FASTREFRESH=20 ; How many consecutive fast-refreshes are permitted + -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. + -DI2C_NO_RESCAN + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/t-echo-plus> + +lib_deps = + ${nrf52840_base.lib_deps} + https://github.com/meshtastic/GxEPD2/archive/55f618961db45a23eff0233546430f1e5a80f63a.zip + lewisxhe/PCF8563_Library@^1.0.1 + adafruit/Adafruit DRV2605 Library@1.2.4 diff --git a/variants/nrf52840/t-echo-plus/variant.cpp b/variants/nrf52840/t-echo-plus/variant.cpp new file mode 100644 index 000000000..084186bf6 --- /dev/null +++ b/variants/nrf52840/t-echo-plus/variant.cpp @@ -0,0 +1,24 @@ +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled + 0xff, 0xff, 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() +{ + // LEDs (if populated) + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + pinMode(PIN_LED3, OUTPUT); + ledOff(PIN_LED3); +} diff --git a/variants/nrf52840/t-echo-plus/variant.h b/variants/nrf52840/t-echo-plus/variant.h new file mode 100644 index 000000000..226f6d6fe --- /dev/null +++ b/variants/nrf52840/t-echo-plus/variant.h @@ -0,0 +1,145 @@ +#ifndef _VARIANT_T_ECHO_PLUS_ +#define _VARIANT_T_ECHO_PLUS_ + +#define VARIANT_MCK (64000000ul) +#define USE_LFXO + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Pin counts +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs (not documented on pinmap; keep defaults for compatibility) +#define PIN_LED1 (0 + 14) +#define PIN_LED2 (0 + 15) +#define PIN_LED3 (0 + 13) + +#define LED_RED PIN_LED3 +#define LED_BLUE PIN_LED1 +#define LED_GREEN PIN_LED2 + +#define LED_BUILTIN LED_BLUE +#define LED_CONN LED_GREEN + +#define LED_STATE_ON 0 + +// Buttons / touch +#define PIN_BUTTON1 (32 + 10) +#define BUTTON_ACTIVE_LOW true +#define BUTTON_ACTIVE_PULLUP true +#define PIN_BUTTON2 (0 + 18) // reset-labelled but usable as GPIO +#define PIN_BUTTON_TOUCH (0 + 11) // capacitive touch +#define BUTTON_TOUCH_ACTIVE_LOW true +#define BUTTON_TOUCH_ACTIVE_PULLUP true + +#define BUTTON_CLICK_MS 400 +#define BUTTON_TOUCH_MS 200 + +// Analog +#define PIN_A0 (4) +#define BATTERY_PIN PIN_A0 +static const uint8_t A0 = PIN_A0; +#define ADC_RESOLUTION 14 +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER (2.0F) + +// NFC +#define PIN_NFC1 (9) +#define PIN_NFC2 (10) + +// I2C (IMU BHI260AP, RTC, etc.) +#define WIRE_INTERFACES_COUNT 1 +#define PIN_WIRE_SDA (0 + 26) +#define PIN_WIRE_SCL (0 + 27) +#define HAS_BHI260AP + +#define TP_SER_IO (0 + 11) + +// RTC interrupt +#define PIN_RTC_INT (0 + 16) + +// QSPI flash +#define PIN_QSPI_SCK (32 + 14) +#define PIN_QSPI_CS (32 + 15) +#define PIN_QSPI_IO0 (32 + 12) +#define PIN_QSPI_IO1 (32 + 13) +#define PIN_QSPI_IO2 (0 + 7) +#define PIN_QSPI_IO3 (0 + 5) + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES MX25R1635F +#define EXTERNAL_FLASH_USE_QSPI + +// LoRa SX1262 +#define USE_SX1262 +#define USE_SX1268 +#define SX126X_CS (0 + 24) +#define SX126X_DIO1 (0 + 20) +#define SX1262_DIO3 (0 + 21) +#define SX126X_BUSY (0 + 17) +#define SX126X_RESET (0 + 25) +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#define TCXO_OPTIONAL + +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO (0 + 23) +#define PIN_SPI_MOSI (0 + 22) +#define PIN_SPI_SCK (0 + 19) + +// E-paper (1.54" per pinmap) +// Alias PIN_EINK_EN to keep common eink power control code working +#define PIN_EINK_BL (32 + 11) // backlight / panel power switch +#define PIN_EINK_EN PIN_EINK_BL +#define PIN_EINK_CS (0 + 30) +#define PIN_EINK_BUSY (0 + 3) +#define PIN_EINK_DC (0 + 28) +#define PIN_EINK_RES (0 + 2) +#define PIN_EINK_SCLK (0 + 31) +#define PIN_EINK_MOSI (0 + 29) // also called SDI + +// Power control +#define PIN_POWER_EN (0 + 12) + +#define PIN_SPI1_MISO (32 + 7) // Placeholder MISO; keep off QSPI pins to avoid contention +#define PIN_SPI1_MOSI PIN_EINK_MOSI +#define PIN_SPI1_SCK PIN_EINK_SCLK + +// GPS (TX/RX/Wake/Reset/PPS per pinmap) +#define GPS_L76K +#define PIN_GPS_REINIT (32 + 5) // Reset +#define PIN_GPS_STANDBY (32 + 2) // Wake +#define PIN_GPS_PPS (32 + 4) +#define GPS_TX_PIN (32 + 8) +#define GPS_RX_PIN (32 + 9) +#define GPS_THREAD_INTERVAL 50 + +#define PIN_SERIAL1_RX GPS_RX_PIN +#define PIN_SERIAL1_TX GPS_TX_PIN + +// Sensors / accessories +#define PIN_BUZZER (0 + 6) +#define PIN_DRV_EN (0 + 8) + +#define HAS_DRV2605 1 + +// Battery / ADC already defined above +#define HAS_RTC 1 + +#ifdef __cplusplus +} +#endif + +#endif