mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-02-23 16:19:59 -05:00
Merge pull request #441 from ArjanOnwezen/make-icao24-db
Show aircraft info based on ICAO 24 bit transponder code in ADS-B app
This commit is contained in:
commit
e2a2f7a448
@ -1,5 +1,5 @@
|
||||
# License
|
||||
Portapack Mayhem is distributed under GPL v3.0, however some sub projects might have different (GPL v3.0 compatible) licenses.
|
||||
Portapack Mayhem is distributed under [GPL v3.0](LICENSE), however some sub projects might have different (GPL v3.0 compatible) licenses.
|
||||
|
||||
## Other Licenses (compatible with GPL v3.0)
|
||||
- Most of Portapack Mayhem is distributed under GPL-2.0-or-later. [license](LICENSE.GPL-2.0-or-later)
|
||||
|
@ -91,6 +91,141 @@ void ADSBLogger::log_str(std::string& logline) {
|
||||
log_file.write_entry(datetime,logline);
|
||||
}
|
||||
|
||||
|
||||
// Aircraft Details
|
||||
void ADSBRxAircraftDetailsView::focus() {
|
||||
button_close.focus();
|
||||
}
|
||||
|
||||
ADSBRxAircraftDetailsView::~ADSBRxAircraftDetailsView() {
|
||||
on_close_();
|
||||
}
|
||||
|
||||
ADSBRxAircraftDetailsView::ADSBRxAircraftDetailsView(
|
||||
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;
|
||||
size_t number_of_icao_codes = 0;
|
||||
std::string icao_code;
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&text_icao_address,
|
||||
&text_registration,
|
||||
&text_manufacturer,
|
||||
&text_model,
|
||||
&text_type,
|
||||
&text_number_of_engines,
|
||||
&text_engine_type,
|
||||
&text_owner,
|
||||
&button_close
|
||||
});
|
||||
|
||||
std::unique_ptr<ADSBLogger> logger { };
|
||||
//update(entry_copy);
|
||||
|
||||
text_icao_address.set(to_string_hex(entry_copy.ICAO_address, 6));
|
||||
|
||||
|
||||
// Try getting the aircraft information from icao24.db
|
||||
auto result = db_file.open("ADSB/icao24.db");
|
||||
if (!result.is_valid()) {
|
||||
number_of_icao_codes = (db_file.size() / 115); // determine number of ICAO24 codes in file
|
||||
icao_code = to_string_hex(entry_copy.ICAO_address, 6);
|
||||
|
||||
// binary search
|
||||
int first = 0, // First search element
|
||||
last = number_of_icao_codes - 1, // Last search element
|
||||
middle, // Mid point of search
|
||||
position = -1; // Position of search value
|
||||
while (!found && first <= last) {
|
||||
middle = (first + last) / 2; // Calculate mid point
|
||||
db_file.seek(middle * 7);
|
||||
db_file.read(file_buffer, 6);
|
||||
if (file_buffer == icao_code) { // If value is found at mid
|
||||
found = true;
|
||||
position = middle;
|
||||
}
|
||||
else if (file_buffer > icao_code) // If value is in lower half
|
||||
last = middle - 1;
|
||||
else
|
||||
first = middle + 1; // If value is in upper half
|
||||
}
|
||||
|
||||
if (position > -1) {
|
||||
db_file.seek((number_of_icao_codes * 7) + (position * 108)); // seek starting after index
|
||||
db_file.read(file_buffer, 8);
|
||||
text_registration.set(file_buffer);
|
||||
db_file.read(file_buffer, 32);
|
||||
text_manufacturer.set(file_buffer);
|
||||
db_file.read(file_buffer, 32);
|
||||
text_model.set(file_buffer);
|
||||
|
||||
|
||||
|
||||
db_file.read(file_buffer, 4); //todo split in engine type, numbe rof engines,etc
|
||||
if(strlen(file_buffer) == 3) {
|
||||
switch(file_buffer[0]) {
|
||||
case 'L':
|
||||
text_type.set("Landplane");
|
||||
break;
|
||||
case 'S':
|
||||
text_type.set("Seaplane");
|
||||
break;
|
||||
case 'A':
|
||||
text_type.set("Amphibian");
|
||||
break;
|
||||
case 'H':
|
||||
text_type.set("Helicopter");
|
||||
break;
|
||||
case 'G':
|
||||
text_type.set("Gyrocopter");
|
||||
break;
|
||||
case 'T':
|
||||
text_type.set("Tilt-wing aircraft");
|
||||
break;
|
||||
}
|
||||
text_number_of_engines.set(std::string(1, file_buffer[1]));
|
||||
switch(file_buffer[2]) {
|
||||
case 'P':
|
||||
text_engine_type.set("Piston engine");
|
||||
break;
|
||||
case 'T':
|
||||
text_engine_type.set("Turboprop/Turboshaft engine");
|
||||
break;
|
||||
case 'J':
|
||||
text_engine_type.set("Jet engine");
|
||||
break;
|
||||
case 'E':
|
||||
text_engine_type.set("Electric engine");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
db_file.read(file_buffer, 32);
|
||||
text_owner.set(file_buffer);
|
||||
} else {
|
||||
text_registration.set("Unknown");
|
||||
text_manufacturer.set("Unknown");
|
||||
}
|
||||
} else {
|
||||
text_manufacturer.set("No icao24.db file");
|
||||
}
|
||||
|
||||
|
||||
button_close.on_select = [&nav](Button&){
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// End of Aicraft details
|
||||
|
||||
void ADSBRxDetailsView::focus() {
|
||||
button_see_map.focus();
|
||||
}
|
||||
@ -130,12 +265,13 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
{
|
||||
char file_buffer[32] { 0 };
|
||||
bool found = false;
|
||||
int number_of_airlines = 0;
|
||||
size_t number_of_airlines = 0;
|
||||
std::string airline_code;
|
||||
size_t c;
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&text_icao_address,
|
||||
&text_callsign,
|
||||
&text_last_seen,
|
||||
&text_airline,
|
||||
@ -144,6 +280,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
&text_info2,
|
||||
&text_frame_pos_even,
|
||||
&text_frame_pos_odd,
|
||||
&button_aircraft_details,
|
||||
&button_see_map
|
||||
});
|
||||
|
||||
@ -184,9 +321,20 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
}
|
||||
|
||||
text_callsign.set(entry_copy.callsign);
|
||||
|
||||
text_icao_address.set(to_string_hex(entry_copy.ICAO_address, 6));
|
||||
|
||||
button_aircraft_details.on_select = [this, &nav](Button&) {
|
||||
//detailed_entry_key = entry.key();
|
||||
aircraft_details_view = nav.push<ADSBRxAircraftDetailsView>(
|
||||
entry_copy,
|
||||
[this]() {
|
||||
send_updates = false;
|
||||
});
|
||||
send_updates = false;
|
||||
};
|
||||
|
||||
button_see_map.on_select = [this, &nav](Button&) {
|
||||
if (!send_updates) { // Prevent recursivley launching the map
|
||||
if (!send_updates) { // Prevent recursively launching the map
|
||||
geomap_view = nav.push<GeoMapView>(
|
||||
entry_copy.callsign,
|
||||
entry_copy.pos.altitude,
|
||||
@ -202,6 +350,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
void ADSBRxView::focus() {
|
||||
field_vga.focus();
|
||||
}
|
||||
|
@ -159,6 +159,88 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class ADSBRxAircraftDetailsView : public View {
|
||||
public:
|
||||
ADSBRxAircraftDetailsView(NavigationView&, const AircraftRecentEntry& entry, const std::function<void(void)> on_close);
|
||||
~ADSBRxAircraftDetailsView();
|
||||
|
||||
ADSBRxAircraftDetailsView(const ADSBRxAircraftDetailsView&) = delete;
|
||||
ADSBRxAircraftDetailsView(ADSBRxAircraftDetailsView&&) = delete;
|
||||
ADSBRxAircraftDetailsView& operator=(const ADSBRxAircraftDetailsView&) = delete;
|
||||
ADSBRxAircraftDetailsView& operator=(ADSBRxAircraftDetailsView&&) = delete;
|
||||
|
||||
void focus() override;
|
||||
|
||||
void update(const AircraftRecentEntry& entry);
|
||||
|
||||
std::string title() const override { return "AC Details"; };
|
||||
|
||||
AircraftRecentEntry get_current_entry() { return entry_copy; }
|
||||
|
||||
private:
|
||||
AircraftRecentEntry entry_copy { 0 };
|
||||
std::function<void(void)> on_close_ { };
|
||||
bool send_updates { false };
|
||||
File db_file { };
|
||||
|
||||
Labels labels {
|
||||
{ { 0 * 8, 1 * 16 }, "ICAO:", Color::light_grey() },
|
||||
{ { 0 * 8, 2 * 16 }, "Registration:", Color::light_grey() },
|
||||
{ { 0 * 8, 3 * 16 }, "Manufacturer:", Color::light_grey() },
|
||||
{ { 0 * 8, 5 * 16 }, "Model:", Color::light_grey() },
|
||||
{ { 0 * 8, 7 * 16 }, "Type:", Color::light_grey() },
|
||||
{ { 0 * 8, 8 * 16 }, "Number of engines:", Color::light_grey() },
|
||||
{ { 0 * 8, 9 * 16 }, "Engine type:", Color::light_grey() },
|
||||
{ { 0 * 8, 10 * 16 }, "Owner:", Color::light_grey() }
|
||||
};
|
||||
|
||||
Text text_icao_address {
|
||||
{ 5 * 8, 1 * 16, 6 * 8, 16},
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_registration {
|
||||
{ 13 * 8, 2 * 16, 8 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_manufacturer {
|
||||
{ 0 * 8, 4 * 16, 19 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_model {
|
||||
{ 0 * 8, 6 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_type {
|
||||
{ 5 * 8, 7 * 16, 22 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_number_of_engines {
|
||||
{ 18 * 8, 8 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_engine_type {
|
||||
{ 12 * 8, 9 * 16, 30 * 8, 16},
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_owner {
|
||||
{ 0 * 8, 11 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Button button_close {
|
||||
{ 9 * 8, 16 * 16, 12 * 8, 3 * 16 },
|
||||
"Back"
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class ADSBRxDetailsView : public View {
|
||||
public:
|
||||
ADSBRxDetailsView(NavigationView&, const AircraftRecentEntry& entry, const std::function<void(void)> on_close);
|
||||
@ -181,11 +263,13 @@ private:
|
||||
AircraftRecentEntry entry_copy { 0 };
|
||||
std::function<void(void)> on_close_ { };
|
||||
GeoMapView* geomap_view { nullptr };
|
||||
ADSBRxAircraftDetailsView* aircraft_details_view { nullptr };
|
||||
bool send_updates { false };
|
||||
File db_file { };
|
||||
|
||||
Labels labels {
|
||||
{ { 0 * 8, 1 * 16 }, "Callsign:", Color::light_grey() },
|
||||
{ { 0 * 8, 1 * 16 }, "ICAO:", Color::light_grey() },
|
||||
{ { 13 * 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() },
|
||||
@ -193,8 +277,13 @@ private:
|
||||
{ { 0 * 8, 15 * 16 }, "Odd position frame:", Color::light_grey() }
|
||||
};
|
||||
|
||||
Text text_icao_address {
|
||||
{ 5 * 8, 1 * 16, 6 * 8, 16},
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_callsign {
|
||||
{ 9 * 8, 1 * 16, 8 * 8, 16 },
|
||||
{ 22 * 8, 1 * 16, 8 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
@ -232,11 +321,17 @@ private:
|
||||
"-"
|
||||
};
|
||||
|
||||
Button button_aircraft_details {
|
||||
{ 2 * 8, 9 * 16, 12 * 8, 3 * 16 },
|
||||
"A/C details"
|
||||
};
|
||||
|
||||
Button button_see_map {
|
||||
{ 8 * 8, 9 * 16, 14 * 8, 3 * 16 },
|
||||
{ 16 * 8, 9 * 16, 12 * 8, 3 * 16 },
|
||||
"See on map"
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class ADSBRxView : public View {
|
||||
public:
|
||||
|
2
firmware/tools/generate_world_map.bin.py
Normal file → Executable file
2
firmware/tools/generate_world_map.bin.py
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2017 Furrtek
|
||||
#
|
||||
|
@ -1,7 +1,8 @@
|
||||
# Make airlines.db
|
||||
|
||||
Licensed under GNU GPL v3 (license)[../../../LICENSE]
|
||||
Licensed under [GNU GPL v3](../../../LICENSE)
|
||||
|
||||
USAGE:
|
||||
- Copy file from: https://raw.githubusercontent.com/kx1t/planefence-airlinecodes/main/airlinecodes.txt
|
||||
- Run Python 3 script: `./make_airlines_db.py`
|
||||
- Copy file to /ADSB folder on SDCARD
|
||||
|
8
firmware/tools/make_icao24_db/README.md
Normal file
8
firmware/tools/make_icao24_db/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Make icao24.db
|
||||
|
||||
Licensed under [GNU GPL v3](../../../LICENSE)
|
||||
|
||||
USAGE:
|
||||
- Copy file from: https://opensky-network.org/datasets/metadata/aircraftDatabase.csv
|
||||
- Run Python 3 script: `./make_icao24_db.py`
|
||||
- Copy file to /ADSB folder on SDCARD
|
460059
firmware/tools/make_icao24_db/aircraftDatabase.csv
Normal file
460059
firmware/tools/make_icao24_db/aircraftDatabase.csv
Normal file
File diff suppressed because it is too large
Load Diff
68
firmware/tools/make_icao24_db/make_icao24_db.py
Executable file
68
firmware/tools/make_icao24_db/make_icao24_db.py
Executable file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2021 ArjanOnwezen
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
# Create icao24.db, used for ADS-B receiver application, using
|
||||
# https://opensky-network.org/datasets/metadata/aircraftDatabase.csv
|
||||
# as a source.
|
||||
# -------------------------------------------------------------------------------------
|
||||
import csv
|
||||
import unicodedata
|
||||
icao24_codes=bytearray()
|
||||
data=bytearray()
|
||||
row_count=0
|
||||
|
||||
database=open("icao24.db", "wb")
|
||||
|
||||
with open('aircraftDatabase.csv', 'rt') as csv_file:
|
||||
sorted_lines=sorted(csv_file.readlines()[1:])
|
||||
for row in csv.reader(sorted_lines, quotechar='"', delimiter=',', quoting=csv.QUOTE_ALL, skipinitialspace=True):
|
||||
# only store in case enough info is available
|
||||
if len(row) == 27 and len(row[0]) == 6 and len(row[1]) > 0:
|
||||
icao24_code=row[0][:6].upper()
|
||||
registration=row[1][:8].encode('ascii', 'ignore')
|
||||
manufacturer=row[3][:32].encode('ascii', 'ignore')
|
||||
model=row[4][:32].encode('ascii', 'ignore')
|
||||
# in case icao aircraft type isn't, use ac type like BALL for balloon
|
||||
if len(row[8]) == 3:
|
||||
actype=row[8][:3].encode('ascii', 'ignore')
|
||||
else:
|
||||
actype=row[5][:4].encode('ascii', 'ignore')
|
||||
|
||||
owner=row[13][:32].encode('ascii', 'ignore')
|
||||
#padding
|
||||
registration_padding=bytearray()
|
||||
manufacturer_padding=bytearray()
|
||||
model_padding=bytearray()
|
||||
actype_padding=bytearray()
|
||||
owner_padding=bytearray()
|
||||
# debug print(icao24_code,' - ', registration,' - ', manufacturer, '-', model, '-', actype, '-', owner)
|
||||
icao24_codes=icao24_codes+bytearray(icao24_code+'\0', encoding='ascii')
|
||||
registration_padding=bytearray('\0' * (8 - len(registration)), encoding='ascii')
|
||||
manufacturer_padding=bytearray('\0' * (32 - len(manufacturer)), encoding='ascii')
|
||||
model_padding=bytearray('\0' * (32 - len(model)), encoding='ascii')
|
||||
actype_padding=bytearray('\0' * (4 - len(actype)), encoding='ascii')
|
||||
owner_padding=bytearray('\0' * (32 - len(owner)), encoding='ascii')
|
||||
data=data+bytearray(registration+registration_padding+manufacturer+manufacturer_padding+model+model_padding+actype+actype_padding+owner+owner_padding)
|
||||
row_count+=1
|
||||
|
||||
database.write(icao24_codes+data)
|
||||
print("Total of", row_count, "ICAO codes stored in database")
|
||||
|
BIN
sdcard/ADSB/icao24.db
Normal file
BIN
sdcard/ADSB/icao24.db
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user