diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index e3d705d9..3f8cf55b 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -53,7 +53,11 @@ #include #include static HeltecV3Board board; -#elif defined(ARDUINO_XIAO_ESP32C3) + #elif defined(HELTEC_LORA_V2) + #include + #include + static HeltecV2Board board; + #elif defined(ARDUINO_XIAO_ESP32C3) #include #include #include diff --git a/platformio.ini b/platformio.ini index 3648f1ad..7bce422f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,13 +29,32 @@ monitor_filters = esp32_exception_decoder extra_scripts = merge-bin.py build_src_filter = ${arduino_base.build_src_filter} -[Heltec_stick_lite] -extends = esp32_base -board = heltec_wireless_stick_lite - +; ================ [Heltec_lora32_v2] extends = esp32_base board = heltec_wifi_lora_32_V2 +build_flags = + ${esp32_base.build_flags} + -D HELTEC_LORA_V2 + -D RADIO_CLASS=CustomSX1276 + -D WRAPPER_CLASS=CustomSX1276Wrapper + -D LORA_TX_POWER=20 + -D P_LORA_TX_LED=25 +build_src_filter = ${esp32_base.build_src_filter} + +[env:Heltec_v2_terminal_chat] +extends = Heltec_lora32_v2 +build_flags = + ${Heltec_lora32_v2.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Heltec_lora32_v2.build_src_filter} +<../examples/simple_secure_chat/main.cpp> +lib_deps = + ${Heltec_lora32_v2.lib_deps} + adafruit/RTClib @ ^2.1.3 + densaugeo/base64 @ ~1.4.0 ; ================ [Heltec_lora32_v3] diff --git a/src/helpers/CustomSX1276.h b/src/helpers/CustomSX1276.h new file mode 100644 index 00000000..35d879fc --- /dev/null +++ b/src/helpers/CustomSX1276.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#define RH_RF95_MODEM_STATUS_CLEAR 0x10 +#define RH_RF95_MODEM_STATUS_HEADER_INFO_VALID 0x08 +#define RH_RF95_MODEM_STATUS_RX_ONGOING 0x04 +#define RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED 0x02 +#define RH_RF95_MODEM_STATUS_SIGNAL_DETECTED 0x01 + +class CustomSX1276 : public SX1276 { + public: + CustomSX1276(Module *mod) : SX1276(mod) { } + + bool isReceiving() { + return (getModemStatus() & + (RH_RF95_MODEM_STATUS_SIGNAL_DETECTED + | RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED + | RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0; + } + + int tryScanChannel() { + // start CAD + int16_t state = startChannelScan(); + RADIOLIB_ASSERT(state); + + // wait for channel activity detected or timeout + unsigned long timeout = millis() + 16; + while(!this->mod->hal->digitalRead(this->mod->getIrq()) && millis() < timeout) { + this->mod->hal->yield(); + if(this->mod->hal->digitalRead(this->mod->getGpio())) { + return(RADIOLIB_PREAMBLE_DETECTED); + } + } + return 0; // timed out + } +}; diff --git a/src/helpers/CustomSX1276Wrapper.h b/src/helpers/CustomSX1276Wrapper.h new file mode 100644 index 00000000..23e9b72e --- /dev/null +++ b/src/helpers/CustomSX1276Wrapper.h @@ -0,0 +1,26 @@ +#pragma once + +#include "CustomSX1276.h" +#include "RadioLibWrappers.h" + +class CustomSX1276Wrapper : public RadioLibWrapper { +public: + CustomSX1276Wrapper(CustomSX1276& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } + bool isReceiving() override { + if (((CustomSX1276 *)_radio)->isReceiving()) return true; + + idle(); // put into standby + // do some basic CAD (blocks for ~12780 micros (on SF 10)!) + bool activity = (((CustomSX1276 *)_radio)->tryScanChannel() == RADIOLIB_PREAMBLE_DETECTED); + idle(); + + return activity; + } + float getLastRSSI() const override { return ((CustomSX1276 *)_radio)->getRSSI(); } + float getLastSNR() const override { return ((CustomSX1276 *)_radio)->getSNR(); } + + float packetScore(float snr, int packet_len) override { + int sf = ((CustomSX1276 *)_radio)->spreadingFactor; + return packetScoreInt(snr, sf, packet_len); + } +}; diff --git a/src/helpers/HeltecV2Board.h b/src/helpers/HeltecV2Board.h new file mode 100644 index 00000000..b44448a1 --- /dev/null +++ b/src/helpers/HeltecV2Board.h @@ -0,0 +1,77 @@ +#pragma once + +#include + +// LoRa radio module pins for Heltec V2 +#define P_LORA_DIO_1 26 // DIO0 +#define P_LORA_NSS 18 +#define P_LORA_RESET RADIOLIB_NC // 14 +#define P_LORA_BUSY RADIOLIB_NC +#define P_LORA_SCLK 5 +#define P_LORA_MISO 19 +#define P_LORA_MOSI 27 + +// built-ins +#define PIN_VBAT_READ 37 +#define PIN_LED_BUILTIN 25 + +#include "ESP32Board.h" + +#include + +class HeltecV2Board : public ESP32Board { +public: + void begin() { + ESP32Board::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 enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) { + 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! + } + + uint16_t getBattMilliVolts() override { + analogReadResolution(10); + + uint32_t raw = 0; + for (int i = 0; i < 8; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / 8; + + return (1.883 * (2 * 3.3 / 1024.0) * raw) * 1000; + } + + const char* getManufacturerName() const override { + return "Heltec V2"; + } +};