dB output

This commit is contained in:
Egor Shitikov
2024-09-17 10:17:25 -07:00
parent 6203bdc33f
commit fa55cb2fd0
6 changed files with 241 additions and 45 deletions

126
gps_src/main.cpp Normal file
View File

@@ -0,0 +1,126 @@
#include <TinyGPS++.h>
#include <time.h>
// Objects for GNSS parsing and serial communication
TinyGPSPlus gps;
HardwareSerial GNSSSerial(2);
// Pin definitions for GNSS module communication
const int GNSS_RXPin = 34;
const int GNSS_TXPin = 33;
const int GNSS_RSTPin = 35; // There is a function built for this in the example below-
// currently it isn't used
const int GNSS_PPS_Pin = 36;
// Flags for PPS handling and synchronization status
volatile bool ppsFlag = false;
volatile bool initialSyncDone = false;
// Timestamp for the last valid GNSS data received
unsigned long lastGNSSDataMillis = 0;
void setup()
{
// Initialize serial communication for debugging
USBSerial.begin(115200);
while (!USBSerial)
;
// Start GNSS module communication
GNSSSerial.begin(115200, SERIAL_8N1, GNSS_TXPin, GNSS_RXPin);
while (!GNSSSerial)
;
// Configure GNSS reset pin
pinMode(GNSS_RSTPin, OUTPUT);
digitalWrite(GNSS_RSTPin, HIGH);
// Set up PPS pin and attach an interrupt handler
pinMode(GNSS_PPS_Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(GNSS_PPS_Pin), ppsInterrupt, RISING);
// Short delay for GNSS module initialization
delay(1000);
}
void loop()
{
// Process incoming GNSS data
while (GNSSSerial.available())
{
if (gps.encode(GNSSSerial.read()))
{
// Update the timestamp when valid GNSS data is received
lastGNSSDataMillis = millis();
displayGNSSData(); // Display GNSS data for debugging
}
}
// Perform initial synchronization using NMEA time data
if (!initialSyncDone && gps.date.isValid() && gps.time.isValid())
{
setSystemTime();
initialSyncDone = true;
USBSerial.println("Initial time synchronization done using NMEA data.");
}
// Disable interrupts to safely check and reset the PPS flag
noInterrupts();
if (ppsFlag)
{
fineTuneSystemTime(); // Adjust system time based on the PPS pulse
ppsFlag = false;
}
// Re-enable interrupts
interrupts();
// Check if GNSS data has been absent for more than a minute
if (millis() - lastGNSSDataMillis > 60000)
{
USBSerial.println("Warning: Haven't received GNSS data for more than 1 minute!");
// Additional actions can be added here, like alerts or module resets.
}
}
// Interrupt handler for the PPS signal
void ppsInterrupt() { ppsFlag = true; }
// Function to set system time using GNSS data
void setSystemTime()
{
struct tm timeinfo;
timeinfo.tm_year = gps.date.year() - 1900;
timeinfo.tm_mon = gps.date.month() - 1;
timeinfo.tm_mday = gps.date.day();
timeinfo.tm_hour = gps.time.hour();
timeinfo.tm_min = gps.time.minute();
timeinfo.tm_sec = gps.time.second();
time_t t = mktime(&timeinfo);
timeval tv = {t, 0};
settimeofday(&tv, NULL); // Update system time
}
// Function to fine-tune system time using the PPS pulse
void fineTuneSystemTime()
{
timeval tv;
gettimeofday(&tv, NULL);
tv.tv_usec = 0; // Reset microseconds to zero
settimeofday(&tv, NULL); // Update system time
USBSerial.println("System time fine-tuned using PPS signal.");
}
// Debugging function to display GNSS data
void displayGNSSData()
{
USBSerial.print("Latitude: ");
USBSerial.println(gps.location.lat(), 6);
USBSerial.print("Longitude: ");
USBSerial.println(gps.location.lng(), 6);
USBSerial.print("Altitude: ");
USBSerial.println(gps.altitude.meters());
USBSerial.print("Speed: ");
USBSerial.println(gps.speed.kmph());
USBSerial.println("-----------------------------");
}

View File

@@ -40,4 +40,5 @@ extern void UI_Init(SSD1306Wire *);
extern void UI_displayDecorate(int, int, bool);
extern void UI_setLedFlag(bool);
extern void UI_clearPlotter(void);
extern void UI_clearTopStatus(void);
extern void UI_drawCursor(int16_t);

View File

@@ -15,6 +15,8 @@
; src_dir = eink_src
; for env:heltec_wifi_lora_32_V3
; src_dir = src ;;Default
; for heltec_wifi_lora_32_V3-test-signal-generator
; src_dir = trans_src
[env:heltec_wifi_lora_32_V3]
platform = espressif32

View File

@@ -194,12 +194,15 @@ bool ANIMATED_RELOAD = false;
#define FILTER_SPECTRUM_RESULTS true
#define FILTER_SAMPLES_MIN
constexpr bool DRAW_DETECTION_TICKS = true;
int16_t max_x_rssi[STEPS] = {999};
int16_t max_x_window[STEPS / 14] = {999};
int x_window = 0;
constexpr int WINDOW_SIZE = 15;
// Number of samples for each frequency scan. Fewer samples = better temporal resolution.
// if more than 100 it can freeze
#define SAMPLES 35 //(scan time = 1294)
// number of samples for RSSI method
#define SAMPLES_RSSI 20 // 21 //
#define SAMPLES_RSSI 12 // 21 //
#define RANGE (int)(FREQ_END - FREQ_BEGIN)
@@ -217,10 +220,9 @@ uint64_t median_frequency = FREQ_BEGIN + FREQ_END - FREQ_BEGIN / 2;
// #define DISABLE_PLOT_CHART false // unused
// 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];
int16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
bool filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
int max_bins_array_value[MAX_POWER_LEVELS];
int max_step_range = 32;
@@ -235,6 +237,7 @@ bool first_run, new_pixel, detected_x = false;
// drone detection flag
bool detected = false;
uint64_t drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL;
uint64_t show_db_after = 80;
uint64_t drone_detected_frequency_start = 0;
uint64_t drone_detected_frequency_end = 0;
uint64_t detection_count = 0;
@@ -610,11 +613,14 @@ bool buttonPressHandler(float freq)
#endif
)
{
// Print Curent frequency once
if (button_pressed_counter == 0)
{
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(128 / 2, 0, String(freq));
display.display();
}
delay(10);
// Print Curent frequency
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(128 / 2, 0, String(freq));
display.display();
button_pressed_counter++;
if (button_pressed_counter > 150)
{
@@ -663,21 +669,28 @@ bool buttonPressHandler(float freq)
return true;
}
void drone_sound_alarm(int drone_detection_level, int detection_count)
void drone_sound_alarm(int drone_detection_level, int detection_count,
int tone_freq_db = 205)
{
// If level is set to sensitive,
// start beeping every 10th frequency and shorter
// it improves performance less short beep delays...
if (drone_detection_level <= 25)
{
if (tone_freq_db != 205)
{
tone_freq_db = 285 - tone_freq_db;
}
if (detection_count == 1 && SOUND_ON)
{
tone(BUZZER_PIN, 205,
tone(BUZZER_PIN, tone_freq_db,
10); // same action ??? but first time
}
if (detection_count % 5 == 0 && SOUND_ON)
{
tone(BUZZER_PIN, 205,
tone(BUZZER_PIN, tone_freq_db,
10); // same action ??? but every 5th time
}
}
@@ -775,6 +788,7 @@ void loop(void)
{
// clear the scan plot rectangle
UI_clearPlotter();
UI_clearTopStatus();
}
// do the scan
@@ -934,6 +948,7 @@ void loop(void)
for (int r = 0; r < SAMPLES_RSSI; r++)
{
rssi = radio.getRSSI(false);
int abs_rssi = abs(rssi);
// ToDO: check if 4 is correct value for 33 power bins
// Now we have more space because we are ignoring low dB values
// we can / 3 default 4
@@ -941,12 +956,12 @@ void loop(void)
{
result_index =
/// still not clear formula but it works
uint8_t(abs(rssi) / 4);
uint8_t(abs_rssi / 4);
}
else if (RSSI_OUTPUT_FORMULA == 2)
{
// I like this formula better
result_index = uint8_t(abs(rssi) / 2) - 22;
result_index = uint8_t(abs_rssi / 2) - 22;
}
if (result_index >= RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE)
{
@@ -960,11 +975,15 @@ void loop(void)
// avoid buffer overflow
if (result_index < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE)
{
// Saving max ABS value of rssi. dB is negative so smaller is
// bigger
if (result[result_index] == 0 || result[result_index] > abs(rssi))
// Saving max ABS value of RSSI. dB is negative, so smaller
// absolute value represents stronger signal.
if (result[result_index] == 0 || result[result_index] > abs_rssi)
{
result[result_index] = abs(rssi);
result[result_index] = abs_rssi;
}
if (max_x_rssi[display_x] > abs_rssi)
{
max_x_rssi[display_x] = abs_rssi;
}
}
else
@@ -1024,7 +1043,7 @@ void loop(void)
{
// do not process 'first' and 'last' row to avoid out of index
// access.
if ((y > 0) && (y < (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 1)))
if ((y > 0) && (y < (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 2)))
{
if (((result[y + 1] != 0) && (result[y + 2] != 0)) ||
(result[y - 1] != 0))
@@ -1040,12 +1059,23 @@ void loop(void)
#endif
}
}
} // not filtering if samples == 1
} // not filtering if samples == 1 because it will be filtered
else if (result[y] > 0 && samples == 1)
{
filtered_result[y] = 1;
}
// calculating max window x RSSI after filters
x_window = (int)(display_x / WINDOW_SIZE);
int abs_result = abs(result[y]);
if (filtered_result[y] == 1 && result[y] != 0 && result[y] != 1 &&
max_x_window[x_window] > abs_result)
{
max_x_window[x_window] = abs_result;
#ifdef PRINT_DEBUG
Serial.println("MAX x window: " + String(x_window) + " " +
String(abs_result));
#endif
}
#endif
// check if we should alarm about a drone presence
if ((filtered_result[y] == 1) // we have some data and
@@ -1076,18 +1106,21 @@ void loop(void)
drone_detected_frequency_end = freq;
if (SOUND_ON == true)
{
drone_sound_alarm(drone_detection_level, detection_count);
drone_sound_alarm(drone_detection_level, detection_count,
max_rssi_x * 2);
}
if (DRAW_DETECTION_TICKS == true)
{
// draw vertical line on top of display for "drone detected"
// frequencies
// draw vertical line on top of display for "drone detected"
// frequencies
#ifdef METHOD_SPECTRAL
if (!detected_y[display_x])
{
display.drawLine(display_x, 1, display_x, 4);
detected_y[display_x] = true;
}
#endif
}
}
#if (WATERFALL_ENABLED == true)
@@ -1114,7 +1147,7 @@ void loop(void)
// MAx bin Value not RSSI
max_rssi_x = y;
}
// Set signal level pixel
// Set MAIN signal level pixel
if (y < MAX_POWER_LEVELS - START_LOW)
{
display.setPixel(display_x, y + START_LOW);
@@ -1232,6 +1265,19 @@ void loop(void)
display.setColor(WHITE);
}
#endif
#ifdef METHOD_RSSI
// Printing Max Window DB.
for (int x2 = 0; x2 < STEPS / WINDOW_SIZE; x2++)
{
if (max_x_window[x2] < show_db_after && max_x_window[x2] != 0)
{
display.drawString(x2 * WINDOW_SIZE + WINDOW_SIZE, 0,
"-" + String(max_x_window[x2]));
}
max_x_window[x2] = 999;
}
#endif
// Render display data here
display.display();
#ifdef OSD_ENABLED
@@ -1251,7 +1297,7 @@ void loop(void)
#endif
}
#ifdef PRINT_DEBUG
// Serial.println("----");
// Serial.println("----");
#endif
loop_time = millis() - loop_start;

View File

@@ -80,7 +80,15 @@ void UI_clearPlotter(void)
{
// clear the scan plot rectangle (top part)
display_instance->setColor(BLACK);
display_instance->fillRect(0, 0, STEPS, HEIGHT);
display_instance->fillRect(0, 10, STEPS, HEIGHT - 10);
display_instance->setColor(WHITE);
}
void UI_clearTopStatus(void)
{
// clear the scan plot rectangle (top part)
display_instance->setColor(BLACK);
display_instance->fillRect(0, 0, STEPS, 10);
display_instance->setColor(WHITE);
}

View File

@@ -8,6 +8,7 @@
* This works on the stick, but the output on the screen gets cut off.
*/
#include <Arduino.h>
// Turns the 'PRG' button into the power button, long press is off
#define HELTEC_POWER_BUTTON // must be before "#include <heltec_unofficial.h>"
#include <heltec_unofficial.h>
@@ -15,11 +16,11 @@
// Pause between transmited packets in mseconds.
// Set to zero to only transmit a packet when pressing the user button
// Will not exceed 1% duty cycle, even if you set a lower value.
#define PAUSE 20
#define PAUSE 10
// Frequency in MHz. Keep the decimal point to designate float.
// Check your own rules and regulations to see what is legal where you are.
#define FREQUENCY 866.3 // for Europe
#define FREQUENCY 915 // for Europe
// #define FREQUENCY 905.2 // for US
// LoRa bandwidth. Keep the decimal point to designate float.
@@ -29,13 +30,13 @@
// Number from 5 to 12. Higher means slower but higher "processor gain",
// meaning (in nutshell) longer range and more robust against interference.
#define SPREADING_FACTOR 9
#define SPREADING_FACTOR 7
// Transmit power in dBm. 0 dBm = 1 mW, enough for tabletop-testing. This value can be
// set anywhere between -9 dBm (0.125 mW) to 22 dBm (158 mW). Note that the maximum ERP
// (which is what your antenna maximally radiates) on the EU ISM band is 25 mW, and that
// transmissting without an antenna can damage your hardware.
#define TRANSMIT_POWER -9
#define TRANSMIT_POWER 22
String rxdata;
volatile bool rxFlag = false;
@@ -67,35 +68,41 @@ void setup()
RADIOLIB_OR_HALT(radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF));
}
int FHSS = 0.25;
float FHSS_counter = -10;
void loop()
{
heltec_loop();
bool tx_legal = millis() > last_tx + minimum_pause;
bool tx_legal = true; // millis() > last_tx + minimum_pause;
// Emulate frequency hopping spread spectrum (FHSS) is a method of transmitting radio
// signals by rapidly switching the carrier between different frequency channels.
float fr = (float)(FREQUENCY + (float)(FHSS_counter));
RADIOLIB_OR_HALT(radio.setFrequency(fr, false));
// Transmit a packet every PAUSE seconds or when the button is pressed
if ((PAUSE && tx_legal && millis() - last_tx > (PAUSE)) || button.isSingleClick())
{
// In case of button click, tell user to wait
if (!tx_legal)
if (button.isSingleClick())
{
both.printf("Legal limit, wait %i sec.\n",
(int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
return;
fr = 1000;
RADIOLIB_OR_HALT(radio.setFrequency(fr, false));
}
both.printf("TX [%s] ", String(counter).c_str());
// In case of button click, tell user to wait
display.printf("TX[%s]", String(counter).c_str());
radio.clearDio1Action();
heltec_led(50); // 50% brightness is plenty for this LED
tx_time = millis();
RADIOLIB(radio.transmit(String(counter++).c_str()));
RADIOLIB(radio.transmit(String("Putin Huylo!!! LA-LA-LA-LA").c_str()));
tx_time = millis() - tx_time;
heltec_led(0);
if (_radiolib_status == RADIOLIB_ERR_NONE)
{
both.printf("OK (%i ms)\n", (int)tx_time);
display.printf("OK(%ims)/%.2fMhz\n", (int)tx_time, fr);
}
else
{
both.printf("fail (%i)\n", _radiolib_status);
display.printf("fail (%i)\n", _radiolib_status);
heltec_delay(100);
}
// Maximum 1% duty cycle
minimum_pause = tx_time * 100;
@@ -111,10 +118,16 @@ void loop()
radio.readData(rxdata);
if (_radiolib_status == RADIOLIB_ERR_NONE)
{
both.printf("RX [%s]\n", rxdata.c_str());
both.printf(" RSSI: %.2f dBm\n", radio.getRSSI());
both.printf(" SNR: %.2f dB\n", radio.getSNR());
display.printf("RX [%s]\n", rxdata.c_str());
display.printf(" RSSI: %.2f dBm\n", radio.getRSSI());
display.printf(" SNR: %.2f dB\n", radio.getSNR());
}
RADIOLIB_OR_HALT(radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF));
}
FHSS_counter += 0.250;
counter++;
if (FHSS_counter > 20)
{
FHSS_counter = -10;
}
}