diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml new file mode 100644 index 000000000..786feeced --- /dev/null +++ b/.github/workflows/pr_tests.yml @@ -0,0 +1,238 @@ +name: Tests + +# DISABLED: Changed from automatic PR triggers to manual only +on: + workflow_dispatch: + inputs: + reason: + description: "Reason for manual test run" + required: false + default: "Manual test execution" + +concurrency: + group: tests-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + actions: read + checks: write + pull-requests: write + +jobs: + native-tests: + name: "πŸ§ͺ Native Tests" + if: github.repository == 'meshtastic/firmware' + uses: ./.github/workflows/test_native.yml + permissions: + contents: read + actions: read + checks: write + + test-summary: + name: "πŸ“Š Test Results" + runs-on: ubuntu-latest + needs: [native-tests] + if: always() + permissions: + contents: read + actions: read + checks: write + pull-requests: write + steps: + - uses: actions/checkout@v5 + with: + submodules: recursive + + - name: Get release version string + run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + + - name: Download test artifacts + if: needs.native-tests.result != 'skipped' + uses: actions/download-artifact@v5 + with: + name: platformio-test-report-${{ steps.version.outputs.long }}.zip + merge-multiple: true + + - name: Parse test results and create detailed summary + id: test-results + run: | + echo "## πŸ§ͺ Test Results Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # Check overall job status first + if [[ "${{ needs.native-tests.result }}" == "success" ]]; then + echo "βœ… **Overall Status**: PASSED" >> $GITHUB_STEP_SUMMARY + elif [[ "${{ needs.native-tests.result }}" == "failure" ]]; then + echo "❌ **Overall Status**: FAILED" >> $GITHUB_STEP_SUMMARY + elif [[ "${{ needs.native-tests.result }}" == "cancelled" ]]; then + echo "⏸️ **Overall Status**: CANCELLED" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Tests were cancelled before completion." >> $GITHUB_STEP_SUMMARY + exit 0 + else + echo "⚠️ **Overall Status**: SKIPPED" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Tests were skipped." >> $GITHUB_STEP_SUMMARY + exit 0 + fi + + echo "" >> $GITHUB_STEP_SUMMARY + + # Parse detailed test results if available + if [ -f "testreport.xml" ]; then + echo "### πŸ” Individual Test Results" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + python3 << 'EOF' + import xml.etree.ElementTree as ET + import os + + try: + tree = ET.parse('testreport.xml') + root = tree.getroot() + + total_tests = 0 + passed_tests = 0 + failed_tests = 0 + skipped_tests = 0 + + # Parse testsuite elements + for testsuite in root.findall('.//testsuite'): + suite_name = testsuite.get('name', 'Unknown') + suite_tests = int(testsuite.get('tests', '0')) + suite_failures = int(testsuite.get('failures', '0')) + suite_errors = int(testsuite.get('errors', '0')) + suite_skipped = int(testsuite.get('skipped', '0')) + + total_tests += suite_tests + failed_tests += suite_failures + suite_errors + skipped_tests += suite_skipped + passed_tests += suite_tests - suite_failures - suite_errors - suite_skipped + + if suite_tests > 0: + status = "βœ…" if (suite_failures + suite_errors) == 0 else "❌" + print(f"**{status} Test Suite: {suite_name}**") + print(f"- Total: {suite_tests}") + print(f"- Passed: βœ… {suite_tests - suite_failures - suite_errors - suite_skipped}") + print(f"- Failed: ❌ {suite_failures + suite_errors}") + if suite_skipped > 0: + print(f"- Skipped: ⏭️ {suite_skipped}") + print("") + + # Show individual test results for failed suites + if suite_failures + suite_errors > 0: + print("**Failed Tests:**") + for testcase in testsuite.findall('testcase'): + test_name = testcase.get('name', 'Unknown') + failure = testcase.find('failure') + error = testcase.find('error') + + if failure is not None: + msg = failure.get('message', 'Unknown error')[:100] + print(f"- ❌ `{test_name}`: {msg}") + elif error is not None: + msg = error.get('message', 'Unknown error')[:100] + print(f"- ❌ `{test_name}`: ERROR - {msg}") + print("") + else: + # Show passed tests for successful suites + passed_count = 0 + for testcase in testsuite.findall('testcase'): + if testcase.find('failure') is None and testcase.find('error') is None: + if passed_count < 5: # Limit to first 5 to avoid spam + test_name = testcase.get('name', 'Unknown') + print(f"- βœ… `{test_name}`: PASSED") + passed_count += 1 + if passed_count > 5: + print(f"- ... and {passed_count - 5} more tests passed") + print("") + + # Summary statistics + print("### πŸ“Š Test Statistics") + print(f"- **Total Tests**: {total_tests}") + print(f"- **Passed**: βœ… {passed_tests}") + print(f"- **Failed**: ❌ {failed_tests}") + if skipped_tests > 0: + print(f"- **Skipped**: ⏭️ {skipped_tests}") + + if failed_tests > 0: + print(f"\n❌ **{failed_tests} tests failed out of {total_tests} total**") + else: + print(f"\nβœ… **All {total_tests} tests passed!**") + + except Exception as e: + print(f"❌ Error parsing test results: {e}") + EOF + else + echo "⚠️ **No detailed test report available**" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Test artifacts may not have been generated properly." >> $GITHUB_STEP_SUMMARY + fi + + echo "" >> $GITHUB_STEP_SUMMARY + echo "---" >> $GITHUB_STEP_SUMMARY + echo "View detailed logs in the [Actions tab](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY + + - name: Comment test results on PR + if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + + // Read the step summary to use as PR comment + let testSummary = "## πŸ§ͺ Test Results Summary\n\n"; + + if ("${{ needs.native-tests.result }}" === "success") { + testSummary += "βœ… **All tests passed!**\n\n"; + } else if ("${{ needs.native-tests.result }}" === "failure") { + testSummary += "❌ **Some tests failed.**\n\n"; + } else { + testSummary += "⚠️ **Tests did not complete normally.**\n\n"; + } + + testSummary += `View detailed results: [Actions Run](${context.payload.repository.html_url}/actions/runs/${context.runId})\n\n`; + testSummary += "---\n"; + testSummary += "*This comment will be automatically updated when new commits are pushed.*"; + + // Find existing comment + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }); + + const botComment = comments.data.find(comment => + comment.user.type === 'Bot' && + comment.body.includes('πŸ§ͺ Test Results Summary') + ); + + if (botComment) { + // Update existing comment + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: testSummary + }); + } else { + // Create new comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: testSummary + }); + } + + - name: Set overall status + run: | + if [[ "${{ needs.native-tests.result }}" == "success" ]]; then + echo "All tests passed! βœ…" + exit 0 + else + echo "Some tests failed! ❌" + exit 1 + fi diff --git a/Dockerfile b/Dockerfile index 6a2ddeece..b1e151ac7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,7 +61,7 @@ RUN apt-get update && apt-get --no-install-recommends -y install \ # Fetch compiled binary from the builder COPY --from=builder /tmp/firmware/release/meshtasticd /usr/bin/ -COPY --from=builder /tmp/web /usr/share/meshtasticd/ +COPY --from=builder /tmp/web /usr/share/meshtasticd/web/ # Copy config templates COPY ./bin/config.d /etc/meshtasticd/available.d diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index ae68159eb..20b3f8e3d 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -2,7 +2,7 @@ [portduino_base] platform = # renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop - https://github.com/meshtastic/platform-native/archive/6cb7a455b440dd0738e8ed74a18136ed5cf7ea63.zip + https://github.com/meshtastic/platform-native/archive/37d986499ce24511952d7146db72d667c6bdaff7.zip framework = arduino build_src_filter = diff --git a/boards/meshtiny.json b/boards/meshtiny.json new file mode 100644 index 000000000..1473388ea --- /dev/null +++ b/boards/meshtiny.json @@ -0,0 +1,52 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x8029"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"], + ["0x239A", "0x802A"] + ], + "usb_product": "MeshTiny", + "mcu": "nrf52840", + "variant": "meshtiny", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "6.1.1", + "sd_fwid": "0x00B6" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52840-mdk-rs" + }, + "frameworks": ["arduino", "freertos"], + "name": "MeshTiny", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://github.com/meshtastic/firmware", + "vendor": "MTools Tec" +} diff --git a/platformio.ini b/platformio.ini index 528563def..ac30eb32e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -60,7 +60,7 @@ monitor_speed = 115200 monitor_filters = direct lib_deps = # renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master - https://github.com/meshtastic/esp8266-oled-ssd1306/archive/0119501e9983bd894830b02f545c377ee08d66fe.zip + https://github.com/meshtastic/esp8266-oled-ssd1306/archive/9573abb64dc9c94f3051348f2bf4fc5cedf03c22.zip # renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip # renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master @@ -118,7 +118,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/0cd108ff783539e41ef38258ba2784ab3b1bdc97.zip + https://github.com/meshtastic/device-ui/archive/8f5094b248c15ea2f9acf19cedfef6d2248fc1ff.zip ; Common libs for environmental measurements in telemetry module [environmental_base] diff --git a/protobufs b/protobufs index 5dd723fe6..be5137698 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 5dd723fe6f33a8613ec81acf5e15be26365c7cce +Subproject commit be5137698027f9e9fe6e68d5d5d638049f61ba8f diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 305689fff..a3a8a2087 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -192,12 +192,6 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) size_t PhoneAPI::getFromRadio(uint8_t *buf) { - if (!available()) { - return 0; - } - // In case we send a FromRadio packet - memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); - // Respond to heartbeat by sending queue status if (heartbeatReceived) { memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); @@ -209,6 +203,12 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) return numbytes; } + if (!available()) { + return 0; + } + // In case we send a FromRadio packet + memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); + // Advance states as needed switch (state) { case STATE_SEND_NOTHING: diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index a54dcb976..cceacfe9e 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -523,8 +523,10 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) // is not in the local nodedb // First, only PKC encrypt packets we are originating if (isFromUs(p) && - // Don't use PKC with simulator - radioType != SIM_RADIO && +#if ARCH_PORTDUINO + // Sim radio via the cli flag skips PKC + !portduino_config.force_simradio && +#endif // Don't use PKC with Ham mode !owner.is_licensed && // Don't use PKC if it's not explicitly requested and a non-primary channel is requested diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index f758995c2..9af095e78 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -99,7 +99,9 @@ typedef enum _meshtastic_TelemetrySensorType { /* Sensirion SFA30 Formaldehyde sensor */ meshtastic_TelemetrySensorType_SFA30 = 42, /* SEN5X PM SENSORS */ - meshtastic_TelemetrySensorType_SEN5X = 43 + meshtastic_TelemetrySensorType_SEN5X = 43, + /* TSL2561 light sensor */ + meshtastic_TelemetrySensorType_TSL2561 = 44 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -434,8 +436,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SEN5X -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SEN5X+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_TSL2561 +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_TSL2561+1)) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index d94aeff95..7f7a9d511 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -279,6 +279,8 @@ struct PubSubConfig { // Defaults static constexpr uint16_t defaultPort = 1883; + static constexpr uint16_t defaultPortTls = 8883; + uint16_t serverPort = defaultPort; String serverAddr = default_mqtt_address; const char *mqttUsername = default_mqtt_username; @@ -641,7 +643,7 @@ bool MQTT::isValidConfig(const meshtastic_ModuleConfig_MQTTConfig &config, MQTTC } const bool defaultServer = isDefaultServer(parsed.serverAddr); - if (defaultServer && parsed.serverPort != PubSubConfig::defaultPort) { + if (defaultServer && !IS_ONE_OF(parsed.serverPort, PubSubConfig::defaultPort, PubSubConfig::defaultPortTls)) { const char *warning = "Invalid MQTT config: default server address must not have a port specified"; LOG_ERROR(warning); #if !IS_RUNNING_TESTS diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index ac4e79af1..3753c944c 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -34,7 +34,6 @@ std::ofstream traceFile; Ch341Hal *ch341Hal = nullptr; char *configPath = nullptr; char *optionMac = nullptr; -bool forceSimulated = false; bool verboseEnabled = false; const char *argp_program_version = optstr(APP_VERSION); @@ -67,7 +66,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) configPath = arg; break; case 's': - forceSimulated = true; + portduino_config.force_simradio = true; break; case 'h': optionMac = arg; @@ -190,7 +189,7 @@ void portduinoSetup() YAML::Node yamlConfig; - if (forceSimulated == true) { + if (portduino_config.force_simradio == true) { settingsMap[use_simradio] = true; } else if (configPath != nullptr) { if (loadConfig(configPath)) { diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 64277322a..6e450c90e 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -134,4 +134,5 @@ extern struct portduino_config_struct { bool has_rfswitch_table = false; uint32_t rfswitch_dio_pins[5] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC}; Module::RfSwitchMode_t rfswitch_table[8]; + bool force_simradio = false; } portduino_config; \ No newline at end of file diff --git a/variants/nrf52840/meshtiny/platformio.ini b/variants/nrf52840/meshtiny/platformio.ini new file mode 100644 index 000000000..ef744a1c3 --- /dev/null +++ b/variants/nrf52840/meshtiny/platformio.ini @@ -0,0 +1,19 @@ +; MeshTiny - Custom device based on GAT562 with encoder and buzzer support +[env:meshtiny] +extends = nrf52840_base +board = meshtiny +board_level = extra +build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/meshtiny -D MESHTINY + -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + -DRADIOLIB_EXCLUDE_SX128X=1 + -DRADIOLIB_EXCLUDE_SX127X=1 + -DRADIOLIB_EXCLUDE_LR11X0=1 + -D INPUTDRIVER_ENCODER_TYPE=2 + -D INPUTDRIVER_ENCODER_UP=4 + -D INPUTDRIVER_ENCODER_DOWN=26 + -D INPUTDRIVER_ENCODER_BTN=28 + -D USE_PIN_BUZZER=PIN_BUZZER + -D MESHTASTIC_EXCLUDE_GPS=1 +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/meshtiny> +lib_deps = + ${nrf52840_base.lib_deps} diff --git a/variants/nrf52840/meshtiny/variant.cpp b/variants/nrf52840/meshtiny/variant.cpp new file mode 100644 index 000000000..2e8b00e4b --- /dev/null +++ b/variants/nrf52840/meshtiny/variant.cpp @@ -0,0 +1,54 @@ +/* + 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); + + // 3V3 Power Rail + pinMode(PIN_3V3_EN, OUTPUT); + digitalWrite(PIN_3V3_EN, HIGH); + + // Initialize Encoder pins + pinMode(INPUTDRIVER_ENCODER_UP, INPUT_PULLUP); + pinMode(INPUTDRIVER_ENCODER_DOWN, INPUT_PULLUP); + pinMode(INPUTDRIVER_ENCODER_BTN, INPUT_PULLUP); + + // Initialize Buzzer pin + pinMode(PIN_BUZZER, OUTPUT); + digitalWrite(PIN_BUZZER, LOW); +} diff --git a/variants/nrf52840/meshtiny/variant.h b/variants/nrf52840/meshtiny/variant.h new file mode 100644 index 000000000..83ad4c5b9 --- /dev/null +++ b/variants/nrf52840/meshtiny/variant.h @@ -0,0 +1,199 @@ +/* + 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_MESHTINY_ +#define _VARIANT_MESHTINY_ + +#define MESHTINY + +// #define RAK4630 + +/** 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) + +#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 + +/* + * Encoder + */ +#define INPUTDRIVER_ENCODER_TYPE 2 +#define INPUTDRIVER_ENCODER_UP 26 +#define INPUTDRIVER_ENCODER_DOWN 4 +#define INPUTDRIVER_ENCODER_BTN 28 + +#define CANNED_MESSAGE_MODULE_ENABLE 1 + +/* + * Buzzer - PWM + */ +#define PIN_BUZZER 30 + +/* + * Buttons + */ + +#define PIN_BUTTON1 9 +#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 HAS_SCREEN 1 +#define USE_SSD1306 + +/* + * Wire Interfaces + */ +#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 22 // Changed from 26 to avoid conflict with encoder +#define PIN_QSPI_IO0 27 // Changed from 30 to avoid conflict with buzzer +#define PIN_QSPI_IO1 29 +#define PIN_QSPI_IO2 21 // Changed from 28 to avoid conflict with encoder button +#define PIN_QSPI_IO3 2 + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES IS25LP080D +#define EXTERNAL_FLASH_USE_QSPI + +#define USE_SX1262 +#define SX126X_CS (42) +#define SX126X_DIO1 (47) +#define SX126X_BUSY (46) +#define SX126X_RESET (38) +#define SX126X_POWER_EN (37) +// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +// Testing USB detection +#define NRF_APM + +#define PIN_3V3_EN (34) + +// 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 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER 1.73 + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif