mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-13 19:54:39 +00:00
ADSB position decoding
Date and time string format function Binary update
This commit is contained in:
parent
9d902bc224
commit
2628f9c03d
@ -727,6 +727,28 @@ static constexpr Bitmap bitmap_icon_setup {
|
|||||||
{ 16, 16 }, bitmap_icon_setup_data
|
{ 16, 16 }, bitmap_icon_setup_data
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr uint8_t bitmap_target_data[] = {
|
||||||
|
0x80, 0x00,
|
||||||
|
0x80, 0x00,
|
||||||
|
0xE0, 0x03,
|
||||||
|
0x90, 0x04,
|
||||||
|
0x88, 0x08,
|
||||||
|
0x04, 0x10,
|
||||||
|
0x04, 0x10,
|
||||||
|
0x1F, 0x7C,
|
||||||
|
0x04, 0x10,
|
||||||
|
0x04, 0x10,
|
||||||
|
0x88, 0x08,
|
||||||
|
0x90, 0x04,
|
||||||
|
0xE0, 0x03,
|
||||||
|
0x80, 0x00,
|
||||||
|
0x80, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
};
|
||||||
|
static constexpr Bitmap bitmap_target {
|
||||||
|
{ 16, 16 }, bitmap_target_data
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr uint8_t bitmap_sig_saw_down_data[] = {
|
static constexpr uint8_t bitmap_sig_saw_down_data[] = {
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
@ -157,7 +157,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) {
|
|||||||
|
|
||||||
std::string console_info;
|
std::string console_info;
|
||||||
|
|
||||||
console_info = "\n\x1B\x02" + to_string_time(message->packet.timestamp());
|
console_info = "\n" + to_string_datetime(message->packet.timestamp(), HM);
|
||||||
console_info += " " + pocsag::bitrate_str(message->packet.bitrate());
|
console_info += " " + pocsag::bitrate_str(message->packet.bitrate());
|
||||||
console_info += " ADDR:" + to_string_dec_uint(pocsag_state.address);
|
console_info += " ADDR:" + to_string_dec_uint(pocsag_state.address);
|
||||||
console_info += " F" + to_string_dec_uint(pocsag_state.function);
|
console_info += " F" + to_string_dec_uint(pocsag_state.function);
|
||||||
|
@ -41,7 +41,7 @@ void RecentEntriesHeader::paint(Painter& painter) {
|
|||||||
|
|
||||||
const Style style {
|
const Style style {
|
||||||
.font = parent_style.font,
|
.font = parent_style.font,
|
||||||
.background = Color::dark_blue(),
|
.background = Color::blue(),
|
||||||
.foreground = parent_style.foreground,
|
.foreground = parent_style.foreground,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -144,18 +144,22 @@ std::string to_string_hex_array(uint8_t * const array, const int32_t l) {
|
|||||||
return str_return;
|
return str_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string_datetime(const rtc::RTC& value) {
|
std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format) {
|
||||||
return to_string_dec_uint(value.year(), 4, '0') + "/" +
|
std::string string { "" };
|
||||||
to_string_dec_uint(value.month(), 2, '0') + "/" +
|
|
||||||
to_string_dec_uint(value.day(), 2, '0') + " " +
|
|
||||||
to_string_dec_uint(value.hour(), 2, '0') + ":" +
|
|
||||||
to_string_dec_uint(value.minute(), 2, '0') + ":" +
|
|
||||||
to_string_dec_uint(value.second(), 2, '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string to_string_time(const rtc::RTC& value) {
|
if (format == YMDHMS) {
|
||||||
return to_string_dec_uint(value.hour(), 2, '0') + ":" +
|
string += to_string_dec_uint(value.year(), 4, '0') + "/" +
|
||||||
to_string_dec_uint(value.minute(), 2, '0');
|
to_string_dec_uint(value.month(), 2, '0') + "/" +
|
||||||
|
to_string_dec_uint(value.day(), 2, '0') + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
string += to_string_dec_uint(value.hour(), 2, '0') + ":" +
|
||||||
|
string += to_string_dec_uint(value.minute(), 2, '0');
|
||||||
|
|
||||||
|
if ((format == YMDHMS) || (format == HMS))
|
||||||
|
string += ":" + to_string_dec_uint(value.second(), 2, '0');
|
||||||
|
|
||||||
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string_timestamp(const rtc::RTC& value) {
|
std::string to_string_timestamp(const rtc::RTC& value) {
|
||||||
|
@ -29,6 +29,12 @@
|
|||||||
#include "lpc43xx_cpp.hpp"
|
#include "lpc43xx_cpp.hpp"
|
||||||
using namespace lpc43xx;
|
using namespace lpc43xx;
|
||||||
|
|
||||||
|
enum TimeFormat {
|
||||||
|
YMDHMS = 0,
|
||||||
|
HMS = 1,
|
||||||
|
HM = 2
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Allow l=0 to not fill/justify? Already using this way in ui_spectrum.hpp...
|
// TODO: Allow l=0 to not fill/justify? Already using this way in ui_spectrum.hpp...
|
||||||
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
|
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
|
||||||
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = 0);
|
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = 0);
|
||||||
@ -38,8 +44,7 @@ std::string to_string_hex_array(uint8_t * const array, const int32_t l = 0);
|
|||||||
|
|
||||||
std::string to_string_short_freq(const uint64_t f);
|
std::string to_string_short_freq(const uint64_t f);
|
||||||
|
|
||||||
std::string to_string_datetime(const rtc::RTC& value);
|
std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format = YMDHMS);
|
||||||
std::string to_string_time(const rtc::RTC& value);
|
|
||||||
std::string to_string_timestamp(const rtc::RTC& value);
|
std::string to_string_timestamp(const rtc::RTC& value);
|
||||||
|
|
||||||
#endif/*__STRING_FORMAT_H__*/
|
#endif/*__STRING_FORMAT_H__*/
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "ui_alphanum.hpp"
|
#include "ui_alphanum.hpp"
|
||||||
#include "ui_geomap.hpp"
|
#include "ui_geomap.hpp"
|
||||||
|
|
||||||
#include "adsb.hpp"
|
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "baseband_api.hpp"
|
#include "baseband_api.hpp"
|
||||||
@ -33,13 +32,12 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
using namespace adsb;
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void RecentEntriesTable<ADSBRecentEntries>::draw(
|
void RecentEntriesTable<AircraftRecentEntries>::draw(
|
||||||
const Entry& entry,
|
const Entry& entry,
|
||||||
const Rect& target_rect,
|
const Rect& target_rect,
|
||||||
Painter& painter,
|
Painter& painter,
|
||||||
@ -48,9 +46,15 @@ void RecentEntriesTable<ADSBRecentEntries>::draw(
|
|||||||
painter.draw_string(
|
painter.draw_string(
|
||||||
target_rect.location(),
|
target_rect.location(),
|
||||||
style,
|
style,
|
||||||
to_string_hex(entry.ICAO_address, 6) + " " + entry.callsign + " " + (entry.hits <= 9999 ? to_string_dec_uint(entry.hits, 5) : "9999+") + " " + entry.time
|
to_string_hex(entry.ICAO_address, 6) +
|
||||||
//to_string_hex_array((uint8_t*)entry.raw_data, 10) + " " + entry.time
|
(entry.pos.valid ? " \x1B\x02" : " ") +
|
||||||
|
entry.callsign + " \x1B\x00" +
|
||||||
|
(entry.hits <= 999 ? to_string_dec_uint(entry.hits, 4) : "999+") + " " +
|
||||||
|
entry.time_string
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (entry.pos.valid)
|
||||||
|
painter.draw_bitmap(target_rect.location() + Point(15 * 8, 0), bitmap_target, style.foreground, style.background);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADSBRxView::focus() {
|
void ADSBRxView::focus() {
|
||||||
@ -73,24 +77,35 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
|||||||
|
|
||||||
|
|
||||||
if (frame.check_CRC() && frame.get_ICAO_address()) {
|
if (frame.check_CRC() && frame.get_ICAO_address()) {
|
||||||
|
frame.set_rx_timestamp(datetime.minute() * 60 + datetime.second());
|
||||||
|
|
||||||
auto& entry = ::on_packet(recent, ICAO_address);
|
auto& entry = ::on_packet(recent, ICAO_address);
|
||||||
|
|
||||||
rtcGetTime(&RTCD1, &datetime);
|
rtcGetTime(&RTCD1, &datetime);
|
||||||
str_timestamp = to_string_dec_uint(datetime.hour(), 2, '0') + ":" +
|
str_timestamp = to_string_datetime(datetime, HMS);
|
||||||
to_string_dec_uint(datetime.minute(), 2, '0') + ":" +
|
entry.set_time_string(str_timestamp);
|
||||||
to_string_dec_uint(datetime.second(), 2, '0');
|
|
||||||
|
|
||||||
entry.set_time(str_timestamp);
|
|
||||||
entry.set_raw(frame.get_raw_data());
|
|
||||||
entry.inc_hit();
|
entry.inc_hit();
|
||||||
|
|
||||||
if (frame.get_DF() == DF_ADSB) {
|
if (frame.get_DF() == DF_ADSB) {
|
||||||
if (frame.get_msg_type() == TC_IDENT) {
|
uint8_t msg_type = frame.get_msg_type();
|
||||||
|
uint8_t * raw_data = frame.get_raw_data();
|
||||||
|
|
||||||
|
if ((msg_type >= 1) && (msg_type <= 4)) {
|
||||||
callsign = decode_frame_id(frame);
|
callsign = decode_frame_id(frame);
|
||||||
entry.set_callsign(callsign);
|
entry.set_callsign(callsign);
|
||||||
} else if (frame.get_msg_type() == TC_AIRBORNE_POS) {
|
} else if ((msg_type >= 9) && (msg_type <= 18)) {
|
||||||
callsign = "Altitude: " + to_string_dec_uint(decode_frame_pos(frame)) + "ft";
|
entry.set_frame_pos(frame, raw_data[6] & 4);
|
||||||
entry.set_pos(callsign);
|
|
||||||
|
if (entry.pos.valid) {
|
||||||
|
callsign = "Alt:" + to_string_dec_uint(entry.pos.altitude) +
|
||||||
|
" Lat" + to_string_dec_int(entry.pos.latitude) +
|
||||||
|
"." + to_string_dec_int((int)(entry.pos.latitude * 1000) % 100) +
|
||||||
|
" Lon" + to_string_dec_int(entry.pos.longitude) +
|
||||||
|
"." + to_string_dec_int((int)(entry.pos.longitude * 1000) % 100);
|
||||||
|
|
||||||
|
entry.set_pos_string(callsign);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +113,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ADSBRxView::ADSBRxView(NavigationView& nav) {
|
ADSBRxView::ADSBRxView(NavigationView&) {
|
||||||
baseband::run_image(portapack::spi_flash::image_tag_adsb_rx);
|
baseband::run_image(portapack::spi_flash::image_tag_adsb_rx);
|
||||||
|
|
||||||
add_children({
|
add_children({
|
||||||
@ -113,8 +128,10 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
recent_entries_view.set_parent_rect({ 0, 64, 240, 224 });
|
recent_entries_view.set_parent_rect({ 0, 64, 240, 224 });
|
||||||
recent_entries_view.on_select = [this](const ADSBRecentEntry& entry) {
|
recent_entries_view.on_select = [this](const AircraftRecentEntry& entry) {
|
||||||
text_debug_a.set(entry.geo_pos);
|
text_debug_a.set(entry.pos_string);
|
||||||
|
text_debug_b.set(to_string_hex_array(entry.frame_pos_even.get_raw_data(), 14));
|
||||||
|
text_debug_c.set(to_string_hex_array(entry.frame_pos_odd.get_raw_data(), 14));
|
||||||
};
|
};
|
||||||
|
|
||||||
baseband::set_adsb();
|
baseband::set_adsb();
|
||||||
|
@ -26,28 +26,30 @@
|
|||||||
#include "ui_font_fixed_8x16.hpp"
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
#include "recent_entries.hpp"
|
#include "recent_entries.hpp"
|
||||||
|
|
||||||
|
#include "adsb.hpp"
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
|
|
||||||
|
using namespace adsb;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
struct ADSBRecentEntry {
|
struct AircraftRecentEntry {
|
||||||
using Key = uint32_t;
|
using Key = uint32_t;
|
||||||
|
|
||||||
static constexpr Key invalid_key = 0xffffffff;
|
static constexpr Key invalid_key = 0xffffffff;
|
||||||
|
|
||||||
uint32_t ICAO_address { };
|
uint32_t ICAO_address { };
|
||||||
uint16_t hits { 0 };
|
uint16_t hits { 0 };
|
||||||
uint8_t raw_data[14] { }; // 112 bits at most
|
adsb_pos pos { false, 0, 0, 0 };
|
||||||
|
|
||||||
|
ADSBFrame frame_pos_even { };
|
||||||
|
ADSBFrame frame_pos_odd { };
|
||||||
|
|
||||||
std::string callsign { " " };
|
std::string callsign { " " };
|
||||||
std::string time { "" };
|
std::string time_string { "" };
|
||||||
std::string geo_pos { "" };
|
std::string pos_string { "" };
|
||||||
|
|
||||||
ADSBRecentEntry(
|
AircraftRecentEntry(
|
||||||
) : ADSBRecentEntry { 0 }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ADSBRecentEntry(
|
|
||||||
const uint32_t ICAO_address
|
const uint32_t ICAO_address
|
||||||
) : ICAO_address { ICAO_address }
|
) : ICAO_address { ICAO_address }
|
||||||
{
|
{
|
||||||
@ -65,24 +67,32 @@ struct ADSBRecentEntry {
|
|||||||
hits++;
|
hits++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_pos(std::string& new_pos) {
|
void set_frame_pos(ADSBFrame& frame, uint32_t parity) {
|
||||||
geo_pos = new_pos;
|
if (!parity)
|
||||||
|
frame_pos_even = frame;
|
||||||
|
else
|
||||||
|
frame_pos_odd = frame;
|
||||||
|
|
||||||
|
if (!frame_pos_even.empty() && !frame_pos_odd.empty()) {
|
||||||
|
if (abs(frame_pos_even.get_rx_timestamp() - frame_pos_odd.get_rx_timestamp()) < 20)
|
||||||
|
pos = decode_frame_pos(frame_pos_even, frame_pos_odd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_time(std::string& new_time) {
|
void set_pos_string(std::string& new_pos_string) {
|
||||||
time = new_time;
|
pos_string = new_pos_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_raw(uint8_t * raw_ptr) {
|
void set_time_string(std::string& new_time_string) {
|
||||||
memcpy(raw_data, raw_ptr, 14);
|
time_string = new_time_string;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using ADSBRecentEntries = RecentEntries<ADSBRecentEntry>;
|
using AircraftRecentEntries = RecentEntries<AircraftRecentEntry>;
|
||||||
|
|
||||||
class ADSBRxView : public View {
|
class ADSBRxView : public View {
|
||||||
public:
|
public:
|
||||||
ADSBRxView(NavigationView& nav);
|
ADSBRxView(NavigationView&);
|
||||||
~ADSBRxView();
|
~ADSBRxView();
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
@ -94,12 +104,12 @@ private:
|
|||||||
|
|
||||||
const RecentEntriesColumns columns { {
|
const RecentEntriesColumns columns { {
|
||||||
{ "ICAO", 6 },
|
{ "ICAO", 6 },
|
||||||
{ "Callsign", 8 },
|
{ "Callsign", 9 },
|
||||||
{ "Hits", 5 },
|
{ "Hits", 4 },
|
||||||
{ "Time", 8 }
|
{ "Time", 8 }
|
||||||
} };
|
} };
|
||||||
ADSBRecentEntries recent { };
|
AircraftRecentEntries recent { };
|
||||||
RecentEntriesView<RecentEntries<ADSBRecentEntry>> recent_entries_view { columns, recent };
|
RecentEntriesView<RecentEntries<AircraftRecentEntry>> recent_entries_view { columns, recent };
|
||||||
|
|
||||||
RSSI rssi {
|
RSSI rssi {
|
||||||
{ 19 * 8, 4, 10 * 8, 8 },
|
{ 19 * 8, 4, 10 * 8, 8 },
|
||||||
|
@ -162,6 +162,10 @@ int cpr_N(float lat, int is_odd) {
|
|||||||
return nl;
|
return nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float cpr_Dlon(float lat, int is_odd) {
|
||||||
|
return 360.0 / cpr_N(lat, is_odd);
|
||||||
|
}
|
||||||
|
|
||||||
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude,
|
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude,
|
||||||
const float latitude, const float longitude, const uint32_t time_parity) {
|
const float latitude, const float longitude, const uint32_t time_parity) {
|
||||||
|
|
||||||
@ -203,35 +207,76 @@ void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32
|
|||||||
frame.make_CRC();
|
frame.make_CRC();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decoding method (from dump1090):
|
// Decoding method from dump1090
|
||||||
// index int j = floor(((59 * latcprE - 60 * latcprO) / 131072) + 0.50)
|
adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
|
||||||
// latE = DlatE * (cpr_mod(j, 60) + (latcprE / 131072))
|
uint8_t * raw_data;
|
||||||
// latO = DlatO * (cpr_mod(j, 59) + (latcprO / 131072))
|
uint32_t latcprE, latcprO, loncprE, loncprO;
|
||||||
// if latE >= 270 -> latE -= 360
|
float latE, latO, m, Dlon;
|
||||||
// if latO >= 270 -> latO -= 360
|
int ni;
|
||||||
// if (cpr_NL(latE) != cpr_NL(latO)) return;
|
adsb_pos position { false, 0, 0, 0 };
|
||||||
|
|
||||||
// int ni = cpr_N(latE ,0);
|
uint32_t time_even = frame_even.get_rx_timestamp();
|
||||||
// int m = floor((((loncprE * (cpr_NL(latE) - 1)) - (loncprO * cpr_NL(latE))) / 131072) + 0.5)
|
uint32_t time_odd = frame_odd.get_rx_timestamp();
|
||||||
// lon = cpr_Dlon(latE, 0) * (cpr_mod(m, ni) + loncprE / 131072);
|
uint8_t * frame_data_even = frame_even.get_raw_data();
|
||||||
// lat = latE;
|
uint8_t * frame_data_odd = frame_odd.get_raw_data();
|
||||||
// ... or ...
|
|
||||||
// int ni = cpr_N(latO ,0);
|
|
||||||
// int m = floor((((loncprE * (cpr_NL(latO) - 1)) - (loncprO * cpr_NL(latO))) / 131072) + 0.5)
|
|
||||||
// lon = cpr_Dlon(latO, 0) * (cpr_mod(m, ni) + loncprO / 131072);
|
|
||||||
// lat = latO;
|
|
||||||
// ... and ...
|
|
||||||
// if (lon > 180) lon -= 360;
|
|
||||||
|
|
||||||
// Only altitude is decoded for now
|
// Return most recent altitude
|
||||||
uint32_t decode_frame_pos(ADSBFrame& frame) {
|
if (time_even > time_odd)
|
||||||
uint8_t * raw_data = frame.get_raw_data();
|
raw_data = frame_data_even;
|
||||||
|
else
|
||||||
|
raw_data = frame_data_odd;
|
||||||
|
|
||||||
// Q-bit is present
|
// Q-bit must be present
|
||||||
if (raw_data[5] & 1)
|
if (raw_data[5] & 1)
|
||||||
return ((((raw_data[5] >> 1) << 4) | ((raw_data[6] & 0xF0) >> 4)) * 25) - 1000;
|
position.altitude = ((((raw_data[5] & 0xFE) << 3) | ((raw_data[6] & 0xF0) >> 4)) * 25) - 1000;
|
||||||
|
|
||||||
return 0;
|
// Position
|
||||||
|
latcprE = ((frame_data_even[6] & 3) << 15) | (frame_data_even[7] << 7) | (frame_data_even[8] >> 1);
|
||||||
|
loncprE = ((frame_data_even[8] & 1) << 16) | (frame_data_even[9] << 8) | frame_data_even[10];
|
||||||
|
|
||||||
|
latcprO = ((frame_data_odd[6] & 3) << 15) | (frame_data_odd[7] << 7) | (frame_data_odd[8] >> 1);
|
||||||
|
loncprO = ((frame_data_odd[8] & 1) << 16) | (frame_data_odd[9] << 8) | frame_data_odd[10];
|
||||||
|
|
||||||
|
// Compute latitude index
|
||||||
|
float j = floor((((59.0 * latcprE) - (60.0 * latcprO)) / 131072.0) + 0.5);
|
||||||
|
latE = (360.0 / 60.0) * (cpr_mod(j, 60) + (latcprE / 131072.0));
|
||||||
|
latO = (360.0 / 59.0) * (cpr_mod(j, 59) + (latcprO / 131072.0));
|
||||||
|
|
||||||
|
if (latE >= 270) latE -= 360;
|
||||||
|
if (latO >= 270) latO -= 360;
|
||||||
|
|
||||||
|
// Both frames must be in the same latitude zone
|
||||||
|
if (cpr_NL(latE) != cpr_NL(latO))
|
||||||
|
return position;
|
||||||
|
|
||||||
|
// Compute longitude
|
||||||
|
if (time_even > time_odd) {
|
||||||
|
// Use even frame
|
||||||
|
ni = cpr_N(latE, 0);
|
||||||
|
Dlon = 360.0 / ni;
|
||||||
|
|
||||||
|
m = floor((((loncprE * (cpr_NL(latE) - 1)) - (loncprO * cpr_NL(latE))) / 131072.0) + 0.5);
|
||||||
|
|
||||||
|
position.longitude = Dlon * (cpr_mod(m, ni) + loncprE / 131072.0);
|
||||||
|
|
||||||
|
position.latitude = latE;
|
||||||
|
} else {
|
||||||
|
// Use odd frame
|
||||||
|
ni = cpr_N(latO, 1);
|
||||||
|
Dlon = 360.0 / ni;
|
||||||
|
|
||||||
|
m = floor((((loncprE * (cpr_NL(latO) - 1)) - (loncprO * cpr_NL(latO))) / 131072.0) + 0.5);
|
||||||
|
|
||||||
|
position.longitude = Dlon * (cpr_mod(m, ni) + loncprO / 131072.0);
|
||||||
|
|
||||||
|
position.latitude = latO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position.longitude > 180) position.longitude -= 360;
|
||||||
|
|
||||||
|
position.valid = true;
|
||||||
|
|
||||||
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
// speed is in knots
|
// speed is in knots
|
||||||
|
@ -49,6 +49,13 @@ enum data_selector {
|
|||||||
BDS_HEADING = 0x60
|
BDS_HEADING = 0x60
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct adsb_pos {
|
||||||
|
bool valid;
|
||||||
|
float latitude;
|
||||||
|
float longitude;
|
||||||
|
int32_t altitude;
|
||||||
|
};
|
||||||
|
|
||||||
const float adsb_lat_lut[58] = {
|
const float adsb_lat_lut[58] = {
|
||||||
10.47047130, 14.82817437, 18.18626357, 21.02939493,
|
10.47047130, 14.82817437, 18.18626357, 21.02939493,
|
||||||
23.54504487, 25.82924707, 27.93898710, 29.91135686,
|
23.54504487, 25.82924707, 27.93898710, 29.91135686,
|
||||||
@ -74,7 +81,8 @@ std::string decode_frame_id(ADSBFrame& frame);
|
|||||||
|
|
||||||
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude,
|
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude,
|
||||||
const float latitude, const float longitude, const uint32_t time_parity);
|
const float latitude, const float longitude, const uint32_t time_parity);
|
||||||
uint32_t decode_frame_pos(ADSBFrame& frame);
|
|
||||||
|
adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd);
|
||||||
|
|
||||||
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
|
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
|
||||||
const float angle, const int32_t v_rate);
|
const float angle, const int32_t v_rate);
|
||||||
|
@ -45,6 +45,13 @@ public:
|
|||||||
return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
|
return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_rx_timestamp(uint32_t timestamp) {
|
||||||
|
rx_timestamp = timestamp;
|
||||||
|
}
|
||||||
|
uint32_t get_rx_timestamp() {
|
||||||
|
return rx_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
index = 0;
|
index = 0;
|
||||||
memset(raw_data, 0, 14);
|
memset(raw_data, 0, 14);
|
||||||
@ -57,8 +64,8 @@ public:
|
|||||||
raw_data[index++] = byte;
|
raw_data[index++] = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t * get_raw_data() {
|
uint8_t * get_raw_data() const {
|
||||||
return raw_data;
|
return (uint8_t* const)raw_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void make_CRC() {
|
void make_CRC() {
|
||||||
@ -73,18 +80,23 @@ public:
|
|||||||
bool check_CRC() {
|
bool check_CRC() {
|
||||||
uint32_t computed_CRC = compute_CRC();
|
uint32_t computed_CRC = compute_CRC();
|
||||||
|
|
||||||
if (raw_data[11] != ((computed_CRC >> 16) & 0xFF)) return false;
|
if ((raw_data[11] != ((computed_CRC >> 16) & 0xFF)) ||
|
||||||
if (raw_data[12] != ((computed_CRC >> 8) & 0xFF)) return false;
|
(raw_data[12] != ((computed_CRC >> 8) & 0xFF)) ||
|
||||||
if (raw_data[13] != (computed_CRC & 0xFF)) return false;
|
(raw_data[13] != (computed_CRC & 0xFF))) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool empty() {
|
||||||
|
return (index == 0);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const uint8_t adsb_preamble[16];
|
static const uint8_t adsb_preamble[16];
|
||||||
static const char icao_id_lut[65];
|
static const char icao_id_lut[65];
|
||||||
alignas(4) uint8_t index { 0 };
|
alignas(4) uint8_t index { 0 };
|
||||||
alignas(4) uint8_t raw_data[14] { }; // 112 bits at most
|
alignas(4) uint8_t raw_data[14] { }; // 112 bits at most
|
||||||
|
uint32_t rx_timestamp { };
|
||||||
|
|
||||||
uint32_t compute_CRC() {
|
uint32_t compute_CRC() {
|
||||||
uint8_t adsb_crc[14] = { 0 }; // Temp buffer
|
uint8_t adsb_crc[14] = { 0 }; // Temp buffer
|
||||||
|
@ -26,6 +26,17 @@
|
|||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
Color term_colors[8] = {
|
||||||
|
Color::black(),
|
||||||
|
Color::red(),
|
||||||
|
Color::green(),
|
||||||
|
Color::yellow(),
|
||||||
|
Color::blue(),
|
||||||
|
Color::magenta(),
|
||||||
|
Color::cyan(),
|
||||||
|
Color::white()
|
||||||
|
};
|
||||||
|
|
||||||
bool Rect::contains(const Point p) const {
|
bool Rect::contains(const Point p) const {
|
||||||
return (p.x() >= left()) && (p.y() >= top()) &&
|
return (p.x() >= left()) && (p.y() >= top()) &&
|
||||||
(p.x() < right()) && (p.y() < bottom());
|
(p.x() < right()) && (p.y() < bottom());
|
||||||
|
@ -105,6 +105,10 @@ struct Color {
|
|||||||
return { 0, 255, 255 };
|
return { 0, 255, 255 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr Color magenta() {
|
||||||
|
return { 255, 0, 255 };
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr Color white() {
|
static constexpr Color white() {
|
||||||
return { 255, 255, 255 };
|
return { 255, 255, 255 };
|
||||||
}
|
}
|
||||||
@ -124,6 +128,8 @@ struct Color {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern Color term_colors[8];
|
||||||
|
|
||||||
struct ColorRGB888 {
|
struct ColorRGB888 {
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
|
@ -45,15 +45,27 @@ int Painter::draw_char(const Point p, const Style& style, const char c) {
|
|||||||
int Painter::draw_string(Point p, const Font& font, const Color foreground,
|
int Painter::draw_string(Point p, const Font& font, const Color foreground,
|
||||||
const Color background, const std::string text) {
|
const Color background, const std::string text) {
|
||||||
|
|
||||||
|
bool escape = false;
|
||||||
size_t width = 0;
|
size_t width = 0;
|
||||||
|
Color pen = foreground;
|
||||||
|
|
||||||
for(const auto c : text) {
|
for(const auto c : text) {
|
||||||
|
if (escape) {
|
||||||
|
pen = term_colors[c & 7];
|
||||||
|
if (!c) pen = foreground;
|
||||||
|
escape = false;
|
||||||
|
} else {
|
||||||
|
if (c == '\x1B') {
|
||||||
|
escape = true;
|
||||||
|
} else {
|
||||||
const auto glyph = font.glyph(c);
|
const auto glyph = font.glyph(c);
|
||||||
display.draw_glyph(p, glyph, foreground, background);
|
display.draw_glyph(p, glyph, pen, background);
|
||||||
const auto advance = glyph.advance();
|
const auto advance = glyph.advance();
|
||||||
p += advance;
|
p += advance;
|
||||||
width += advance.x();
|
width += advance.x();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,12 +546,7 @@ void Console::write(std::string message) {
|
|||||||
|
|
||||||
for (const auto c : message) {
|
for (const auto c : message) {
|
||||||
if (escape) {
|
if (escape) {
|
||||||
if (c == '\x01')
|
pen_color = term_colors[c & 7];
|
||||||
pen_color = ui::Color::red();
|
|
||||||
else if (c == '\x02')
|
|
||||||
pen_color = ui::Color::green();
|
|
||||||
else if (c == '\x03')
|
|
||||||
pen_color = ui::Color::blue();
|
|
||||||
escape = false;
|
escape = false;
|
||||||
} else {
|
} else {
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user