Skip to content

Commit c86b22c

Browse files
authored
Merge pull request #1219 from DevEclipse1/main
Added spectogram to subghz
2 parents af4c30c + d334d90 commit c86b22c

3 files changed

Lines changed: 225 additions & 0 deletions

File tree

src/core/menu_items/RFMenu.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "modules/rf/rf_scan.h"
88
#include "modules/rf/rf_send.h"
99
#include "modules/rf/rf_spectrum.h"
10+
#include "modules/rf/rf_waterfall.h"
1011

1112
void RFMenu::optionsMenu() {
1213
options = {
@@ -15,6 +16,7 @@ void RFMenu::optionsMenu() {
1516
{"Custom SubGhz", sendCustomRF },
1617
{"Spectrum", rf_spectrum },
1718
{"SquareWave Spec", rf_SquareWave }, // @Pirata
19+
{"Spectogram", rf_waterfall }, // dev_eclipse
1820
{"Jammer Itmt", [=]() { RFJammer(false); }},
1921
{"Jammer Full", [=]() { RFJammer(true); } },
2022
{"Config", [=]() { configMenu(); } },

src/modules/rf/rf_waterfall.cpp

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
#include "rf_waterfall.h"
2+
3+
float m_rf_waterfall_start_freq = 433.0;
4+
float m_rf_waterfall_end_freq = 434.0;
5+
6+
void rf_waterfall() {
7+
if (bruceConfig.rfModule != CC1101_SPI_MODULE) {
8+
displayError("Waterfall needs a CC1101!", true);
9+
return;
10+
}
11+
if (!initRfModule("rx", m_rf_waterfall_start_freq)) {
12+
displayError("CC1101 not found!", true);
13+
return;
14+
}
15+
16+
ELECHOUSE_cc1101.setRxBW(200);
17+
18+
select:
19+
20+
int option = 0;
21+
options = {
22+
{"Start Freq.", [&]() { option = 1; }},
23+
{"End Freq.", [&]() { option = 2; }},
24+
{"Start", [&]() { option = 3; }},
25+
{"Main Menu", [&]() { option = 4; }},
26+
};
27+
loopOptions(options);
28+
29+
tft.fillScreen(0x0);
30+
31+
if (option == 4) {
32+
return;
33+
} else if (option == 3) {
34+
rf_waterfall_run();
35+
goto select;
36+
} else if (option == 1) {
37+
rf_waterfall_start_freq();
38+
goto select;
39+
} else if (option == 2) {
40+
rf_waterfall_end_freq();
41+
goto select;
42+
}
43+
}
44+
45+
void rf_waterfall_start_freq() {
46+
options = {};
47+
int ind = 0;
48+
int arraySize = sizeof(subghz_frequency_list) / sizeof(subghz_frequency_list[0]);
49+
for (int i = 0; i < arraySize; i++) {
50+
String tmp = String(subghz_frequency_list[i], 2) + "Mhz";
51+
options.push_back({tmp.c_str(), [=]() { m_rf_waterfall_start_freq = subghz_frequency_list[i]; }});
52+
}
53+
loopOptions(options, ind);
54+
options.clear();
55+
}
56+
57+
void rf_waterfall_end_freq() {
58+
options = {};
59+
int ind = 0;
60+
int arraySize = sizeof(subghz_frequency_list) / sizeof(subghz_frequency_list[0]);
61+
for (int i = 0; i < arraySize; i++) {
62+
String tmp = String(subghz_frequency_list[i], 2) + "Mhz";
63+
options.push_back({tmp.c_str(), [=]() { m_rf_waterfall_end_freq = subghz_frequency_list[i]; }});
64+
}
65+
loopOptions(options, ind);
66+
options.clear();
67+
}
68+
69+
void rf_waterfall_run() {
70+
float f_start = m_rf_waterfall_start_freq;
71+
float f_end = m_rf_waterfall_end_freq;
72+
const int screen_width = tft.width();
73+
const int screen_height = tft.height();
74+
const int display_top = screen_height / 5;
75+
float f_freq_step;
76+
77+
int current_line = display_top;
78+
initRfModule("rx", f_start);
79+
80+
float max_freq = f_start;
81+
int max_rssi = -100;
82+
unsigned long lastMaxUpdate = millis();
83+
84+
tft.fillRect(0, 0, screen_width, display_top, TFT_BLACK);
85+
86+
int selected_item = 0;
87+
bool exitting = false;
88+
unsigned long exit_time = 0;
89+
90+
while (1) {
91+
for (int i = 0; i < 4; i++) {
92+
int x = i * (screen_width / 4);
93+
float f_freq = f_start + (f_end - f_start) * i / 4.0;
94+
tft.setCursor(x, 0);
95+
tft.setTextSize(1);
96+
97+
if (i == 0 && selected_item == 0) {
98+
tft.setTextColor(TFT_PINK, TFT_BLACK);
99+
} else if (i == 3 && selected_item == 1) {
100+
tft.setTextColor(TFT_PINK, TFT_BLACK);
101+
} else {
102+
tft.setTextColor(TFT_WHITE, TFT_BLACK);
103+
}
104+
105+
tft.drawFastVLine(x, 0, tft.height(), TFT_DARKGREY);
106+
tft.print(String(f_freq, 1));
107+
}
108+
109+
f_freq_step = (f_end - f_start) / screen_width;
110+
111+
float temp_max_freq = f_start;
112+
int temp_max_rssi = -100;
113+
114+
float range = abs(f_end - f_start);
115+
float step;
116+
117+
if (range > 100) step = 10;
118+
else if (range > 10) step = 1;
119+
else if (range > 1) step = 0.1;
120+
else if (range > 0.1) step = 0.01;
121+
else step = 0.001;
122+
123+
for (int i = 0; i < screen_width; ++i) {
124+
float f_freq = f_start + i * f_freq_step;
125+
setMHZ(f_freq);
126+
delayMicroseconds(100);
127+
int i_rssi = ELECHOUSE_cc1101.getRssi();
128+
if (i_rssi > temp_max_rssi) {
129+
temp_max_rssi = i_rssi;
130+
temp_max_freq = f_freq;
131+
}
132+
133+
int rawLevel = map(i_rssi, -100, -30, 0, 255);
134+
int level = 255 - constrain(rawLevel, 0, 255);
135+
136+
uint8_t r = 0, g = 0, b = 0;
137+
if (level <= 63) {
138+
b = map(level, 0, 63, 64, 255);
139+
} else if (level <= 127) {
140+
g = map(level, 64, 127, 0, 255);
141+
b = map(level, 64, 127, 255, 0);
142+
} else if (level <= 191) {
143+
r = map(level, 128, 191, 0, 255);
144+
g = 255;
145+
} else {
146+
r = 255;
147+
g = map(level, 192, 255, 255, 0);
148+
}
149+
150+
uint16_t color = tft.color565(r, g, b);
151+
tft.drawPixel(i, current_line, color);
152+
153+
if (check(SelPress)) {
154+
selected_item++;
155+
if (selected_item > 2) selected_item = 0;
156+
}
157+
158+
if (check(UpPress) || check(NextPress)) {
159+
switch (selected_item) {
160+
case 0: f_start += step; break;
161+
case 1: f_end += step; break;
162+
case 2: return;
163+
}
164+
delay(100);
165+
} else if (check(DownPress) || check(PrevPress)) {
166+
switch (selected_item) {
167+
case 0: f_start -= step; break;
168+
case 1: f_end -= step; break;
169+
case 2: return;
170+
}
171+
delay(100);
172+
}
173+
}
174+
175+
if (millis() - lastMaxUpdate >= 5000) {
176+
max_rssi = temp_max_rssi;
177+
max_freq = temp_max_freq;
178+
tft.fillRect(0, 10, screen_width, 10, TFT_BLACK);
179+
tft.setCursor(3, 10);
180+
tft.setTextSize(1);
181+
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
182+
tft.print(max_rssi);
183+
tft.print(" dBm @ ");
184+
tft.print(max_freq, 3);
185+
tft.print(" MHz ");
186+
187+
lastMaxUpdate = millis();
188+
}
189+
190+
tft.setCursor(3, 20);
191+
tft.setTextColor(TFT_DARKCYAN);
192+
tft.print("[OK] Item [PREV/NEXT] Value ");
193+
194+
if (selected_item == 2) {
195+
tft.setTextColor(TFT_RED);
196+
tft.print("EXIT");
197+
} else {
198+
tft.setTextColor(TFT_WHITE);
199+
tft.print("EXIT");
200+
}
201+
202+
current_line++;
203+
if (current_line >= screen_height) current_line = display_top;
204+
}
205+
206+
returnToMenu = true;
207+
rmt_rx_stop(RMT_RX_CHANNEL);
208+
deinitRMT();
209+
deinitRfModule();
210+
delay(10);
211+
}

src/modules/rf/rf_waterfall.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include "rf_utils.h"
4+
5+
void rf_waterfall_start_freq();
6+
void rf_waterfall_end_freq();
7+
void rf_waterfall_run();
8+
9+
extern float m_rf_waterfall_start_freq;
10+
extern float m_rf_waterfall_end_freq;
11+
12+
void rf_waterfall();

0 commit comments

Comments
 (0)