Browse Source

Add HELTEC MeshSolar board.

Quency-D 1 năm trước cách đây
mục cha
commit
612dde73e9

+ 61 - 0
boards/heltec_mesh_solar.json

@@ -0,0 +1,61 @@
+{
+  "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": "HT-n5262",
+    "mcu": "nrf52840",
+    "variant": "heltec_mesh_solar",
+    "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": "nrf52.cfg"
+  },
+  "frameworks": [
+    "arduino"
+  ],
+  "name": "Heltec Mesh Solar Board",
+  "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://heltec.org/",
+  "vendor": "Heltec"
+}

+ 77 - 0
src/helpers/nrf52/MeshSolarBoard.cpp

@@ -0,0 +1,77 @@
+#include <Arduino.h>
+#include "MeshSolarBoard.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 MeshSolarBoard::begin() {
+  // for future use, sub-classes SHOULD call this from their begin()
+  startup_reason = BD_STARTUP_NORMAL;
+
+  meshSolarStart();
+
+#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
+  Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
+#endif
+
+  Wire.begin();
+}
+
+bool MeshSolarBoard::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("MESH_SOLAR_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
+
+  strcpy(reply, "OK - started");
+  return true;
+}

+ 44 - 0
src/helpers/nrf52/MeshSolarBoard.h

@@ -0,0 +1,44 @@
+#pragma once
+
+#include <MeshCore.h>
+#include <Arduino.h>
+
+#ifdef HELTEC_MESH_SOLAR
+#include "meshSolarApp.h"
+#endif
+
+// LoRa radio module pins for Heltec T114
+#define  P_LORA_DIO_1     20
+#define  P_LORA_NSS       24
+#define  P_LORA_RESET     25
+#define  P_LORA_BUSY      17
+#define  P_LORA_SCLK      19
+#define  P_LORA_MISO      23
+#define  P_LORA_MOSI      22
+
+#define SX126X_DIO2_AS_RF_SWITCH  true
+#define SX126X_DIO3_TCXO_VOLTAGE   1.8
+
+
+class MeshSolarBoard : public mesh::MainBoard {
+protected:
+  uint8_t startup_reason;
+
+public:
+  void begin();
+  uint8_t getStartupReason() const override { return startup_reason; }
+
+  uint16_t getBattMilliVolts() override {
+    return meshSolarGetBattVoltage();
+  }
+
+  const char* getManufacturerName() const override {
+    return "Heltec Mesh Solar";
+  }
+
+  void reboot() override {
+    NVIC_SystemReset();
+  }
+
+  bool startOTAUpdate(const char* id, char reply[]) override;
+};

+ 92 - 0
variants/heltec_mesh_solar/platformio.ini

@@ -0,0 +1,92 @@
+[Heltec_mesh_solar]
+extends = nrf52_base
+board = heltec_mesh_solar
+platform_packages = framework-arduinoadafruitnrf52
+board_build.ldscript = boards/nrf52840_s140_v6.ld
+build_flags =  ${nrf52_base.build_flags}
+  -I src/helpers/nrf52
+  -I lib/nrf52/s140_nrf52_6.1.1_API/include
+  -I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
+  -I variants/heltec_mesh_solar
+  -D HELTEC_MESH_SOLAR
+  -D RADIO_CLASS=CustomSX1262
+  -D WRAPPER_CLASS=CustomSX1262Wrapper
+  -D LORA_TX_POWER=22
+  -D SX126X_CURRENT_LIMIT=140
+  -D SX126X_RX_BOOSTED_GAIN=1
+build_src_filter = ${nrf52_base.build_src_filter}
+  +<helpers/*.cpp>
+  +<helpers/nrf52/MeshSolarBoard.cpp>
+  +<../variants/heltec_mesh_solar>
+lib_deps =
+  ${nrf52_base.lib_deps}
+  rweather/Crypto @ ^0.4.0
+  stevemarple/MicroNMEA @ ^2.0.6
+  adafruit/Adafruit NeoPixel@^1.10.0
+  https://github.com/NMIoT/meshsolar/archive/dfc5330dad443982e6cdd37a61d33fc7252f468b.zip
+debug_tool = jlink
+upload_protocol = nrfutil
+
+[env:Heltec_mesh_solar_repeater]
+extends = Heltec_mesh_solar
+build_src_filter = ${Heltec_mesh_solar.build_src_filter}
+  +<../examples/simple_repeater>
+
+build_flags =
+  ${Heltec_mesh_solar.build_flags}
+  -D ADVERT_NAME='"Heltec_Mesh_Solar Repeater"'
+  -D ADVERT_LAT=0.0
+  -D ADVERT_LON=0.0
+  -D ADMIN_PASSWORD='"password"'
+  -D MAX_NEIGHBOURS=8
+;  -D MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+
+[env:Heltec_mesh_solar_room_server]
+extends = Heltec_mesh_solar
+build_src_filter = ${Heltec_mesh_solar.build_src_filter}
+  +<../examples/simple_room_server>
+build_flags =
+  ${Heltec_mesh_solar.build_flags}
+  -D ADVERT_NAME='"Heltec_Mesh_Solar Room"'
+  -D ADVERT_LAT=0.0
+  -D ADVERT_LON=0.0
+  -D ADMIN_PASSWORD='"password"'
+  -D ROOM_PASSWORD='"hello"'
+;  -D MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+
+[env:Heltec_mesh_solar_companion_radio_ble]
+extends = Heltec_mesh_solar
+build_flags =
+  ${Heltec_mesh_solar.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 MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+build_src_filter = ${Heltec_mesh_solar.build_src_filter}
+  +<helpers/nrf52/SerialBLEInterface.cpp>
+  +<../examples/companion_radio>
+lib_deps =
+  ${Heltec_mesh_solar.lib_deps}
+  densaugeo/base64 @ ~1.4.0
+
+[env:Heltec_mesh_solar_companion_radio_usb]
+extends = Heltec_mesh_solar
+build_flags =
+  ${Heltec_mesh_solar.build_flags}
+  -D MAX_CONTACTS=100
+  -D MAX_GROUP_CHANNELS=8
+;  -D BLE_PIN_CODE=123456
+;  -D BLE_DEBUG_LOGGING=1
+;  -D MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+build_src_filter = ${Heltec_mesh_solar.build_src_filter}
+  +<helpers/nrf52/*.cpp>
+  +<../examples/companion_radio>
+lib_deps =
+  ${Heltec_mesh_solar.lib_deps}
+  densaugeo/base64 @ ~1.4.0

+ 123 - 0
variants/heltec_mesh_solar/target.cpp

@@ -0,0 +1,123 @@
+#include <Arduino.h>
+#include "target.h"
+#include <helpers/ArduinoHelpers.h>
+#include <helpers/sensors/MicroNMEALocationProvider.h>
+
+MeshSolarBoard 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);
+SolarSensorManager sensors = SolarSensorManager(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);
+}
+
+mesh::LocalIdentity radio_new_identity() {
+  RadioNoiseListener rng(radio);
+  return mesh::LocalIdentity(&rng);  // create new random identity
+}
+
+void SolarSensorManager::start_gps() {
+  if (!gps_active) {
+    gps_active = true;
+    _location->begin();
+  }
+}
+
+void SolarSensorManager::stop_gps() {
+  if (gps_active) {
+    gps_active = false;
+    _location->stop();
+  }
+}
+
+bool SolarSensorManager::begin() {
+  Serial1.begin(9600);
+
+  // We'll consider GPS detected if we see any data on Serial1
+  gps_detected = (Serial1.available() > 0);
+
+  if (gps_detected) {
+    MESH_DEBUG_PRINTLN("GPS detected");
+  } else {
+    MESH_DEBUG_PRINTLN("No GPS detected");
+  }
+
+  return true;
+}
+
+bool SolarSensorManager::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 SolarSensorManager::loop() {
+  static long next_gps_update = 0;
+
+  _location->loop();
+
+  if (millis() > next_gps_update) {
+    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;
+  }
+}
+
+int SolarSensorManager::getNumSettings() const {
+  return gps_detected ? 1 : 0;  // only show GPS setting if GPS is detected
+}
+
+const char* SolarSensorManager::getSettingName(int i) const {
+  return (gps_detected && i == 0) ? "gps" : NULL;
+}
+
+const char* SolarSensorManager::getSettingValue(int i) const {
+  if (gps_detected && i == 0) {
+    return gps_active ? "1" : "0";
+  }
+  return NULL;
+}
+
+bool SolarSensorManager::setSettingValue(const char* name, const char* value) {
+  if (gps_detected && strcmp(name, "gps") == 0) {
+    if (strcmp(value, "0") == 0) {
+      stop_gps();
+    } else {
+      start_gps();
+    }
+    return true;
+  }
+  return false;  // not supported
+}

+ 46 - 0
variants/heltec_mesh_solar/target.h

@@ -0,0 +1,46 @@
+#pragma once
+
+#define RADIOLIB_STATIC_ONLY 1
+#include <RadioLib.h>
+#include <helpers/radiolib/RadioLibWrappers.h>
+#include <helpers/nrf52/MeshSolarBoard.h>
+#include <helpers/radiolib/CustomSX1262Wrapper.h>
+#include <helpers/AutoDiscoverRTCClock.h>
+#include <helpers/SensorManager.h>
+#include <helpers/sensors/LocationProvider.h>
+#ifdef DISPLAY_CLASS
+  #include <helpers/ui/ST7789Display.h>
+#endif
+
+class SolarSensorManager : public SensorManager {
+  bool gps_active = false;
+  bool gps_detected = false;
+  LocationProvider* _location;
+
+  void start_gps();
+  void stop_gps();
+public:
+  SolarSensorManager(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 MeshSolarBoard board;
+extern WRAPPER_CLASS radio_driver;
+extern AutoDiscoverRTCClock rtc_clock;
+extern SolarSensorManager 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();

+ 16 - 0
variants/heltec_mesh_solar/variant.cpp

@@ -0,0 +1,16 @@
+#include "variant.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+
+const uint32_t g_ADigitalPinMap[] = {
+  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, 32, 33, 34, 35, 36, 37, 38, 39,
+  40, 41, 42, 43, 44, 45, 46, 47
+};
+
+void initVariant()
+{
+  pinMode(PIN_USER_BTN, INPUT);
+  pinMode(BQ4050_EMERGENCY_SHUTDOWN_PIN, INPUT);
+}

+ 127 - 0
variants/heltec_mesh_solar/variant.h

@@ -0,0 +1,127 @@
+/*
+ * variant.h
+ * Copyright (C) 2023 Seeed K.K.
+ * MIT License
+ */
+
+#pragma once
+
+#include "WVariant.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Low frequency clock source
+
+#define USE_LFXO    // 32.768 kHz crystal oscillator
+#define VARIANT_MCK (64000000ul)
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Power
+
+#define NRF_APM
+
+////////////////////////////////////////////////////////////////////////////////
+// Number of pins
+
+#define PINS_COUNT              (48)
+#define NUM_DIGITAL_PINS        (48)
+#define NUM_ANALOG_INPUTS       (1)
+#define NUM_ANALOG_OUTPUTS      (0)
+
+////////////////////////////////////////////////////////////////////////////////
+// UART pin definition
+
+#define PIN_SERIAL1_RX          (37)
+#define PIN_SERIAL1_TX          (39)
+
+#define PIN_SERIAL2_RX          (9)
+#define PIN_SERIAL2_TX          (10)
+
+////////////////////////////////////////////////////////////////////////////////
+// I2C pin definition
+#define WIRE_INTERFACES_COUNT 	(2)
+
+#define PIN_WIRE_SDA            (6) 
+#define PIN_WIRE_SCL            (26)
+
+#define PIN_WIRE1_SDA           (30) 
+#define PIN_WIRE1_SCL           (5)
+
+////////////////////////////////////////////////////////////////////////////////
+// SPI pin definition
+
+#define SPI_INTERFACES_COUNT    (2)
+
+#define PIN_SPI_MISO            (23)
+#define PIN_SPI_MOSI            (22)
+#define PIN_SPI_SCK             (19)
+#define PIN_SPI_NSS             (24)
+
+////////////////////////////////////////////////////////////////////////////////
+// Builtin LEDs
+
+#define LED_BUILTIN             (12)
+#define PIN_LED                 LED_BUILTIN
+#define LED_RED                 LED_BUILTIN
+#define LED_BLUE                (-1)            // No blue led, prevents Bluefruit flashing the green LED during advertising
+#define LED_PIN                 LED_BUILTIN
+
+#define LED_STATE_ON            LOW
+
+#define PIN_NEOPIXEL            (47)
+#define NEOPIXEL_NUM            (1)
+
+////////////////////////////////////////////////////////////////////////////////
+// Builtin buttons
+
+#define PIN_BUTTON1             (42)
+#define BUTTON_PIN              PIN_BUTTON1
+
+// #define PIN_BUTTON2             (11)
+// #define BUTTON_PIN2             PIN_BUTTON2
+
+#define PIN_USER_BTN            BUTTON_PIN
+
+#define EXTERNAL_FLASH_DEVICES MX25R1635F
+#define EXTERNAL_FLASH_USE_QSPI
+
+////////////////////////////////////////////////////////////////////////////////
+// Lora
+
+#define USE_SX1262
+#define LORA_CS                 (24)
+#define SX126X_DIO1             (20)
+#define SX126X_BUSY             (17)
+#define SX126X_RESET            (25)
+#define SX126X_DIO2_AS_RF_SWITCH
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+
+#define PIN_SPI1_MISO           (43)
+#define PIN_SPI1_MOSI           (41)
+#define PIN_SPI1_SCK            (40)
+
+////////////////////////////////////////////////////////////////////////////////
+// Buzzer
+
+// #define PIN_BUZZER              (46)
+
+
+////////////////////////////////////////////////////////////////////////////////
+// GPS
+
+#define GPS_RESET               (38)
+
+////////////////////////////////////////////////////////////////////////////////
+// TFT
+// #define PIN_TFT_SCL             (40)
+// #define PIN_TFT_SDA             (41)
+// #define PIN_TFT_RST             (2)
+// #define PIN_TFT_VDD_CTL         (3)
+// #define PIN_TFT_LEDA_CTL        (15)
+// #define PIN_TFT_CS              (11)
+// #define PIN_TFT_DC              (12)
+
+////////////////////////////////////////////////////////////////////////////////
+#define BQ4050_SDA_PIN                      (33) // I2C data line pin
+#define BQ4050_SCL_PIN                      (32) // I2C clock line pin
+#define BQ4050_EMERGENCY_SHUTDOWN_PIN       (35) // Emergency shutdown pin