mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-11-20 20:13:10 -05:00
Epirb 406 v2 (#2761)
* Adding channel selection to EPIRB receiver * UI enhancement, Packet error check and color display of error * code formating
This commit is contained in:
parent
a6f886ad0a
commit
29bba4d0ea
2 changed files with 235 additions and 9 deletions
|
|
@ -29,6 +29,7 @@ using namespace portapack;
|
||||||
|
|
||||||
#include "rtc_time.hpp"
|
#include "rtc_time.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
|
#include "ui.hpp"
|
||||||
|
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
|
|
||||||
|
|
@ -53,6 +54,11 @@ EPIRBBeacon EPIRBDecoder::decode_packet(const baseband::Packet& packet) {
|
||||||
data[i] = byte_val;
|
data[i] = byte_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform BCH error detection and correction
|
||||||
|
uint8_t error_count = 0;
|
||||||
|
beacon.packet_status = perform_bch_check(data, error_count);
|
||||||
|
beacon.error_count = error_count;
|
||||||
|
|
||||||
// Extract beacon ID (bits 26-85, 15 hex digits)
|
// Extract beacon ID (bits 26-85, 15 hex digits)
|
||||||
beacon.beacon_id = 0;
|
beacon.beacon_id = 0;
|
||||||
for (int i = 3; i < 11; i++) {
|
for (int i = 3; i < 11; i++) {
|
||||||
|
|
@ -161,6 +167,98 @@ std::string EPIRBDecoder::decode_vessel_name(const std::array<uint8_t, 16>& /* d
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PacketStatus EPIRBDecoder::perform_bch_check(std::array<uint8_t, 16>& data, uint8_t& error_count) {
|
||||||
|
// Make a copy to detect changes
|
||||||
|
std::array<uint8_t, 16> original_data = data;
|
||||||
|
|
||||||
|
// Calculate BCH syndrome
|
||||||
|
uint32_t syndrome = calculate_bch_syndrome(data);
|
||||||
|
|
||||||
|
if (syndrome == 0) {
|
||||||
|
// No errors detected
|
||||||
|
error_count = 0;
|
||||||
|
return PacketStatus::Valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to correct single-bit error
|
||||||
|
if (correct_single_error(data, syndrome)) {
|
||||||
|
// Successfully corrected
|
||||||
|
error_count = count_bit_errors(original_data, data);
|
||||||
|
return PacketStatus::Corrected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple errors or uncorrectable
|
||||||
|
error_count = 255; // Indicate unknown error count
|
||||||
|
return PacketStatus::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t EPIRBDecoder::calculate_bch_syndrome(const std::array<uint8_t, 16>& data) {
|
||||||
|
// BCH(127,92,5) polynomial for EPIRB: x^35 + x^2 + x + 1
|
||||||
|
// This is a simplified implementation - actual EPIRB uses BCH(63,21,6)
|
||||||
|
uint32_t syndrome = 0;
|
||||||
|
uint32_t polynomial = 0x80000007; // x^31 + x^2 + x + 1 (simplified)
|
||||||
|
|
||||||
|
// Process each byte of the data
|
||||||
|
for (int i = 0; i < 14; i++) { // Only data bits, not parity
|
||||||
|
uint32_t byte_val = data[i];
|
||||||
|
for (int bit = 7; bit >= 0; bit--) {
|
||||||
|
syndrome <<= 1;
|
||||||
|
if (byte_val & (1 << bit)) {
|
||||||
|
syndrome |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR with polynomial if MSB is set
|
||||||
|
if (syndrome & 0x80000000) {
|
||||||
|
syndrome ^= polynomial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR with parity bits
|
||||||
|
syndrome ^= (data[14] << 8) | data[15];
|
||||||
|
|
||||||
|
return syndrome & 0xFFFF; // 16-bit syndrome
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EPIRBDecoder::correct_single_error(std::array<uint8_t, 16>& data, uint32_t syndrome) {
|
||||||
|
// Simplified single-error correction
|
||||||
|
// This is a basic implementation - real BCH correction is more complex
|
||||||
|
|
||||||
|
if (syndrome == 0) return true; // No error
|
||||||
|
|
||||||
|
// Look up table for single-bit error patterns (simplified)
|
||||||
|
// In a real implementation, this would be a proper BCH syndrome table
|
||||||
|
for (int byte_idx = 0; byte_idx < 14; byte_idx++) {
|
||||||
|
for (int bit_idx = 0; bit_idx < 8; bit_idx++) {
|
||||||
|
// Create test error pattern
|
||||||
|
std::array<uint8_t, 16> test_data = data;
|
||||||
|
test_data[byte_idx] ^= (1 << bit_idx);
|
||||||
|
|
||||||
|
// Check if this correction produces zero syndrome
|
||||||
|
if (calculate_bch_syndrome(test_data) == 0) {
|
||||||
|
// Found the error location, apply correction
|
||||||
|
data[byte_idx] ^= (1 << bit_idx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Could not correct
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t EPIRBDecoder::count_bit_errors(const std::array<uint8_t, 16>& original, const std::array<uint8_t, 16>& corrected) {
|
||||||
|
uint8_t count = 0;
|
||||||
|
for (size_t i = 0; i < 16; i++) {
|
||||||
|
uint8_t diff = original[i] ^ corrected[i];
|
||||||
|
// Count set bits in diff
|
||||||
|
while (diff) {
|
||||||
|
count += diff & 1;
|
||||||
|
diff >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
void EPIRBLogger::on_packet(const EPIRBBeacon& beacon) {
|
void EPIRBLogger::on_packet(const EPIRBBeacon& beacon) {
|
||||||
std::string entry = "EPIRB," +
|
std::string entry = "EPIRB," +
|
||||||
to_string_dec_uint(beacon.beacon_id, 15, '0') + "," +
|
to_string_dec_uint(beacon.beacon_id, 15, '0') + "," +
|
||||||
|
|
@ -174,7 +272,9 @@ void EPIRBLogger::on_packet(const EPIRBBeacon& beacon) {
|
||||||
entry += ",";
|
entry += ",";
|
||||||
}
|
}
|
||||||
|
|
||||||
entry += "," + to_string_dec_uint(beacon.country_code) + "\n";
|
entry += "," + to_string_dec_uint(beacon.country_code) + "," +
|
||||||
|
format_packet_status(beacon.packet_status) + "," +
|
||||||
|
to_string_dec_uint(beacon.error_count) + "\n";
|
||||||
|
|
||||||
log_file.write_entry(beacon.timestamp, entry);
|
log_file.write_entry(beacon.timestamp, entry);
|
||||||
}
|
}
|
||||||
|
|
@ -221,6 +321,32 @@ std::string format_emergency_type(EmergencyType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string format_packet_status(PacketStatus status) {
|
||||||
|
switch (status) {
|
||||||
|
case PacketStatus::Valid:
|
||||||
|
return "OK";
|
||||||
|
case PacketStatus::Corrected:
|
||||||
|
return "CORR";
|
||||||
|
case PacketStatus::Error:
|
||||||
|
return "ERR";
|
||||||
|
default:
|
||||||
|
return "UNK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui::Color get_packet_status_color(PacketStatus status) {
|
||||||
|
switch (status) {
|
||||||
|
case PacketStatus::Valid:
|
||||||
|
return ui::Color::green();
|
||||||
|
case PacketStatus::Corrected:
|
||||||
|
return ui::Color::yellow();
|
||||||
|
case PacketStatus::Error:
|
||||||
|
return ui::Color::red();
|
||||||
|
default:
|
||||||
|
return ui::Color::white();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EPIRBBeaconDetailView::EPIRBBeaconDetailView(ui::NavigationView& nav) {
|
EPIRBBeaconDetailView::EPIRBBeaconDetailView(ui::NavigationView& nav) {
|
||||||
add_children({&button_done,
|
add_children({&button_done,
|
||||||
&button_see_map});
|
&button_see_map});
|
||||||
|
|
@ -297,6 +423,15 @@ void EPIRBBeaconDetailView::paint(ui::Painter& painter) {
|
||||||
draw_cursor = draw_field(painter, {draw_cursor, {200, 16}}, s,
|
draw_cursor = draw_field(painter, {draw_cursor, {200, 16}}, s,
|
||||||
"Time", to_string_datetime(beacon_.timestamp, HMS))
|
"Time", to_string_datetime(beacon_.timestamp, HMS))
|
||||||
.location();
|
.location();
|
||||||
|
|
||||||
|
// Show packet status with appropriate color
|
||||||
|
std::string status_text = format_packet_status(beacon_.packet_status);
|
||||||
|
if (beacon_.error_count > 0 && beacon_.packet_status == PacketStatus::Corrected) {
|
||||||
|
status_text += " (" + to_string_dec_uint(beacon_.error_count) + " err)";
|
||||||
|
}
|
||||||
|
draw_cursor = draw_field(painter, {draw_cursor, {200, 16}}, s,
|
||||||
|
"Status", status_text)
|
||||||
|
.location();
|
||||||
}
|
}
|
||||||
|
|
||||||
ui::Rect EPIRBBeaconDetailView::draw_field(
|
ui::Rect EPIRBBeaconDetailView::draw_field(
|
||||||
|
|
@ -318,6 +453,7 @@ EPIRBAppView::EPIRBAppView(ui::NavigationView& nav)
|
||||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||||
|
|
||||||
add_children({&label_frequency,
|
add_children({&label_frequency,
|
||||||
|
&options_frequency,
|
||||||
&field_rf_amp,
|
&field_rf_amp,
|
||||||
&field_lna,
|
&field_lna,
|
||||||
&field_vga,
|
&field_vga,
|
||||||
|
|
@ -328,6 +464,7 @@ EPIRBAppView::EPIRBAppView(ui::NavigationView& nav)
|
||||||
&label_beacons_count,
|
&label_beacons_count,
|
||||||
&label_latest,
|
&label_latest,
|
||||||
&text_latest_info,
|
&text_latest_info,
|
||||||
|
&label_packet_stats,
|
||||||
&console,
|
&console,
|
||||||
&button_map,
|
&button_map,
|
||||||
&button_clear,
|
&button_clear,
|
||||||
|
|
@ -345,11 +482,16 @@ EPIRBAppView::EPIRBAppView(ui::NavigationView& nav)
|
||||||
this->on_toggle_log();
|
this->on_toggle_log();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
options_frequency.on_change = [this](size_t, ui::OptionsField::value_t v) {
|
||||||
|
receiver_model.set_target_frequency(v);
|
||||||
|
};
|
||||||
|
options_frequency.set_by_value(receiver_model.target_frequency());
|
||||||
|
|
||||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||||
this->on_tick_second();
|
this->on_tick_second();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Configure receiver for 406.028 MHz EPIRB frequency
|
// Configure receiver for default EPIRB frequency (406.028 MHz)
|
||||||
receiver_model.set_target_frequency(406028000);
|
receiver_model.set_target_frequency(406028000);
|
||||||
receiver_model.set_rf_amp(true);
|
receiver_model.set_rf_amp(true);
|
||||||
receiver_model.set_lna(32);
|
receiver_model.set_lna(32);
|
||||||
|
|
@ -386,7 +528,7 @@ void EPIRBAppView::paint(ui::Painter& /* painter */) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EPIRBAppView::focus() {
|
void EPIRBAppView::focus() {
|
||||||
field_rf_amp.focus();
|
options_frequency.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EPIRBAppView::on_packet(const baseband::Packet& packet) {
|
void EPIRBAppView::on_packet(const baseband::Packet& packet) {
|
||||||
|
|
@ -400,6 +542,20 @@ void EPIRBAppView::on_packet(const baseband::Packet& packet) {
|
||||||
|
|
||||||
void EPIRBAppView::on_beacon_decoded(const EPIRBBeacon& beacon) {
|
void EPIRBAppView::on_beacon_decoded(const EPIRBBeacon& beacon) {
|
||||||
beacons_received++;
|
beacons_received++;
|
||||||
|
|
||||||
|
// Track packet statistics
|
||||||
|
switch (beacon.packet_status) {
|
||||||
|
case PacketStatus::Valid:
|
||||||
|
packets_valid++;
|
||||||
|
break;
|
||||||
|
case PacketStatus::Corrected:
|
||||||
|
packets_corrected++;
|
||||||
|
break;
|
||||||
|
case PacketStatus::Error:
|
||||||
|
packets_error++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
recent_beacons.push_back(beacon);
|
recent_beacons.push_back(beacon);
|
||||||
|
|
||||||
// Keep only last 50 beacons
|
// Keep only last 50 beacons
|
||||||
|
|
@ -415,11 +571,34 @@ void EPIRBAppView::on_beacon_decoded(const EPIRBBeacon& beacon) {
|
||||||
logger->on_packet(beacon);
|
logger->on_packet(beacon);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display in console with full details
|
// Display in console with full details and colored status
|
||||||
std::string beacon_info = format_beacon_summary(beacon);
|
std::string beacon_info = format_beacon_summary(beacon);
|
||||||
if (beacon.emergency_type != EmergencyType::Other) {
|
if (beacon.emergency_type != EmergencyType::Other) {
|
||||||
beacon_info += " [" + format_emergency_type(beacon.emergency_type) + "]";
|
beacon_info += " [" + format_emergency_type(beacon.emergency_type) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add colored status indicator
|
||||||
|
std::string status_color;
|
||||||
|
switch (beacon.packet_status) {
|
||||||
|
case PacketStatus::Valid:
|
||||||
|
status_color = STR_COLOR_GREEN;
|
||||||
|
break;
|
||||||
|
case PacketStatus::Corrected:
|
||||||
|
status_color = STR_COLOR_YELLOW;
|
||||||
|
break;
|
||||||
|
case PacketStatus::Error:
|
||||||
|
status_color = STR_COLOR_RED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
status_color = STR_COLOR_WHITE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
beacon_info += " [" + status_color + format_packet_status(beacon.packet_status) + STR_COLOR_WHITE + "]";
|
||||||
|
if (beacon.error_count > 0 && beacon.packet_status == PacketStatus::Corrected) {
|
||||||
|
beacon_info += " (" + to_string_dec_uint(beacon.error_count) + "e)";
|
||||||
|
}
|
||||||
|
|
||||||
console.write(beacon_info + "\n");
|
console.write(beacon_info + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -463,6 +642,9 @@ void EPIRBAppView::on_show_map() {
|
||||||
void EPIRBAppView::on_clear_beacons() {
|
void EPIRBAppView::on_clear_beacons() {
|
||||||
recent_beacons.clear();
|
recent_beacons.clear();
|
||||||
beacons_received = 0;
|
beacons_received = 0;
|
||||||
|
packets_valid = 0;
|
||||||
|
packets_corrected = 0;
|
||||||
|
packets_error = 0;
|
||||||
console.clear(true);
|
console.clear(true);
|
||||||
update_display();
|
update_display();
|
||||||
}
|
}
|
||||||
|
|
@ -490,6 +672,13 @@ void EPIRBAppView::on_tick_second() {
|
||||||
void EPIRBAppView::update_display() {
|
void EPIRBAppView::update_display() {
|
||||||
label_beacons_count.set("Beacons: " + to_string_dec_uint(beacons_received));
|
label_beacons_count.set("Beacons: " + to_string_dec_uint(beacons_received));
|
||||||
|
|
||||||
|
// Update packet statistics display
|
||||||
|
std::string stats = std::string("Stats: ") +
|
||||||
|
STR_COLOR_GREEN + to_string_dec_uint(packets_valid) + "OK " +
|
||||||
|
STR_COLOR_YELLOW + to_string_dec_uint(packets_corrected) + "CORR " +
|
||||||
|
STR_COLOR_RED + to_string_dec_uint(packets_error) + "ERR" + STR_COLOR_WHITE;
|
||||||
|
label_packet_stats.set(stats);
|
||||||
|
|
||||||
if (!recent_beacons.empty()) {
|
if (!recent_beacons.empty()) {
|
||||||
const auto& latest = recent_beacons.back();
|
const auto& latest = recent_beacons.back();
|
||||||
text_latest_info.set(format_beacon_summary(latest));
|
text_latest_info.set(format_beacon_summary(latest));
|
||||||
|
|
@ -504,6 +693,9 @@ std::string EPIRBAppView::format_beacon_summary(const EPIRBBeacon& beacon) {
|
||||||
summary += " " + format_location(beacon.location);
|
summary += " " + format_location(beacon.location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add status indicator for summary display
|
||||||
|
summary += " " + format_packet_status(beacon.packet_status);
|
||||||
|
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,12 @@ struct EPIRBLocation {
|
||||||
: latitude(lat), longitude(lon), valid(true) {}
|
: latitude(lat), longitude(lon), valid(true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PacketStatus : uint8_t {
|
||||||
|
Valid = 0,
|
||||||
|
Corrected = 1,
|
||||||
|
Error = 2
|
||||||
|
};
|
||||||
|
|
||||||
struct EPIRBBeacon {
|
struct EPIRBBeacon {
|
||||||
uint32_t beacon_id;
|
uint32_t beacon_id;
|
||||||
BeaconType beacon_type;
|
BeaconType beacon_type;
|
||||||
|
|
@ -87,9 +93,11 @@ struct EPIRBBeacon {
|
||||||
std::string vessel_name;
|
std::string vessel_name;
|
||||||
rtc::RTC timestamp;
|
rtc::RTC timestamp;
|
||||||
uint32_t sequence_number;
|
uint32_t sequence_number;
|
||||||
|
PacketStatus packet_status;
|
||||||
|
uint8_t error_count;
|
||||||
|
|
||||||
EPIRBBeacon()
|
EPIRBBeacon()
|
||||||
: beacon_id(0), beacon_type(BeaconType::Other), emergency_type(EmergencyType::Other), location(), country_code(0), vessel_name(), timestamp(), sequence_number(0) {}
|
: beacon_id(0), beacon_type(BeaconType::Other), emergency_type(EmergencyType::Other), location(), country_code(0), vessel_name(), timestamp(), sequence_number(0), packet_status(PacketStatus::Error), error_count(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EPIRBDecoder {
|
class EPIRBDecoder {
|
||||||
|
|
@ -102,6 +110,12 @@ class EPIRBDecoder {
|
||||||
static EmergencyType decode_emergency_type(uint8_t emergency_bits);
|
static EmergencyType decode_emergency_type(uint8_t emergency_bits);
|
||||||
static uint32_t decode_country_code(const std::array<uint8_t, 16>& data);
|
static uint32_t decode_country_code(const std::array<uint8_t, 16>& data);
|
||||||
static std::string decode_vessel_name(const std::array<uint8_t, 16>& data);
|
static std::string decode_vessel_name(const std::array<uint8_t, 16>& data);
|
||||||
|
|
||||||
|
// BCH error correction methods
|
||||||
|
static PacketStatus perform_bch_check(std::array<uint8_t, 16>& data, uint8_t& error_count);
|
||||||
|
static uint32_t calculate_bch_syndrome(const std::array<uint8_t, 16>& data);
|
||||||
|
static bool correct_single_error(std::array<uint8_t, 16>& data, uint32_t syndrome);
|
||||||
|
static uint8_t count_bit_errors(const std::array<uint8_t, 16>& original, const std::array<uint8_t, 16>& corrected);
|
||||||
};
|
};
|
||||||
|
|
||||||
class EPIRBLogger {
|
class EPIRBLogger {
|
||||||
|
|
@ -119,6 +133,8 @@ class EPIRBLogger {
|
||||||
// Forward declarations of formatting functions
|
// Forward declarations of formatting functions
|
||||||
std::string format_beacon_type(BeaconType type);
|
std::string format_beacon_type(BeaconType type);
|
||||||
std::string format_emergency_type(EmergencyType type);
|
std::string format_emergency_type(EmergencyType type);
|
||||||
|
std::string format_packet_status(PacketStatus status);
|
||||||
|
ui::Color get_packet_status_color(PacketStatus status);
|
||||||
|
|
||||||
class EPIRBBeaconDetailView : public ui::View {
|
class EPIRBBeaconDetailView : public ui::View {
|
||||||
public:
|
public:
|
||||||
|
|
@ -178,11 +194,22 @@ class EPIRBAppView : public ui::View {
|
||||||
|
|
||||||
EPIRBBeaconDetailView beacon_detail_view{nav_};
|
EPIRBBeaconDetailView beacon_detail_view{nav_};
|
||||||
|
|
||||||
static constexpr auto header_height = 3 * 16;
|
static constexpr auto header_height = 4 * 16;
|
||||||
|
|
||||||
ui::Text label_frequency{
|
ui::Text label_frequency{
|
||||||
{0 * 8, 0 * 16, 10 * 8, 1 * 16},
|
{0 * 8, 0 * 16, 4 * 8, 1 * 16},
|
||||||
"406.028 MHz"};
|
"Freq"};
|
||||||
|
|
||||||
|
ui::OptionsField options_frequency{
|
||||||
|
{5 * 8, 0 * 16},
|
||||||
|
7,
|
||||||
|
{
|
||||||
|
{"406.028", 406028000},
|
||||||
|
{"406.025", 406025000},
|
||||||
|
{"406.037", 406037000},
|
||||||
|
{"433.025", 433025000},
|
||||||
|
{"144.875", 144875000},
|
||||||
|
}};
|
||||||
|
|
||||||
ui::RFAmpField field_rf_amp{
|
ui::RFAmpField field_rf_amp{
|
||||||
{13 * 8, 0 * 16}};
|
{13 * 8, 0 * 16}};
|
||||||
|
|
@ -211,6 +238,10 @@ class EPIRBAppView : public ui::View {
|
||||||
{16 * 8, 1 * 16, 14 * 8, 1 * 16},
|
{16 * 8, 1 * 16, 14 * 8, 1 * 16},
|
||||||
"Beacons: 0"};
|
"Beacons: 0"};
|
||||||
|
|
||||||
|
ui::Text label_packet_stats{
|
||||||
|
{0 * 8, 3 * 16, 29 * 8, 1 * 16},
|
||||||
|
""};
|
||||||
|
|
||||||
// Latest beacon info display
|
// Latest beacon info display
|
||||||
ui::Text label_latest{
|
ui::Text label_latest{
|
||||||
{0 * 8, 2 * 16, 8 * 8, 1 * 16},
|
{0 * 8, 2 * 16, 8 * 8, 1 * 16},
|
||||||
|
|
@ -222,7 +253,7 @@ class EPIRBAppView : public ui::View {
|
||||||
|
|
||||||
// Beacon list
|
// Beacon list
|
||||||
ui::Console console{
|
ui::Console console{
|
||||||
{0, 3 * 16, 240, 168}};
|
{0, 4 * 16, 240, 152}};
|
||||||
|
|
||||||
ui::Button button_map{
|
ui::Button button_map{
|
||||||
{0, 224, 60, 24},
|
{0, 224, 60, 24},
|
||||||
|
|
@ -238,6 +269,9 @@ class EPIRBAppView : public ui::View {
|
||||||
|
|
||||||
SignalToken signal_token_tick_second{};
|
SignalToken signal_token_tick_second{};
|
||||||
uint32_t beacons_received = 0;
|
uint32_t beacons_received = 0;
|
||||||
|
uint32_t packets_valid = 0;
|
||||||
|
uint32_t packets_corrected = 0;
|
||||||
|
uint32_t packets_error = 0;
|
||||||
|
|
||||||
MessageHandlerRegistration message_handler_packet{
|
MessageHandlerRegistration message_handler_packet{
|
||||||
Message::ID::EPIRBPacket,
|
Message::ID::EPIRBPacket,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue