OSD integration

This commit is contained in:
Egor Shitikov
2024-08-13 03:12:29 -07:00
parent f54a0b07bc
commit 2e3d413309
3 changed files with 612 additions and 9 deletions

224
include/DFRobot_OSD.cpp Normal file
View File

@@ -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 <DFRobot_OSD.h>
#include <SPI.h>
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;
}

228
include/DFRobot_OSD.h Normal file
View File

@@ -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 <Arduino.h>
// #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) ///< clear20us
#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

View File

@@ -24,7 +24,35 @@
#include <Arduino.h>
#include <heltec_unofficial.h>
// 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)