diff --git a/include/DFRobot_OSD.h b/include/DFRobot_OSD.h new file mode 100644 index 0000000..8c7720f --- /dev/null +++ b/include/DFRobot_OSD.h @@ -0,0 +1,210 @@ +/*! + * @file DFRobot_OSD.h + * @brief Define infrastructure of DFRobot_OSD class + * @details This is a Library for OSD,the function is the superposition of characters. + * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Luyuhao](yuhao.lu@dfrobot.com) + * @maintainer [qsjhyy](yihuan.huang@dfrobot.com) + * @version V1.0 + * @date 2022-05-19 + * @url https://github.com/DFRobot/DFRobot_OSD + */ +#ifndef _DFRobot_OSD_H_ +#define _DFRobot_OSD_H_ + +#include + +// #define ENABLE_DBG //!< Open this macro and you can see the details of the program +#ifdef ENABLE_DBG +#define DBG(...) \ + { \ + Serial.print("["); \ + Serial.print(__FUNCTION__); \ + Serial.print("(): "); \ + Serial.print(__LINE__); \ + Serial.print(" ] "); \ + Serial.println(__VA_ARGS__); \ + } +#else +#define DBG(...) +#endif + +/* at7456 */ +#define VM0 0x00 ///< Video Mode0 +#define VM1 0x01 ///< Video Mode1 +#define HOS 0x02 ///< Horizontal Offset +#define VOS 0x03 ///< Vertical Offset +#define DMM 0x04 ///< Display Memory Mode +#define DMAH 0x05 ///< Display Memory Address High +#define DMAL 0x06 ///< Display Memory Address Low +#define DMDI 0x07 ///< Display Memory Data In +#define CMM 0x08 ///< Character Memory Mode +#define CMAH 0x09 ///< Character Memory Address High +#define CMAL 0x0a ///< Character Memory Address Low +#define CMDI 0x0b ///< Character Memory Data In +#define OSDM 0x0c ///< OSD Insertion Mux +#define RB0 0x10 ///< Row 0 Brightness +#define RB1 0x11 ///< Row 1 Brightness +#define RB2 0x12 ///< Row 2 Brightness +#define RB3 0x13 ///< Row 3 Brightness +#define RB4 0x14 ///< Row 4 Brightness +#define RB5 0x15 ///< Row 5 Brightness +#define RB6 0x16 ///< Row 6 Brightness +#define RB7 0x17 ///< Row 7 Brightness +#define RB8 0x18 ///< Row 8 Brightness +#define RB9 0x19 ///< Row 9 Brightness +#define RB10 0x1a ///< Row 10 Brightness +#define RB11 0x1b ///< Row 11 Brightness +#define RB12 0x1c ///< Row 12 Brightness +#define RB13 0x1d ///< Row 13 Brightness +#define RB14 0x1e ///< Row 14 Brightness +#define RB15 0x1f ///< Row 15 Brightness +#define OSDBL 0x6c ///< OSD Black Level +#define STAT 0x20 ///< Status +#define DMDO 0x30 ///< Display Memory Data Out +#define CMDO 0x40 ///< Character Memory Data Out +#define NVM_RAM 0x50 ///< Read the fonts in the NVM into the mirror RAM +#define RAM_NVM 0xa0 ///< Write the database data in the mirror RAM to the NVM +/* VM0 */ +#define NTSC (0 << 6) ///< D6 --- Vidoe Standard Select +#define PAL (1 << 6) +#define SYNC_AUTO (0 << 4) ///< D5,D4 --- Sync Select Mode +#define SYNC_EXTERNAL (2 << 4) +#define SYNC_INTERNAL (3 << 4) +#define OSD_ENABLE (1 << 3) ///< D3 --- Enable Display of OSD image +#define OSD_DISABLE (0 << 3) +#define SOFT_RESET (1 << 1) ///< D1 --- Software Reset +#define VOUT_ENABLE (0 << 0) +#define VOUT_DISABLE (1 << 0) +/* VM1 */ +#define BACKGND_0 (0 << 4) ///< Background level WHT% +#define BACKGND_7 (1 << 4) +#define BACKGND_14 (2 << 4) +#define BACKGND_21 (3 << 4) +#define BACKGND_28 (4 << 4) +#define BACKGND_35 (5 << 4) +#define BACKGND_42 (6 << 4) +#define BACKGND_49 (7 << 4) +#define BLINK_TIME40 (0 << 2) ///< Blink cycle, ms +#define BLINK_TIME80 (1 << 2) +#define BLINK_TIME120 (2 << 2) +#define BLINK_TIME160 (3 << 2) ///< Scintillation ratio(ON : OFF) +#define BLINK_DUTY_1_1 0 ///< BT : BT +#define BLINK_DUTY_1_2 1 ///< BT : 2BT +#define BLINK_DUTY_1_3 2 ///< BT : 3BT +#define BLINK_DUTY_3_1 3 ///< 3BT : BT // DMM +#define SPI_BIT16 \ + (0 << 6) ///< use 16bit When writing characters, and the character attribute is from + ///< the DMM[5:3] +#define SPI_BIT8 \ + (1 << 6) ///< Write characters in 8bit, and character attributes are written + ///< separately +#define CHAR_LBC (1 << 5) ///< The local background +#define CHAR_BLK (1 << 4) ///< blinking display +#define CHAR_INV (1 << 3) ///< display negative image +#define CLEAR_SRAM (1 << 2) ///< clear,20us +#define VETICAL_SYNC (1 << 1) ///< The command is in sync with the action +#define AUTO_INC (1 << 0) ///< The character address automatically increases +/* RBi */ +#define BLACK_LEVEL_0 (0 << 2) ///< 0% white level +#define BLACK_LEVEL_10 (1 << 2) ///< 10% white level +#define BLACK_LEVEL_20 (2 << 2) ///< 20% white level +#define BLACK_LEVEL_30 (3 << 2) ///< 30% white level +#define WHITE_LEVEL_120 (0 << 0) ///< 120% white level +#define WHITE_LEVEL_100 (1 << 0) ///< 110% white level +#define WHITE_LEVEL_90 (2 << 0) ///< 90% white level +#define WHITE_LEVEL_80 (3 << 0) ///< 80% white level +/* STAT */ +#define PAL_DETECT (1 << 0) ///< Check the PAL signal +#define NTSC_DETECT (1 << 1) ///< Check the NTSC signal +#define LOS_DETECT (1 << 2) ///< Check the LOS signal +#define VSYNC (1 << 4) ///< synchronous + +/** + * @struct AsciiAddr + * @brief Ascii corresponding address struct + */ +typedef struct +{ + char ascii; + short addr; +} AsciiAddr; + +const AsciiAddr tAsciiAddr[] = { + {' ', 0x00}, {'(', 0x3f}, {')', 0x40}, {'.', 0x41}, {'?', 0x42}, {';', 0x43}, + {':', 0x44}, {',', 0x45}, {'\'', 0x46}, {'/', 0x47}, {'"', 0x48}, {'-', 0x49}, + {'<', 0x4a}, {'>', 0x4b}, {'@', 0x4c}, {'!', 0x121}, {'#', 0x123}, {'$', 0x124}, + {'%', 0x125}, {'&', 0x126}, {'(', 0x128}, {')', 0x129}, {'*', 0x12a}, {'+', 0x12b}, + {'_', 0x12d}, {'=', 0x13d}, {'[', 0x15b}, {']', 0x15d}, {'^', 0x15e}, {'`', 0x160}, + {'{', 0x17b}, {'|', 0x17c}, {'}', 0x17d}, {'~', 0x17e}, +}; + +class DFRobot_OSD +{ + public: + /** + * @fn DFRobot_OSD + * @brief Constructor + * @param CS - CS selection pin + * @return None + */ + DFRobot_OSD(int CS); + ~DFRobot_OSD(); + + /** + * @fn init + * @brief Init function + * @return None + */ + void init(int a, int b, int c); + + /** + * @fn displayChar + * @brief display char + * @param row - Horizontal coordinate, range(0,15) + * @param col - Vertical coordinate, range(0,29) + * @param value - addr of char in eeprom + * @return None + */ + void displayChar(unsigned char row, unsigned char col, unsigned short addr); + + /** + * @fn displayChar + * @brief display string + * @param row - Horizontal coordinate, range(0,15) + * @param col - Vertical coordinate, range(0,29) + * @param s - String + * @return None + */ + void displayString(unsigned char row, unsigned char col, const char *s); + void displayString(unsigned char row, unsigned char col, String s); + + /** + * @fn clear + * @brief Clear screen + * @return None + */ + void clear(void); + + /** + * @fn storeChar + * @brief Write the custom character to the OSD, replacing the original character + * @param addr - Address of the stored character + * @param dt - Array generated through the tool + * @return None + */ + void storeChar(unsigned short addr, const int dt[]); + + private: + void writeAddrData(unsigned char addr, unsigned char dat); + void writeAT7456E(unsigned short addr, int *dt); + void writeData(unsigned char dat); + int *extend(int src); + int unified(int src); + + private: + int nCS; +}; + +#endif diff --git a/src/DFRobot_OSD.cpp b/src/DFRobot_OSD.cpp new file mode 100644 index 0000000..ccdc284 --- /dev/null +++ b/src/DFRobot_OSD.cpp @@ -0,0 +1,224 @@ +/*! + * @file DFRobot_OSD.cpp + * @brief Define the infrastructure DFRobot_OSD class + * @details This is a Library for OSD,the function is the superposition of characters. + * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Luyuhao](yuhao.lu@dfrobot.com) + * @maintainer [qsjhyy](yihuan.huang@dfrobot.com) + * @version V1.0 + * @date 2022-05-19 + * @url https://github.com/DFRobot/DFRobot_OSD + */ +#include +#include + +void DFRobot_OSD::writeAddrData(unsigned char addr, unsigned char value) +{ + digitalWrite(nCS, LOW); + SPI.transfer(addr); + SPI.transfer(value); + digitalWrite(nCS, HIGH); +} + +void DFRobot_OSD::writeData(unsigned char value) +{ + digitalWrite(nCS, LOW); + SPI.transfer(value); + digitalWrite(nCS, HIGH); +} + +void DFRobot_OSD::clear(void) +{ + unsigned int i; + writeAddrData(DMAH, 0x00); // address + writeAddrData(DMAL, 0); + writeAddrData(DMM, 0x01); + for (i = 0; i < (16 * 30); i++) + { + writeData(0); + } + writeData(0xff); +} + +void DFRobot_OSD::displayChar(unsigned char row, unsigned char col, unsigned short addr) +{ + unsigned short k; + unsigned char addrH, j; + + k = row * 30 + col; + addrH = k >> 8; + writeAddrData(OSDBL, 0X00); + writeAddrData(DMM, 0x40); + writeAddrData(DMAH, addrH | 0x2); + writeAddrData(DMAL, k); + j = CHAR_LBC; + if ((addr >> 8) != 0) + j |= 0x10; + writeAddrData(DMDI, j); + writeAddrData(DMAH, addrH); + writeAddrData(DMAL, k); + writeAddrData(DMDI, addr); + writeAddrData(VM0, 0x48); +} + +void DFRobot_OSD::displayString(unsigned char row, unsigned char col, const char *s) +{ + unsigned short k; + unsigned char addrH, j; + unsigned char c; + unsigned short value; + c = *s++; + int flag = 0; + k = row * 30 + col; + writeAddrData(OSDBL, 0X00); + while (c != 0) + { + flag = 0; + int i = 0; + for (i = 0; i < 34; i++) + { + if (c == tAsciiAddr[i].ascii) + { + value = tAsciiAddr[i].addr; + flag = 1; + } + } + if (flag == 0) + { + if ((c >= '0') && (c <= '9')) + value = ((c == '0') ? 10 : c - '1' + 1); + else if ((c >= 'A') && (c <= 'Z')) + value = (c - 'A' + 11); + else if ((c >= 'a') && (c <= 'z')) + value = (c - 'a' + 37); + else + value = (0x00); + } + + addrH = k >> 8; + writeAddrData(DMM, 0x40); + writeAddrData(DMAH, addrH | 0x2); + writeAddrData(DMAL, k); + j = CHAR_LBC; + if ((value >> 8) != 0) + j |= 0x10; + writeAddrData(DMDI, j); + writeAddrData(DMAH, addrH); + writeAddrData(DMAL, k); + writeAddrData(DMDI, value); + c = *s++; + k = k + 1; + } + writeAddrData(VM0, 0x48); +} + +void DFRobot_OSD::displayString(unsigned char row, unsigned char col, String s) +{ + const char *str = s.c_str(); + displayString(row, col, str); +} + +void DFRobot_OSD::init(int SCK, int MISO, int MOSI) +{ + pinMode(nCS, OUTPUT); + SPI.begin(SCK, MISO, MOSI); + writeAddrData(VM0, 0x42); // Software Reset, takes 100us, PAL/NTSC???? + writeAddrData(DMAH, 0x00); // address + writeAddrData(DMAL, 68); + writeAddrData(OSDM, 0x00); +} + +DFRobot_OSD::DFRobot_OSD(int CS) { nCS = CS; } + +DFRobot_OSD::~DFRobot_OSD() {} + +void DFRobot_OSD::writeAT7456E(unsigned short addr, int *dt) +{ + unsigned char addrH, n; + addrH = (addr >> 8); + + writeAddrData(VM0, (0x00)); + delay(30); + writeAddrData(CMAH, addr); + + writeAddrData(DMM, 0); + + for (n = 0; n < 54; n++) + { + char i = *dt; + writeAddrData(CMAL, n | (addrH << 6)); + writeAddrData(CMDI, i); + dt++; + } + writeAddrData(CMM, RAM_NVM); + delay(10); + + writeAddrData(VM0, 0x01 << 3); +} + +void DFRobot_OSD::storeChar(unsigned short addr, const int temp[]) +{ + int buf[54] = {0}; + int dt[54] = {0}; + int i = 0; + int n = 0; + int *p; + for (i = 0; i < 54; i++) + { + if (i < 8) + { + dt[i] = 0; + } + else + dt[i] = temp[i - 8]; + } + for (i = 0; i < 18; i++) + { + p = extend(dt[i * 2]); + buf[n++] = *p; + buf[n++] = *(p + 1); + p = extend(dt[i * 2 + 1]); + buf[n++] = *p; + } + writeAT7456E(addr, buf); +} + +int *DFRobot_OSD::extend(int src) +{ + int i = 0; + src = unified(src); + static int tar[2]; + tar[0] = 0; + tar[1] = 0; + for (i = 0; i < 4; i++) + { + if ((src >> i) & 0x01) + { + tar[0] = 0x02 | (tar[0] << 2); + } + else + tar[0] = 0x01 | (tar[0] << 2); + } + for (i = 4; i < 8; i++) + { + if ((src >> i) & 0x01) + { + tar[1] = 0x02 | (tar[1] << 2); + } + else + tar[1] = 0x01 | (tar[1] << 2); + } + return tar; +} + +int DFRobot_OSD::unified(int src) +{ + int num = 0; + int i = 0; + for (i = 0; i < 8; i++) + { + num = (num << 1) | ((src >> i) & 0x01); + } + return num; +} diff --git a/src/main.cpp b/src/main.cpp index c4d0f23..ef370dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,7 +24,37 @@ #include #include // This file contains a binary patch for the SX1262 +#include "DFRobot_OSD.h" #include "modules/SX126x/patches/SX126x_patch_scan.h" +#define CS 47 +#define OSD_MISO 33 +#define OSD_MOSI 34 +#define OSD_SCK 26 +#define OSD_WIDTH 30 +#define OSD_HEIGHT 16 +#define OSD_CHART_WIDTH 15 +#define OSD_CHART_HEIGHT 5 +#define OSD_X_START 1 +#define OSD_Y_START 16 + +DFRobot_OSD osd(CS); + +/*Define Chinese characters*/ +static const int buf0[36] = {0x02, 0x80, 0x02, 0x40, 0x7F, 0xE0, 0x42, 0x00, + 0x42, 0x00, 0x7A, 0x40, 0x4A, 0x40, 0x4A, 0x80, + 0x49, 0x20, 0x5A, 0xA0, 0x44, 0x60, 0x88, 0x20}; +static const int buf1[36] = {0x20, 0x00, 0x25, 0xE0, 0x75, 0x20, 0x29, 0x20, + 0xFD, 0x40, 0x21, 0x40, 0x7D, 0x20, 0xC5, 0x20, + 0x7D, 0x20, 0x45, 0xC0, 0x7D, 0x00, 0x45, 0x00}; +static const int buf2[36] = {0x20, 0x00, 0x2F, 0xC0, 0x24, 0x40, 0xF4, 0x40, + 0x24, 0x80, 0x64, 0xE0, 0x74, 0x20, 0xA6, 0x20, + 0x25, 0x40, 0x28, 0x80, 0x29, 0x40, 0x32, 0x20}; +static const int buf3[36] = {0x3F, 0x00, 0x2A, 0xE0, 0xFA, 0x20, 0x2E, 0xA0, + 0x2A, 0xA0, 0xFE, 0xA0, 0x2A, 0x40, 0xAB, 0x40, + 0xBE, 0xA0, 0xA3, 0x20, 0xE2, 0x00, 0xBF, 0xE0}; + +// SPI pins +// .pio/libdeps/heltec_wifi_lora_32_V3/Heltec_ESP32_LoRa_v3/src/heltec_unofficial.h#L34-L35 // project components #include "global_config.h" @@ -50,6 +80,11 @@ int SCAN_RANGES[] = {}; // to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN +// multiplies STEPS * N to increase scan resolution. +#define SCAN_RBW_RFACTOR 2 + +int OSD_PIXELS_PER_CHAR = (STEPS * SCAN_RBW_RFACTOR) / OSD_CHART_WIDTH; + // To Enable Multi Screen scan // uint64_t RANGE_PER_PAGE = 50; // Default Range on Menu Button Switch @@ -71,7 +106,7 @@ uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN #define RANGE (int)(FREQ_END - FREQ_BEGIN) -#define SINGLE_STEP (float)(RANGE / STEPS) +#define SINGLE_STEP (float)(RANGE / (STEPS * SCAN_RBW_RFACTOR)) uint64_t range = (int)(FREQ_END - FREQ_BEGIN); uint64_t fr_begin = FREQ_BEGIN; @@ -87,15 +122,17 @@ 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_display_set[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t result_detections[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; uint16_t filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; // Waterfall array -bool waterfall[10][STEPS][10]; // 10 - ??? steps of the waterfall +bool waterfall[STEPS], detected_y[STEPS]; // 20 - ??? steps of the waterfall // global variable // Used as a Led Light and Buzzer/count trigger -bool first_run = false; +bool first_run, new_pixel, detected_x = false; // drone detection flag bool detected = false; uint64_t drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; @@ -103,7 +140,7 @@ uint64_t drone_detected_frequency_start = 0; uint64_t drone_detected_frequency_end = 0; uint64_t detection_count = 0; bool single_page_scan = false; -bool SOUND_ON = true; +bool SOUND_ON = false; #define PRINT_PROFILE_TIME @@ -114,7 +151,8 @@ uint64_t scan_time = 0; uint64_t scan_start_time = 0; #endif -uint64_t x, y, range_item, w = 0; +uint64_t x, y, range_item, w, i = 0; +int osd_x = 1, osd_y = 2; uint64_t ranges_count = 0; float freq = 0; @@ -126,8 +164,77 @@ uint8_t button_pressed_counter = 0; uint64_t loop_cnt = 0; +unsigned short selectFreqChar(int bin) +{ + if (bin > 26) + { + return 0x105; + } + if (bin == 25) + { + return 0x106; + } + if (bin == 24) + { + return 0x107; + } + if (bin == 23) + { + return 0x108; + } + if (bin == 22) + { + return 0x109; + } + if (bin == 21) + { + return 0x10a; + } + if (bin == 20) + { + return 0x10b; + } + if (bin == 19) + { + return 0x10c; + } + if (bin == 18) + { + return 0x10d; + } + if (bin == 17) + { + return 0x10e; + } + return 0x105; +} + void setup(void) { + + osd.init(OSD_SCK, OSD_MISO, OSD_MOSI); + osd.clear(); + /* Write the custom character to the OSD, replacing the original character*/ + /* Expand 0xe0 to 0x0e0, the high 8 bits indicate page number and the low 8 bits + * indicate the inpage address.*/ + osd.storeChar(0xe0, buf0); + osd.storeChar(0xe1, buf1); + osd.storeChar(0xe2, buf2); + osd.storeChar(0xe3, buf3); + /*Displays custom characters*/ + osd.displayChar(2, 2, 0xe0); + osd.displayChar(2, 3, 0xe1); + osd.displayChar(2, 4, 0xe2); + osd.displayChar(2, 5, 0xe3); + /*display character*/ + osd.displayChar(9, 9, 0x11d); + osd.displayChar(9, 10, 0x11e); + osd.displayChar(8, 11, 0x10f); + osd.displayChar(14, 0, 0x10f); + /*display String*/ + osd.displayString(14, 15, " Lora SA"); + osd.displayString(2, 1, " Spectral RF Analyzer"); + float vbat; float resolution; loop_cnt = 0; @@ -143,7 +250,7 @@ void setup(void) delay(10); if (button.pressed()) { - SOUND_ON = false; + SOUND_ON = !SOUND_ON; tone(BUZZER_PIN, 205, 100); delay(50); tone(BUZZER_PIN, 205, 100); @@ -176,7 +283,7 @@ void setup(void) delay(300); display.clear(); - resolution = RANGE / STEPS; + resolution = RANGE / (STEPS * SCAN_RBW_RFACTOR); single_page_scan = (RANGE_PER_PAGE == range); @@ -192,9 +299,10 @@ void setup(void) { both.println("Single Page Screen MODE"); both.println("Multi Screen View Press P - button"); - both.println("Single Screen Resolution: " + String(resolution) + "Mhz/tick"); - both.println("Curent Resolution: " + String((float)RANGE_PER_PAGE / STEPS) + - "Mhz/tick"); + both.println("Multi Screan Res: " + String(resolution) + "Mhz/tick"); + both.println( + "Resolution: " + String((float)RANGE_PER_PAGE / (STEPS * SCAN_RBW_RFACTOR)) + + "Mhz/tick"); for (int i = 0; i < 500; i++) { button.update(); @@ -215,9 +323,10 @@ void setup(void) { both.println("Multi Page Screen MODE"); both.println("Single screen View Press P - button"); - both.println("Single screen Resolution: " + String(resolution) + "Mhz/tick"); - both.println("Curent Resolution: " + String((float)RANGE_PER_PAGE / STEPS) + - "Mhz/tick"); + both.println("Single screen Resol: " + String(resolution) + "Mhz/tick"); + both.println( + "Resolution: " + String((float)RANGE_PER_PAGE / (STEPS * SCAN_RBW_RFACTOR)) + + "Mhz/tick"); for (int i = 0; i < 500; i++) { button.update(); @@ -337,10 +446,23 @@ void loop(void) drone_detected_frequency_start = 0; display.setTextAlignment(TEXT_ALIGN_RIGHT); - - // horizontal x axis loop - for (x = 0; x < STEPS; x++) + int max_bins_array[30]; + for (int i = 0; i < 30; i++) { + max_bins_array[i] = 33; + } + // memset(max_bins_array, 33, 30); + + // horizontal (x axis) Frequency loop + int osd_x = 1, osd_y = 1, s = 0; + // x loop + for (x = 0; x < STEPS * SCAN_RBW_RFACTOR; x++) + { + + if (x % SCAN_RBW_RFACTOR == 0) + new_pixel = true; + else + new_pixel = false; #if ANIMATED_RELOAD UI_drawCursor(x); #endif @@ -348,9 +470,14 @@ void loop(void) #ifdef PRINT_PROFILE_TIME scan_start_time = millis(); #endif + // Real display pixel x - axis. + // Because of the SCAN_RBW_RFACTOR x is not a display coordinate anymore + // x > STEPS on SCAN_RBW_RFACTOR + int dispaly_x = x / SCAN_RBW_RFACTOR; + waterfall[dispaly_x] = false; + float step = (range * ((float)x / (STEPS * SCAN_RBW_RFACTOR))); - waterfall[range_item][x][w] = false; - freq = fr_begin + (range * ((float)x / STEPS)); + freq = fr_begin + step; radio.setFrequency(freq, false); // false = no calibration need here @@ -371,6 +498,39 @@ void loop(void) } // read the results Array to which the results will be saved radio.spectralScanGetResult(result); + int max_bin = 0; + + int mhz_in_bin = 5; + int steps = 12; + + for (int i = 1; i < 33; i++) + { + if (result[i] > 0 && (result[i + 1] > 0)) + { + max_bin = i; + Serial.println(String(max_bin)); + break; + } + } + if (max_bins_array[s] > max_bin) + { + max_bins_array[s] = max_bin; + } + // Going to the next OSD step + if (x % steps == 0 && s < 30) + { + // PRINT SIGNAL CHAR ROW, COL, VALUE + osd.displayChar(14, s + 1, selectFreqChar(max_bins_array[s])); + Serial.println("MAX:" + String(max_bins_array[s])); + // osd.displayString(14, s, "" + String(max_bins_array[s]) + ""); + s++; + if (s == 30) + { + s = 0; + } + } + // osd.displayString(osd_y++, osd_x, + // String(freq) + "-" + String((max_bin * 4)) + "dB"); } #endif #if SCAN_METHOD == METHOD_RSSI @@ -384,8 +544,12 @@ void loop(void) } // memset - memset(result, 0, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); - result_index = 0u; + // memset(result, 0, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); + for (i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) + { + result[i] = 0; + } + result_index = 0; // N of samples for (int r = 0; r < SAMPLES_RSSI; r++) { @@ -417,9 +581,11 @@ void loop(void) #endif // SCAN_METHOD == METHOD_RSSI detected = false; + detected_y[dispaly_x] = false; for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { + #ifdef PRINT_DEBUG // Serial.printf("%04X,", result[y]); #endif @@ -463,8 +629,9 @@ void loop(void) // if (result[y] || y == drone_detection_level) { // check if we should alarm about a drone presence - if ((filtered_result[y] == 1) // we have some data and - && (y <= drone_detection_level)) // detection threshold match + if ((filtered_result[y] == 1) // we have some data and + && (y <= drone_detection_level) && + detected_y[dispaly_x] == false) // detection threshold match { // Set LED to ON (filtered in UI component) @@ -474,9 +641,12 @@ void loop(void) if (single_page_scan) { // Drone detection true for waterfall - waterfall[range_item][x][w] = true; - display.setColor(WHITE); - display.setPixel(x, w); + if (!waterfall[dispaly_x]) + { + waterfall[dispaly_x] = true; + display.setColor(WHITE); + display.setPixel(dispaly_x, w); + } } #endif if (drone_detected_frequency_start == 0) @@ -516,19 +686,23 @@ void loop(void) #if (DRAW_DETECTION_TICKS == true) // draw vertical line on top of display for "drone detected" // frequencies - display.drawLine(x, 1, x, 6); + if (!detected_y[dispaly_x]) + { + display.drawLine(dispaly_x, 1, dispaly_x, 6); + detected_y[dispaly_x] = true; + } #endif } #if (WATERFALL_ENABLED == true) - if ((filtered_result[y] == 1) && (y > drone_detection_level) && - (single_page_scan) && (waterfall[range_item][x][w] != true)) + if ((filtered_result[y] == 1) && (y < drone_detection_level) && + (single_page_scan) && (waterfall[dispaly_x] != true) && new_pixel) { // If drone not found set dark pixel on the waterfall // TODO: make something like scrolling up if possible - waterfall[range_item][x][w] = false; + waterfall[dispaly_x] = false; display.setColor(BLACK); - display.setPixel(x, w); + display.setPixel(dispaly_x, w); display.setColor(WHITE); } #endif @@ -541,19 +715,26 @@ void loop(void) if (filtered_result[y] == 1) { // Set signal level pixel - display.setPixel(x, y); + display.setPixel(dispaly_x, y); if (!detected) + { detected = true; + } } // ------------------------------------------------------------- // Draw "Detection Level line" every 2 pixel // ------------------------------------------------------------- - if ((y == drone_detection_level) && (x % 2 == 0)) + if ((y == drone_detection_level) && (dispaly_x % 2 == 0)) { - display.setColor(INVERSE); - display.setPixel(x, y); - display.setPixel(x, y + 1); // 2 px wide + display.setColor(WHITE); + if (filtered_result[y] == 1) + { + display.setColor(INVERSE); + } + display.setPixel(dispaly_x, y); + display.setPixel(dispaly_x, y - 1); // 2 px wide + display.setColor(WHITE); } } @@ -663,8 +844,6 @@ void loop(void) loop_time = millis() - loop_start; #ifdef PRINT_PROFILE_TIME -#ifdef PRINT_DEBUG Serial.printf("LOOP: %lld ms; SCAN: %lld ms;\n ", loop_time, scan_time); #endif -#endif }