diff --git a/firmware/application/external/epirb_rx/ui_epirb_rx.cpp b/firmware/application/external/epirb_rx/ui_epirb_rx.cpp index 82107e2dc..7f8d9c4ee 100644 --- a/firmware/application/external/epirb_rx/ui_epirb_rx.cpp +++ b/firmware/application/external/epirb_rx/ui_epirb_rx.cpp @@ -1,616 +1,616 @@ -/* - * Copyright (C) 2024 EPIRB Decoder Implementation - * Copyright (C) 2026 Frederic BORRY - ADRASEC 31 - * - * 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 "baseband_api.hpp" -#include "portapack_persistent_memory.hpp" -#include "file_path.hpp" - -#include "ui_epirb_rx.hpp" - -using namespace portapack; - -#include "rtc_time.hpp" -#include "string_format.hpp" -#include "ui.hpp" - -#include "message.hpp" -#include "resources.hpp" - -namespace ui::external_app::epirb_rx { - -// URL templates -#define MAPS_URL_TEMPLATE "https://www.google.com/maps/search/?api=1&query=%s%%2C%s" -#define BEACON_URL_TEMPLATE "https://decoder2.herokuapp.com/decoded/" - -#ifndef DISABLE_COUNTRY_CACHE -int CountryManager::cache_count = 0; -Country CountryManager::cache[16]; -#endif - -// ResourceManager class -ResourceManager* ResourceManager::current = nullptr; - -void ResourceManager::destroy() { - if (current != nullptr) - delete current; - current = nullptr; -} - -ResourceManager* ResourceManager::getInstance() { - if (current == nullptr) current = new ResourceManager(); - return ResourceManager::current; -} - -// TextArea class -TextArea::TextArea( - Rect parent_rect) - : Widget{parent_rect} { -} - -void TextArea::paint(Painter& painter) { - const auto rect = screen_rect(); - const Style& s = has_focus() ? style().invert() : style(); - - painter.fill_rectangle(rect, s.background); - - const int line_height = s.font.line_height(); - int line_idx = 0; - - // Efficiently draw lines separated by \t without heap allocations - std::string_view sv{content}; - size_t start = 0; - size_t end; - - while ((end = sv.find('\t', start)) != std::string_view::npos) { - painter.draw_string(rect.location() + Point(0, line_idx * line_height), s, sv.substr(start, end - start)); - start = end + 1; - line_idx++; - } - - if (start < sv.length()) { - painter.draw_string(rect.location() + Point(0, line_idx * line_height), s, sv.substr(start)); - } -} - -void TextArea::set_content(std::string_view value) { - content = std::string{value}; - set_dirty(); -} - -#ifdef RESET_TIMER -bool TextArea::on_key(const KeyEvent key) { - if (key == KeyEvent::Select && on_select) { - on_select(*this); - set_dirty(); - return true; - } - return false; -} -#endif - -// EPIRBAppView class -void EPIRBAppView::decode_packet(const baseband::Packet& packet, Beacon& beacon) { - // Convert packet bits to byte array for easier processing - uint8_t data[BEACON_DATA_SIZE]{}; - for (size_t i = 0; i < std::min(packet.size() / 8, (size_t)BEACON_DATA_SIZE); i++) { - uint8_t byte_val = 0; - for (int bit = 0; bit < 8 && (i * 8 + bit) < packet.size(); bit++) { - if (packet[i * 8 + bit]) { - byte_val |= (1 << (7 - bit)); - } - } - data[i] = byte_val; - } - beacon.setFrame(data); - // Set timestamp - rtc::RTC datetime; - rtcGetTime(&RTCD1, &datetime); - beacon.date = datetime; -} - -#ifdef LOGGER -void EPIRBLogger::on_packet(Beacon& beacon) { - std::string entry = std::string(beacon.getType()) + "," + - beacon.hexId + "," + - beacon.getProtocolName(); // + ","; - // to_string_dec_uint(static_cast(beacon.emergency_type)) + ","; - /*if (!beacon.location.isUnknown()) { - entry += beacon.location.toString(Location::LocationFormat::DECIMAL); - } else { - entry += ","; - } - entry += "," + beacon.country.toString() + "," + - beacon.getSatus() + "\n";*/ - log_file.write_entry(beacon.date, entry); -} -#endif - -// EPIRBDetailView class -EPIRBDetailView::EPIRBDetailView( - Rect parent_rect, - EPIRBAppView& parent) - : View(parent_rect), parent_app(parent) { - add_children({&text_beacon}); - set_focusable(true); -} - -#ifdef DETAIL_TAB_BEACON_SEL -bool EPIRBDetailView::on_encoder(EncoderEvent delta) { - // Change position in the list according to encoder - int32_t size = (int32_t)parent_app.beacon_db.size(); - if (size == 0) return true; - // Get current index - int32_t current_index = (int32_t)parent_app.beacon_db.get_current_beacon_index(); - // Compute new index with wrap around - int32_t new_index = (current_index + delta + size) % size; - // Set new index - parent_app.beacon_db.set_current_beacon(new_index % size); - parent_app.on_beacon_change(); - return true; -} -#endif - -// Append "CYAN