mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-18 05:34:01 +00:00
Move AIS receiver to external app
This commit is contained in:
@@ -279,7 +279,6 @@ set(CPPSRC
|
||||
ui/ui_tone_key.cpp
|
||||
ui/ui_transmitter.cpp
|
||||
ui/ui_bmpview.cpp
|
||||
apps/ais_app.cpp
|
||||
apps/analog_audio_app.cpp
|
||||
apps/ble_rx_app.cpp
|
||||
apps/ble_tx_app.cpp
|
||||
|
||||
+37
-29
@@ -35,7 +35,8 @@ using namespace portapack;
|
||||
|
||||
namespace pmem = portapack::persistent_memory;
|
||||
|
||||
namespace ais {
|
||||
namespace ui::external_app::ais_rx {
|
||||
|
||||
namespace format {
|
||||
|
||||
static std::string latlon_abs_normalized(const int32_t normalized, const char suffixes[2]) {
|
||||
@@ -47,7 +48,7 @@ static std::string latlon_abs_normalized(const int32_t normalized, const char su
|
||||
return to_string_dec_uint(degrees) + "." + to_string_dec_uint(fraction, 6, '0') + suffix;
|
||||
}
|
||||
|
||||
static std::string latlon(const Latitude latitude, const Longitude longitude) {
|
||||
static std::string latlon(const ais::Latitude latitude, const ais::Longitude longitude) {
|
||||
if (latitude.is_valid() && longitude.is_valid()) {
|
||||
return latlon_abs_normalized(latitude.normalized(), "SN") + " " + latlon_abs_normalized(longitude.normalized(), "WE");
|
||||
} else if (latitude.is_not_available() && longitude.is_not_available()) {
|
||||
@@ -128,7 +129,7 @@ static std::string navigational_status(const unsigned int value) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string rate_of_turn(const RateOfTurn value) {
|
||||
static std::string rate_of_turn(const ais::RateOfTurn value) {
|
||||
switch (value) {
|
||||
case -128:
|
||||
return "not available";
|
||||
@@ -149,7 +150,7 @@ static std::string rate_of_turn(const RateOfTurn value) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string speed_over_ground(const SpeedOverGround value) {
|
||||
static std::string speed_over_ground(const ais::SpeedOverGround value) {
|
||||
if (value == 1023) {
|
||||
return "not available";
|
||||
} else if (value == 1022) {
|
||||
@@ -159,7 +160,7 @@ static std::string speed_over_ground(const SpeedOverGround value) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string course_over_ground(const CourseOverGround value) {
|
||||
static std::string course_over_ground(const ais::CourseOverGround value) {
|
||||
if (value > 3600) {
|
||||
return "invalid";
|
||||
} else if (value == 3600) {
|
||||
@@ -169,7 +170,7 @@ static std::string course_over_ground(const CourseOverGround value) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string true_heading(const TrueHeading value) {
|
||||
static std::string true_heading(const ais::TrueHeading value) {
|
||||
if (value == 511) {
|
||||
return "not available";
|
||||
} else if (value > 359) {
|
||||
@@ -180,7 +181,6 @@ static std::string true_heading(const TrueHeading value) {
|
||||
}
|
||||
|
||||
} /* namespace format */
|
||||
} /* namespace ais */
|
||||
|
||||
void AISLogger::on_packet(const ais::Packet& packet) {
|
||||
// TODO: Unstuff here, not in baseband!
|
||||
@@ -265,25 +265,33 @@ void AISRecentEntry::update(const ais::Packet& packet) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::ais_rx
|
||||
|
||||
namespace ui {
|
||||
|
||||
template <>
|
||||
void RecentEntriesTable<AISRecentEntries>::draw(
|
||||
void RecentEntriesTable<external_app::ais_rx::AISRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
const Rect& target_rect,
|
||||
Painter& painter,
|
||||
const Style& style,
|
||||
RecentEntriesColumns&) {
|
||||
std::string line = ais::format::mmsi(entry.mmsi) + " ";
|
||||
using namespace external_app::ais_rx;
|
||||
|
||||
std::string line = format::mmsi(entry.mmsi) + " ";
|
||||
if (!entry.name.empty()) {
|
||||
line += ais::format::text(entry.name);
|
||||
line += format::text(entry.name);
|
||||
} else {
|
||||
line += ais::format::text(entry.call_sign);
|
||||
line += format::text(entry.call_sign);
|
||||
}
|
||||
line.resize(target_rect.width() / 8, ' ');
|
||||
painter.draw_string(target_rect.location(), style, line);
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
||||
namespace ui::external_app::ais_rx {
|
||||
|
||||
AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) {
|
||||
add_children({
|
||||
&button_done,
|
||||
@@ -298,12 +306,12 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) {
|
||||
|
||||
button_see_map.on_select = [this, &nav](Button&) {
|
||||
geomap_view = nav.push<GeoMapView>(
|
||||
ais::format::text(entry_.name),
|
||||
format::text(entry_.name),
|
||||
0,
|
||||
GeoPos::alt_unit::METERS,
|
||||
GeoPos::spd_unit::KNOTS,
|
||||
ais::format::latlon_float(entry_.last_position.latitude.normalized()),
|
||||
ais::format::latlon_float(entry_.last_position.longitude.normalized()),
|
||||
format::latlon_float(entry_.last_position.latitude.normalized()),
|
||||
format::latlon_float(entry_.last_position.longitude.normalized()),
|
||||
entry_.last_position.true_heading,
|
||||
[this]() {
|
||||
send_updates = false;
|
||||
@@ -324,14 +332,14 @@ AISRecentEntryDetailView& AISRecentEntryDetailView::operator=(const AISRecentEnt
|
||||
|
||||
void AISRecentEntryDetailView::update_position() {
|
||||
if (send_updates)
|
||||
geomap_view->update_position(ais::format::latlon_float(entry_.last_position.latitude.normalized()), ais::format::latlon_float(entry_.last_position.longitude.normalized()), (float)entry_.last_position.true_heading, 0, entry_.last_position.speed_over_ground > 1022 ? 0 : entry_.last_position.speed_over_ground / 10);
|
||||
geomap_view->update_position(format::latlon_float(entry_.last_position.latitude.normalized()), format::latlon_float(entry_.last_position.longitude.normalized()), (float)entry_.last_position.true_heading, 0, entry_.last_position.speed_over_ground > 1022 ? 0 : entry_.last_position.speed_over_ground / 10);
|
||||
}
|
||||
|
||||
bool AISRecentEntryDetailView::add_map_marker(const AISRecentEntry& entry) {
|
||||
if (geomap_view && send_updates) {
|
||||
GeoMarker marker{};
|
||||
marker.lon = ais::format::latlon_float(entry.last_position.longitude.normalized());
|
||||
marker.lat = ais::format::latlon_float(entry.last_position.latitude.normalized());
|
||||
marker.lon = format::latlon_float(entry.last_position.longitude.normalized());
|
||||
marker.lat = format::latlon_float(entry.last_position.latitude.normalized());
|
||||
marker.angle = entry.last_position.true_heading;
|
||||
marker.tag = entry.call_sign.empty() ? to_string_dec_uint(entry.mmsi) : entry.call_sign;
|
||||
auto markerStored = geomap_view->store_marker(marker);
|
||||
@@ -377,18 +385,18 @@ void AISRecentEntryDetailView::paint(Painter& painter) {
|
||||
|
||||
auto field_rect = Rect{rect.left(), rect.top() + 16, rect.width(), 16};
|
||||
|
||||
field_rect = draw_field(painter, field_rect, s, "MMSI", ais::format::mmsi(entry_.mmsi));
|
||||
field_rect = draw_field(painter, field_rect, s, "Ctry", ais::format::mid(entry_.mmsi));
|
||||
field_rect = draw_field(painter, field_rect, s, "Name", ais::format::text(entry_.name));
|
||||
field_rect = draw_field(painter, field_rect, s, "Call", ais::format::text(entry_.call_sign));
|
||||
field_rect = draw_field(painter, field_rect, s, "Dest", ais::format::text(entry_.destination));
|
||||
field_rect = draw_field(painter, field_rect, s, "MMSI", format::mmsi(entry_.mmsi));
|
||||
field_rect = draw_field(painter, field_rect, s, "Ctry", format::mid(entry_.mmsi));
|
||||
field_rect = draw_field(painter, field_rect, s, "Name", format::text(entry_.name));
|
||||
field_rect = draw_field(painter, field_rect, s, "Call", format::text(entry_.call_sign));
|
||||
field_rect = draw_field(painter, field_rect, s, "Dest", format::text(entry_.destination));
|
||||
field_rect = draw_field(painter, field_rect, s, "Last", to_string_datetime(entry_.last_position.timestamp));
|
||||
field_rect = draw_field(painter, field_rect, s, "Pos ", ais::format::latlon(entry_.last_position.latitude, entry_.last_position.longitude));
|
||||
field_rect = draw_field(painter, field_rect, s, "Stat", ais::format::navigational_status(entry_.navigational_status));
|
||||
field_rect = draw_field(painter, field_rect, s, "RoT ", ais::format::rate_of_turn(entry_.last_position.rate_of_turn));
|
||||
field_rect = draw_field(painter, field_rect, s, "SoG ", ais::format::speed_over_ground(entry_.last_position.speed_over_ground));
|
||||
field_rect = draw_field(painter, field_rect, s, "CoG ", ais::format::course_over_ground(entry_.last_position.course_over_ground));
|
||||
field_rect = draw_field(painter, field_rect, s, "Head", ais::format::true_heading(entry_.last_position.true_heading));
|
||||
field_rect = draw_field(painter, field_rect, s, "Pos ", format::latlon(entry_.last_position.latitude, entry_.last_position.longitude));
|
||||
field_rect = draw_field(painter, field_rect, s, "Stat", format::navigational_status(entry_.navigational_status));
|
||||
field_rect = draw_field(painter, field_rect, s, "RoT ", format::rate_of_turn(entry_.last_position.rate_of_turn));
|
||||
field_rect = draw_field(painter, field_rect, s, "SoG ", format::speed_over_ground(entry_.last_position.speed_over_ground));
|
||||
field_rect = draw_field(painter, field_rect, s, "CoG ", format::course_over_ground(entry_.last_position.course_over_ground));
|
||||
field_rect = draw_field(painter, field_rect, s, "Head", format::true_heading(entry_.last_position.true_heading));
|
||||
field_rect = draw_field(painter, field_rect, s, "Rx #", to_string_dec_uint(entry_.received_count));
|
||||
}
|
||||
|
||||
@@ -504,4 +512,4 @@ void AISAppView::on_show_detail(const AISRecentEntry& entry) {
|
||||
recent_entry_detail_view.update_map_markers(recent);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::ais_rx
|
||||
+3
-3
@@ -50,6 +50,8 @@ using namespace lpc43xx;
|
||||
|
||||
#include "recent_entries.hpp"
|
||||
|
||||
namespace ui::external_app::ais_rx {
|
||||
|
||||
struct AISPosition {
|
||||
rtc::RTC timestamp{};
|
||||
ais::Latitude latitude{};
|
||||
@@ -109,8 +111,6 @@ class AISLogger {
|
||||
LogFile log_file{};
|
||||
};
|
||||
|
||||
namespace ui {
|
||||
|
||||
using AISRecentEntriesView = RecentEntriesView<AISRecentEntries>;
|
||||
|
||||
class AISRecentEntryDetailView : public View {
|
||||
@@ -239,6 +239,6 @@ class AISAppView : public View {
|
||||
void on_tick_second();
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::ais_rx
|
||||
|
||||
#endif /*__AIS_APP_H__*/
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2026 PortaPack Mayhem
|
||||
*
|
||||
* 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 "ais_app.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::ais_rx {
|
||||
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<AISAppView>();
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::ais_rx
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_ais_rx.application_information"), used)) application_information_t _application_information_ais_rx = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::ais_rx::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "AIS Boats",
|
||||
/*.bitmap_data = */ {
|
||||
0x00, 0x01, 0x80, 0x01, 0xC0, 0x01, 0xC0, 0x0D,
|
||||
0xE0, 0x3D, 0xF0, 0x3D, 0xF8, 0x7D, 0xFC, 0x7D,
|
||||
0xFC, 0x7D, 0xFE, 0x7D, 0xFF, 0x7D, 0x00, 0x00,
|
||||
0xF8, 0x7F, 0xF8, 0x3F, 0xF0, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::RX,
|
||||
/*.desired_menu_position = */ -1,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_ais */ {'P', 'A', 'I', 'S'},
|
||||
/*.m4_app_offset = */ 0x00000000,
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
@@ -395,6 +395,10 @@ set(EXTCPPSRC
|
||||
external/adsbrx/main.cpp
|
||||
external/adsbrx/ui_adsb_rx.cpp
|
||||
|
||||
#ais rx
|
||||
external/ais_rx/main.cpp
|
||||
external/ais_rx/ais_app.cpp
|
||||
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -490,6 +494,7 @@ set(EXTAPPLIST
|
||||
signal_hunter
|
||||
tetra_rx
|
||||
adsbrx
|
||||
ais_rx
|
||||
)
|
||||
|
||||
# sdusb has type conflicts with PRALINE (HackRF Pro) - add only for non-PRALINE builds
|
||||
|
||||
+7
@@ -116,6 +116,7 @@ MEMORY
|
||||
ram_external_app_signal_hunter (rwx) : org = 0xAE0B0000, len = 32k
|
||||
ram_external_app_tetra_rx (rwx) : org = 0xAE0C0000, len = 32k
|
||||
ram_external_app_adsbrx (rwx) : org = 0xAE0D0000, len = 32k
|
||||
ram_external_app_ais_rx (rwx) : org = 0xAE0E0000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -678,6 +679,12 @@ SECTIONS
|
||||
*(*ui*external_app*adsbrx*);
|
||||
} > ram_external_app_adsbrx
|
||||
|
||||
.external_app_ais_rx : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_ais_rx.application_information));
|
||||
*(*ui*external_app*ais_rx*);
|
||||
} > ram_external_app_ais_rx
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
#include "ui_battinfo.hpp"
|
||||
#include "ui_external_items_menu_loader.hpp"
|
||||
|
||||
#include "ais_app.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "ble_rx_app.hpp"
|
||||
#include "ble_tx_app.hpp"
|
||||
@@ -98,7 +97,6 @@ const NavigationView::AppList NavigationView::appList = {
|
||||
{nullptr, "Games", HOME, Color::cyan(), &bitmap_icon_games, new ViewFactory<GamesMenuView>()},
|
||||
{nullptr, "Settings", HOME, Color::cyan(), &bitmap_icon_setup, new ViewFactory<SettingsMenuView>()},
|
||||
/* RX ********************************************************************/
|
||||
{"ais", "AIS Boats", RX, Color::green(), &bitmap_icon_ais, new ViewFactory<AISAppView>()},
|
||||
{"aprsrx", "APRS", RX, Color::green(), &bitmap_icon_aprs, new ViewFactory<APRSRXView>()},
|
||||
{"audio", "Audio", RX, Color::green(), &bitmap_icon_speaker, new ViewFactory<AnalogAudioView>()},
|
||||
{"blerx", "BLE Rx", RX, Color::green(), &bitmap_icon_btle, new ViewFactory<BLERxView>()},
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
# external app address ranges below must match those in linker file "external.ld"
|
||||
maximum_application_size = 32*1024
|
||||
external_apps_address_start = 0xADB00000
|
||||
external_apps_address_end = 0xAE0E0000
|
||||
external_apps_address_end = 0xAE0F0000
|
||||
|
||||
Reference in New Issue
Block a user