Эх сурвалжийг харах

Seeed Wio Tracker L1: initial support

taco 1 жил өмнө
parent
commit
78cd655789

+ 61 - 0
boards/seeed-wio-tracker-l1.json

@@ -0,0 +1,61 @@
+{
+  "build": {
+    "arduino": {
+    "ldscript": "nrf52840_s140_v7.ld"
+    },
+    "core": "nRF5",
+    "cpu": "cortex-m4",
+    "extra_flags": "-DARDUINO_SEEED_WIO_TRACKER_L1 -DNRF52840_XXAA -DSEEED_WIO_TRACKER_L1 ",
+    "f_cpu": "64000000L",
+    "hwids": [
+      [ "0x2886", "0x1667" ],
+      [ "0x2886", "0x1668" ]
+    ],
+    "mcu": "nrf52840",
+    "variant": "Seeed_Wio_Tracker_L1",
+    "softdevice": {
+      "sd_flags": "-DS140",
+      "sd_name": "s140",
+      "sd_version": "7.3.0",
+      "sd_fwid": "0x0123"
+    },
+    "bsp": {
+      "name": "adafruit"
+    },
+    "bootloader": {
+      "settings_addr": "0xFF000"
+    },
+    "usb_product": "Seeed Wio Tracker L1"
+  },
+  "connectivity": [
+    "bluetooth"
+  ],
+  "debug": {
+    "jlink_device": "nRF52840_xxAA",
+    "openocd_target": "nrf52.cfg",
+    "svd_path": "nrf52840.svd"
+  },
+  "frameworks": [
+    "arduino"
+  ],
+  "name": "Seeed Wio Tracker L1",
+  "upload": {
+    "maximum_ram_size": 248832,
+    "maximum_size": 815104,
+    "protocol": "nrfutil",
+    "speed": 115200,
+    "protocols": [
+      "jlink",
+      "nrfjprog",
+      "nrfutil",
+      "cmsis-dap",
+      "sam-ba",
+      "blackmagic"
+    ],
+    "use_1200bps_touch": true,
+    "require_upload_port": true,
+    "wait_for_upload_port": true
+  },
+  "url": "https://wiki.seeedstudio.com/wio_tracker_l1_node/",
+  "vendor": "Seeed Studio"
+}

+ 96 - 0
variants/wio-tracker-l1/WioTrackerL1Board.cpp

@@ -0,0 +1,96 @@
+#include <Arduino.h>
+#include "WioTrackerL1Board.h"
+
+#include <bluefruit.h>
+#include <Wire.h>
+
+static BLEDfu bledfu;
+
+static void connect_callback(uint16_t conn_handle) {
+  (void)conn_handle;
+  MESH_DEBUG_PRINTLN("BLE client connected");
+}
+
+static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
+  (void)conn_handle;
+  (void)reason;
+
+  MESH_DEBUG_PRINTLN("BLE client disconnected");
+}
+
+void WioTrackerL1Board::begin() {
+  // for future use, sub-classes SHOULD call this from their begin()
+  startup_reason = BD_STARTUP_NORMAL;
+  btn_prev_state = HIGH;
+
+  pinMode(PIN_VBAT_READ, INPUT); // VBAT ADC input
+  // Set all button pins to INPUT_PULLUP
+  pinMode(PIN_BUTTON1, INPUT_PULLUP);
+  pinMode(PIN_BUTTON2, INPUT_PULLUP);
+  pinMode(PIN_BUTTON3, INPUT_PULLUP);
+  pinMode(PIN_BUTTON4, INPUT_PULLUP);
+  pinMode(PIN_BUTTON5, INPUT_PULLUP);
+  pinMode(PIN_BUTTON6, INPUT_PULLUP);
+  
+
+  #if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL)
+    Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL);
+  #endif
+
+  Wire.begin();
+
+  #ifdef P_LORA_TX_LED
+    pinMode(P_LORA_TX_LED, OUTPUT);
+    digitalWrite(P_LORA_TX_LED, LOW);
+  #endif
+
+  delay(10);   // give sx1262 some time to power up
+}
+
+bool WioTrackerL1Board::startOTAUpdate(const char* id, char reply[]) {
+  // Config the peripheral connection with maximum bandwidth
+  // more SRAM required by SoftDevice
+  // Note: All config***() function must be called before begin()
+  Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+  Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
+
+  Bluefruit.begin(1, 0);
+  // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+  Bluefruit.setTxPower(4);
+  // Set the BLE device name
+  Bluefruit.setName("WioTrackerL1 OTA");
+
+  Bluefruit.Periph.setConnectCallback(connect_callback);
+  Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
+
+  // To be consistent OTA DFU should be added first if it exists
+  bledfu.begin();
+
+  // Set up and start advertising
+  // Advertising packet
+  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+  Bluefruit.Advertising.addTxPower();
+  Bluefruit.Advertising.addName();
+
+  /* Start Advertising
+    - Enable auto advertising if disconnected
+    - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
+    - Timeout for fast mode is 30 seconds
+    - Start(timeout) with timeout = 0 will advertise forever (until connected)
+
+    For recommended advertising interval
+    https://developer.apple.com/library/content/qa/qa1931/_index.html
+  */
+  Bluefruit.Advertising.restartOnDisconnect(true);
+  Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+  Bluefruit.Advertising.setFastTimeout(30);   // number of seconds in fast mode
+  Bluefruit.Advertising.start(0);             // 0 = Don't stop advertising after n seconds
+
+  uint8_t mac_addr[6];
+  memset(mac_addr, 0, sizeof(mac_addr));
+  Bluefruit.getAddr(mac_addr);
+  sprintf(reply, "OK - mac: %02X:%02X:%02X:%02X:%02X:%02X", 
+      mac_addr[5], mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], mac_addr[0]);
+
+  return true;
+}

+ 42 - 0
variants/wio-tracker-l1/WioTrackerL1Board.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include <MeshCore.h>
+#include <Arduino.h>
+
+class WioTrackerL1Board : public mesh::MainBoard {
+protected:
+  uint8_t startup_reason;
+  uint8_t btn_prev_state;
+
+public:
+  void begin();
+  uint8_t getStartupReason() const override { return startup_reason; }
+
+#if defined(P_LORA_TX_LED)
+  void onBeforeTransmit() override {
+    digitalWrite(P_LORA_TX_LED, HIGH);   // turn TX LED on
+  }
+  void onAfterTransmit() override {
+    digitalWrite(P_LORA_TX_LED, LOW);   // turn TX LED off
+  }
+#endif
+
+  uint16_t getBattMilliVolts() override {
+    int adcvalue = 0;
+    analogReadResolution(12);
+    analogReference(AR_INTERNAL);
+    delay(10);
+    adcvalue = analogRead(PIN_VBAT_READ);
+    return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096;
+  }
+
+  const char* getManufacturerName() const override {
+    return "Seeed Wio Tracker L1";
+  }
+
+  void reboot() override {
+    NVIC_SystemReset();
+  }
+
+  bool startOTAUpdate(const char* id, char reply[]) override;
+};

+ 92 - 0
variants/wio-tracker-l1/platformio.ini

@@ -0,0 +1,92 @@
+[WioTrackerL1]
+extends = nrf52_base
+board = seeed-wio-tracker-l1
+board_build.ldscript = boards/nrf52840_s140_v7.ld
+build_flags = ${nrf52_base.build_flags}
+  -I lib/nrf52/s140_nrf52_7.3.0_API/include
+  -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
+  -I variants/wio-tracker-l1
+  -D WIO_TRACKER_L1
+  -D RADIO_CLASS=CustomSX1262
+  -D WRAPPER_CLASS=CustomSX1262Wrapper
+  -D LORA_TX_POWER=22
+  -D SX126X_CURRENT_LIMIT=140
+  -D SX126X_RX_BOOSTED_GAIN=1
+  -D PIN_OLED_RESET=-1
+  ; -D MESH_DEBUG=1
+build_src_filter = ${nrf52_base.build_src_filter}
+  +<WioTrackerL1Board.cpp>
+  +<../variants/wio-tracker-l1>
+  +<helpers/ui/SH1106Display.cpp>
+  +<helpers/sensors>
+lib_deps= ${nrf52_base.lib_deps}
+  adafruit/Adafruit SH110X @ ^2.1.13
+  adafruit/Adafruit GFX Library @ ^1.12.1
+  stevemarple/MicroNMEA @ ^2.0.6
+
+[env:WioTrackerL1_Repeater]
+extends = WioTrackerL1
+build_src_filter = ${WioTrackerL1.build_src_filter}
+  +<../examples/simple_repeater>
+build_flags =
+  ${WioTrackerL1.build_flags}
+  -D ADVERT_NAME='"WioTrackerL1 Repeater"'
+  -D ADMIN_PASSWORD='"password"'
+  -D MAX_NEIGHBOURS=8
+  -D DISPLAY_CLASS=SH1106Display
+;  -D MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+lib_deps = ${WioTrackerL1.lib_deps}
+  adafruit/RTClib @ ^2.1.3
+
+[env:WioTrackerL1_room_server]
+extends = WioTrackerL1
+build_src_filter = ${WioTrackerL1.build_src_filter}
+  +<../examples/simple_room_server>
+build_flags = ${WioTrackerL1.build_flags}
+  -D ADVERT_NAME='"WioTrackerL1 Room"'
+  -D ADMIN_PASSWORD='"password"'
+  -D ROOM_PASSWORD='"hello"'
+  -D DISPLAY_CLASS=SH1106Display
+;  -D MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+lib_deps = ${WioTrackerL1.lib_deps}
+  adafruit/RTClib @ ^2.1.3
+
+[env:WioTrackerL1_companion_radio_usb]
+extends = WioTrackerL1
+build_flags = ${WioTrackerL1.build_flags}
+  -D MAX_CONTACTS=100
+  -D MAX_GROUP_CHANNELS=8
+  -D DISPLAY_CLASS=SH1106Display
+; NOTE: DO NOT ENABLE -->  -D MESH_PACKET_LOGGING=1
+; NOTE: DO NOT ENABLE -->  -D MESH_DEBUG=1
+build_src_filter = ${WioTrackerL1.build_src_filter}
+  +<../examples/companion_radio>
+  +<helpers/ui/SH1106Display.cpp>
+  +<helpers/ui/buzzer.cpp>
+lib_deps = ${WioTrackerL1.lib_deps}
+  adafruit/RTClib @ ^2.1.3
+  densaugeo/base64 @ ~1.4.0
+  end2endzone/NonBlockingRTTTL@^1.3.0
+
+[env:WioTrackerL1_companion_radio_ble]
+extends = WioTrackerL1
+build_flags = ${WioTrackerL1.build_flags}
+  -D MAX_CONTACTS=100
+  -D MAX_GROUP_CHANNELS=8
+  -D BLE_PIN_CODE=123456
+  -D BLE_DEBUG_LOGGING=1
+  -D OFFLINE_QUEUE_SIZE=256
+  -D DISPLAY_CLASS=SH1106Display
+;  -D MESH_PACKET_LOGGING=1
+  -D MESH_DEBUG=1
+  -D PIN_BUZZER=12
+build_src_filter = ${WioTrackerL1.build_src_filter}
+  +<helpers/nrf52/SerialBLEInterface.cpp>
+  +<../examples/companion_radio>
+  +<helpers/ui/buzzer.cpp>
+lib_deps = ${WioTrackerL1.lib_deps}
+  adafruit/RTClib @ ^2.1.3
+  densaugeo/base64 @ ~1.4.0
+  end2endzone/NonBlockingRTTTL@^1.3.0

+ 146 - 0
variants/wio-tracker-l1/target.cpp

@@ -0,0 +1,146 @@
+#include <Arduino.h>
+#include "target.h"
+#include <helpers/ArduinoHelpers.h>
+#include <helpers/sensors/MicroNMEALocationProvider.h>
+
+WioTrackerL1Board board;
+
+RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
+
+WRAPPER_CLASS radio_driver(radio, board);
+
+VolatileRTCClock fallback_clock;
+AutoDiscoverRTCClock rtc_clock(fallback_clock);
+MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
+WioTrackerL1SensorManager sensors = WioTrackerL1SensorManager(nmea);
+
+#ifdef DISPLAY_CLASS
+  DISPLAY_CLASS display;
+#endif
+
+bool radio_init() {
+  rtc_clock.begin(Wire);
+
+  return radio.std_init(&SPI);
+}
+
+uint32_t radio_get_rng_seed() {
+  return radio.random(0x7FFFFFFF);
+}
+
+void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
+  radio.setFrequency(freq);
+  radio.setSpreadingFactor(sf);
+  radio.setBandwidth(bw);
+  radio.setCodingRate(cr);
+}
+
+void radio_set_tx_power(uint8_t dbm) {
+  radio.setOutputPower(dbm);
+}
+
+void WioTrackerL1SensorManager::start_gps()
+{
+  if (!gps_active)
+  {
+    MESH_DEBUG_PRINTLN("starting GPS");
+    digitalWrite(PIN_GPS_STANDBY, HIGH);
+    gps_active = true;
+  }
+}
+
+void WioTrackerL1SensorManager::stop_gps()
+{
+  if (gps_active)
+  {
+    MESH_DEBUG_PRINTLN("stopping GPS");
+    digitalWrite(PIN_GPS_STANDBY, LOW);
+    gps_active = false;
+  }
+}
+
+bool WioTrackerL1SensorManager::begin()
+{
+  Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX); // be sure to tx into rx and rx into tx
+  Serial1.begin(GPS_BAUDRATE);
+
+  pinMode(PIN_GPS_STANDBY, OUTPUT);
+  digitalWrite(PIN_GPS_STANDBY, HIGH); // Wake GPS from standby
+  delay(500);
+
+  // We'll consider GPS detected if we see any data on Serial1
+  if (Serial1.available() > 0)
+  {
+    MESH_DEBUG_PRINTLN("GPS detected");
+  }
+  else
+  {
+    MESH_DEBUG_PRINTLN("No GPS detected");
+  }
+  digitalWrite(PIN_GPS_STANDBY, LOW); // Put GPS back into standby mode
+  return true;
+}
+
+bool WioTrackerL1SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP &telemetry)
+{
+  if (requester_permissions & TELEM_PERM_LOCATION)
+  { // does requester have permission?
+    telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
+  }
+  return true;
+}
+
+void WioTrackerL1SensorManager::loop()
+{
+  static long next_gps_update = 0;
+  _location->loop();
+  if (millis() > next_gps_update && gps_active) // don't bother if gps position is not enabled
+  {
+    if (_location->isValid())
+    {
+      node_lat = ((double)_location->getLatitude()) / 1000000.;
+      node_lon = ((double)_location->getLongitude()) / 1000000.;
+      node_altitude = ((double)_location->getAltitude()) / 1000.0;
+      MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon);
+    }
+    next_gps_update = millis() + (1000 * 60); // after initial update, only check every minute TODO: should be configurable
+  }
+}
+
+int WioTrackerL1SensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch)
+
+const char *WioTrackerL1SensorManager::getSettingName(int i) const
+{
+  return i == 0 ? "gps" : NULL;
+}
+
+const char *WioTrackerL1SensorManager::getSettingValue(int i) const
+{
+  if (i == 0)
+  {
+    return gps_active ? "1" : "0";
+  }
+  return NULL;
+}
+
+bool WioTrackerL1SensorManager::setSettingValue(const char *name, const char *value)
+{
+  if (strcmp(name, "gps") == 0)
+  {
+    if (strcmp(value, "0") == 0)
+    {
+      stop_gps();
+    }
+    else
+    {
+      start_gps();
+    }
+    return true;
+  }
+  return false; // not supported
+}
+
+mesh::LocalIdentity radio_new_identity() {
+  RadioNoiseListener rng(radio);
+  return mesh::LocalIdentity(&rng);  // create new random identity
+}

+ 47 - 0
variants/wio-tracker-l1/target.h

@@ -0,0 +1,47 @@
+#pragma once
+
+#define RADIOLIB_STATIC_ONLY 1
+#include <RadioLib.h>
+#include <helpers/RadioLibWrappers.h>
+#include <WioTrackerL1Board.h>
+#include <helpers/CustomSX1262Wrapper.h>
+#include <helpers/AutoDiscoverRTCClock.h>
+#include <helpers/ArduinoHelpers.h>
+#ifdef DISPLAY_CLASS
+  #include <helpers/ui/SH1106Display.h>
+#endif
+#include <helpers/sensors/EnvironmentSensorManager.h>
+
+class WioTrackerL1SensorManager : public SensorManager
+{
+  bool gps_active = false;
+  LocationProvider *_location;
+
+  void start_gps();
+  void stop_gps();
+
+public:
+  WioTrackerL1SensorManager(LocationProvider &location) : _location(&location) {}
+  bool begin() override;
+  bool querySensors(uint8_t requester_permissions, CayenneLPP &telemetry) override;
+  void loop() override;
+  int getNumSettings() const override;
+  const char *getSettingName(int i) const override;
+  const char *getSettingValue(int i) const override;
+  bool setSettingValue(const char *name, const char *value) override;
+};
+
+
+extern WioTrackerL1Board board;
+extern WRAPPER_CLASS radio_driver;
+extern AutoDiscoverRTCClock rtc_clock;
+extern WioTrackerL1SensorManager sensors;
+#ifdef DISPLAY_CLASS
+  extern DISPLAY_CLASS display;
+#endif
+
+bool radio_init();
+uint32_t radio_get_rng_seed();
+void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
+void radio_set_tx_power(uint8_t dbm);
+mesh::LocalIdentity radio_new_identity();

+ 73 - 0
variants/wio-tracker-l1/variant.cpp

@@ -0,0 +1,73 @@
+#include "variant.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+#include "nrf.h"
+
+const uint32_t g_ADigitalPinMap[] = {
+    // D0 .. D10 - Peripheral control pins
+    41, // D0  P1.09    GNSS_WAKEUP
+    7,  // D1  P0.07     LORA_DIO1
+    39, // D2  P1,07     LORA_RESET
+    42, // D3  P1.10     LORA_BUSY
+    46, // D4  P1.14 (A4/SDA) LORA_CS
+    40, // D5  P1.08 (A5/SCL) LORA_SW
+    27, // D6  P0.27 (UART_TX) GNSS_TX
+    26, // D7  P0.26 (UART_RX) GNSS_RX
+    30, // D8  P0.30 (SPI_SCK) LORA_SCK
+    3,  // D9  P0.3 (SPI_MISO) LORA_MISO
+    28, // D10 P0.28 (SPI_MOSI) LORA_MOSI
+
+    // D11-D12 - LED outputs
+    33, // D11 P1.1 User LED
+    // Buzzzer
+    32, // D12 P1.0 Buzzer
+
+    // D13 - User input
+    8, // D13 P0.08 User Button
+
+    // D14-D15 - OLED
+    6, // D14 P0.06 OLED SDA
+    5, // D15 P0.05 OLED SCL
+
+    // D16 - Battery voltage ADC input
+    31, // D16 P0.31 VBAT_ADC
+    // GROVE
+    43, // D17 P0.00 GROVE SDA
+    44, // D18 P0.01 GROVE SCL
+
+    // FLASH
+    21, // D19 P0.21 (QSPI_SCK)
+    25, // D20 P0.25 (QSPI_CSN)
+    20, // D21 P0.20 (QSPI_SIO_0 DI)
+    24, // D22 P0.24 (QSPI_SIO_1 DO)
+    22, // D23 P0.22 (QSPI_SIO_2 WP)
+    23, // D24 P0.23 (QSPI_SIO_3 HOLD)
+
+    // JOYSTICK
+    36, // D25 TB_UP
+    12, // D26 TB_DOWN
+    11, // D27 TB_LEFT
+    35, // D28 TB_RIGHT
+    37, // D29 TB_PRESS
+
+    // VBAT ENABLE
+    4,  // D30 BAT_CTL
+};
+
+void initVariant() {
+    pinMode(PIN_QSPI_CS, OUTPUT);
+    digitalWrite(PIN_QSPI_CS, HIGH);
+
+    // VBAT_ENABLE
+    pinMode(VBAT_ENABLE, OUTPUT);
+    digitalWrite(VBAT_ENABLE, HIGH);
+
+    // set LED pin as output and set it low
+    pinMode(PIN_LED, OUTPUT);
+    digitalWrite(PIN_LED, LOW);
+    
+    // set buzzer pin as output and set it low
+    pinMode(12, OUTPUT);
+    digitalWrite(12, LOW);
+    pinMode(12, OUTPUT);
+}

+ 102 - 0
variants/wio-tracker-l1/variant.h

@@ -0,0 +1,102 @@
+#ifndef _SEEED_WIO_TRACKER_L1_H_
+#define _SEEED_WIO_TRACKER_L1_H_
+
+/** Master clock frequency */
+#define VARIANT_MCK             (64000000ul)
+
+#define USE_LFXO                // Board uses 32khz crystal for LF
+
+/*----------------------------------------------------------------------------
+ *        Headers
+ *----------------------------------------------------------------------------*/
+
+#include "WVariant.h"
+
+#define PINS_COUNT              (33)
+#define NUM_DIGITAL_PINS        (33)
+#define NUM_ANALOG_INPUTS       (8)
+#define NUM_ANALOG_OUTPUTS      (0)
+
+// LEDs
+#define PIN_LED                 (11)
+#define LED_BLUE                (-1) // Disable annoying flashing caused by Bluefruit
+#define LED_BUILTIN             PIN_LED
+#define P_LORA_TX_LED           PIN_LED
+#define LED_STATE_ON            1
+
+// Buttons
+#define PIN_BUTTON1             (13) // Menu / User Button
+#define PIN_BUTTON2             (25) // Joystick Up
+#define PIN_BUTTON3             (26) // Joystick Down
+#define PIN_BUTTON4             (27) // Joystick Left
+#define PIN_BUTTON5             (28) // Joystick Right
+#define PIN_BUTTON6             (28) // Joystick Press
+#define PIN_USER_BTN            PIN_BUTTON1
+#define JOYSTICK_UP             PIN_BUTTON2
+#define JOYSTICK_DOWN           PIN_BUTTON3
+#define JOYSTICK_LEFT           PIN_BUTTON4
+#define JOYSTICK_RIGHT          PIN_BUTTON5
+#define JOYSTICK_PRESS          PIN_BUTTON6
+
+// Buzzer
+// #define PIN_BUZZER           (12) // Buzzer pin (defined per firmware type)
+
+#define VBAT_ENABLE             (30)
+
+// Analog pins
+#define PIN_VBAT_READ           (16)
+#define AREF_VOLTAGE            (3.6F)
+#define ADC_MULTIPLIER          (2.0F)
+#define ADC_RESOLUTION          (12)
+
+// Serial interfaces
+#define PIN_SERIAL1_RX          (7)
+#define PIN_SERIAL1_TX          (6)
+
+// SPI Interfaces
+#define SPI_INTERFACES_COUNT    (1)
+
+#define PIN_SPI_MISO            (9)
+#define PIN_SPI_MOSI            (10)
+#define PIN_SPI_SCK             (8)
+
+// Lora Pins
+#define  P_LORA_SCLK            PIN_SPI_SCK
+#define  P_LORA_MISO            PIN_SPI_MISO
+#define  P_LORA_MOSI            PIN_SPI_MOSI
+#define  P_LORA_DIO_1           (1)
+#define  P_LORA_RESET           (2)
+#define  P_LORA_BUSY            (3)
+#define  P_LORA_NSS             (4)
+#define  SX126X_RXEN            (5)
+#define  SX126X_TXEN            RADIOLIB_NC
+
+// Wire Interfaces
+#define WIRE_INTERFACES_COUNT   (2)
+
+#define PIN_WIRE_SDA            (14)
+#define PIN_WIRE_SCL            (15)
+#define PIN_WIRE1_SDA           (17)
+#define PIN_WIRE1_SCL           (18)
+#define I2C_NO_RESCAN
+#define DISPLAY_ADDRESS         0x3D  // SH1106 OLED I2C address
+
+// GPS L76KB
+#define GPS_BAUDRATE            9600
+#define PIN_GPS_TX              PIN_SERIAL1_RX
+#define PIN_GPS_RX              PIN_SERIAL1_TX
+#define PIN_GPS_STANDBY         (0)
+#define PIN_GPS_EN              (18)
+
+// QSPI Pins
+#define PIN_QSPI_SCK            (21)
+#define PIN_QSPI_CS             (22)
+#define PIN_QSPI_IO0            (23)
+#define PIN_QSPI_IO1            (24)
+#define PIN_QSPI_IO2            (25)
+#define PIN_QSPI_IO3            (26)
+
+#define EXTERNAL_FLASH_DEVICES P25Q16H
+#define EXTERNAL_FLASH_USE_QSPI
+
+#endif