diff --git a/boards/meshnology_w12.json b/boards/meshnology_w12.json new file mode 100644 index 0000000000..2e74af9b32 --- /dev/null +++ b/boards/meshnology_w12.json @@ -0,0 +1,43 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "partitions": "default_16MB.csv", + "memory_type": "qio_opi" + }, + "core": "esp32", + "extra_flags": [ + "-DBOARD_HAS_PSRAM", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_USB_MODE=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "psram_type": "opi", + "hwids": [["0x303A", "0x0002"], ["0x303A", "0x1001"]], + "mcu": "esp32s3", + "variant": "meshnology_w12" + }, + "connectivity": ["wifi", "bluetooth", "lora"], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": ["esp-builtin"], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino", "espidf"], + "name": "heltec_wifi_lora_32 v5 (16 MB FLASH, 8 MB PSRAM)", + "upload": { + "flash_size": "16MB", + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "use_1200bps_touch": true, + "wait_for_upload_port": true, + "require_upload_port": true, + "speed": 921600 + }, + "url": "https://heltec.org/", + "vendor": "heltec" +} \ No newline at end of file diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 09f74cbeaf..6da8cca2c2 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -1064,6 +1064,12 @@ bool MyMesh::setRxBoostedGain(bool enable) { return radio_driver.setRxBoostedGainMode(enable); } +#if defined(USE_LR2021) +bool MyMesh::configSideDetectors(const uint8_t sideDetSFs[], uint8_t num, float bw) { + return radio_driver.configSideDetectors(sideDetSFs, num, bw); +} +#endif + void MyMesh::formatNeighborsReply(char *reply) { char *dp = reply; diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index aa7d30b062..ff35cfab20 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -255,4 +255,8 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { bool setRxBoostedGain(bool enable) override; + #if defined(USE_LR2021) + virtual bool configSideDetectors(const uint8_t sideDetSFs[], uint8_t num, float bw) override; + #endif + }; diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 9d0571d987..07181e16ad 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -753,6 +753,28 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep _prefs->adc_multiplier = 0.0f; strcpy(reply, "Error: unsupported"); }; + #if defined(USE_LR2021) + } else if (memcmp(config, "extra.sf ", 9) == 0) { + strcpy(tmp, &config[9]); + const char *parts[4]; + uint8_t sideDetSFs[4]; + int num = mesh::Utils::parseTextParts(tmp, parts, 4); + if (num > 3) { + sprintf(reply, "Invalid extra SF config"); + } else { + for (int i = 0; i < num; i++) { + sideDetSFs[i] = atoi(parts[i]); + } + sideDetSFs[num] = 0; + if (_callbacks->configSideDetectors(sideDetSFs, num, _prefs->bw)) { + for (int i = 0; i <= num; i++) _prefs->extra_sf[i] = sideDetSFs[i]; + savePrefs(); + sprintf(reply, "OK - extra SFs set"); + } else { + sprintf(reply, "Invalid extra SF config"); + } + } + #endif } else { strcpy(reply, "unknown config: "); StrHelper::strncpy(&reply[16], config, 160-17); @@ -922,6 +944,14 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep #else strcpy(reply, "ERROR: Power management not supported"); #endif + } else if (memcmp(config, "extra.sf", 8) == 0) { + char* tmp = reply; + for (int i = 0; i < 3 && _prefs->extra_sf[i] != 0; i++) { + tmp += sprintf(tmp, "%s%d", (i == 0) ? "" : ",", _prefs->extra_sf[i]); + } + if (tmp == reply) { + sprintf(reply, "No extra SF configured"); + } } else { sprintf(reply, "??: %s", config); } diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 69fe03150c..2a9ec43bcb 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -68,6 +68,7 @@ class NodePrefs : public ConfigSerializer { uint8_t path_hash_mode = 0; // which path mode to use when sending uint8_t loop_detect = 0; uint8_t cad_enabled = 0; // hardware Channel Activity Detection before TX (boolean) + uint8_t extra_sf[4]; private: class RadioPrefs : public ConfigSerializer { @@ -238,6 +239,12 @@ class CommonCLICallbacks { virtual bool setRxBoostedGain(bool enable) { return false; // CommonCLI reports unsupported if not overridden by wrapper }; + + #if defined(USE_LR2021) + virtual bool configSideDetectors(const uint8_t sideDetSFs[], uint8_t num, float bw) { + return false; // Override in wrapper + } + #endif }; class CommonCLI { diff --git a/src/helpers/radiolib/CustomLR2021.h b/src/helpers/radiolib/CustomLR2021.h new file mode 100644 index 0000000000..17944ef006 --- /dev/null +++ b/src/helpers/radiolib/CustomLR2021.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include "MeshCore.h" + +class CustomLR2021 : public LR2021 { + bool _rx_boosted = false; + + public: + CustomLR2021(Module *mod) : LR2021(mod) { irqDioNum = LR2021_IRQ_DIO; } + + bool std_init(SPIClass* spi = NULL) + { + + #ifdef LR2021_TCXO_VOLTAGE + float tcxo = LR2021_TCXO_VOLTAGE; + #else + float tcxo = 1.6f; + #endif + + #ifdef LORA_CR + uint8_t cr = LORA_CR; + #else + uint8_t cr = 5; + #endif + + #if defined(P_LORA_SCLK) + #ifdef NRF52_PLATFORM + if (spi) { spi->setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); spi->begin(); } + #elif defined(RP2040_PLATFORM) + if (spi) { + spi->setMISO(P_LORA_MISO); + //spi->setCS(P_LORA_NSS); // Setting CS results in freeze + spi->setSCK(P_LORA_SCLK); + spi->setMOSI(P_LORA_MOSI); + spi->begin(); + } + #else + if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + #endif + #endif + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f + if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) { + tcxo = 0.0f; + status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + } + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + setCRC(2); + explicitHeader(); + + + #ifdef LR2021_RX_BOOSTED_GAIN + setRxBoostedGainMode(LR2021_RX_BOOSTED_GAIN); + #endif + + return true; // success + } + + float getFreqMHz() const { return freqMHz; } + + bool getRxBoostedGainMode() const { return _rx_boosted; } + + bool isReceiving() { + uint32_t irq = getIrqStatus(); + bool detected = ((irq & RADIOLIB_LR2021_IRQ_SYNCWORD_VALID) || (irq & RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED)); + return detected; + } + + uint8_t getSpreadingFactor() const { return spreadingFactor; } +}; \ No newline at end of file diff --git a/src/helpers/radiolib/CustomLR2021Wrapper.h b/src/helpers/radiolib/CustomLR2021Wrapper.h new file mode 100644 index 0000000000..879898315e --- /dev/null +++ b/src/helpers/radiolib/CustomLR2021Wrapper.h @@ -0,0 +1,107 @@ +#pragma once + +#include "CustomLR2021.h" +#include "RadioLibWrappers.h" + +#ifndef USE_LR2021 +#define USE_LR2021 +#endif + +#ifndef LR2021_RX_BOOST_LEVEL +#define LR2021_RX_BOOST_LEVEL 7 +#endif + +class CustomLR2021Wrapper : public RadioLibWrapper { +public: + CustomLR2021Wrapper(CustomLR2021& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } + + void setParams(float freq, float bw, uint8_t sf, uint8_t cr) override { + ((CustomLR2021 *)_radio)->setFrequency(freq); + ((CustomLR2021 *)_radio)->setSpreadingFactor(sf); + ((CustomLR2021 *)_radio)->setBandwidth(bw); + ((CustomLR2021 *)_radio)->setCodingRate(cr); + updatePreamble(sf); + applySideDetectorConfig(); + } + + bool configSideDetectors(const uint8_t* sideDetSFs, uint8_t num, float bw) override { + LR2021LoRaSideDetector_t tmp[3]; + uint8_t sf = getSpreadingFactor(); + + if (sf >= 10 && num > 1) { return false; } // only 1 side detector allowed when primary SF >= 10 + for (int i = 0; i < num; i++) { + if (sideDetSFs[i] > 12 || sideDetSFs[i] < 5) { return false; } // must be valid SF + if (sideDetSFs[i] <= sf) { return false; } // must be < primary SF + if (sideDetSFs[i] > sf + 4) { return false; } // span must not be > 4 + + tmp[i].sf = sideDetSFs[i]; + float tSym = calcTsym(tmp[i].sf, bw); + if (tSym >= 16.0f) { + tmp[i].ldro = true; + } else { + tmp[i].ldro = false; + } + tmp[i].invertIQ = false; + tmp[i].syncWord = 0x12; + } + int16_t status = ((CustomLR2021 *)_radio)->setSideDetector(tmp, num); + RadioLibWrapper::idle(); // trigger startReceive() + MESH_DEBUG_PRINTLN("setSideDetector() returned %d", status); + + if (status == RADIOLIB_ERR_NONE) { + for (int i = 0; i < num; i++) { _sideDet[i] = tmp[i]; } + _numSideDet = num; + } else { + return false; + } + + return true; + } + + int16_t applySideDetectorConfig() { + int16_t status = ((CustomLR2021 *)_radio)->setSideDetector(_sideDet, _numSideDet); + RadioLibWrapper::idle(); // trigger startReceive() + return status; + } + + float calcTsym(uint8_t sf, float bw) { + float tSym = (float)(uint32_t(1) << sf) / (float)bw; + return tSym; + } + + bool isReceivingPacket() override { + return ((CustomLR2021 *)_radio)->isReceiving(); + } + + float getCurrentRSSI() override { + float rssi = -110; + ((CustomLR2021 *)_radio)->getRssiInst(&rssi); + return rssi; + } + + void onSendFinished() override { + RadioLibWrapper::onSendFinished(); + _radio->setPreambleLength(preambleLengthForSF(getSpreadingFactor())); // overcomes weird issues with small and big pkts + } + + float getLastRSSI() const override { return ((CustomLR2021 *)_radio)->getRSSI(); } + float getLastSNR() const override { return ((CustomLR2021 *)_radio)->getSNR(); } + + uint8_t getSpreadingFactor() const override { return ((CustomLR2021 *)_radio)->getSpreadingFactor(); } + + bool setRxBoostedGainMode(bool en) override { + ((CustomLR2021 *)_radio)->standby(); // LR2021 must be in standby to accept setRxBoostedGainMode + int16_t status = ((CustomLR2021 *)_radio)->setRxBoostedGainMode(en ? LR2021_RX_BOOST_LEVEL: 0); + RadioLibWrapper::idle(); // trigger startReceive() + return status == RADIOLIB_ERR_NONE; + } + + bool getRxBoostedGainMode() const override { + return ((CustomLR2021 *)_radio)->getRxBoostedGainMode(); + } + + protected: + LR2021LoRaSideDetector_t _sideDet[3]; + size_t _numSideDet = 0; + +}; diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index 7146e47b6a..dc851e5cfe 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -105,6 +105,9 @@ void RadioLibWrapper::loop() { } void RadioLibWrapper::startRecv() { + #if defined(USE_LR2021) + _radio->standby(); // without this LR2021 can throw -706 when calling startReceive after hardware CAD when side detectors are enabled + #endif int err = _radio->startReceive(); if (err == RADIOLIB_ERR_NONE) { state = STATE_RX; @@ -133,7 +136,11 @@ int RadioLibWrapper::recvRaw(uint8_t* bytes, int sz) { n_recv++; } } + #if defined(USE_LR2021) + state = STATE_RX; // LR2021 stays in Rx after readData, calling startReceive while still in Rx throws -706 errors + #else state = STATE_IDLE; // need another startReceive() + #endif } if (state != STATE_RX) { diff --git a/src/helpers/radiolib/RadioLibWrappers.h b/src/helpers/radiolib/RadioLibWrappers.h index e886c81b22..99f5ebbd8e 100644 --- a/src/helpers/radiolib/RadioLibWrappers.h +++ b/src/helpers/radiolib/RadioLibWrappers.h @@ -77,6 +77,8 @@ class RadioLibWrapper : public mesh::Radio { virtual bool setRxBoostedGainMode(bool) { return false; } virtual bool getRxBoostedGainMode() const { return false; } + + virtual bool configSideDetectors(const uint8_t sideDetSFs[], uint8_t num, float bw) { return false; } }; /** diff --git a/variants/meshnology_w12/MeshnologyW12Board.cpp b/variants/meshnology_w12/MeshnologyW12Board.cpp new file mode 100644 index 0000000000..25c0d4f1a8 --- /dev/null +++ b/variants/meshnology_w12/MeshnologyW12Board.cpp @@ -0,0 +1,83 @@ +#include "MeshnologyW12Board.h" + +void MeshnologyW12Board::begin() { + ESP32Board::begin(); + + pinMode(PIN_ADC_CTRL, OUTPUT); + digitalWrite(PIN_ADC_CTRL, LOW); // Disable battery sense until required + + pinMode(P_LORA_LF_PA_POWER, OUTPUT); + digitalWrite(P_LORA_LF_PA_POWER, HIGH); // PA_EN_M — power the GC1109 FEM + + pinMode(P_LORA_HF_PA_POWER, OUTPUT); + digitalWrite(P_LORA_HF_PA_POWER, LOW); // PA_EN_G — disable the 2.4GHz FEM + + delay(100); // give the GC1109 some time to start + + periph_power.begin(); + esp_reset_reason_t reason = esp_reset_reason(); + if (reason == ESP_RST_DEEPSLEEP) { + long wakeup_source = esp_sleep_get_ext1_wakeup_status(); + if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep) + startup_reason = BD_STARTUP_RX_PACKET; + } + + rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS); + rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1); + } + } + + void MeshnologyW12Board::onBeforeTransmit(void) { + neopixelWrite(NEOPIXEL_LED, NEOPIXEL_BRIGHTNESS, NEOPIXEL_BRIGHTNESS, NEOPIXEL_BRIGHTNESS); // turn TX neopixel on (White) + } + + void MeshnologyW12Board::onAfterTransmit(void) { + neopixelWrite(NEOPIXEL_LED, 0, 0, 0); // turn TX neopixel off + } + + void MeshnologyW12Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + + // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep + rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); + + rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); + + if (pin_wake_btn < 0) { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet + } else { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn + } + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); + } + + // Finally set ESP32 into sleep + esp_deep_sleep_start(); // CPU halts here and never returns! + } + + void MeshnologyW12Board::powerOff() { + enterDeepSleep(0); + } + + uint16_t MeshnologyW12Board::getBattMilliVolts() { + analogReadResolution(12); + analogSetAttenuation(ADC_11db); + digitalWrite(PIN_ADC_CTRL, HIGH); + delay(10); + uint32_t raw = 0; + for (int i = 0; i < 8; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / 8; + + digitalWrite(PIN_ADC_CTRL, LOW); + + return (adc_mult * (3.3 / 4096.0) * raw) * 1000; + } + + const char* MeshnologyW12Board::getManufacturerName() const { + return "Meshnology W12"; + } \ No newline at end of file diff --git a/variants/meshnology_w12/MeshnologyW12Board.h b/variants/meshnology_w12/MeshnologyW12Board.h new file mode 100644 index 0000000000..85bec99041 --- /dev/null +++ b/variants/meshnology_w12/MeshnologyW12Board.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +#ifndef ADC_MULTIPLIER + #define ADC_MULTIPLIER 5.42 +#endif + +class MeshnologyW12Board : public ESP32Board { + +protected: + float adc_mult = ADC_MULTIPLIER; + +public: + RefCountedDigitalPin periph_power; + MeshnologyW12Board() : periph_power(PIN_VEXT_EN, PIN_VEXT_EN_ACTIVE) { } + + void begin(); + void onBeforeTransmit(void) override; + void onAfterTransmit(void) override; + void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1); + void powerOff() override; + uint16_t getBattMilliVolts() override; + bool setAdcMultiplier(float multiplier) override { + if (multiplier == 0.0f) { + adc_mult = ADC_MULTIPLIER; + } else { + adc_mult = multiplier; + } + return true; + } + float getAdcMultiplier() const override { return adc_mult; } + const char* getManufacturerName() const override; +}; diff --git a/variants/meshnology_w12/pins_arduino.h b/variants/meshnology_w12/pins_arduino.h new file mode 100644 index 0000000000..5cfb36970b --- /dev/null +++ b/variants/meshnology_w12/pins_arduino.h @@ -0,0 +1,69 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +static const uint8_t LED_BUILTIN = -1; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 3; +static const uint8_t SCL = 4; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 10; +static const uint8_t MISO = 11; +static const uint8_t SCK = 9; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t Vext = 45; +static const uint8_t LED = -1; +static const uint8_t RST_OLED = 21; +static const uint8_t SCL_OLED = 18; +static const uint8_t SDA_OLED = 17; + +static const uint8_t RST_LoRa = 12; +static const uint8_t BUSY_LoRa = 13; +static const uint8_t DIO0 = 14; + + + +#endif /* Pins_Arduino_h */ \ No newline at end of file diff --git a/variants/meshnology_w12/platformio.ini b/variants/meshnology_w12/platformio.ini new file mode 100644 index 0000000000..1168f10a0f --- /dev/null +++ b/variants/meshnology_w12/platformio.ini @@ -0,0 +1,216 @@ +[meshnology_w12] +extends = esp32_base +board = meshnology_w12 +build_flags = + ${esp32_base.build_flags} + ${sensor_base.build_flags} + -I variants/meshnology_w12 + -D MESHNOLOGY_W12 + -D ESP32_CPU_FREQ=80 + -D RADIO_CLASS=CustomLR2021 + -D WRAPPER_CLASS=CustomLR2021Wrapper + -D USE_LR2021 + -D NEOPIXEL_LED=46 + -D NEOPIXEL_BRIGHTNESS=64 + -D P_LORA_DIO_1=14 + -D LR2021_IRQ_DIO=8 ; GPIO14 is connected to LR2021 DIO8 + -D P_LORA_NSS=8 + -D P_LORA_SCLK=9 + -D P_LORA_MOSI=10 + -D P_LORA_MISO=11 + -D P_LORA_RESET=12 + -D P_LORA_BUSY=13 + -D LR2021_TCXO_VOLTAGE=0.0f ; this board has no tcxo + -D RF_SWITCH_TABLE ; used below in commented code for the RF switch table. + -D P_LORA_LF_PA_POWER=4 ; PA_EN_M - power enable for the GC1109 868/915 PA + -D P_LORA_HF_PA_POWER=3 ; PA_EN_G - power enable for RFX2402E 2.4G PA + -D PIN_USER_BTN=0 + -D PIN_VEXT_EN=45 + -D PIN_VEXT_EN_ACTIVE=HIGH + -D LORA_TX_POWER=4 + -D MAX_LORA_TX_POWER=4 ; GC1109 datasheet says max input at TX port is +5dbm, confirmed full saturation seems to occur at around 3-4dbm + -D PIN_GPS_RX=38 + -D PIN_GPS_TX=39 + -D PIN_GPS_RESET=42 + -D PIN_GPS_RESET_ACTIVE=LOW + -D PIN_GPS_EN=48 + -D PIN_GPS_EN_ACTIVE=LOW + ; -D ENV_INCLUDE_GPS=1 + -D PIN_VBAT_READ=1 + -D PIN_ADC_CTRL=2 + -D PIN_BOARD_SDA=17 + -D PIN_BOARD_SCL=18 + -D PIN_RESET=47 +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/meshnology_w12> + + +lib_deps = + ${esp32_base.lib_deps} + ${sensor_base.lib_deps} + +[env:meshnology_w12_repeater] +extends = meshnology_w12 +build_flags = + ${meshnology_w12.build_flags} + -D DISPLAY_CLASS=SSD1306Display + -D ADVERT_NAME='"Meshnology W12 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +build_src_filter = ${meshnology_w12.build_src_filter} + + + +<../examples/simple_repeater> +lib_deps = + ${meshnology_w12.lib_deps} + ${esp32_ota.lib_deps} + bakercp/CRC32 @ ^2.0.0 + +[env:meshnology_w12_repeater_bridge_espnow] +extends = meshnology_w12 +build_flags = + ${meshnology_w12.build_flags} + -D DISPLAY_CLASS=SSD1306Display + -D ADVERT_NAME='"ESPNow Bridge"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 + -D WITH_ESPNOW_BRIDGE=1 + ; -D BRIDGE_DEBUG=1 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +build_src_filter = ${meshnology_w12.build_src_filter} + + + + + +<../examples/simple_repeater> +lib_deps = + ${meshnology_w12.lib_deps} + ${esp32_ota.lib_deps} + +[env:meshnology_w12_room_server] +extends = meshnology_w12 +build_flags = + ${meshnology_w12.build_flags} + -D DISPLAY_CLASS=SSD1306Display + -D ADVERT_NAME='"Meshnology W12 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 +build_src_filter = ${meshnology_w12.build_src_filter} + + + +<../examples/simple_room_server> +lib_deps = + ${meshnology_w12.lib_deps} + ${esp32_ota.lib_deps} + +[env:meshnology_w12_terminal_chat] +extends = meshnology_w12 +build_flags = + ${meshnology_w12.build_flags} + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=1 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +build_src_filter = ${meshnology_w12.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> +lib_deps = + ${meshnology_w12.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:meshnology_w12_companion_radio_usb] +extends = meshnology_w12 +build_flags = + ${meshnology_w12.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D DISPLAY_CLASS=SSD1306Display +; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 +; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 +build_src_filter = ${meshnology_w12.build_src_filter} + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${meshnology_w12.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:meshnology_w12_companion_radio_ble] +extends = meshnology_w12 +build_flags = + ${meshnology_w12.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D DISPLAY_CLASS=SSD1306Display + -D BLE_PIN_CODE=123456 ; dynamic, random PIN + ; -D AUTO_SHUTDOWN_MILLIVOLTS=3400 ; disabled by default, otherwise reading bounce causes shutdown when there's no battery connected. + ; -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +build_src_filter = ${meshnology_w12.build_src_filter} + + + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${meshnology_w12.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:meshnology_w12_companion_radio_wifi] +extends = meshnology_w12 +build_flags = + ${meshnology_w12.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D OFFLINE_QUEUE_SIZE=256 + -D DISPLAY_CLASS=SSD1306Display + ; -D WIFI_DEBUG_LOGGING=1 + -D WIFI_SSID='"myssid"' + -D WIFI_PWD='"mypwd"' + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +build_src_filter = ${meshnology_w12.build_src_filter} + + + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${meshnology_w12.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:meshnology_w12_sensor] +extends = meshnology_w12 +build_flags = + ${meshnology_w12.build_flags} + -D ADVERT_NAME='"Meshnology W12 Sensor"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ENV_PIN_SDA=3 + -D ENV_PIN_SCL=4 + -D DISPLAY_CLASS=SSD1306Display + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +build_src_filter = ${meshnology_w12.build_src_filter} + + + +<../examples/simple_sensor> +lib_deps = + ${meshnology_w12.lib_deps} + ${esp32_ota.lib_deps} + +[env:meshnology_w12_kiss_modem] +extends = meshnology_w12 +build_src_filter = ${meshnology_w12.build_src_filter} + +<../examples/kiss_modem/> diff --git a/variants/meshnology_w12/target.cpp b/variants/meshnology_w12/target.cpp new file mode 100644 index 0000000000..bf04ba3647 --- /dev/null +++ b/variants/meshnology_w12/target.cpp @@ -0,0 +1,73 @@ +#include +#include "target.h" + +MeshnologyW12Board board; + +#if defined(P_LORA_SCLK) + static SPIClass spi; + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); +#else + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); +#endif + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); + +#if ENV_INCLUDE_GPS + #include + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); + EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#else + EnvironmentSensorManager sensors; +#endif + +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display(NULL); + MomentaryButton user_btn(PIN_USER_BTN, 1000, true); +#endif + +const uint32_t rfswitch_dios[] = { + RADIOLIB_LR2021_DIO5, // RFX2402E 2.4G_TX_EN + RADIOLIB_LR2021_DIO6, // RFX2402E 2.4G_RX_EN + RADIOLIB_LR2021_DIO9, // GC1109 CTX (Transmit mode) + RADIOLIB_LR2021_DIO10, // GC1109 CPS (Bypass mode) + RADIOLIB_LR2021_DIO11, // GC1109 CSD (Shutdown) +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // DIO5 DIO6 DIO9 DIO10 DIO11 + { LR2021::MODE_STBY, { LOW, LOW, LOW, LOW, LOW } }, // everything off + { LR2021::MODE_RX, { LOW, LOW, LOW, LOW, HIGH } }, // rx_lf: GC1109 LNA + { LR2021::MODE_TX, { LOW, LOW, HIGH, HIGH, HIGH } }, // tx_lf: GC1109 full PA + { LR2021::MODE_RX_HF, { LOW, HIGH, LOW, LOW, LOW } }, // rx_hf: 2G4 LNA, GC1109 off + { LR2021::MODE_TX_HF, { HIGH, LOW, LOW, LOW, LOW } }, // tx_hf: 2G4 PA, GC1109 off + END_OF_MODE_TABLE, +}; + + +bool radio_init() { + fallback_clock.begin(); + rtc_clock.begin(Wire); + +#if defined(P_LORA_SCLK) + int err = radio.std_init(&spi); + if (err != 1) return err; +#else + int err = radio.std_init(); + if (err != 1) return err; +#endif + +#ifdef RF_SWITCH_TABLE + radio.setRfSwitchTable(rfswitch_dios, rfswitch_table); +#endif + + return true; +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} + diff --git a/variants/meshnology_w12/target.h b/variants/meshnology_w12/target.h new file mode 100644 index 0000000000..1bf8876b28 --- /dev/null +++ b/variants/meshnology_w12/target.h @@ -0,0 +1,28 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include + #include +#endif + +extern MeshnologyW12Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; + +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; + extern MomentaryButton user_btn; +#endif + +bool radio_init(); +mesh::LocalIdentity radio_new_identity(); +