From 6531d3a1708df9448ebd9a8372ce98ae9925390b Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sat, 10 Aug 2024 16:04:53 -0700 Subject: [PATCH 01/11] better resolution factor --- src/main.cpp | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c4d0f23..dfe806d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,6 +50,9 @@ 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. +uint64_t SCAN_RBW_RFACTOR = 2; + // To Enable Multi Screen scan // uint64_t RANGE_PER_PAGE = 50; // Default Range on Menu Button Switch @@ -71,7 +74,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; @@ -176,7 +179,7 @@ void setup(void) delay(300); display.clear(); - resolution = RANGE / STEPS; + resolution = RANGE / (STEPS * SCAN_RBW_RFACTOR); single_page_scan = (RANGE_PER_PAGE == range); @@ -193,7 +196,8 @@ 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) + + both.println("Curent Resolution: " + + String((float)RANGE_PER_PAGE / (STEPS * SCAN_RBW_RFACTOR)) + "Mhz/tick"); for (int i = 0; i < 500; i++) { @@ -216,7 +220,8 @@ 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) + + both.println("Curent Resolution: " + + String((float)RANGE_PER_PAGE / (STEPS * SCAN_RBW_RFACTOR)) + "Mhz/tick"); for (int i = 0; i < 500; i++) { @@ -339,7 +344,7 @@ void loop(void) display.setTextAlignment(TEXT_ALIGN_RIGHT); // horizontal x axis loop - for (x = 0; x < STEPS; x++) + for (x = 0; x < STEPS * SCAN_RBW_RFACTOR; x++) { #if ANIMATED_RELOAD UI_drawCursor(x); @@ -349,8 +354,8 @@ void loop(void) scan_start_time = millis(); #endif - waterfall[range_item][x][w] = false; - freq = fr_begin + (range * ((float)x / STEPS)); + waterfall[range_item][x / SCAN_RBW_RFACTOR][w] = false; + freq = fr_begin + (range * ((float)x / (STEPS * SCAN_RBW_RFACTOR))); radio.setFrequency(freq, false); // false = no calibration need here @@ -474,9 +479,9 @@ void loop(void) if (single_page_scan) { // Drone detection true for waterfall - waterfall[range_item][x][w] = true; + waterfall[range_item][x / SCAN_RBW_RFACTOR][w] = true; display.setColor(WHITE); - display.setPixel(x, w); + display.setPixel(x / SCAN_RBW_RFACTOR, w); } #endif if (drone_detected_frequency_start == 0) @@ -516,19 +521,21 @@ 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); + display.drawLine(x / SCAN_RBW_RFACTOR, 1, x / SCAN_RBW_RFACTOR, + 6); #endif } #if (WATERFALL_ENABLED == true) if ((filtered_result[y] == 1) && (y > drone_detection_level) && - (single_page_scan) && (waterfall[range_item][x][w] != true)) + (single_page_scan) && + (waterfall[range_item][x / SCAN_RBW_RFACTOR][w] != true)) { // 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[range_item][x / SCAN_RBW_RFACTOR][w] = false; display.setColor(BLACK); - display.setPixel(x, w); + display.setPixel(x / SCAN_RBW_RFACTOR, w); display.setColor(WHITE); } #endif @@ -541,7 +548,7 @@ void loop(void) if (filtered_result[y] == 1) { // Set signal level pixel - display.setPixel(x, y); + display.setPixel(x / SCAN_RBW_RFACTOR, y); if (!detected) detected = true; } @@ -552,8 +559,8 @@ void loop(void) if ((y == drone_detection_level) && (x % 2 == 0)) { display.setColor(INVERSE); - display.setPixel(x, y); - display.setPixel(x, y + 1); // 2 px wide + display.setPixel((int)x / SCAN_RBW_RFACTOR, y); + display.setPixel((int)x / SCAN_RBW_RFACTOR, y + 1); // 2 px wide display.setColor(WHITE); } } From c1954dc6d8c21563707a0e7560eb7c919d51db68 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sun, 11 Aug 2024 01:31:09 -0700 Subject: [PATCH 02/11] resolution --- src/main.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index dfe806d..d43863a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,10 +90,12 @@ 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[20][STEPS][20]; // 20 - ??? steps of the waterfall // global variable @@ -479,9 +481,12 @@ void loop(void) if (single_page_scan) { // Drone detection true for waterfall - waterfall[range_item][x / SCAN_RBW_RFACTOR][w] = true; - display.setColor(WHITE); - display.setPixel(x / SCAN_RBW_RFACTOR, w); + if (!waterfall[range_item][x / SCAN_RBW_RFACTOR][w]) + { + waterfall[range_item][x / SCAN_RBW_RFACTOR][w] = true; + display.setColor(WHITE); + display.setPixel(x / SCAN_RBW_RFACTOR, w); + } } #endif if (drone_detected_frequency_start == 0) @@ -527,7 +532,7 @@ void loop(void) } #if (WATERFALL_ENABLED == true) - if ((filtered_result[y] == 1) && (y > drone_detection_level) && + if ((filtered_result[y] == 1) && (y < drone_detection_level) && (single_page_scan) && (waterfall[range_item][x / SCAN_RBW_RFACTOR][w] != true)) { @@ -556,11 +561,11 @@ void loop(void) // ------------------------------------------------------------- // Draw "Detection Level line" every 2 pixel // ------------------------------------------------------------- - if ((y == drone_detection_level) && (x % 2 == 0)) + if ((y == drone_detection_level) && (x % 2 == 0) && x < STEPS) { display.setColor(INVERSE); - display.setPixel((int)x / SCAN_RBW_RFACTOR, y); - display.setPixel((int)x / SCAN_RBW_RFACTOR, y + 1); // 2 px wide + display.setPixel((int)x, y); + display.setPixel((int)x, y + 1); // 2 px wide display.setColor(WHITE); } } From d0d352d4dcef3803588b2467e63f957c734ac8a7 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Mon, 12 Aug 2024 09:40:09 -0700 Subject: [PATCH 03/11] some improvements --- src/main.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d43863a..d02253e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,7 +95,7 @@ uint16_t result_detections[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; uint16_t filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; // Waterfall array -bool waterfall[20][STEPS][20]; // 20 - ??? steps of the waterfall +bool waterfall[STEPS]; // 20 - ??? steps of the waterfall // global variable @@ -345,7 +345,7 @@ void loop(void) drone_detected_frequency_start = 0; display.setTextAlignment(TEXT_ALIGN_RIGHT); - // horizontal x axis loop + // horizontal (x axis) Frequency loop for (x = 0; x < STEPS * SCAN_RBW_RFACTOR; x++) { #if ANIMATED_RELOAD @@ -355,8 +355,10 @@ void loop(void) #ifdef PRINT_PROFILE_TIME scan_start_time = millis(); #endif - - waterfall[range_item][x / SCAN_RBW_RFACTOR][w] = false; + // Real display pixel x - axis. + // Beacuse of the SCAN_RBW_RFACTOR x is not a display coordinate anymore. + int dispaly_x = x / SCAN_RBW_RFACTOR; + waterfall[dispaly_x] = false; freq = fr_begin + (range * ((float)x / (STEPS * SCAN_RBW_RFACTOR))); radio.setFrequency(freq, false); // false = no calibration need here @@ -481,11 +483,11 @@ void loop(void) if (single_page_scan) { // Drone detection true for waterfall - if (!waterfall[range_item][x / SCAN_RBW_RFACTOR][w]) + if (!waterfall[dispaly_x]) { - waterfall[range_item][x / SCAN_RBW_RFACTOR][w] = true; + waterfall[dispaly_x] = true; display.setColor(WHITE); - display.setPixel(x / SCAN_RBW_RFACTOR, w); + display.setPixel(dispaly_x, w); } } #endif @@ -526,21 +528,19 @@ void loop(void) #if (DRAW_DETECTION_TICKS == true) // draw vertical line on top of display for "drone detected" // frequencies - display.drawLine(x / SCAN_RBW_RFACTOR, 1, x / SCAN_RBW_RFACTOR, - 6); + display.drawLine(dispaly_x, 1, dispaly_x, 6); #endif } #if (WATERFALL_ENABLED == true) if ((filtered_result[y] == 1) && (y < drone_detection_level) && - (single_page_scan) && - (waterfall[range_item][x / SCAN_RBW_RFACTOR][w] != true)) + (single_page_scan) && (waterfall[dispaly_x] != true)) { // If drone not found set dark pixel on the waterfall // TODO: make something like scrolling up if possible - waterfall[range_item][x / SCAN_RBW_RFACTOR][w] = false; + waterfall[dispaly_x] = false; display.setColor(BLACK); - display.setPixel(x / SCAN_RBW_RFACTOR, w); + display.setPixel(dispaly_x, w); display.setColor(WHITE); } #endif @@ -553,7 +553,7 @@ void loop(void) if (filtered_result[y] == 1) { // Set signal level pixel - display.setPixel(x / SCAN_RBW_RFACTOR, y); + display.setPixel(dispaly_x, y); if (!detected) detected = true; } From 6c3a2188bf3a66ccca01f08b127dd8c8c3d3a3a7 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Mon, 12 Aug 2024 09:42:17 -0700 Subject: [PATCH 04/11] profiler debug --- src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d02253e..f43c638 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -675,8 +675,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 } From 360643aa3a2e930b783cf3a1c58141db7b2dfcb6 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Mon, 12 Aug 2024 10:38:58 -0700 Subject: [PATCH 05/11] add inverese fix --- src/main.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f43c638..dfae3c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -561,11 +561,15 @@ void loop(void) // ------------------------------------------------------------- // Draw "Detection Level line" every 2 pixel // ------------------------------------------------------------- - if ((y == drone_detection_level) && (x % 2 == 0) && x < STEPS) + if ((y == drone_detection_level) && (dispaly_x % 2 == 0)) { - display.setColor(INVERSE); - display.setPixel((int)x, y); - display.setPixel((int)x, y + 1); // 2 px wide + display.setColor(WHITE); + if (filtered_result[y] == 1 && filtered_result[y + 1] == 1) + { + display.setColor(INVERSE); + } + display.setPixel(dispaly_x, y); + display.setPixel(dispaly_x, y + 1); // 2 px wide display.setColor(WHITE); } } From 0c4d617e41b37398e556241ad91a0969cfe78229 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Mon, 12 Aug 2024 11:07:08 -0700 Subject: [PATCH 06/11] some fixes --- src/main.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index dfae3c3..e97cc4b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -356,7 +356,8 @@ void loop(void) scan_start_time = millis(); #endif // Real display pixel x - axis. - // Beacuse of the SCAN_RBW_RFACTOR x is not a display coordinate anymore. + // 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; freq = fr_begin + (range * ((float)x / (STEPS * SCAN_RBW_RFACTOR))); @@ -564,12 +565,13 @@ void loop(void) if ((y == drone_detection_level) && (dispaly_x % 2 == 0)) { display.setColor(WHITE); - if (filtered_result[y] == 1 && filtered_result[y + 1] == 1) + if (filtered_result[y] == 1) { display.setColor(INVERSE); } display.setPixel(dispaly_x, y); - display.setPixel(dispaly_x, y + 1); // 2 px wide + display.setPixel(dispaly_x, y - 1); // 2 px wide + display.setColor(WHITE); } } From f54a0b07bc7c2f662c2444687693170707f8ef2e Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Mon, 12 Aug 2024 12:55:35 -0700 Subject: [PATCH 07/11] some fixes --- src/main.cpp | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e97cc4b..a6ad755 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,7 +51,7 @@ int SCAN_RANGES[] = {}; uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // multiplies STEPS * N to increase scan resolution. -uint64_t SCAN_RBW_RFACTOR = 2; +#define SCAN_RBW_RFACTOR 2 // To Enable Multi Screen scan // uint64_t RANGE_PER_PAGE = 50; @@ -95,12 +95,12 @@ uint16_t result_detections[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; uint16_t filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; // Waterfall array -bool waterfall[STEPS]; // 20 - ??? 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; @@ -197,10 +197,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 * SCAN_RBW_RFACTOR)) + - "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(); @@ -221,10 +221,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 * SCAN_RBW_RFACTOR)) + - "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(); @@ -348,6 +348,11 @@ void loop(void) // horizontal (x axis) Frequency 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 @@ -427,6 +432,7 @@ 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++) { @@ -473,8 +479,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) @@ -530,12 +537,13 @@ void loop(void) // draw vertical line on top of display for "drone detected" // frequencies 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[dispaly_x] != true)) + (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 @@ -556,13 +564,15 @@ void loop(void) // Set signal level pixel display.setPixel(dispaly_x, y); if (!detected) + { detected = true; + } } // ------------------------------------------------------------- // Draw "Detection Level line" every 2 pixel // ------------------------------------------------------------- - if ((y == drone_detection_level) && (dispaly_x % 2 == 0)) + if ((y == drone_detection_level) && (dispaly_x % 2 == 0) && new_pixel) { display.setColor(WHITE); if (filtered_result[y] == 1) From 2e3d413309905f6facbb011e29cda40b5fd86815 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 13 Aug 2024 03:12:29 -0700 Subject: [PATCH 08/11] OSD integration --- include/DFRobot_OSD.cpp | 224 +++++++++++++++++++++++++++++++++++++++ include/DFRobot_OSD.h | 228 ++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 169 +++++++++++++++++++++++++++-- 3 files changed, 612 insertions(+), 9 deletions(-) create mode 100644 include/DFRobot_OSD.cpp create mode 100644 include/DFRobot_OSD.h diff --git a/include/DFRobot_OSD.cpp b/include/DFRobot_OSD.cpp new file mode 100644 index 0000000..66a1941 --- /dev/null +++ b/include/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 << 5; + 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 << 5; + 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, 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/include/DFRobot_OSD.h b/include/DFRobot_OSD.h new file mode 100644 index 0000000..4b07007 --- /dev/null +++ b/include/DFRobot_OSD.h @@ -0,0 +1,228 @@ +/*! + * @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,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/main.cpp b/src/main.cpp index a6ad755..0a3df3f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,7 +24,35 @@ #include #include // This file contains a binary patch for the SX1262 +#include "DFRobot_OSD.cpp" #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 + +int osd_chart_buffer[OSD_CHART_WIDTH]; + +DFRobot_OSD osd(CS); + +/*Define Chinese characters*/ +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}; +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}; +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}; +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" @@ -53,6 +81,8 @@ 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 @@ -108,7 +138,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 @@ -119,7 +149,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; @@ -131,8 +162,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; @@ -148,7 +248,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); @@ -344,8 +444,16 @@ void loop(void) drone_detected_frequency_start = 0; display.setTextAlignment(TEXT_ALIGN_RIGHT); + 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++) { @@ -365,7 +473,9 @@ void loop(void) // x > STEPS on SCAN_RBW_RFACTOR int dispaly_x = x / SCAN_RBW_RFACTOR; waterfall[dispaly_x] = false; - freq = fr_begin + (range * ((float)x / (STEPS * SCAN_RBW_RFACTOR))); + float step = (range * ((float)x / (STEPS * SCAN_RBW_RFACTOR))); + + freq = fr_begin + step; radio.setFrequency(freq, false); // false = no calibration need here @@ -386,6 +496,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 @@ -399,8 +542,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++) { @@ -436,6 +583,7 @@ void loop(void) for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { + #ifdef PRINT_DEBUG // Serial.printf("%04X,", result[y]); #endif @@ -536,8 +684,11 @@ void loop(void) #if (DRAW_DETECTION_TICKS == true) // draw vertical line on top of display for "drone detected" // frequencies - display.drawLine(dispaly_x, 1, dispaly_x, 6); - detected_y[dispaly_x] = true; + if (!detected_y[dispaly_x]) + { + display.drawLine(dispaly_x, 1, dispaly_x, 6); + detected_y[dispaly_x] = true; + } #endif } @@ -572,7 +723,7 @@ void loop(void) // ------------------------------------------------------------- // Draw "Detection Level line" every 2 pixel // ------------------------------------------------------------- - if ((y == drone_detection_level) && (dispaly_x % 2 == 0) && new_pixel) + if ((y == drone_detection_level) && (dispaly_x % 2 == 0)) { display.setColor(WHITE); if (filtered_result[y] == 1) From c3fccead9fb1c253a8e1449bac622375984c9f16 Mon Sep 17 00:00:00 2001 From: "ionsurdu@github.com" Date: Tue, 13 Aug 2024 13:46:33 +0300 Subject: [PATCH 09/11] Move source file to SRC folder. --- {include => src}/DFRobot_OSD.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {include => src}/DFRobot_OSD.cpp (100%) diff --git a/include/DFRobot_OSD.cpp b/src/DFRobot_OSD.cpp similarity index 100% rename from include/DFRobot_OSD.cpp rename to src/DFRobot_OSD.cpp From d2c02b62ebd56e8818d264675a7014f439a3e116 Mon Sep 17 00:00:00 2001 From: "ionsurdu@github.com" Date: Tue, 13 Aug 2024 14:11:08 +0300 Subject: [PATCH 10/11] Move source file to SRC folder. --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 0a3df3f..ca1ff05 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,7 +24,7 @@ #include #include // This file contains a binary patch for the SX1262 -#include "DFRobot_OSD.cpp" +#include "DFRobot_OSD.h" #include "modules/SX126x/patches/SX126x_patch_scan.h" #define CS 47 #define OSD_MISO 33 From b388ef6fdc40adef85288ffe6f498ce5c495e50f Mon Sep 17 00:00:00 2001 From: "ionsurdu@github.com" Date: Tue, 13 Aug 2024 14:49:51 +0300 Subject: [PATCH 11/11] minor cleanup and optimizations --- include/DFRobot_OSD.h | 340 ++++++++++++++++++++---------------------- src/DFRobot_OSD.cpp | 6 +- src/main.cpp | 22 +-- 3 files changed, 176 insertions(+), 192 deletions(-) diff --git a/include/DFRobot_OSD.h b/include/DFRobot_OSD.h index 4b07007..8c7720f 100644 --- a/include/DFRobot_OSD.h +++ b/include/DFRobot_OSD.h @@ -15,101 +15,111 @@ #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__);} +#define DBG(...) \ + { \ + Serial.print("["); \ + Serial.print(__FUNCTION__); \ + Serial.print("(): "); \ + Serial.print(__LINE__); \ + Serial.print(" ] "); \ + Serial.println(__VA_ARGS__); \ + } #else - #define DBG(...) +#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 +#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) +#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 +#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 +#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 +#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 @@ -117,112 +127,84 @@ */ typedef struct { - char ascii; - short addr; -}AsciiAddr; + 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}, +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(); + 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 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 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 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 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,int dt[]); + /** + * @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: + 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; + private: + int nCS; }; #endif diff --git a/src/DFRobot_OSD.cpp b/src/DFRobot_OSD.cpp index 66a1941..ccdc284 100644 --- a/src/DFRobot_OSD.cpp +++ b/src/DFRobot_OSD.cpp @@ -52,7 +52,7 @@ void DFRobot_OSD::displayChar(unsigned char row, unsigned char col, unsigned sho writeAddrData(DMM, 0x40); writeAddrData(DMAH, addrH | 0x2); writeAddrData(DMAL, k); - j = CHAR_LBC << 5; + j = CHAR_LBC; if ((addr >> 8) != 0) j |= 0x10; writeAddrData(DMDI, j); @@ -100,7 +100,7 @@ void DFRobot_OSD::displayString(unsigned char row, unsigned char col, const char writeAddrData(DMM, 0x40); writeAddrData(DMAH, addrH | 0x2); writeAddrData(DMAL, k); - j = CHAR_LBC << 5; + j = CHAR_LBC; if ((value >> 8) != 0) j |= 0x10; writeAddrData(DMDI, j); @@ -157,7 +157,7 @@ void DFRobot_OSD::writeAT7456E(unsigned short addr, int *dt) writeAddrData(VM0, 0x01 << 3); } -void DFRobot_OSD::storeChar(unsigned short addr, int temp[]) +void DFRobot_OSD::storeChar(unsigned short addr, const int temp[]) { int buf[54] = {0}; int dt[54] = {0}; diff --git a/src/main.cpp b/src/main.cpp index ca1ff05..ef370dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,19 +37,21 @@ #define OSD_X_START 1 #define OSD_Y_START 16 -int osd_chart_buffer[OSD_CHART_WIDTH]; - DFRobot_OSD osd(CS); /*Define Chinese characters*/ -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}; -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}; -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}; -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}; +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