mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
ADS-B receive app debug code
This commit is contained in:
parent
46515ebb05
commit
802b91964b
@ -160,7 +160,8 @@ set(CPPSRC
|
|||||||
${COMMON}/ui_painter.cpp
|
${COMMON}/ui_painter.cpp
|
||||||
${COMMON}/ui_focus.cpp
|
${COMMON}/ui_focus.cpp
|
||||||
ui_about.cpp
|
ui_about.cpp
|
||||||
ui_adsbtx.cpp
|
ui_adsb_tx.cpp
|
||||||
|
ui_adsb_rx.cpp
|
||||||
ui_aprstx.cpp
|
ui_aprstx.cpp
|
||||||
ui_modemsetup.cpp
|
ui_modemsetup.cpp
|
||||||
ui_alphanum.cpp
|
ui_alphanum.cpp
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
namespace adsb {
|
namespace adsb {
|
||||||
|
|
||||||
const char icao_id_lut[65] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######";
|
const char icao_id_lut[65] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######";
|
||||||
|
const uint8_t adsb_preamble[16] = { 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
void make_frame_mode_s(uint8_t * const adsb_frame, const uint32_t ICAO_address);
|
void make_frame_mode_s(uint8_t * const adsb_frame, const uint32_t ICAO_address);
|
||||||
|
|
||||||
|
255
firmware/application/ui_adsb_rx.cpp
Normal file
255
firmware/application/ui_adsb_rx.cpp
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2017 Furrtek
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ui_adsb_rx.hpp"
|
||||||
|
#include "ui_alphanum.hpp"
|
||||||
|
|
||||||
|
#include "adsb.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
#include "portapack.hpp"
|
||||||
|
#include "baseband_api.hpp"
|
||||||
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace adsb;
|
||||||
|
using namespace portapack;
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
void ADSBRxView::focus() {
|
||||||
|
offset_field.focus();
|
||||||
|
offset_field.set_value(13179);
|
||||||
|
}
|
||||||
|
|
||||||
|
ADSBRxView::~ADSBRxView() {
|
||||||
|
//transmitter_model.disable();
|
||||||
|
//baseband::shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADSBRxView::analyze(uint64_t offset) {
|
||||||
|
size_t c;
|
||||||
|
Coord lcd_x = 0, lcd_y = 0;
|
||||||
|
int16_t file_data[128]; // 256 bytes / 2 IQ / 16 bits = 64 samples
|
||||||
|
complex8_t iq_data[256]; // 256 samples
|
||||||
|
uint64_t file_offset = 0;
|
||||||
|
uint8_t data_put = 0, data_get = 0;
|
||||||
|
int16_t f_re, f_im;
|
||||||
|
int8_t re, im;
|
||||||
|
uint8_t level, bit, byte;
|
||||||
|
Color mark_color;
|
||||||
|
size_t preamble_count = 0, null_count = 0, bit_count = 0, sample_count = 0;
|
||||||
|
bool decoding = false;
|
||||||
|
float prev_mag, mag;
|
||||||
|
float threshold, threshold_low, threshold_high;
|
||||||
|
std::string bits;
|
||||||
|
std::string hex_str;
|
||||||
|
bool confidence, first_in_window, last_in_window;
|
||||||
|
uint8_t frame_index;
|
||||||
|
uint8_t adsb_frame[256];
|
||||||
|
|
||||||
|
// Use vectors and std::rotate !
|
||||||
|
float shifter[16];
|
||||||
|
uint8_t shifter_bits[16];
|
||||||
|
|
||||||
|
iq_file.seek(offset * 256);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (data_put == data_get) {
|
||||||
|
auto result = iq_file.read(file_data, 256);
|
||||||
|
if (!result.is_error()) {
|
||||||
|
// Convert file's C16 to C8
|
||||||
|
for (c = 0; c < (result.value() / 4); c++) {
|
||||||
|
f_re = file_data[(c * 2) + 0] >> 5;
|
||||||
|
f_im = file_data[(c * 2) + 1] >> 5;
|
||||||
|
iq_data[data_put] = { f_re, f_im };
|
||||||
|
data_put++;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_offset += result.value();
|
||||||
|
|
||||||
|
if (file_offset >= 4096) {
|
||||||
|
text_debug_e.set("Read @ " + to_string_dec_uint(offset * 256 / 2000 / 4) + "ms ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text_debug_a.set("Read error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
re = iq_data[data_get].real();
|
||||||
|
im = iq_data[data_get].imag();
|
||||||
|
mag = __builtin_sqrtf((re * re) + (im * im)) * k;
|
||||||
|
data_get++;
|
||||||
|
|
||||||
|
// Only used for preamble detection and visualisation
|
||||||
|
level = (mag < 0.3) ? 0 : // Blank weak signals
|
||||||
|
(mag > prev_mag) ? 1 : 0;
|
||||||
|
|
||||||
|
if (decoding) {
|
||||||
|
// Decode
|
||||||
|
mark_color = Color::grey();
|
||||||
|
if (sample_count & 1) {
|
||||||
|
if ((prev_mag < threshold_low) && (mag < threshold_low)) {
|
||||||
|
// Both under window, silence.
|
||||||
|
mark_color = Color::black();
|
||||||
|
if (null_count > 3) {
|
||||||
|
text_debug_b.set("Bits:" + bits.substr(0, 25));
|
||||||
|
text_debug_c.set("Hex:" + hex_str.substr(0, 26));
|
||||||
|
text_debug_d.set("DF=" + to_string_dec_uint(adsb_frame[0] >> 3) + " ICAO=" + to_string_hex((adsb_frame[1] << 16) + (adsb_frame[2] << 8) + adsb_frame[3], 6));
|
||||||
|
decoding = false;
|
||||||
|
} else
|
||||||
|
null_count++;
|
||||||
|
|
||||||
|
confidence = false;
|
||||||
|
if (prev_mag > mag)
|
||||||
|
bit = 1;
|
||||||
|
else
|
||||||
|
bit = 0;
|
||||||
|
|
||||||
|
mark_color = bit ? Color::dark_red() : Color::dark_green();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
null_count = 0;
|
||||||
|
|
||||||
|
first_in_window = ((prev_mag >= threshold_low) && (prev_mag <= threshold_high));
|
||||||
|
last_in_window = ((mag >= threshold_low) && (mag <= threshold_high));
|
||||||
|
|
||||||
|
if ((first_in_window && !last_in_window) || (!first_in_window && last_in_window)) {
|
||||||
|
confidence = true;
|
||||||
|
if (prev_mag > mag)
|
||||||
|
bit = 1;
|
||||||
|
else
|
||||||
|
bit = 0;
|
||||||
|
} else {
|
||||||
|
confidence = false;
|
||||||
|
if (prev_mag > mag)
|
||||||
|
bit = 1;
|
||||||
|
else
|
||||||
|
bit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_color = bit ? Color::red() : Color::green();
|
||||||
|
}
|
||||||
|
|
||||||
|
bits.append(bit ? "1" : "0");
|
||||||
|
byte = bit | (byte << 1);
|
||||||
|
bit_count++;
|
||||||
|
if (!(bit_count & 7)) {
|
||||||
|
// Got one byte
|
||||||
|
hex_str += to_string_hex(byte, 2);
|
||||||
|
adsb_frame[frame_index++] = byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sample_count++;
|
||||||
|
} else {
|
||||||
|
// Look for preamble
|
||||||
|
mark_color = Color::white();
|
||||||
|
|
||||||
|
// TODO: Stop using 2 separate shift registers for float and bit...
|
||||||
|
for (c = 0; c < 15; c++)
|
||||||
|
shifter[c] = shifter[c + 1];
|
||||||
|
shifter[15] = mag;
|
||||||
|
|
||||||
|
for (c = 0; c < 15; c++)
|
||||||
|
shifter_bits[c] = shifter_bits[c + 1];
|
||||||
|
shifter_bits[15] = level;
|
||||||
|
|
||||||
|
if (!memcmp(shifter_bits, adsb_preamble, 16)) {
|
||||||
|
preamble_count++;
|
||||||
|
if (preamble_count == 1) {
|
||||||
|
// Try decoding the first frame found
|
||||||
|
decoding = true;
|
||||||
|
sample_count = 0;
|
||||||
|
frame_index = 0;
|
||||||
|
|
||||||
|
// Compute preamble pulses power to set thresholds
|
||||||
|
threshold = (shifter[0] + shifter[2] + shifter[7] + shifter[9]) / 4;
|
||||||
|
threshold_high = threshold * 1.414; // +3dB
|
||||||
|
threshold_low = threshold * 0.707; // -3dB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_mag = mag;
|
||||||
|
|
||||||
|
/*if (!lcd_y && !lcd_x) {
|
||||||
|
for (c = 0; c < 16; c++)
|
||||||
|
display.fill_rectangle({c * 4, 300, 4, 16}, shifter[c] ? Color::white() : Color::blue());
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (lcd_y < 188) {
|
||||||
|
mag *= 16;
|
||||||
|
// Background
|
||||||
|
display.fill_rectangle({lcd_x, 100 + lcd_y, 2, 32 - mag}, decoding ? mark_color : Color::grey());
|
||||||
|
// Bar
|
||||||
|
display.fill_rectangle({lcd_x, 132 + lcd_y - mag, 2, mag}, Color::white());
|
||||||
|
// Level
|
||||||
|
display.fill_rectangle({lcd_x, 132 + lcd_y, 2, 4}, decoding ? ((sample_count & 1) ? Color::white() : Color::light_grey()) : (level ? Color::white() : Color::dark_blue()));
|
||||||
|
if (lcd_x == 238) {
|
||||||
|
lcd_x = 0;
|
||||||
|
lcd_y += 40;
|
||||||
|
} else {
|
||||||
|
lcd_x += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text_debug_a.set("Found " + to_string_dec_uint(preamble_count) + " preambles ");
|
||||||
|
}
|
||||||
|
|
||||||
|
ADSBRxView::ADSBRxView(NavigationView& nav) {
|
||||||
|
uint32_t c;
|
||||||
|
|
||||||
|
//baseband::run_image(portapack::spi_flash::image_tag_adsb_rx);
|
||||||
|
|
||||||
|
add_children({
|
||||||
|
&labels,
|
||||||
|
&offset_field,
|
||||||
|
&button_ffw,
|
||||||
|
&text_debug_a,
|
||||||
|
&text_debug_b,
|
||||||
|
&text_debug_c,
|
||||||
|
&text_debug_d,
|
||||||
|
&text_debug_e
|
||||||
|
});
|
||||||
|
|
||||||
|
// File must be 16bit complex @ 2Msps !
|
||||||
|
|
||||||
|
auto result = iq_file.open("ADSB.C16");
|
||||||
|
if (result.is_valid()) {
|
||||||
|
text_debug_a.set("Can't open file");
|
||||||
|
}
|
||||||
|
|
||||||
|
offset_field.on_change = [this, &nav](int32_t value) {
|
||||||
|
analyze(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
button_ffw.on_select = [this, &nav](Button&) {
|
||||||
|
offset_field.set_value(offset_field.value() + 1562);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace ui */
|
99
firmware/application/ui_adsb_rx.hpp
Normal file
99
firmware/application/ui_adsb_rx.hpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2017 Furrtek
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
|
#include "file.hpp"
|
||||||
|
//#include "ui_textentry.hpp"
|
||||||
|
//#include "ui_widget.hpp"
|
||||||
|
#include "ui_navigation.hpp"
|
||||||
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
|
|
||||||
|
#include "message.hpp"
|
||||||
|
#include "portapack.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class ADSBRxView : public View {
|
||||||
|
public:
|
||||||
|
ADSBRxView(NavigationView& nav);
|
||||||
|
~ADSBRxView();
|
||||||
|
|
||||||
|
void focus() override;
|
||||||
|
|
||||||
|
std::string title() const override { return "ADS-B debug"; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr float k = 1.0f / 128.0f;
|
||||||
|
|
||||||
|
File iq_file { };
|
||||||
|
|
||||||
|
void analyze(uint64_t offset);
|
||||||
|
|
||||||
|
Labels labels {
|
||||||
|
{ { 0 * 8, 0 * 8 }, "Test", Color::light_grey() }
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberField offset_field {
|
||||||
|
{ 0, 0 },
|
||||||
|
6,
|
||||||
|
{ 0, 819200 }, // * 256 -> file offset
|
||||||
|
1,
|
||||||
|
'0'
|
||||||
|
};
|
||||||
|
Text text_debug_e {
|
||||||
|
{ 7 * 8, 0 * 16, 14 * 8, 16 },
|
||||||
|
"-"
|
||||||
|
};
|
||||||
|
|
||||||
|
Text text_debug_a {
|
||||||
|
{ 0 * 8, 1 * 16, 30 * 8, 16 },
|
||||||
|
"-"
|
||||||
|
};
|
||||||
|
Text text_debug_b {
|
||||||
|
{ 0 * 8, 2 * 16, 30 * 8, 16 },
|
||||||
|
"-"
|
||||||
|
};
|
||||||
|
Text text_debug_c {
|
||||||
|
{ 0 * 8, 3 * 16, 30 * 8, 16 },
|
||||||
|
"-"
|
||||||
|
};
|
||||||
|
Text text_debug_d {
|
||||||
|
{ 0 * 8, 4 * 16, 30 * 8, 16 },
|
||||||
|
"-"
|
||||||
|
};
|
||||||
|
|
||||||
|
Button button_ffw {
|
||||||
|
{ 176, 0 * 16, 64, 16 },
|
||||||
|
"+50ms"
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
MessageHandlerRegistration message_handler_tx_done {
|
||||||
|
Message::ID::TXDone,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = *reinterpret_cast<const TXDoneMessage*>(p);
|
||||||
|
this->on_txdone(message.done);
|
||||||
|
}
|
||||||
|
};*/
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace ui */
|
@ -20,7 +20,7 @@
|
|||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui_adsbtx.hpp"
|
#include "ui_adsb_tx.hpp"
|
||||||
#include "ui_alphanum.hpp"
|
#include "ui_alphanum.hpp"
|
||||||
|
|
||||||
#include "adsb.hpp"
|
#include "adsb.hpp"
|
@ -31,7 +31,8 @@
|
|||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
|
||||||
#include "ui_about.hpp"
|
#include "ui_about.hpp"
|
||||||
#include "ui_adsbtx.hpp"
|
#include "ui_adsb_tx.hpp"
|
||||||
|
#include "ui_adsb_rx.hpp"
|
||||||
#include "ui_aprstx.hpp"
|
#include "ui_aprstx.hpp"
|
||||||
#include "ui_bht_tx.hpp"
|
#include "ui_bht_tx.hpp"
|
||||||
#include "ui_coasterp.hpp"
|
#include "ui_coasterp.hpp"
|
||||||
@ -282,7 +283,7 @@ void NavigationView::focus() {
|
|||||||
|
|
||||||
ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
||||||
add_items({
|
add_items({
|
||||||
{ "ADS-B: Planes", ui::Color::grey(), &bitmap_icon_adsb, [&nav](){ nav.push<NotImplementedView>(); }, },
|
{ "ADS-B: Planes", ui::Color::orange(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBRxView>(); }, },
|
||||||
{ "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
|
{ "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
|
||||||
{ "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||||
{ "Audio", ui::Color::green(), nullptr, [&nav](){ nav.push<AnalogAudioView>(false); } },
|
{ "Audio", ui::Color::green(), nullptr, [&nav](){ nav.push<AnalogAudioView>(false); } },
|
||||||
|
Loading…
Reference in New Issue
Block a user