Added ADSB RX details view

ADSB RX: Details and map view shouldn't freeze anymore
Added instructions to generate world_map.bin
This commit is contained in:
furrtek 2017-08-28 07:05:31 +01:00
parent fa519bba63
commit 986b54e43f
9 changed files with 233 additions and 53 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@
/firmware/application/portapack_cpld_data.cpp /firmware/application/portapack_cpld_data.cpp
/firmware/application/hackrf_cpld_data.cpp /firmware/application/hackrf_cpld_data.cpp
/firmware/application/hackrf_cpld_data.hpp /firmware/application/hackrf_cpld_data.hpp
/sdcard/ADSB/world_map.bin
# Compiled Object files # Compiled Object files
*.slo *.slo

View File

@ -94,7 +94,7 @@ private:
{"E. Oenal", "", MEMBER_LF}, {"E. Oenal", "", MEMBER_LF},
{"RDS waveform", "C. Jacquet", TITLE_LF}, {"RDS waveform", "C. Jacquet", TITLE_LF},
{"Xy. infos", "cLx", TITLE_LF}, {"Xy. infos", "cLx", TITLE_LF},
{"ADS-B map", "D. Strebe", TITLE_LF}, {"World map", "NASA", TITLE_LF},
{"Thanks", "", SECTION}, {"Thanks", "", SECTION},
{"Rainer Matla", "Keld Norman", TITLE}, {"Rainer Matla", "Keld Norman", TITLE},
{"Giorgio C.", "DC1RDB", TITLE}, {"Giorgio C.", "DC1RDB", TITLE},

View File

@ -74,8 +74,109 @@ void RecentEntriesTable<AircraftRecentEntries>::draw(
painter.draw_bitmap(target_rect.location() + Point(15 * 8, 0), bitmap_target, target_color, style.background); painter.draw_bitmap(target_rect.location() + Point(15 * 8, 0), bitmap_target, target_color, style.background);
} }
void ADSBRxDetailsView::focus() {
button_see_map.focus();
}
void ADSBRxDetailsView::update(const AircraftRecentEntry& entry) {
entry_copy = entry;
uint32_t age = entry_copy.age;
if (age < 60)
text_last_seen.set(to_string_dec_uint(age) + " seconds ago");
else
text_last_seen.set(to_string_dec_uint(age / 60) + " minutes ago");
text_infos.set(entry_copy.info_string);
text_frame_pos_even.set(to_string_hex_array(entry_copy.frame_pos_even.get_raw_data(), 14));
text_frame_pos_odd.set(to_string_hex_array(entry_copy.frame_pos_odd.get_raw_data(), 14));
if (send_updates)
geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude);
}
ADSBRxDetailsView::~ADSBRxDetailsView() {
on_close_();
}
ADSBRxDetailsView::ADSBRxDetailsView(
NavigationView& nav,
const AircraftRecentEntry& entry,
const std::function<void(void)> on_close
) : entry_copy(entry),
on_close_(on_close)
{
char file_buffer[32] { 0 };
bool found = false;
std::string airline_code;
size_t c;
add_children({
&labels,
&text_callsign,
&text_last_seen,
&text_airline,
&text_country,
&text_infos,
&text_frame_pos_even,
&text_frame_pos_odd,
&button_see_map
});
update(entry_copy);
// The following won't (shouldn't !) change for a given airborne aircraft
// Try getting the airline's name from airlines.db
auto result = db_file.open("ADSB/airlines.db");
if (!result.is_valid()) {
// Search for 3-letter code in 0x0000~0x2000
airline_code = entry_copy.callsign.substr(0, 3);
c = 0;
do {
db_file.read(file_buffer, 4);
if (!file_buffer[0])
break;
if (!airline_code.compare(0, 4, file_buffer))
found = true;
else
c++;
} while (!found);
if (found) {
db_file.seek(0x2000 + (c << 6));
db_file.read(file_buffer, 32);
text_airline.set(file_buffer);
db_file.read(file_buffer, 32);
text_country.set(file_buffer);
} else {
text_airline.set("Unknown");
text_country.set("Unknown");
}
} else {
text_airline.set("No airlines.db file");
text_country.set("No airlines.db file");
}
text_callsign.set(entry_copy.callsign);
button_see_map.on_select = [this, &nav](Button&) {
geomap_view = nav.push<GeoMapView>(
entry_copy.callsign,
entry_copy.pos.altitude,
entry_copy.pos.latitude,
entry_copy.pos.longitude,
0,
[this]() {
send_updates = false;
});
send_updates = true;
};
};
void ADSBRxView::focus() { void ADSBRxView::focus() {
field_lna.focus(); field_vga.focus();
} }
ADSBRxView::~ADSBRxView() { ADSBRxView::~ADSBRxView() {
@ -123,8 +224,8 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
entry.set_info_string(str_info); entry.set_info_string(str_info);
if (geomap_view) if (send_updates)
geomap_view->update_pos(entry.pos.latitude, entry.pos.longitude); details_view->update(entry);
} }
} }
} }
@ -138,6 +239,8 @@ void ADSBRxView::on_tick_second() {
entry.inc_age(); entry.inc_age();
if ((entry.age == 10) || (entry.age == 30)) if ((entry.age == 10) || (entry.age == 30))
recent_entries_view.set_dirty(); recent_entries_view.set_dirty();
if (details_view && send_updates && (entry.key() == detailed_entry_key))
details_view->update(entry);
} }
} }
@ -149,24 +252,18 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
&rssi, &rssi,
&field_lna, &field_lna,
&field_vga, &field_vga,
//&text_debug_a,
//&text_debug_b,
//&text_debug_c,
&recent_entries_view &recent_entries_view
}); });
recent_entries_view.set_parent_rect({ 0, 64, 240, 224 }); recent_entries_view.set_parent_rect({ 0, 16, 240, 272 });
recent_entries_view.on_select = [this, &nav](const AircraftRecentEntry& entry) { recent_entries_view.on_select = [this, &nav](const AircraftRecentEntry& entry) {
//text_debug_a.set(entry.info_string); detailed_entry_key = entry.key();
//text_debug_b.set(to_string_hex_array(entry.frame_pos_even.get_raw_data(), 14)); details_view = nav.push<ADSBRxDetailsView>(
//text_debug_c.set(to_string_hex_array(entry.frame_pos_odd.get_raw_data(), 14)); entry,
[this]() {
geomap_view = nav.push<GeoMapView>( send_updates = false;
entry.callsign, });
entry.pos.altitude, send_updates = true;
entry.pos.latitude,
entry.pos.longitude,
0.0);
}; };
signal_token_tick_second = rtc_time::signal_tick_second += [this]() { signal_token_tick_second = rtc_time::signal_tick_second += [this]() {

View File

@ -100,9 +100,80 @@ struct AircraftRecentEntry {
using AircraftRecentEntries = RecentEntries<AircraftRecentEntry>; using AircraftRecentEntries = RecentEntries<AircraftRecentEntry>;
class ADSBRxDetailsView : public View {
public:
ADSBRxDetailsView(NavigationView&, const AircraftRecentEntry& entry, const std::function<void(void)> on_close);
~ADSBRxDetailsView();
ADSBRxDetailsView(const ADSBRxDetailsView&) = delete;
ADSBRxDetailsView(ADSBRxDetailsView&&) = delete;
ADSBRxDetailsView& operator=(const ADSBRxDetailsView&) = delete;
ADSBRxDetailsView& operator=(ADSBRxDetailsView&&) = delete;
void focus() override;
void update(const AircraftRecentEntry& entry);
std::string title() const override { return "Aircraft details"; };
private:
AircraftRecentEntry entry_copy { 0 };
std::function<void(void)> on_close_ { };
GeoMapView* geomap_view { nullptr };
bool send_updates { false };
File db_file { };
Labels labels {
{ { 0 * 8, 1 * 16 }, "Callsign:", Color::light_grey() },
{ { 0 * 8, 2 * 16 }, "Last seen:", Color::light_grey() },
{ { 0 * 8, 3 * 16 }, "Airline:", Color::light_grey() },
{ { 0 * 8, 5 * 16 }, "Country:", Color::light_grey() },
{ { 0 * 8, 12 * 16 }, "Even position frame:", Color::light_grey() },
{ { 0 * 8, 14 * 16 }, "Odd position frame:", Color::light_grey() }
};
Text text_callsign {
{ 9 * 8, 1 * 16, 8 * 8, 16 },
"-"
};
Text text_last_seen {
{ 11 * 8, 2 * 16, 19 * 8, 16 },
"-"
};
Text text_airline {
{ 0 * 8, 4 * 16, 30 * 8, 16 },
"-"
};
Text text_country {
{ 8 * 8, 5 * 16, 22 * 8, 16 },
"-"
};
Text text_infos {
{ 0 * 8, 6 * 16, 30 * 8, 16 },
"-"
};
Text text_frame_pos_even {
{ 0 * 8, 13 * 16, 30 * 8, 16 },
"-"
};
Text text_frame_pos_odd {
{ 0 * 8, 15 * 16, 30 * 8, 16 },
"-"
};
Button button_see_map {
{ 8 * 8, 8 * 16, 14 * 8, 3 * 16 },
"See on map"
};
};
class ADSBRxView : public View { class ADSBRxView : public View {
public: public:
ADSBRxView(NavigationView&); ADSBRxView(NavigationView& nav);
~ADSBRxView(); ~ADSBRxView();
ADSBRxView(const ADSBRxView&) = delete; ADSBRxView(const ADSBRxView&) = delete;
@ -127,8 +198,14 @@ private:
AircraftRecentEntries recent { }; AircraftRecentEntries recent { };
RecentEntriesView<RecentEntries<AircraftRecentEntry>> recent_entries_view { columns, recent }; RecentEntriesView<RecentEntries<AircraftRecentEntry>> recent_entries_view { columns, recent };
GeoMapView* geomap_view { };
SignalToken signal_token_tick_second { }; SignalToken signal_token_tick_second { };
ADSBRxDetailsView* details_view { nullptr };
uint32_t detailed_entry_key { 0 };
bool send_updates { false };
Labels labels {
{ { 0 * 8, 0 * 8 }, "LNA: VGA: RSSI:", Color::light_grey() }
};
RSSI rssi { RSSI rssi {
{ 19 * 8, 4, 10 * 8, 8 }, { 19 * 8, 4, 10 * 8, 8 },
@ -142,23 +219,6 @@ private:
{ 11 * 8, 0 * 16 } { 11 * 8, 0 * 16 }
}; };
Labels labels {
{ { 0 * 8, 0 * 8 }, "LNA: VGA: RSSI:", Color::light_grey() }
};
/*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 },
"-"
};*/
MessageHandlerRegistration message_handler_frame { MessageHandlerRegistration message_handler_frame {
Message::ID::ADSBFrame, Message::ID::ADSBFrame,
[this](Message* const p) { [this](Message* const p) {

View File

@ -140,16 +140,6 @@ void GeoMap::paint(Painter& painter) {
draw_bearing({ 120, 32 + 144 }, angle_, 16, Color::red()); draw_bearing({ 120, 32 + 144 }, angle_, 16, Color::red());
painter.draw_string({ 120 - ((int)tag_.length() * 8 / 2), 32 + 144 - 32 }, style(), tag_); painter.draw_string({ 120 - ((int)tag_.length() * 8 / 2), 32 + 144 - 32 }, style(), tag_);
} }
/*if (has_focus() || highlighted())
border = style().foreground;
else
border = Color::grey();
painter.draw_rectangle(
{ r.location().x(), r.location().y(), r.size().width(), r.size().height() },
border
);*/
} }
bool GeoMap::on_touch(const TouchEvent event) { bool GeoMap::on_touch(const TouchEvent event) {
@ -226,7 +216,7 @@ void GeoMapView::focus() {
nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT, nullptr); nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT, nullptr);
} }
void GeoMapView::update_pos(float lat, float lon) { void GeoMapView::update_position(float lat, float lon) {
lat_ = lat; lat_ = lat;
lon_ = lon; lon_ = lon;
geomap.move(lon_, lat_); geomap.move(lon_, lat_);
@ -266,6 +256,12 @@ void GeoMapView::setup() {
}; };
} }
GeoMapView::~GeoMapView() {
if (on_close_)
on_close_();
}
// Display mode // Display mode
GeoMapView::GeoMapView( GeoMapView::GeoMapView(
NavigationView& nav, NavigationView& nav,
@ -273,12 +269,14 @@ GeoMapView::GeoMapView(
int32_t altitude, int32_t altitude,
float lat, float lat,
float lon, float lon,
float angle float angle,
const std::function<void(void)> on_close
) : nav_ (nav), ) : nav_ (nav),
altitude_ (altitude), altitude_ (altitude),
lat_ (lat), lat_ (lat),
lon_ (lon), lon_ (lon),
angle_ (angle) angle_ (angle),
on_close_(on_close)
{ {
mode_ = DISPLAY; mode_ = DISPLAY;

View File

@ -129,8 +129,22 @@ private:
class GeoMapView : public View { class GeoMapView : public View {
public: public:
GeoMapView(NavigationView& nav, const std::string& tag, int32_t altitude, float lat, float lon, float angle); GeoMapView(
GeoMapView(NavigationView& nav, int32_t altitude, float lat, float lon, const std::function<void(int32_t, float, float)> on_done); NavigationView& nav,
const std::string& tag,
int32_t altitude,
float lat,
float lon,
float angle,
const std::function<void(void)> on_close
);
GeoMapView(NavigationView& nav,
int32_t altitude,
float lat,
float lon,
const std::function<void(int32_t, float, float)> on_done
);
~GeoMapView();
GeoMapView(const GeoMapView&) = delete; GeoMapView(const GeoMapView&) = delete;
GeoMapView(GeoMapView&&) = delete; GeoMapView(GeoMapView&&) = delete;
@ -139,7 +153,7 @@ public:
void focus() override; void focus() override;
void update_pos(float lat, float lon); void update_position(float lat, float lon);
std::string title() const override { return "Map view"; }; std::string title() const override { return "Map view"; };
@ -156,6 +170,7 @@ private:
float lat_ { }; float lat_ { };
float lon_ { }; float lon_ { };
float angle_ { }; float angle_ { };
std::function<void(void)> on_close_ { nullptr };
bool file_error { }; bool file_error { };

Binary file not shown.

BIN
sdcard/ADSB/world_map.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 MiB

9
sdcard/README.md Normal file
View File

@ -0,0 +1,9 @@
# How to generate world_map.bin
World_map.bin is a huge (~450MB) raw image file in a format that can be easily rendered by the PortaPack.
Since Github doesn't allow uploading such large files, you must generate it yourself from the provided jpg file.
1. Make sur that `world_map.jpg` is in `/sdcard/ADSB`.
1. Go in `/firmware/tools`.
1. Run 'python adsb_map.py'. Give it some time.
1. `world_map.bin` should appear !