Сканер WiFi диапазона на NRF24 и микроконтроллерах ESP32 или RP2040

Перенесу тему со старого форума сюда так как неспешная работа над проектом продолжается.

Спойлер
// 07.10.2022 - Добавлена поддержка дисплея ILI9341
//            - в локальной библиотеке ST77XX расширен набор цветов
//            - в локальной библиотеке ILI9341 исправлена последовательность пинов для &SPI
//            - добавлен вывод на большой дисплей частоты и MAC адресов обнаруженных устройств. 

// 09.10.2022 - Дорисована сетка каналов, исправлены мелкие ошибки,работа проверена с конфигурацией
//              дисплея и модуля NRF24 на портах SPI по умолчанию, альтернативное подключение 
//              не проверялось. (SPI0 - NRF24, SPI1 - дисплей.) Для ESP32 реализован только SOFT SPI
//              так как в ядре прописан только один SPI и по умолчанию выбран SPI3,(hard-в реализации )
//              Для ESP32 распиновка SPI выбрана в соответствии с ядром GENERIC. 
//              Режим HARD SPI создаёт помехи на NRF модуль на частотах до 500Mhz (выше не проверялось)
//              При монтаже линии SPI делаем как можно короче!!!

//              Из планируемого - добавление энкодера и усилителя на вход NRF24 что даст возможность
//              видеть сигналы с уровнем -100дб и просматривать конкретный участок частотного диапазона.


// 11.10.2022 для RP2040 ILI9341 работает   

#define HARD_SPI

#include <Adafruit_GFX.h>    // Core graphics library
#include <SPI.h>
#include <Arduino.h>


// ДИСПЛЕЙ
uint8_t q = 2; // пропорциональность дисплея ILI9341 по горизонтали

// Размаркировать для дисплея на контроллере ST7735
// #define ST7735

#ifdef ST7735
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789

#else // ILI9341
//#include <Adafruit_ILI9341.h> //  Hardware-specific library for ILI9341 240x320
#include <TFT_eSPI.h>

// Some ready-made 16-bit ('565') color settings:
#define ST77XX_BLACK 0x0000       ///<   0,   0,   0
#define ST77XX_NAVY 0x000F        ///<   0,   0, 123
#define ST77XX_DARKGREEN 0x03E0   ///<   0, 125,   0
#define ST77XX_DARKCYAN 0x03EF    ///<   0, 125, 123
#define ST77XX_MAROON 0x7800      ///< 123,   0,   0
#define ST77XX_PURPLE 0x780F      ///< 123,   0, 123
#define ST77XX_OLIVE 0x7BE0       ///< 123, 125,   0
#define ST77XX_LIGHTGREY 0xC618   ///< 198, 195, 198
#define ST77XX_DARKGREY 0x7BEF    ///< 123, 125, 123
#define ST77XX_BLUE 0x001F        ///<   0,   0, 255
#define ST77XX_GREEN 0x07E0       ///<   0, 255,   0
#define ST77XX_CYAN 0x07FF        ///<   0, 255, 255
#define ST77XX_RED 0xF800         ///< 255,   0,   0
#define ST77XX_MAGENTA 0xF81F     ///< 255,   0, 255
#define ST77XX_YELLOW 0xFFE0      ///< 255, 255,   0
#define ST77XX_WHITE 0xFFFF       ///< 255, 255, 255
#define ST77XX_ORANGE 0xFD20      ///< 255, 165,   0
#define ST77XX_GREENYELLOW 0xAFE5 ///< 173, 255,  41
#define ST77XX_PINK 0xFC18        ///< 255, 130, 198
#endif


#if ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \
      defined(ARDUINO_GENERIC_RP2040) )

// замаркировать если используем наоборот
#define SPI01             // Дисплей на SPIO1, NRF24L01 на SPI0 (выбор между SPI0 и SPI1)
#if defined(SPI01)        // для RP2040 SPI1
#define TFT_CS        13  // GP13 - CS              (hard - 13)
#define TFT_RST       10  // GP14 - RESET           (10)  
#define TFT_DC        11  // GP15 - A0              (11)  
#define TFT_MISO      12  // GP12 - MISO (MISO, RX) (hard - 12)
#define TFT_MOSI      15  // GP11 - SDA  (MOSI, TX) (hard - 15)
#define TFT_SCLK      14  // GP10 - SCK             (hard - 14)
#else                     // для RP2040 SPI0
#define TFT_CS        17  //5   // GP5 - CS               (hard - 17)
#define TFT_RST       20  //6   // GP6 - RESET
#define TFT_DC        21  //7   // GP7 - A0
#define TFT_MISO      16  //4   // GP4 - MISO (MISO, RX)  (hard - 16)
#define TFT_MOSI      19  //3   // GP3 - SDA  (MOSI, TX)  (hard - 19)
#define TFT_SCLK      18  //2   // GP2 - SCK              (hard - 18)
#endif

// SPI definitions and macros то NRF24L01
#if defined(SPI01)
#define CE_pin    21 //7
#define RST_pin   20 // не используется
#define CS_pin    17 //5
#define MOSI_pin  19 //3
#define MISO_pin  16 //4
#define SCK_pin   18 //2
#else
#define CE_pin    11 //15
#define RST_pin   10 // не используется
#define CS_pin    13
#define MOSI_pin  15 //11
#define MISO_pin  12
#define SCK_pin   14 //10
#endif
#include "api/HardwareSPI.h"

#elif ( defined(ESP32))

#define WIFI             // Используем модуль вайфая
#include "WiFi.h"
#include <Ticker.h>
Ticker blinks;
float blinkPeriod = 0.25;

// ***   ***   ***           Для ESP32 подключаем SPI так:
#define HSPIs             // Дисплей на HSPI, NRF24L01 на VSPI
#if defined(HSPIs)         // для ESP32 HSPI
#define TFT_CS        15  // GP13 - CS
#define TFT_RST       16  // GP14 - RESET
#define TFT_DC        17  // GP15 - A0
#define TFT_MISO      12  // GP12 - MISO (MISO, RX)
#define TFT_MOSI      13  // GP11 - SDA  (MOSI, TX)
#define TFT_SCLK      14  // GP10 - SCK
#else                     // для ESP32 VSPI
#define TFT_CS        5   // GP5  - CS
#define TFT_RST       20  // GP20 - RESET
#define TFT_DC        21  // GP21 - A0
#define TFT_MISO      19  // GP19 - MISO (MISO, RX)
#define TFT_MOSI      23  // GP23 - SDA  (MOSI, TX)
#define TFT_SCLK      18  // GP18 - SCK
#endif

// SPI definitions and macros то NRF24L01
#if defined(HSPIs) // NRF24L01 на VSPI если монитор на HSPI и наоборот ;-)
#define CE_pin    21
#define CS_pin    5
#define MOSI_pin  23
#define MISO_pin  19
#define SCK_pin   18
#else // HSPIs
#define CE_pin    17
#define CS_pin    15
#define MOSI_pin  13
#define MISO_pin  12
#define SCK_pin   14
#endif


#else
#error This code is intended to run on the RP2040 or ESP32 modules!
#endif

/********************/
#ifdef ST7735
/********************/
  #ifndef WIFI // Если это не ESP32 то
    #ifdef HARD_SPI
      #ifndef SPI01
      // For ST7735-based displays, we will use this call
      Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); // Only SPI0 ???
      #else
      //hard SPI для RP2040
      Adafruit_ST7735 tft = Adafruit_ST7735(&SPI1, TFT_CS, TFT_DC, TFT_RST); //via hard SPI1
      #endif
    #else
    //Soft SPI для RP2040
    Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); // Via Soft SPI
    #endif
  #else  //Для ESP32
  // SOFT SPI для ESP32
  Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); // Via Soft SPI
  #endif
/********************/
#else  // * ILI9341 *
/********************/
  #ifndef WIFI // Если это не ESP32 то
    #ifdef HARD_SPI
      #ifndef SPI01
      // For ILI9341-based displays, we will use this call
      TFT_eSPI tft = TFT_eSPI (TFT_CS, TFT_DC, TFT_RST); // Only SPI0 ???
      #else // define SPI01
      //hard SPI01 для RP2040
      //Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI1, TFT_DC, TFT_CS, TFT_RST); //via hard SPI1 old LIB
      TFT_eSPI  tft = TFT_eSPI (); //&SPI1, TFT_CS, TFT_DC, TFT_RST); //via hard SPI1 

      #endif
    #else // Soft SPI
    //Soft SPI для RP2040
    TFT_eSPI  tft = TFT_eSPI (TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST,TFT_MISO); // Via Soft SPI
    #endif
  #else  //Для ESP32 используем только SOFT SPI
  // SOFT SPI для ESP32
  TFT_eSPI  tft = TFT_eSPI(); //TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST,TFT_MISO); // Via Soft SPI
  #endif
/********************/
#endif
/********************/

// Образцы инициализации TFT SPI
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST,TFT_MISO); 
//Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI1,  TFT_DC,TFT_CS, TFT_RST);
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

// the nRF24L01+ can tune to 128 channels with 1 MHz spacing from 2.400 GHz to 2.527 GHz.
#define CHANNELS 128

uint16_t signalStrength[CHANNELS]; // smooths signal strength with numerical range 0 - 0x7FFF
uint16_t CH[] = {2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472};

#define  CE_on    digitalWrite(CE_pin, HIGH)
#define  CE_off   digitalWrite(CE_pin, LOW)
#define  CS_on    digitalWrite(CS_pin, HIGH)
#define  CS_off   digitalWrite(CS_pin, LOW)
#define  MOSI_on  digitalWrite(MOSI_pin, HIGH)
#define  MOSI_off digitalWrite(MOSI_pin, LOW)
#define  MISO_on  digitalRead(MISO_pin) // input
#define  SCK_on   digitalWrite(SCK_pin, HIGH)
#define  SCK_off  digitalWrite(SCK_pin, LOW)

// nRF24 Register map
enum {
  NRF24L01_00_CONFIG      = 0x00,
  NRF24L01_01_EN_AA       = 0x01,
  NRF24L01_02_EN_RXADDR   = 0x02,
  NRF24L01_03_SETUP_AW    = 0x03,
  NRF24L01_04_SETUP_RETR  = 0x04,
  NRF24L01_05_RF_CH       = 0x05,
  NRF24L01_06_RF_SETUP    = 0x06,
  NRF24L01_07_STATUS      = 0x07,
  NRF24L01_08_OBSERVE_TX  = 0x08,
  NRF24L01_09_CD          = 0x09,
  NRF24L01_0A_RX_ADDR_P0  = 0x0A,
  NRF24L01_0B_RX_ADDR_P1  = 0x0B,
  NRF24L01_0C_RX_ADDR_P2  = 0x0C,
  NRF24L01_0D_RX_ADDR_P3  = 0x0D,
  NRF24L01_0E_RX_ADDR_P4  = 0x0E,
  NRF24L01_0F_RX_ADDR_P5  = 0x0F,
  NRF24L01_10_TX_ADDR     = 0x10,
  NRF24L01_11_RX_PW_P0    = 0x11,
  NRF24L01_12_RX_PW_P1    = 0x12,
  NRF24L01_13_RX_PW_P2    = 0x13,
  NRF24L01_14_RX_PW_P3    = 0x14,
  NRF24L01_15_RX_PW_P4    = 0x15,
  NRF24L01_16_RX_PW_P5    = 0x16,
  NRF24L01_17_FIFO_STATUS = 0x17,
  NRF24L01_1C_DYNPD       = 0x1C,
  NRF24L01_1D_FEATURE     = 0x1D,
  //Instructions
  NRF24L01_61_RX_PAYLOAD     = 0x61,
  NRF24L01_A0_TX_PAYLOAD     = 0xA0,
  NRF24L01_E1_FLUSH_TX       = 0xE1,
  NRF24L01_E2_FLUSH_RX       = 0xE2,
  NRF24L01_E3_REUSE_TX_PL    = 0xE3,
  NRF24L01_50_ACTIVATE       = 0x50,
  NRF24L01_60_R_RX_PL_WID    = 0x60,
  NRF24L01_B0_TX_PYLD_NOACK  = 0xB0,
  NRF24L01_FF_NOP            = 0xFF,
  NRF24L01_A8_W_ACK_PAYLOAD0 = 0xA8,
  NRF24L01_A8_W_ACK_PAYLOAD1 = 0xA9,
  NRF24L01_A8_W_ACK_PAYLOAD2 = 0xAA,
  NRF24L01_A8_W_ACK_PAYLOAD3 = 0xAB,
  NRF24L01_A8_W_ACK_PAYLOAD4 = 0xAC,
  NRF24L01_A8_W_ACK_PAYLOAD5 = 0xAD,
};

// Bit mnemonics
enum {
  NRF24L01_00_MASK_RX_DR  = 6,
  NRF24L01_00_MASK_TX_DS  = 5,
  NRF24L01_00_MASK_MAX_RT = 4,
  NRF24L01_00_EN_CRC      = 3,
  NRF24L01_00_CRCO        = 2,
  NRF24L01_00_PWR_UP      = 1,
  NRF24L01_00_PRIM_RX     = 0,

  NRF24L01_07_RX_DR       = 6,
  NRF24L01_07_TX_DS       = 5,
  NRF24L01_07_MAX_RT      = 4,

  NRF2401_1D_EN_DYN_ACK   = 0,
  NRF2401_1D_EN_ACK_PAY   = 1,
  NRF2401_1D_EN_DPL       = 2,
};

enum TXRX_State {
  TXRX_OFF,
  TX_EN,
  RX_EN,
};


// Button and Encoder
#define UsrButton 34
#define Canal 7
bool is_canal = false;
uint32_t old_millis;

#include <GyverButton.h>
GButton btn_01(UsrButton);


uint8_t _spi_write(uint8_t command)
{
  uint8_t result = 0;
  uint8_t n = 8;
  SCK_off;
  MOSI_off;
  while (n--) {
    if (command & 0x80)
      MOSI_on;
    else
      MOSI_off;
    if (MISO_on)
      result |= 0x01;
    SCK_on;
    //      _NOP();
    SCK_off;
    command = command << 1;
    result = result << 1;
  }
  MOSI_on;
  return result;
}

void _spi_write_address(uint8_t address, uint8_t data)
{
  CS_off;
  _spi_write(address);
  //    _NOP();
  _spi_write(data);
  CS_on;
}

uint8_t _spi_read()
{
  uint8_t result = 0;
  uint8_t i;
  MOSI_off;
  //_NOP();
  for (i = 0; i < 8; i++) {
    if (MISO_on) // if MISO is HIGH
      result = (result << 1) | 0x01;
    else
      result = result << 1;
    SCK_on;
    //        _NOP();
    SCK_off;
    //       _NOP();
  }
  return result;
}

uint8_t _spi_read_address(uint8_t address)
{
  uint8_t result;
  CS_off;
  _spi_write(address);
  result = _spi_read();
  CS_on;
  return (result);
}

/* Instruction Mnemonics */
#define R_REGISTER    0x00
#define W_REGISTER    0x20
#define REGISTER_MASK 0x1F
#define ACTIVATE      0x50
#define R_RX_PL_WID   0x60
#define R_RX_PAYLOAD  0x61
#define W_TX_PAYLOAD  0xA0
#define W_ACK_PAYLOAD 0xA8
#define FLUSH_TX      0xE1
#define FLUSH_RX      0xE2
#define REUSE_TX_PL   0xE3
#define NOP_P         0xFF

uint8_t NRF24L01_WriteReg(uint8_t address, uint8_t data)
{
  CS_off;
  _spi_write_address(address | W_REGISTER, data);
  CS_on;
  return 1;
}

uint8_t NRF24L01_FlushTx()
{
  return Strobe(FLUSH_TX);
}

uint8_t NRF24L01_FlushRx()
{
  return Strobe(FLUSH_RX);
}

static uint8_t Strobe(uint8_t state)
{
  uint8_t result;
  CS_off;
  result = _spi_write(state);
  CS_on;
  return result;
}

uint8_t NRF24L01_ReadReg(uint8_t reg)
{
  CS_off;
  uint8_t data = _spi_read_address(reg);
  CS_on;
  return data;
}

void NRF24L01_SetTxRxMode(uint8_t mode)
{
  if (mode == TX_EN) {
    CE_off;
    NRF24L01_WriteReg(NRF24L01_07_STATUS,
                      (1 << NRF24L01_07_RX_DR)    // reset the flag(s)
                      | (1 << NRF24L01_07_TX_DS)
                      | (1 << NRF24L01_07_MAX_RT));
    NRF24L01_WriteReg(NRF24L01_00_CONFIG,
                      (1 << NRF24L01_00_EN_CRC)   // switch to TX mode
                      | (1 << NRF24L01_00_CRCO)
                      | (1 << NRF24L01_00_PWR_UP));
    delayMicroseconds(130);
    CE_on;
  } else if (mode == RX_EN) {
    CE_off;
    NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);        // reset the flag(s)
    NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F);        // switch to RX mode
    NRF24L01_WriteReg(NRF24L01_07_STATUS,
                      (1 << NRF24L01_07_RX_DR)    //reset the flag(s)
                      | (1 << NRF24L01_07_TX_DS)
                      | (1 << NRF24L01_07_MAX_RT));
    NRF24L01_WriteReg(NRF24L01_00_CONFIG,
                      (1 << NRF24L01_00_EN_CRC)   // switch to RX mode
                      | (1 << NRF24L01_00_CRCO)
                      | (1 << NRF24L01_00_PWR_UP)
                      | (1 << NRF24L01_00_PRIM_RX));
    delayMicroseconds(130);
    CE_on;
  } else {
    NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_EN_CRC)); // PowerDown
    CE_off;
  }
}

uint8_t NRF24L01_Reset()
{
  NRF24L01_FlushTx();
  NRF24L01_FlushRx();
  uint8_t status1 = Strobe(0xFF); // NOP
  uint8_t status2 = NRF24L01_ReadReg(0x07);
  NRF24L01_SetTxRxMode(TXRX_OFF);
  return (status1 == status2 && (status1 & 0x0f) == 0x0e);
}


// функция перекодировки цвета в формат библиотеки Adafruin_GFX
//
uint16_t setColor(uint8_t red, uint8_t green, uint8_t blue) {
  return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
}

#ifdef WIFI
volatile  int n;
#define Time_WiFiScan 30000

void WiFi_Scan(void) {
  clearDisplay(); // инициализируем вывод на дисплей

  #ifdef ST7735
  tft.setCursor(20, 40);
  tft.setTextSize(2);
  tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
  tft.print("   SCAN");
  tft.setCursor(20, 70);
  tft.print(" NETWORKS"); 
  #else // ILI9341
  tft.setCursor(95, 80);
  tft.setTextSize(2);
  tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
  tft.print("   SCAN");
  tft.setCursor(95, 120);
  tft.print(" NETWORKS");
  blinks.attach(blinkPeriod,blinker);
  #endif

  Serial.println("scan start");
  // WiFi.scanNetworks will return the number of networks found
  n = WiFi.scanNetworks();
  blinks.detach();
  tft.fillScreen(ST77XX_BLACK);
  tft.invertDisplay(false);
  tft.setTextSize(1);
  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK); 
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      String ssid = (WiFi.SSID(i));

      tft.setCursor(3, 20 + (i * 12));
      tft.print(i + 1);
      tft.print(": ");
      tft.print(ssid);

      // выравнивание текста
      int s = ssid.length(); //sizeof(ssid);
      s = 10 - s;
      if (s >= 0) {
        for (int j = 0; j < s; j++) {
          Serial.print(" ");
          tft.print(" ");
        }
      }
      Serial.print(" (");
      tft.print(" (");
      Serial.print(WiFi.RSSI(i));
      tft.print(WiFi.RSSI(i));
      Serial.print(" CH-");
      tft.print(" CH-");
      if (WiFi.channel(i) < 10) {
        Serial.print(" ");
        //tft.print(" ");
      }
      if(WiFi.channel(i) <10) {
        Serial.print("0");
        tft.print("0");
      }
      Serial.print(WiFi.channel(i));
      tft.print(WiFi.channel(i));
      
      #ifndef ST7735
      tft.print(" F=");
      tft.print(CH[(WiFi.channel(i)) - 1]);
      tft.print("M");
      tft.print(" ");
      //tft.print(" MAC::");
      tft.print(WiFi.BSSIDstr(i));
      //tft.print(" ");
      #endif
       
      Serial.print(" Freq=");
      Serial.print(CH[(WiFi.channel(i)) - 1]);
      Serial.print("MHz MAC::");
      Serial.print(WiFi.BSSIDstr(i));
      Serial.print(" ");
      
      int e = WiFi.encryptionType(i);
      if (e == 0) {
        Serial.print("No Encrypton");
      } else if (e == 1) {
        Serial.print("WEP");
      } else if (e == 2) {
        Serial.print("WPA");
      } else if (e == 3) {
        Serial.print("WPA2/PSK (CCMP)");
      } else if (e == 4) {
        Serial.print("WPA2/PSK (TKIP,CCMP)");
      }
      Serial.println(")");
      tft.println(")");
      delay(10);
    }
  }
  Serial.println("");
  delay(10000);
  tft.fillScreen(ST77XX_BLACK);
  dispHello();
}


void blinker() {
  static bool i;
  i= !i;
  tft.invertDisplay(i);
}

#endif


void clearDisplay() {
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
}



/*********************************** S E T U P ************************************/

void setup() {
  Serial.begin(115200); // debugging without lcd display

#ifdef WIFI
  // WIFI
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
#endif

  //TFT
#ifdef WIFI
  pinMode(27, OUTPUT);
  digitalWrite(27, HIGH); // Led DISPLAY is ON
#else
  pinMode(29, OUTPUT);
  digitalWrite(29, HIGH); // Led DISPLAY is ON
#endif
  dispInit();
  
  //pinMode(UsrButton, INPUT_PULLUP);

  // prepare 'bit banging' SPI interface
  pinMode(MOSI_pin, OUTPUT);
  pinMode(SCK_pin, OUTPUT);
  pinMode(CS_pin, OUTPUT);
  pinMode(CE_pin, OUTPUT);
  pinMode(MISO_pin, INPUT);
  CS_on;
  CE_on;
  MOSI_on;
  SCK_on;
  delay(70);
  CS_off;
  CE_off;
  MOSI_off;
  SCK_off;
  delay(100);
  CS_on;
  delay(10);

  NRF24L01_Reset();
  delay(5000); // Заставку отображаем 5 секунд
  tft.fillScreen(ST77XX_BLACK);

  NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00);    // switch off Shockburst mode
  NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x0F); // write default value to setup register
  NRF24L01_SetTxRxMode(RX_EN);                   // switch to receive mode

  dispHello();

  // выставляем таймер
  old_millis = millis();
  

} // ******* END SETUP *******



/***************************** L O O P **************************/

uint8_t refresh;

void loop() {
  btn_01.tick(); // проверяем кнопки

// если есть модуль WIFI
#ifdef WIFI
  // Сканируем WiFi раз в 30 секунд перед сканированием выводим линейку каналов посередине
  if (millis() - old_millis >= Time_WiFiScan) {

  #ifndef ST7735
   static uint8_t yy = 130;
   draw_CH(yy);
   delay(5000);  
  #endif

   WiFi_Scan();
   old_millis = millis();
  }
#endif

  for (uint8_t MHz = 0; MHz < CHANNELS; MHz++ ) { // tune to frequency (2400 + MHz) so this loop covers 2.400 - 2.527 GHz
    // (maximum range module can handle) when channels is set to 128.
    NRF24L01_WriteReg(NRF24L01_05_RF_CH, MHz);
    CE_on;                                        // start receiving
    delayMicroseconds(random(130, 230));          // allow receiver time to tune and start receiving 130 uS
    // seems to be the minimum time.
    // Random additional delay helps prevent strobing effects
    // with frequency-hopping transmitters.
    CE_off;                                       // stop receiving - one bit is now set if received power
    // was > -64 dBm at that instant
    if (NRF24L01_ReadReg(NRF24L01_09_CD)) {       // signal detected so increase signalStrength unless already maxed out

      signalStrength[MHz] += (0x7FFF - signalStrength[MHz]) >> 5;
      // increase rapidly when previous value was low, with increase reducing
      // exponentially as value approaches maximum
    } else {                                      // no signal detected so reduce signalStrength unless already at minimum

      signalStrength[MHz] -= signalStrength[MHz] >> 5;
      // decrease rapidly when previous value was high, with decrease reducing
      // exponentially as value approaches zero
    }
    //Serial.print((signalStrength[MHz] + 0x0100) >> 9, HEX); // debugging without lcd display
    //Serial.print(" ");                                      // debugging without lcd display

    // Обработка пользовательской кнопки и Энкодера
    /*
      if (!digitalRead(UsrButton) && millis() - old_millis >= 150){
      old_millis = millis();
    *
    if (btn_01.isClick()) {
      is_canal = !is_canal;
      Serial.print("USR BOTTON is ");
      Serial.println(is_canal);
    }
    */

    
    // Вывод информации
#ifdef ST7735    
    if (!is_canal) {
      if (!--refresh) {                             // don't refresh whole display every scan (too slow)
        refresh = 19;                               // speed up by only refreshing every n-th frequency loop - reset number

        tft.setTextSize(1);
        tft.drawLine(20 + MHz, 11, 20 + MHz, 110, ST77XX_BLACK);
        if (signalStrength[MHz] / 73 >= 78) {
          tft.drawLine(20 + MHz, (110 - (signalStrength[MHz] / 346)), 20 + MHz, 110, ST77XX_WHITE);
          tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
          tft.setCursor(136, 3);  tft.print("ATT");
          // tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
        } else {
          tft.drawLine(20 + MHz, (110 - (signalStrength[MHz] / 73)), 20 + MHz, 110, ST77XX_WHITE);
          tft.setTextColor(0xaa84/*ST77XX_MAGENTA*/, ST77XX_BLACK);
          tft.setCursor(136, 3);  tft.print("ATT");
          //  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
        }
        delay(0);
      }
    } else { // смотрим широкий канал (для пробы 7)
      if (!--refresh) {                             // don't refresh whole display every scan (too slow)
        refresh = 9;
        if (MHz >= 31 && MHz <= 53) {
          int i = 0;
          while (i < 5) {
            tft.drawLine(20 + (MHz - 31) * 5 + i, 11, 0 + (MHz - 31) * 5 + i, 111, ST77XX_BLACK);
            if (signalStrength[MHz] / 173 >= 90) {
              tft.drawLine(20 + (MHz - 31) * 5 + i, (110 - (signalStrength[MHz] / 346)), 20 + (MHz - 31) * 5 + i, 110, ST77XX_WHITE);
              tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
              tft.setCursor(136, 3);  tft.print("ATT");
              tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
            } else {
              tft.drawLine(20 + (MHz - 31) * 5 + i, (110 - (signalStrength[MHz] / 173)), 20 + (MHz - 31) * 5 + i, 110, ST77XX_WHITE);
              tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
              tft.setCursor(136, 3);  tft.print("ATT");
              tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
            }
            i++;
          }
        }
      }
    }
#else //ILI9341
      if (!--refresh) {                             // don't refresh whole display every scan (too slow)
        refresh = 19;                               // speed up by only refreshing every n-th frequency loop - reset number

        tft.setTextSize(2);
        tft.drawLine(40 + MHz*2, 40, 40 + MHz*2, 220, ST77XX_BLACK);
        if (signalStrength[MHz] / 73 >= 156) {
          tft.drawLine(40 + MHz*2, (220 - (signalStrength[MHz] / 346)), 40 + MHz*2, 220, ST77XX_WHITE);
          tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
          tft.setCursor(280, 6);  tft.print("ATT");
          // tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
        } else {
          tft.drawLine(40 + MHz*2, (220 - (signalStrength[MHz] / 73)), 40 + MHz*2, 220, ST77XX_WHITE);
          tft.setTextColor(0xaa84/*ST77XX_MAGENTA*/, ST77XX_BLACK);
          tft.setCursor(280, 6);  tft.print("ATT");
          //  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
        }
        tft.setTextSize(1);
        delay(0);
      }
#endif
  }
} // ************************** END LOOP ******************************


void dispInit() {
  
#ifdef ST7735
  // Use this initializer if using a 1.8" TFT screen:
  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
#else
  // 3.2" ILI9341  
  tft.begin();
#endif
  
  tft.setRotation(1);
//  tft.cp437(true); // не пропускаем 176 символ
  
//Если используется HARD SPI устанавливаем скорость порта  
#ifdef HARD_SPI
  #ifdef WIFI 
  // SPI для ESP32  
//  tft.setSPISpeed(20000000);  // отдельные экземпляры дисплеев не работают на такой скорости
  #else                       // откорректируйте под конкретный экземпляр
  // SPI для RP2040  
//  tft.setSPISpeed(25000000);
  #endif
#endif  

#ifdef ST7735
  tft.fillScreen(ST77XX_BLACK);
  tft.setCursor(22, 50);
  tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
  tft.setTextSize(1);
  tft.print("2.4 GHz band scanner");
  tft.setCursor(3, 70);
  tft.setTextSize(1);
  tft.setTextColor(ST77XX_CYAN, ST77XX_BLACK);

  #ifdef WIFI
  tft.print("Modified to ESP32 - UA6EM");
  #else
  tft.print("Modified to RP2040 - UA6EM");
  #endif
  
#else //ILI9341
  tft.fillScreen(ST77XX_BLACK);
  tft.setCursor(50, 100);
  tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
  tft.setTextSize(2);
  tft.print("2.4 GHz band scanner");
  tft.setCursor(3, 140);
  tft.setTextSize(2);
  tft.setTextColor(ST77XX_CYAN, ST77XX_BLACK);

  #ifdef WIFI
  tft.print("Modified to ESP32  - UA6EM");
  #else
  tft.print("Modified to RP2040 - UA6EM");
  #endif
#endif

}


void dispHello() {
#ifdef ST7735  
  // отрисовка сетки графикой
  tft.drawLine(0, 112, 169, 112, ST77XX_WHITE);
  tft.drawLine(20, 112, 20, 120, ST77XX_WHITE);
  tft.drawLine(80, 112, 80, 120, ST77XX_WHITE);
  tft.drawLine(140, 112, 140, 120, ST77XX_WHITE);
  for (int x = 0; x < 154; x++) {
    if (!(x % 10)) {
      tft.drawLine(x, 112, x, 116, ST77XX_WHITE);
    }
  }

  // выводим надписи
  tft.setTextColor(0xaa84, ST77XX_BLACK); // тёмно- кирпичный
  tft.setCursor(136, 3);  tft.print("ATT");
  //  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
  tft.setTextColor(setColor(247, 234, 105), ST77XX_BLACK);
  tft.setCursor(13, 120);  tft.print("2.40");
  tft.setCursor(73, 120);  tft.print("2.46");
  tft.setCursor(133, 120);  tft.print("2.52");
  tft.drawLine(0, 2, 0, 118, ST77XX_WHITE);
  tft.setCursor(1, 3);   tft.print("-10");
  tft.setCursor(1, 23);  tft.print("-20");
  tft.setCursor(1, 43);  tft.print("-30");
  tft.setCursor(1, 63);  tft.print("-40");
  tft.setCursor(1, 83);  tft.print("-50");
  tft.setCursor(1, 103); tft.print("-60");
  
#else // ILI9341

  // отрисовка сетки графикой
  tft.drawLine(0, 220, 320, 220, ST77XX_WHITE);
  tft.drawLine(40, 220, 40, 230, ST77XX_WHITE);   // 2.40
  tft.drawLine(160, 220, 160, 230, ST77XX_WHITE); // 2.46
  tft.drawLine(280, 220, 280, 230, ST77XX_WHITE); // 2.52
  for (int x = 0; x < 308; x++) {
    if (!(x % 20)) {
      tft.drawLine(x, 220, x, 226, ST77XX_WHITE);
    }
  }

  // выводим надписи
  tft.setTextColor(0xaa84, ST77XX_BLACK); // тёмно- кирпичный
  tft.setTextSize(2);
  tft.setCursor(280, 6);  tft.print("ATT");
  tft.setTextSize(1);
  //  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
  tft.setTextColor(setColor(247, 234, 105), ST77XX_BLACK);
  tft.setCursor(33, 230);  tft.print("2.40");
  tft.setCursor(153, 230);  tft.print("2.46");
  tft.setCursor(273, 230);  tft.print("2.52");
  tft.drawLine(1, 50, 1, 230, ST77XX_WHITE);
  tft.setCursor(2, 55);  tft.print("-00");
  tft.setCursor(2, 80);  tft.print("-10");
  tft.setCursor(2, 105); tft.print("-20");
  tft.setCursor(2, 130); tft.print("-30");
  tft.setCursor(2, 155); tft.print("-40");
  tft.setCursor(2, 180); tft.print("-50");
  tft.setCursor(2, 205); tft.print("-60");
  
#endif

  delay(10); // start up message

 // выводим сетку каналов WiFI 2.4GHz
#ifdef ST7735

  tft.drawLine(21, 0, 43, 0, ST77XX_GREEN);   //1
  tft.drawLine(21, 1, 43, 1, ST77XX_GREEN);   //1
  tft.drawLine(26, 3, 48, 3, ST77XX_RED);     //2
  tft.drawLine(26, 4, 48, 4, ST77XX_RED);     //2
  tft.drawLine(31, 5, 53, 5, ST77XX_YELLOW);  //3
  tft.drawLine(31, 6, 53, 6, ST77XX_YELLOW);  //3
  tft.drawLine(36, 7, 58, 7, ST77XX_CYAN);    //4
  tft.drawLine(36, 8, 58, 8, ST77XX_CYAN);    //4
  tft.drawLine(41, 9, 63, 9, ST77XX_BLUE);    //5
  tft.drawLine(41, 10, 63, 10, ST77XX_BLUE);  //5

  tft.drawLine(46, 0, 68, 0, ST77XX_WHITE);   //6
  tft.drawLine(46, 1, 68, 1, ST77XX_WHITE);   //6
  tft.drawLine(51, 3, 73, 3, ST77XX_BLUE);    //7
  tft.drawLine(51, 4, 73, 4, ST77XX_BLUE);    //7
  tft.drawLine(56, 5, 78, 5, ST77XX_RED);     //8
  tft.drawLine(56, 6, 78, 6, ST77XX_RED);     //8
  tft.drawLine(61, 7, 83, 7, ST77XX_MAGENTA); //9
  tft.drawLine(61, 8, 83, 8, ST77XX_MAGENTA); //9
  tft.drawLine(66, 9, 88, 9, ST77XX_CYAN);    //10
  tft.drawLine(66, 10, 88, 10, ST77XX_CYAN);  //10

  tft.drawLine(71, 0, 92, 0, ST77XX_GREEN);   //11
  tft.drawLine(71, 1, 92, 1, ST77XX_GREEN);   //11
  tft.drawLine(76, 3, 98, 3, ST77XX_MAGENTA); //12
  tft.drawLine(76, 4, 98, 4, ST77XX_MAGENTA); //12
  tft.drawLine(81, 5, 103, 5, ST77XX_YELLOW); //13
  tft.drawLine(81, 6, 103, 6, ST77XX_YELLOW); //13
  tft.drawLine(93, 7, 115, 7, ST77XX_RED);    //14
  tft.drawLine(93, 8, 115, 8, ST77XX_RED);    //14

#else // ILI9341

  static uint8_t y = 24;
  draw_CH(y);           // вывести линейку каналов (вверху)
  
  tft.drawLine(21*q, 1*q, 43*q, 1*q, ST77XX_GREEN);   //1
  tft.drawLine(21*q, 2*q, 43*q, 2*q, ST77XX_GREEN);   //1
  tft.drawLine(26*q, 3*q, 48*q, 3*q, ST77XX_RED);     //2
  tft.drawLine(26*q, 4*q, 48*q, 4*q, ST77XX_RED);     //2
  tft.drawLine(31*q, 5*q, 53*q, 5*q, ST77XX_YELLOW);  //3
  tft.drawLine(31*q, 6*q, 53*q, 6*q, ST77XX_YELLOW);  //3
  tft.drawLine(36*q, 7*q, 58*q, 7*q, ST77XX_CYAN);    //4
  tft.drawLine(36*q, 8*q, 58*q, 8*q, ST77XX_CYAN);    //4
  tft.drawLine(41*q, 9*q, 63*q, 9*q, ST77XX_BLUE);    //5
  tft.drawLine(41*q, 10*q, 63*q, 10*q, ST77XX_BLUE);  //5

  tft.drawLine(46*q, 1*q, 68*q, 1*q, ST77XX_WHITE);   //6
  tft.drawLine(46*q, 2*q, 68*q, 2*q, ST77XX_WHITE);   //6
  tft.drawLine(51*q, 3*q, 73*q, 3*q, ST77XX_BLUE);    //7
  tft.drawLine(51*q, 4*q, 73*q, 4*q, ST77XX_BLUE);    //7
  tft.drawLine(56*q, 5*q, 78*q, 5*q, ST77XX_RED);     //8
  tft.drawLine(56*q, 6*q, 78*q, 6*q, ST77XX_RED);     //8
  tft.drawLine(61*q, 7*q, 83*q, 7*q, ST77XX_MAGENTA); //9
  tft.drawLine(61*q, 8*q, 83*q, 8*q, ST77XX_MAGENTA); //9
  tft.drawLine(66*q, 9*q, 88*q, 9*q, ST77XX_CYAN);    //10
  tft.drawLine(66*q, 10*q, 88*q, 10*q, ST77XX_CYAN);  //10

  tft.drawLine(71*q, 1*q, 92*q, 1*q, ST77XX_GREEN);   //11
  tft.drawLine(71*q, 2*q, 92*q, 2*q, ST77XX_GREEN);   //11
  tft.drawLine(76*q, 3*q, 98*q, 3*q, ST77XX_MAGENTA); //12
  tft.drawLine(76*q, 4*q, 98*q, 4*q, ST77XX_MAGENTA); //12
  tft.drawLine(81*q, 5*q, 103*q, 5*q, ST77XX_YELLOW); //13
  tft.drawLine(81*q, 6*q, 103*q, 6*q, ST77XX_YELLOW); //13
  tft.drawLine(93*q, 7*q, 115*q, 7*q, ST77XX_RED);    //14
  tft.drawLine(93*q, 8*q, 115*q, 8*q, ST77XX_RED);    //14
 
#endif
 }

void draw_CH(uint8_t y){
tft.drawLine(42, y, 230, y, ST77XX_WHITE);
  for (int x = 0; x < 14; x++) {
    if(x <12) {
      tft.drawLine(66 + 11 * x, y, 66 + 11 * x, y+4, ST77XX_WHITE);
    }
    if(x > 12) tft.drawLine(66 + 11 * x, y, 66 + 11 * x, y +4, ST77XX_WHITE);  
   }
  
   for (int x = 1; x < 14; x+=2) {
    if(x <10){
      tft.setCursor(53 + 11 * x, y + 8);  tft.print(x);
    }else if(x == 11) {
      tft.setCursor((53 + 11 * x)-3, y + 8);  tft.print(x);
    } else if(x == 13){
      tft.setCursor((64 + 11 * x)-3, y + 8);  tft.print(x);
      }
   }
  tft.setTextSize(2); 
  tft.setCursor(23, y + 3);
  tft.print("CH");
  tft.setTextSize(1);

 } // end draw_CH()
2 лайка

В старом форуме прозвучало о возможности добавления сканирования частот FPV видео передатчика, составил табличку частот (перечень каналов условный):

CH  MHz
1	5362
2	5399
3	5436
4	5473
5	5510
6	5547
7	5584
8	5621
9	5645
10	5658
11	5665
12	5685
13	5695
14	5705
15	5725
16	5732
17	5733
18	5740
19	5745
20	5752
21	5760
22	5765
23	5769
24	5771
25	5780
26	5785
27	5790
28	5800
29	5805
30	5806
31	5809
32	5820
33	5825
34	5828
35	5840
36	5843
37	5845
38	5847
39	5860
40	5865
41	5866
42	5880
43	5885
44	5905
45	5917
46	5925
47	5945

с 5.8 определились, еще бы хотелось добавить приёмник чтобы мониторить каналы телеметрии от 100 до 1000MHz, их много, надо на каком-то остановится

Предлагаю СС1101 https://www.ti.com/lit/ds/symlink/cc1101.pdf
потому что его можно купить
потому что он используется в FlipperZero ) и отлично работает на своих диапазонах
потому что много проэктов с исходниками
потому что другого я ничего не знаю ))) но это не правда

на алике выбор слишком большой https://aliexpress.ru/popular/cc1101-433mhz.html
может кто знает стабильно работающие модули?

@marshallab заказал парочку, будем прикручивать



моя тестовая доска! После небольших изменений все сразу заработало
для WEMOS пришлось изменить пины

Спойлер

//#define HSPIs // Дисплей на HSPI, NRF24L01 на VSPI
#if defined(HSPIs) // для ESP32 HSPI
#define TFT_CS 15 // GP13 - CS
#define TFT_RST 16 // GP14 - RESET
#define TFT_DC 17 // GP15 - A0
#define TFT_MISO 12 // GP12 - MISO (MISO, RX)
#define TFT_MOSI 13 // GP11 - SDA (MOSI, TX)
#define TFT_SCLK 14 // GP10 - SCK
#else // для ESP32 VSPI
#define TFT_CS 5 // GP5 - CS
#define TFT_RST 22//20 // GP20 - RESET
#define TFT_DC 21 // GP21 - A0
#define TFT_MISO 19 // GP19 - MISO (MISO, RX)
#define TFT_MOSI 23 // GP23 - SDA (MOSI, TX)
#define TFT_SCLK 18 // GP18 - SCK
#endif

// SPI definitions and macros то NRF24L01
#if defined(HSPIs) // NRF24L01 на VSPI если монитор на HSPI и наоборот :wink:
#define CE_pin 21
#define CS_pin 5
#define MOSI_pin 23
#define MISO_pin 19
#define SCK_pin 18
#else // HSPIs
#define CE_pin 17 //+
#define CS_pin 27 //15
#define MOSI_pin 16 //13
#define MISO_pin 32 //12
#define SCK_pin 25 //14
#endif

Приемник ROTG02 на 5,8 ГГц содержит два модуля RX5808 внутри, типа режим деверсити… для разных антенн, контроллер внутри выбирает по RSSI сигнал помощнее и обрабатывает сигнал этого приемника.
Пока модуль не пришел буду с этим экспериментировать.
Еще думаю прикрутить энкодер с кнопкой - настройка уровня сигнализации, настройки, еще чего.
Пищался, вибро мотор (не нашел). И WS2812 адресная линейка - просто красивая световая индикация. Но это потом, для начала антенны разные хочу потестить, выяснить реальную применимость радиотракта. На выходных деревню буду сканировать )))

@marshallab а библиотеку энкодера нашёл? (чтобы и для RP2040 подошла)

Для NRF24 можно добавить на вход усилитель, из тех, что находил, шумящих 0.6дб, даст еще +20 децибел

Нет, доп библиотеки не искал. Про то что у RP2040 может быть WiFi только что узнал, плата pi pico W - но не разбирался WiFi на чипе или дополнительно. Если на rp2040 есть ускоритель нейросети, то он окажется в приоритете перед esp32.

Проверил работу детектора в малошумящей местности. Антены 2,4 ГГц разные: штырь, клевер, яга. Больше понравилась работа клевера - она всенаправленная и достаточно чувствительная. Чувствительности модуля nrf24 -60Дб крайне недостаточно, на расстоянии 15-20 метров уже ничего не видит. Ягой можно прицелится на 50 метров, но тогда это уже не детектор получается. Уровень прям линейно от расстояния уменьшается. В основном пробовал с WiFi роутером. Но и модельные пульты пробовал. Turnigy 9X самый мощный, его видно дальше всех, метров на 35. eLRS самый незаметный, уровни у него низкий, а канал широченный, прям невидимка через 10 метров ничего.
Можете дать ссылки на усилители? А то я даже представления не имею какие на вход бывают.
… поискал … называются LNA
https://aliexpress.ru/item/1005004405664745.html?sku_id=12000029065276500&spm=a2g2w.productlist.list.8.34f616f4kajvkd
но лучше скажите проверенный

проверенных нет, надо пробовать
Я хотел пару таких последовательно попробовать
https://aliexpress.ru/item/32958344410.html?spm=a2g2w.cart.0.0.37a74aa6ZD9yv5&mp=1&_ga=2.229125788.1448661620.1666680533-54461723.1663585062&sku_id=12000020659911808

1 лайк

@marshallab модуль с WiFi сильно проигрывает ESP32 по цене, чип вайфая отдельно

@marshallab вот сижу и чешу репу, каким чудесным образом на NRF24 строят радиоаппаратуру чуть ли километровой дальности при 60 дб чувствительности )

Тоже загадка для меня. То что я натестировал это через стену 70 см без арматуры. Когда ставил модуль nrf24 с антенкой на плате, дальность детектирования роутера была до 5 метров через стену.
Возможно 2 направленные антенны и прыгающий протокол дадут надежный результат.

@marshallab наврядли

Получил девайс на ESP32S3 с дисплеем 480х270, очень интересное подключение:

Arduino_ESP32RGBPanel *bus = new Arduino_ESP32RGBPanel(
  GFX_NOT_DEFINED /* CS */, GFX_NOT_DEFINED /* SCK */, GFX_NOT_DEFINED /* SDA */,
  40 /* DE */, 41 /* VSYNC */, 39 /* HSYNC */, 42 /* PCLK */,
  45 /* R0 */, 48 /* R1 */, 47 /* R2 */, 21 /* R3 */, 14 /* R4 */,
  5 /* G0 */, 6 /* G1 */, 7 /* G2 */, 15 /* G3 */, 16 /* G4 */, 4 /* G5 */,
  8 /* B0 */, 3 /* B1 */, 46 /* B2 */, 9 /* B3 */, 1 /* B4 */
);

Тоже занимаюсь данной проблематикой. В планах реализация точно такого же проекта, правда на чужих скетчах (я не программер). Комплектуху заказал, часть приехала, остальное едет. Посмотрите в сторону вот этих модулей, чувствительность вполне нормальная, особенно у второго. Так же в их линейке есть модули на 433, 900 и т.д. На 433 в основном телеметрия. Видео в основном гонят по 5.8. Но у многих брендовых видео передается по 2,4 ГГц, при потере канала в 2,4 дрон переходит в автомате на 5,8 ГГц. Управление как правило по 2,4 ГГц, реже по 900 МГЦ. Так что считаю актуальным просматривать три диапазона 900, 2,4 и 5,8. Надеюсь на дальнейшее сотрудничество. https://aliexpress.ru/item/32974960693.html?spm=a2g2w.orderdetails.0.0.34044aa679IyJq&sku_id=66782616825&_ga=2.250049422.921012365.1668406189-1717319547.1638338358#reviews_anchor

https://aliexpress.ru/item/1005002079395324.html?spm=a2g2w.orderdetails.0.0.5b234aa69oLNEY&sku_id=12000018670645284&_ga=2.173644459.921012365.1668406189-1717319547.1638338358

https://aliexpress.ru/item/1005003462278359.html?spm=a2g2w.orderdetails.0.0.310b4aa6ckC39O&sku_id=12000025895286720&_ga=2.241129227.921012365.1668406189-1717319547.1638338358

Хороший модуль можно попытаться посмотреть сигналы до -130дб, шаг сетки правда странный и непонятно по частотному диапазону, на сколько вверх-вниз позволяет посмотреть…
Если применить более точный кварц шаг будет сильно получше - 52,428800 MHz
(Радио полностью совместимо со всеми мировыми частотами 2,4 ГГц. правила радиосвязи, включая EN 300 440, FCC CFR 47 часть 15 и японский ARIB STD-T66.)
С учетом японского стандарта 2400 -2500 однозначно возьмёт

По поводу колинеарок, с алика купил 2 штуки разные - как правило барахло. Разобрал, переделал, доберусь до векторника посмотрим что получилось. Заказал на алике несколько не дешевых колинеарок, вроде графики с КСВ прилагают в описании и “мамой клянутся”, как получу посмотрим. Купил Кроксовскую штыревую антенну, тоже так себе. Везде одно “Г”.
PS: выходил в эфир раньше с RW4LZZ, был персональный позывной RA4LHQ, но из за особенностей профессии он был закрыт.