diff --git a/include/LiLyGo.h b/include/LiLyGo.h index ec8754c..3c0c262 100644 --- a/include/LiLyGo.h +++ b/include/LiLyGo.h @@ -1,32 +1,4 @@ -#define UNUSED_PIN (0) -// LilyGo defined - -#define I2C_SDA 18 -#define I2C_SCL 17 -#define OLED_RST UNUSED_PIN - -#define RADIO_SCLK_PIN 5 -#define RADIO_MISO_PIN 3 -#define RADIO_MOSI_PIN 6 -#define RADIO_CS_PIN 7 - -#define SDCARD_MOSI 11 -#define SDCARD_MISO 2 -#define SDCARD_SCLK 14 -#define SDCARD_CS 13 - -#define BOARD_LED 37 -#define LED_ON HIGH - -#define BUTTON_PIN 0 -#define ADC_PIN 1 - -#define RADIO_RST_PIN 8 - -#define RADIO_DIO1_PIN 33 -#define RADIO_BUSY_PIN 34 - // Define for our code #define RST_OLED UNUSED_PIN #define LED BOARD_LED @@ -52,11 +24,16 @@ #include SPIClass *hspi = new SPIClass(2); SX1262 radio = new Module(SS, DIO1, RST_LoRa, BUSY_LoRa, *hspi); -#else +#else // ARDUINO_heltec_wifi_32_lora_V3 +#ifdef USING_SX1280PA +SX1280 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN); +#endif // end USING_SX1280PA +#ifdef USING_SX1262 // Default SPI on pins from pins_arduino.h SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN); -#endif -#endif +#endif // end USING_SX1262 +#endif // end ARDUINO_heltec_wifi_32_lora_V3 +#endif // end HELTEC_NO_RADIO_INSTANCE void heltec_loop() {} @@ -107,7 +84,7 @@ PrintSplitter both(Serial, display); Print &both = Serial; #endif // some fake pin -#define BUTTON 38 +#define BUTTON BUTTON_PIN #include "HotButton.h" HotButton button(BUTTON); diff --git a/include/global_config.h b/include/global_config.h index d169fff..f8205e6 100644 --- a/include/global_config.h +++ b/include/global_config.h @@ -1,15 +1,21 @@ #ifndef __GLOBAL_CONFIG_H__ #define __GLOBAL_CONFIG_H__ +#ifndef FREQ_BEGIN // frequency range in MHz to scan #define FREQ_BEGIN 850 +#endif + +#ifndef FREQ_END // TODO: if % RANGE_PER_PAGE != 0 #define FREQ_END 950 +#endif // Measurement bandwidth. Allowed bandwidth values (in kHz) are: // 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, // 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 #define BANDWIDTH 467.0 +#define BANDWIDTH_SX1280 406. // Detection level from the 33 levels. The higher number is more sensitive #define DEFAULT_DRONE_DETECTION_LEVEL 18 diff --git a/platformio.ini b/platformio.ini index 7145e78..5ff09ab 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,7 +30,7 @@ lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 build_flags = -DHELTEC_POWER_BUTTON -[env:lilygo-T3S3-v1-2] +[env:lilygo-T3S3-v1-2-sx1262] platform = espressif32 board = t3_s3_v1_x framework = arduino @@ -52,6 +52,30 @@ build_flags = -DARDUINO_LILYGO_T3_S3_V1_X -DARDUINO_USB_MODE=1 + +[env:lilygo-T3S3-v1-2-xs1280] +platform = espressif32 +board = t3_s3_v1_x +framework = arduino +upload_speed = 921600 +monitor_speed = 115200 +board_build.f_cpu = 240000000 +lib_deps = + ropg/Heltec_ESP32_LoRa_v3@^0.9.1 + RadioLib +build_flags = + -DLILYGO + -DT3_S3_V1_2_SX1280_PA + -DARDUINO_LILYGO_T3S3_SX1280_PA + -DESP32 + -DUSING_SX1280PA + -DFREQ_BEGIN=2400 + -DFREQ_END=2500 + -DARDUINO_ARCH_ESP32 + -DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_LILYGO_T3_S3_V1_X + -DARDUINO_USB_MODE=1 + [env:heltec_wifi_lora_32_V3-test-signal-generator] platform = espressif32 board = heltec_wifi_lora_32_V3 diff --git a/src/main.cpp b/src/main.cpp index b6953bc..a7704e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,14 +29,21 @@ // #define WIFI_SCANNING_ENABLED true // #define BT_SCANNING_ENABLED true -// RSSI Scan Logic -#include +// Direct access to the low-level SPI communication between RadioLib and the radio module. +#define RADIOLIB_LOW_LEVEL (1) +// In this mode, all methods and member variables of all RadioLib classes will be made +// public and so will be exposed to the user. This allows direct manipulation of the +// library internals. +#define RADIOLIB_GODMODE (1) + +#include "radioScan/radioScan.h" #ifndef LILYGO #include // This file contains a binary patch for the SX1262 #include "modules/SX126x/patches/SX126x_patch_scan.h" -#elif defined(LILYGO) +#endif // end LILYGO +#if defined(LILYGO) // LiLyGO device does not support the auto download mode, you need to get into the // download mode manually. To do so, press and hold the BOOT button and then press the // RESET button once. After that release the BOOT button. Or OFF->ON together with BOOT @@ -45,7 +52,6 @@ #include "utilities.h" // Our Code #include "LiLyGo.h" - #endif // end LILYGO #define BT_SCAN_DELAY 60 * 1 * 1000 @@ -102,10 +108,16 @@ typedef enum METHOD_SPECTRAL } TSCAN_METOD_ENUM; +// #define SCAN_METHOD METHOD_SPECTRAL + #define SCAN_METHOD // #define METHOD_SPECTRAL // Spectral scan method #define METHOD_RSSI // Uncomment this and comment METHOD_SPECTRAL fot RSSI +// Output Pixel Formula +// 1 = rssi / 4, 2 = (rssi / 2) - 22 or 20 +// constexpr int RSSI_OUTPUT_FORMULA = 2; + // Feature to scan diapasones. Other frequency settings will be ignored. // int SCAN_RANGES[] = {850890, 920950}; int SCAN_RANGES[] = {}; @@ -114,15 +126,15 @@ int SCAN_RANGES[] = {}; // to put everything into one page set RANGE_PER_PAGE = FREQ_END - 800 uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN +// To Enable Multi Screen scan +// uint64_t RANGE_PER_PAGE = 50; +// Default Range on Menu Button Switch + // multiplies STEPS * N to increase scan resolution. #define SCAN_RBW_FACTOR 2 constexpr int OSD_PIXELS_PER_CHAR = (STEPS * SCAN_RBW_FACTOR) / OSD_CHART_WIDTH; -// To Enable Multi Screen scan -// uint64_t RANGE_PER_PAGE = 50; -// Default Range on Menu Button Switch - #define DEFAULT_RANGE_PER_PAGE 50 // Print spectrum values pixels at once or by line @@ -161,6 +173,7 @@ uint64_t median_frequency = FREQ_BEGIN + FREQ_END - FREQ_BEGIN / 2; // Array to store the scan results uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; bool filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; @@ -343,14 +356,19 @@ void init_radio() { // initialize SX1262 FSK modem at the initial frequency both.println("Init radio"); - state == radio.beginFSK(FREQ_BEGIN); - +#ifdef USING_SX1280PA + // radio.begin(); + state = radio.beginGFSK(FREQ_BEGIN); +#else + state = radio.beginFSK(FREQ_BEGIN); +#endif if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { + display.println("Error:" + String(state)); Serial.print(F("failed, code ")); Serial.println(state); while (true) @@ -372,15 +390,37 @@ void init_radio() #endif both.println("Setting up radio"); +#ifdef USING_SX1280PA + // RADIOLIB_OR_HALT(radio.setBandwidth(RADIOLIB_SX128X_LORA_BW_406_25)); +#else RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); +#endif // and disable the data shaping - RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); + state = radio.setDataShaping(RADIOLIB_SHAPING_NONE); + if (state != RADIOLIB_ERR_NONE) + { + Serial.println("Error:setDataShaping:" + String(state)); + } both.println("Starting scanning..."); - // calibrate only once ,,, at startup - // TODO: check documentation (9.2.1) if we must calibrate in certain ranges +// calibrate only once ,,, at startup +// TODO: check documentation (9.2.1) if we must calibrate in certain ranges +#ifdef USING_SX1280PA + state = radio.setFrequency(FREQ_BEGIN); + if (state != RADIOLIB_ERR_NONE) + { + Serial.println("Error:setFrequency:" + String(state)); + } + state = radio.startReceive(); + if (state != RADIOLIB_ERR_NONE) + { + Serial.println("Error:startReceive:" + String(state)); + } +#else radio.setFrequency(FREQ_BEGIN, true); +#endif + delay(50); } @@ -447,7 +487,7 @@ void setup(void) delay(400); display.clear(); - resolution = RANGE / (STEPS * SCAN_RBW_FACTOR); + resolution = (float)RANGE / (STEPS * SCAN_RBW_FACTOR); single_page_scan = (RANGE_PER_PAGE == range); @@ -510,7 +550,12 @@ void setup(void) #ifdef METHOD_RSSI // TODO: try RADIOLIB_SX126X_RX_TIMEOUT_INF +#ifdef USING_SX1280PA + state = radio.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_NONE); +#else state = radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_NONE); +#endif + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Failed to start receive mode, error code: ")); @@ -706,18 +751,30 @@ void check_ranges() struct RadioScan : Scan { - RadioScan() : Scan(RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) {} - float getRSSI() override; }; -float RadioScan::getRSSI() { return radio.getRSSI(false); } +float RadioScan::getRSSI() +{ +#ifdef USING_SX1280PA + // radio.startReceive(); + // get instantaneous RSSI value + // When PR will be merged we can use radi.getRSSI(false); + uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU + radio.mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3); + return ((float)data[0] / (-2.0)); +#else + return radio.getRSSI(false); +#endif +} // MAX Frequency RSSI BIN value of the samples int max_rssi_x = 999; RadioScan r; +RadioScan r; + void loop(void) { UI_displayDecorate(0, 0, false); // some default values @@ -835,7 +892,13 @@ void loop(void) Serial.println("setFrequency:" + String(freq)); #endif +#ifdef USING_SX1280PA + state = radio.setFrequency(freq); // 1280 doesn't have calibration + radio.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF); +#else state = radio.setFrequency(freq, false); // false = no calibration need here +#endif + int radio_error_count = 0; if (state != RADIOLIB_ERR_NONE) { display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); @@ -882,7 +945,8 @@ void loop(void) // Spectrum analyzer using getRSSI { LOG("METHOD RSSI"); - uint16_t max_rssi = r.rssiMethod(result); + uint16_t max_rssi = r.rssiMethod(SAMPLES_RSSI, result, + RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); if (max_x_rssi[display_x] > max_rssi) { max_x_rssi[display_x] = max_rssi; diff --git a/src/radioScan/radioScan.cpp b/src/radioScan/radioScan.cpp new file mode 100644 index 0000000..73150fc --- /dev/null +++ b/src/radioScan/radioScan.cpp @@ -0,0 +1,69 @@ +#ifndef LORASA_CORE_CPP +#define LORASA_CORE_CPP + +#include "radioScan.h" +#include +#include +#include + +uint16_t Scan::rssiMethod(size_t samples, uint16_t *result, size_t res_size) +{ + float scale((float)res_size / (HI_RSSI_THRESHOLD - LO_RSSI_THRESHOLD + 0.1)); + + memset(result, 0, res_size * sizeof(uint16_t)); + int result_index = 0; + + // + uint16_t max_signal = 65535; + // N of samples + for (int r = 0; r < samples; r++) + { + float rssi = getRSSI(); + if (rssi < -65535) + rssi = -65535; + + uint16_t abs_rssi = abs(rssi); + if (abs_rssi < max_signal) + { + max_signal = abs_rssi; + } + // ToDO: check if 4 is correct value for 33 power bins + // Now we have more space because we are ignoring low dB values + // we can / 3 default 4 + if (RSSI_OUTPUT_FORMULA == 1) + { + result_index = + /// still not clear formula but it works + uint8_t(abs(rssi) / 4); + } + else if (RSSI_OUTPUT_FORMULA == 2) + { + if (rssi > HI_RSSI_THRESHOLD) + { + rssi = HI_RSSI_THRESHOLD; + } + else if (rssi < LO_RSSI_THRESHOLD) + { + rssi = LO_RSSI_THRESHOLD; + } + + result_index = uint8_t((HI_RSSI_THRESHOLD - rssi) * scale); + } + + if (result_index >= res_size) + { + // Maximum index possible + result_index = res_size - 1; + } + + LOG("RSSI: %f IDX: %d\n", rssi, result_index); + if (result[result_index] == 0 || result[result_index] > abs_rssi) + { + result[result_index] = abs_rssi; + } + } + + return max_signal; +} + +#endif diff --git a/src/radioScan/radioScan.h b/src/radioScan/radioScan.h new file mode 100644 index 0000000..1c8ca8e --- /dev/null +++ b/src/radioScan/radioScan.h @@ -0,0 +1,40 @@ +#include +#include + +#ifndef LORASA_CORE_H + +#define LORASA_CORE_H + +#ifdef PRINT_DEBUG +#define LOG(args...) Serial.printf(args...) +#define LOG_IF(cond, args...) \ + if (cond) \ + LOG(args...) +#elif !defined(LOG) +#define LOG(args...) +#define LOG_IF(cond, args...) +#endif + +// Output Pixel Formula +// 1 = rssi / 4, 2 = (rssi / 2) - 22 or 20 +constexpr int RSSI_OUTPUT_FORMULA = 2; + +// based on the formula for RSSI_OUTPUT_FORMULA == 2 +// -2 * (22 + RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) < rssi =< -44 +// practice may require a better pair of thresholds +constexpr float HI_RSSI_THRESHOLD = -44.0; +constexpr float LO_RSSI_THRESHOLD = HI_RSSI_THRESHOLD - 66; + +// number of samples for RSSI method +#define SAMPLES_RSSI 12 // 21 // + +struct Scan +{ + virtual float getRSSI() = 0; + + // rssiMethod gets the data similar to the scan method, + // but uses getRSSI directly. + uint16_t rssiMethod(size_t samples, uint16_t *result, size_t res_size); +}; + +#endif diff --git a/test/test_rssi.cpp b/test/test_rssi.cpp index 9c4b023..0215179 100644 --- a/test/test_rssi.cpp +++ b/test/test_rssi.cpp @@ -1,6 +1,6 @@ #include #define LOG(args...) printf(args) -#include +#include "../src/radioScan/radioScan.cpp" #include void setUp(void) {} @@ -9,7 +9,7 @@ void tearDown(void) {} struct TestScan : Scan { - TestScan(float *ctx, int sz) : Scan(sz), ctx(ctx), sz(sz), idx(0) {} + TestScan(float *ctx, int sz) : ctx(ctx), sz(sz), idx(0) {} float getRSSI() override; @@ -29,18 +29,19 @@ float TestScan::getRSSI() } constexpr int test_sz = 13; +constexpr int inputs_sz = 13; void test_rssi(void) { uint16_t samples[test_sz]; - float inputs[] = {-40.0, -100.0, -200.0, -50.0, -400.0, -60.0, -20, - -75.5, -70, -80, -90, -55.9, -110}; + float inputs[inputs_sz] = {-40.0, -100.0, -200.0, -50.0, -400.0, -60.0, -20, + -75.5, -70, -80, -90, -55.9, -110}; - TestScan t = TestScan(inputs, test_sz); + TestScan t = TestScan(inputs, inputs_sz); - uint16_t r = t.rssiMethod(samples); + uint16_t r = t.rssiMethod(inputs_sz, samples, test_sz); - uint16_t expect[test_sz] = {20, 50, 55, 60, 0, 70, 75, 80, 0, 90, 0, 100, 200}; + uint16_t expect[test_sz] = {20, 50, 55, 60, 0, 70, 75, 80, 0, 90, 0, 100, 110}; TEST_ASSERT_EQUAL_INT16(20, r); TEST_ASSERT_EQUAL_INT16_ARRAY(expect, samples, test_sz);