mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-14 05:17:39 +00:00
Learn ic fix (#2253)
* WIP * Fixed merge * Added test code * WIP * Clean up * add reset learned params * ui fix * ui fix2 * Updated func * Fixed english * WIP * WIP testing * Added new debug app * Got new app for debug * Got new app for debug * Got one full page showing * Got app working with all reg * Got app working with all reg * Got full hex showing * Fixed dp * Fixed dp * Moved entities * Enabled apps again * SHow battery debug if ic * WIP * Refactored further * WIP * Refactor and clean up * Refactor and clean up * fix warning, add tte/ttf, add cycles counter. * wip * morse tx to ext app * fix morse crash * fix ui * Updated wording * WIP * WIP * Updated to display hours and minutes --------- Co-authored-by: HTotoo <ttotoo@gmail.com>
This commit is contained in:
@@ -49,7 +49,10 @@ void BattinfoView::update_result() {
|
||||
text_voltage.set("UNKNOWN");
|
||||
text_current.set("-");
|
||||
text_charge.set("-");
|
||||
text_cycles.set("-");
|
||||
text_ttef.set("-");
|
||||
text_method.set("-");
|
||||
text_warn.set("");
|
||||
return;
|
||||
}
|
||||
bool uichg = false;
|
||||
@@ -73,11 +76,52 @@ void BattinfoView::update_result() {
|
||||
text_current.set(to_string_dec_int(current) + " mA");
|
||||
text_charge.set(current >= 0 ? "Charging" : "Discharging");
|
||||
labels_opt.hidden(false);
|
||||
|
||||
text_ttef.hidden(false);
|
||||
} else {
|
||||
if (!labels_opt.hidden()) uichg = true;
|
||||
labels_opt.hidden(true);
|
||||
text_current.hidden(true);
|
||||
text_charge.hidden(true);
|
||||
text_cycles.hidden(true);
|
||||
text_ttef.hidden(true);
|
||||
text_warn.set("");
|
||||
}
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_CYCLES) == battery::BatteryManagement::BATT_VALID_CYCLES) {
|
||||
text_cycles.hidden(false);
|
||||
uint16_t cycles = battery::BatteryManagement::get_cycles();
|
||||
if (cycles < 2)
|
||||
text_warn.set("SoC improves after 2 cycles");
|
||||
else
|
||||
text_warn.set("");
|
||||
text_cycles.set(to_string_dec_uint(cycles));
|
||||
} else {
|
||||
text_cycles.hidden(true);
|
||||
text_warn.set("");
|
||||
}
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_TTEF) == battery::BatteryManagement::BATT_VALID_TTEF) {
|
||||
text_ttef.hidden(false);
|
||||
float ttef = 0;
|
||||
if (current <= 0) {
|
||||
ttef = battery::BatteryManagement::get_tte();
|
||||
} else {
|
||||
ttef = battery::BatteryManagement::get_ttf();
|
||||
}
|
||||
|
||||
// Convert ttef to hours and minutes
|
||||
uint8_t hours = static_cast<uint8_t>(ttef);
|
||||
uint8_t minutes = static_cast<uint8_t>((ttef - hours) * 60 + 0.5); // +0.5 for rounding
|
||||
|
||||
// Create the formatted string
|
||||
std::string formatted_time;
|
||||
if (hours > 0) {
|
||||
formatted_time += to_string_dec_uint(hours) + "h ";
|
||||
}
|
||||
formatted_time += to_string_dec_uint(minutes) + "m";
|
||||
|
||||
text_ttef.set(formatted_time);
|
||||
} else {
|
||||
text_ttef.hidden(true);
|
||||
}
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_PERCENT) == battery::BatteryManagement::BATT_VALID_PERCENT) {
|
||||
text_method.set("IC");
|
||||
@@ -102,7 +146,10 @@ BattinfoView::BattinfoView(NavigationView& nav)
|
||||
&text_charge,
|
||||
&text_method,
|
||||
&button_mode,
|
||||
&button_exit});
|
||||
&button_exit,
|
||||
&text_cycles,
|
||||
&text_warn,
|
||||
&text_ttef});
|
||||
|
||||
button_exit.on_select = [this, &nav](Button&) {
|
||||
nav.pop();
|
||||
|
@@ -55,12 +55,15 @@ class BattinfoView : public View {
|
||||
{{2 * 8, 1 * 16}, "Percent:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 2 * 16}, "Voltage:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 3 * 16}, "Method:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 7 * 16}, "Change method:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Labels labels_opt{
|
||||
{{2 * 8, 4 * 16}, "Current:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 5 * 16}, "Charge:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{2 * 8, 5 * 16}, "Charge:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 6 * 16}, "TTF/E:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 7 * 16}, "Cycles:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 10 * 16}, "Change method:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Text text_percent{
|
||||
{13 * 8, 1 * 16, 10 * 16, 16},
|
||||
@@ -77,9 +80,19 @@ class BattinfoView : public View {
|
||||
Text text_charge{
|
||||
{13 * 8, 5 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Text text_ttef{
|
||||
{13 * 8, 6 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Text text_cycles{
|
||||
{13 * 8, 7 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
|
||||
Text text_warn{
|
||||
{2 * 8, 8 * 16, 30 * 8, 2 * 16},
|
||||
""};
|
||||
|
||||
Button button_mode{
|
||||
{2 * 8, 8 * 16 + 5, 5 * 16, 32},
|
||||
{2 * 8, 11 * 16 + 5, 5 * 16, 32},
|
||||
"Volt"};
|
||||
|
||||
Button button_exit{
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_external_items_menu_loader.hpp"
|
||||
#include "ui_debug_battery.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
@@ -511,6 +512,11 @@ void DebugMenuView::on_populate() {
|
||||
{"Reboot", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
|
||||
});
|
||||
|
||||
if (battery::BatteryManagement::detectedModule() == battery::BatteryManagement::BatteryModules::BATT_MAX17055) {
|
||||
add_item(
|
||||
{"Battery", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_batt_icon, [this]() { nav_.push<BatteryCapacityView>(); }});
|
||||
}
|
||||
|
||||
for (auto const& gridItem : ExternalItemsMenuLoader::load_external_items(app_location_t::DEBUG, nav_)) {
|
||||
add_item(gridItem);
|
||||
};
|
||||
|
104
firmware/application/apps/ui_debug_battery.cpp
Normal file
104
firmware/application/apps/ui_debug_battery.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "ui_debug_battery.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
BatteryCapacityView::RegisterEntry BatteryCapacityView::get_entry(size_t index) {
|
||||
if (index < battery::max17055::MAX17055::entries_count) {
|
||||
return battery::max17055::MAX17055::entries[index];
|
||||
}
|
||||
return {"", 0, "", 0, false, "", false, 0, false, false, false, 0, false};
|
||||
}
|
||||
|
||||
BatteryCapacityView::BatteryCapacityView(NavigationView& nav) {
|
||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||
name_texts[i].set_parent_rect({0 * 8, static_cast<int>((i + 1) * 16), 8 * 8, 16});
|
||||
addr_texts[i].set_parent_rect({9 * 8, static_cast<int>((i + 1) * 16), 4 * 8, 16});
|
||||
hex_texts[i].set_parent_rect({14 * 8, static_cast<int>((i + 1) * 16), 6 * 8, 16});
|
||||
value_texts[i].set_parent_rect({21 * 8, static_cast<int>((i + 1) * 16), 10 * 8, 16});
|
||||
|
||||
add_child(&name_texts[i]);
|
||||
add_child(&addr_texts[i]);
|
||||
add_child(&hex_texts[i]);
|
||||
add_child(&value_texts[i]);
|
||||
}
|
||||
|
||||
add_children({&labels, &page_text, &button_done});
|
||||
|
||||
button_done.on_select = [&nav](Button&) { nav.pop(); };
|
||||
|
||||
populate_page(0);
|
||||
update_page_text();
|
||||
}
|
||||
|
||||
void BatteryCapacityView::focus() {
|
||||
button_done.focus();
|
||||
}
|
||||
|
||||
bool BatteryCapacityView::on_encoder(const EncoderEvent delta) {
|
||||
int32_t new_page = current_page + delta;
|
||||
if (new_page >= 0 && new_page < ((int32_t)battery::max17055::MAX17055::entries_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE) {
|
||||
current_page = new_page;
|
||||
populate_page(current_page * ENTRIES_PER_PAGE);
|
||||
update_page_text();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BatteryCapacityView::update_values() {
|
||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||
size_t entry_index = current_page * ENTRIES_PER_PAGE + i;
|
||||
if (entry_index < battery::max17055::MAX17055::entries_count) {
|
||||
const auto entry = get_entry(entry_index);
|
||||
uint16_t raw_value = battery::BatteryManagement::read_register(entry.address);
|
||||
|
||||
hex_texts[i].set("0x" + to_string_hex(raw_value, 4));
|
||||
|
||||
float scaled_value;
|
||||
if (entry.is_signed) {
|
||||
int16_t signed_value = static_cast<int16_t>(raw_value);
|
||||
scaled_value = signed_value * entry.scalar;
|
||||
} else {
|
||||
scaled_value = raw_value * entry.scalar;
|
||||
}
|
||||
|
||||
// Format the value with appropriate decimal places
|
||||
std::string formatted_value;
|
||||
if (entry.resolution > 0) {
|
||||
formatted_value = to_string_decimal(scaled_value, std::min(entry.resolution, 3));
|
||||
} else {
|
||||
formatted_value = to_string_dec_int(scaled_value); // Show up to 3 decimal places
|
||||
}
|
||||
|
||||
value_texts[i].set(formatted_value + " " + entry.unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BatteryCapacityView::populate_page(int start_index) {
|
||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||
size_t entry_index = start_index + i;
|
||||
if (entry_index < battery::max17055::MAX17055::entries_count) {
|
||||
const auto entry = get_entry(entry_index);
|
||||
name_texts[i].set(entry.name);
|
||||
addr_texts[i].set("0x" + to_string_hex(entry.address, 2));
|
||||
name_texts[i].hidden(false);
|
||||
addr_texts[i].hidden(false);
|
||||
hex_texts[i].hidden(false);
|
||||
value_texts[i].hidden(false);
|
||||
} else {
|
||||
name_texts[i].hidden(true);
|
||||
addr_texts[i].hidden(true);
|
||||
hex_texts[i].hidden(true);
|
||||
value_texts[i].hidden(true);
|
||||
}
|
||||
}
|
||||
update_values();
|
||||
}
|
||||
|
||||
void BatteryCapacityView::update_page_text() {
|
||||
int total_pages = (battery::max17055::MAX17055::entries_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
|
||||
page_text.set("Page " + to_string_dec_uint(current_page + 1) + "/" + to_string_dec_uint(total_pages));
|
||||
}
|
||||
|
||||
} // namespace ui
|
48
firmware/application/apps/ui_debug_battery.hpp
Normal file
48
firmware/application/apps/ui_debug_battery.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef __UI_DEBUG_BATTERY_HPP__
|
||||
#define __UI_DEBUG_BATTERY_HPP__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "battery.hpp"
|
||||
#include "max17055.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class BatteryCapacityView : public View {
|
||||
public:
|
||||
BatteryCapacityView(NavigationView& nav);
|
||||
void focus() override;
|
||||
std::string title() const override { return "Battery Registers"; }
|
||||
|
||||
bool on_encoder(const EncoderEvent delta) override;
|
||||
|
||||
using RegisterEntry = battery::max17055::RegisterEntry;
|
||||
|
||||
private:
|
||||
static RegisterEntry get_entry(size_t index);
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Reg", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{9 * 8, 0 * 16}, "Addr", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{14 * 8, 0 * 16}, "Hex", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{21 * 8, 0 * 16}, "Value", Theme::getInstance()->fg_yellow->foreground},
|
||||
};
|
||||
std::array<Text, 16> name_texts = {};
|
||||
std::array<Text, 16> addr_texts = {};
|
||||
std::array<Text, 16> hex_texts = {};
|
||||
std::array<Text, 16> value_texts = {};
|
||||
|
||||
Text page_text{{144, 284, 80, 16}, "Page 1/1"};
|
||||
Button button_done{{16, 280, 96, 24}, "Done"};
|
||||
|
||||
void update_values();
|
||||
void populate_page(int start_index);
|
||||
void update_page_text();
|
||||
int current_page = 0;
|
||||
static constexpr int ENTRIES_PER_PAGE = 16;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif // __UI_DEBUG_BATTERY_HPP__
|
@@ -1,287 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* 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 "ui_morse.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "hackrf_gpio.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace portapack;
|
||||
using namespace morse;
|
||||
using namespace hackrf::one;
|
||||
|
||||
namespace ui {
|
||||
|
||||
static WORKING_AREA(ookthread_wa, 256);
|
||||
|
||||
static msg_t ookthread_fn(void* arg) {
|
||||
uint32_t v = 0, delay = 0;
|
||||
uint8_t* message_symbols = shared_memory.bb_data.tones_data.message;
|
||||
uint8_t symbol;
|
||||
MorseView* arg_c = (MorseView*)arg;
|
||||
|
||||
chRegSetThreadName("ookthread");
|
||||
|
||||
for (uint32_t i = 0; i < arg_c->symbol_count; i++) {
|
||||
if (chThdShouldTerminate()) break;
|
||||
|
||||
symbol = message_symbols[i];
|
||||
|
||||
v = (symbol < 2) ? 1 : 0; // TX on for dot or dash, off for pause
|
||||
delay = morse_symbols[symbol];
|
||||
|
||||
if (hackrf_r9) { // r9 has a common PIN 54 for MODE CONTROL TX / RX, <=r6 has two independent MODE CONTROL pins (TX and RX)
|
||||
gpio_r9_rx.write(!v); // in hackrf r9 opposite logic "0" means tx , "1" rx = no tx)
|
||||
} else {
|
||||
gpio_og_tx.write(v); // in hackrf <=r6, "1" means tx , "0" no tx.
|
||||
}
|
||||
|
||||
arg_c->on_tx_progress(i, false);
|
||||
|
||||
chThdSleepMilliseconds(delay * arg_c->time_unit_ms);
|
||||
}
|
||||
|
||||
if (hackrf_r9) { // r9 has a common PIN 54 for MODE CONTROL TX / RX, <=r6 has two independent MODE CONTROL pins (TX and RX)
|
||||
gpio_r9_rx.write(1); // Hackrf_r9 , common pin, rx="1" (we ensure TX is off) / tx="0"
|
||||
} else {
|
||||
gpio_og_tx.write(0); // Hackrf <=r6 independent TX / RX pins ,now touching the tx pin ==> Ensure TX is off
|
||||
}
|
||||
|
||||
arg_c->on_tx_progress(0, true);
|
||||
chThdExit(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static msg_t loopthread_fn(void* arg) {
|
||||
MorseView* arg_c = (MorseView*)arg;
|
||||
uint32_t wait = arg_c->loop;
|
||||
|
||||
chRegSetThreadName("loopthread");
|
||||
|
||||
for (uint32_t i = 0; i < wait; i++) {
|
||||
if (chThdShouldTerminate()) break;
|
||||
|
||||
arg_c->on_loop_progress(i, false);
|
||||
chThdSleepMilliseconds(1000);
|
||||
}
|
||||
|
||||
arg_c->on_loop_progress(0, true);
|
||||
chThdExit(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MorseView::on_set_text(NavigationView& nav) {
|
||||
text_prompt(nav, buffer, 28);
|
||||
}
|
||||
|
||||
void MorseView::focus() {
|
||||
button_message.focus();
|
||||
}
|
||||
|
||||
MorseView::~MorseView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void MorseView::paint(Painter&) {
|
||||
message = buffer;
|
||||
text_message.set(message);
|
||||
update_tx_duration();
|
||||
}
|
||||
|
||||
bool MorseView::start_tx() {
|
||||
// Re-generate message, just in case
|
||||
update_tx_duration();
|
||||
|
||||
if (!symbol_count) {
|
||||
nav_.display_modal("Error", "Message too long,\nmust be < 256 symbols.");
|
||||
return false;
|
||||
}
|
||||
|
||||
progressbar.set_max(symbol_count);
|
||||
// By experimental spectrum measurment, we left exactly same TX LPF settings as previous fw 1.7.4, TX LPF= 1M75 (min).
|
||||
transmitter_model.set_baseband_bandwidth(1'750'000); // Min TX LPF .already tested in FM morse max tone 9,999k , max dev 150khz
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_tones_config(transmitter_model.channel_bandwidth(), 0, symbol_count, false, false);
|
||||
|
||||
if (mode_cw) {
|
||||
ookthread = chThdCreateStatic(ookthread_wa, sizeof(ookthread_wa), NORMALPRIO + 10, ookthread_fn, this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MorseView::update_tx_duration() {
|
||||
uint32_t duration_ms;
|
||||
|
||||
time_unit_ms = 1200 / speed;
|
||||
symbol_count = morse_encode(message, time_unit_ms, tone, &time_units);
|
||||
|
||||
if (symbol_count) {
|
||||
duration_ms = time_units * time_unit_ms;
|
||||
text_tx_duration.set(to_string_dec_uint(duration_ms / 1000) + "." + to_string_dec_uint((duration_ms / 100) % 10, 1) + "s ");
|
||||
} else {
|
||||
text_tx_duration.set("-"); // Error
|
||||
}
|
||||
}
|
||||
|
||||
void MorseView::on_tx_progress(const uint32_t progress, const bool done) {
|
||||
if (done) {
|
||||
transmitter_model.disable();
|
||||
progressbar.set_value(0);
|
||||
|
||||
if (loop && run) {
|
||||
text_tx_duration.set("wait");
|
||||
progressbar.set_max(loop);
|
||||
progressbar.set_value(0);
|
||||
|
||||
if (loopthread) {
|
||||
chThdRelease(loopthread);
|
||||
loopthread = nullptr;
|
||||
}
|
||||
|
||||
loopthread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO, loopthread_fn, this);
|
||||
} else {
|
||||
tx_view.set_transmitting(false);
|
||||
}
|
||||
} else
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void MorseView::on_loop_progress(const uint32_t progress, const bool done) {
|
||||
if (done) {
|
||||
start_tx();
|
||||
} else
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void MorseView::set_foxhunt(size_t i) {
|
||||
message = foxhunt_codes[i - 1];
|
||||
buffer = message.c_str();
|
||||
text_message.set(message);
|
||||
update_tx_duration();
|
||||
}
|
||||
|
||||
MorseView::MorseView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_tones);
|
||||
|
||||
add_children({&labels,
|
||||
&checkbox_foxhunt,
|
||||
&field_foxhunt,
|
||||
&field_speed,
|
||||
&field_tone,
|
||||
&options_modulation,
|
||||
&options_loop,
|
||||
&text_tx_duration,
|
||||
&text_message,
|
||||
&button_message,
|
||||
&progressbar,
|
||||
&tx_view});
|
||||
|
||||
// Default settings
|
||||
field_speed.set_value(speed);
|
||||
field_tone.set_value(tone);
|
||||
options_modulation.set_by_value(mode_cw);
|
||||
options_loop.set_by_value(loop);
|
||||
checkbox_foxhunt.set_value(foxhunt_mode);
|
||||
field_foxhunt.set_value(foxhunt_code);
|
||||
|
||||
checkbox_foxhunt.on_select = [this](Checkbox&, bool value) {
|
||||
foxhunt_mode = value;
|
||||
|
||||
if (foxhunt_mode)
|
||||
set_foxhunt(foxhunt_code);
|
||||
};
|
||||
|
||||
field_foxhunt.on_change = [this](int32_t value) {
|
||||
foxhunt_code = value;
|
||||
|
||||
if (foxhunt_mode)
|
||||
set_foxhunt(foxhunt_code);
|
||||
};
|
||||
|
||||
options_modulation.on_change = [this](size_t i, int32_t value) {
|
||||
(void)i; // avoid unused warning
|
||||
mode_cw = (bool)value;
|
||||
};
|
||||
|
||||
options_loop.on_change = [this](size_t i, uint32_t value) {
|
||||
(void)i; // avoid unused warning
|
||||
loop = value;
|
||||
};
|
||||
|
||||
field_speed.on_change = [this](int32_t value) {
|
||||
speed = value;
|
||||
update_tx_duration();
|
||||
};
|
||||
|
||||
field_tone.on_change = [this](int32_t value) {
|
||||
tone = value;
|
||||
};
|
||||
|
||||
button_message.on_select = [this, &nav](Button&) {
|
||||
this->on_set_text(nav);
|
||||
};
|
||||
|
||||
tx_view.on_edit_frequency = [this, &nav]() {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
transmitter_model.set_target_frequency(f);
|
||||
};
|
||||
};
|
||||
|
||||
tx_view.on_start = [this]() {
|
||||
if (start_tx()) {
|
||||
run = true;
|
||||
tx_view.set_transmitting(true);
|
||||
}
|
||||
};
|
||||
|
||||
tx_view.on_stop = [this]() {
|
||||
run = false;
|
||||
if (ookthread) chThdTerminate(ookthread);
|
||||
|
||||
if (loopthread) {
|
||||
chThdTerminate(loopthread);
|
||||
chThdWait(loopthread);
|
||||
loopthread = nullptr;
|
||||
}
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::kill_tone();
|
||||
tx_view.set_transmitting(false);
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __MORSE_TX_H__
|
||||
#define __MORSE_TX_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_transmitter.hpp"
|
||||
#include "app_settings.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "message.hpp"
|
||||
#include "volume.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "morse.hpp"
|
||||
|
||||
#include <ch.h>
|
||||
|
||||
using namespace morse;
|
||||
|
||||
namespace ui {
|
||||
|
||||
class MorseView : public View {
|
||||
public:
|
||||
MorseView(NavigationView& nav);
|
||||
~MorseView();
|
||||
|
||||
MorseView(const MorseView&) = delete;
|
||||
MorseView(MorseView&&) = delete;
|
||||
MorseView& operator=(const MorseView&) = delete;
|
||||
MorseView& operator=(MorseView&&) = delete;
|
||||
|
||||
void focus() override;
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
void on_tx_progress(const uint32_t progress, const bool done);
|
||||
void on_loop_progress(const uint32_t progress, const bool done);
|
||||
|
||||
std::string title() const override { return "Morse TX"; };
|
||||
|
||||
uint32_t time_unit_ms{0};
|
||||
size_t symbol_count{0};
|
||||
uint32_t loop{0};
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
std::string message{};
|
||||
uint32_t time_units{0};
|
||||
|
||||
TxRadioState radio_state_{
|
||||
0 /* frequency */,
|
||||
1750000 /* bandwidth */,
|
||||
1536000 /* sampling rate */
|
||||
};
|
||||
|
||||
std::string buffer{"PORTAPACK"};
|
||||
bool mode_cw{true};
|
||||
bool foxhunt_mode{false};
|
||||
uint32_t foxhunt_code{1};
|
||||
uint32_t speed{15};
|
||||
uint32_t tone{700};
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_morse",
|
||||
app_settings::Mode::TX,
|
||||
{
|
||||
{"message"sv, &buffer},
|
||||
{"foxhunt"sv, &foxhunt_mode},
|
||||
{"foxhunt_code"sv, &foxhunt_code},
|
||||
{"speed"sv, &speed},
|
||||
{"tone"sv, &tone},
|
||||
{"mode_cw"sv, &mode_cw},
|
||||
{"loop"sv, &loop},
|
||||
}};
|
||||
|
||||
bool start_tx();
|
||||
void update_tx_duration();
|
||||
void on_set_text(NavigationView& nav);
|
||||
void set_foxhunt(size_t i);
|
||||
|
||||
Thread* ookthread{nullptr};
|
||||
Thread* loopthread{nullptr};
|
||||
bool run{false};
|
||||
|
||||
Labels labels{
|
||||
{{4 * 8, 6 * 8}, "Speed: wps", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 8 * 8}, "Tone: Hz", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 10 * 8}, "Modulation:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 12 * 8}, "Loop:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 25 * 8}, "TX will last", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Checkbox checkbox_foxhunt{
|
||||
{4 * 8, 16},
|
||||
8,
|
||||
"Foxhunt:"};
|
||||
NumberField field_foxhunt{
|
||||
{17 * 8, 16 + 4},
|
||||
2,
|
||||
{1, 11},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_speed{
|
||||
{10 * 8, 6 * 8},
|
||||
3,
|
||||
{10, 45},
|
||||
1,
|
||||
' '};
|
||||
|
||||
NumberField field_tone{
|
||||
{9 * 8, 8 * 8},
|
||||
4,
|
||||
{100, 9999},
|
||||
20,
|
||||
' '};
|
||||
|
||||
OptionsField options_modulation{
|
||||
{15 * 8, 10 * 8},
|
||||
2,
|
||||
{{"CW", true},
|
||||
{"FM", false}}};
|
||||
|
||||
OptionsField options_loop{
|
||||
{9 * 8, 12 * 8},
|
||||
6,
|
||||
{{"Off", 0},
|
||||
{"5 sec", 5},
|
||||
{"10 sec", 10},
|
||||
{"30 sec", 30},
|
||||
{"1 min", 60},
|
||||
{"3 min", 180},
|
||||
{"5 min", 300}}};
|
||||
|
||||
Text text_tx_duration{
|
||||
{14 * 8, 25 * 8, 4 * 8, 16},
|
||||
"-"};
|
||||
|
||||
Text text_message{
|
||||
{1 * 8, 15 * 8, 28 * 8, 16},
|
||||
""};
|
||||
|
||||
Button button_message{
|
||||
{1 * 8, 17 * 8, 12 * 8, 28},
|
||||
"Set message"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{2 * 8, 28 * 8, 208, 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
10000,
|
||||
12};
|
||||
|
||||
MessageHandlerRegistration message_handler_tx_progress{
|
||||
Message::ID::TXProgress,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||
this->on_tx_progress(message.progress, message.done);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__MORSE_TX_H__*/
|
@@ -969,6 +969,8 @@ SetBatteryView::SetBatteryView(NavigationView& nav) {
|
||||
&button_cancel,
|
||||
&checkbox_overridebatt});
|
||||
|
||||
if (battery::BatteryManagement::detectedModule() == battery::BatteryManagement::BATT_MAX17055) add_children({&button_reset, &labels2});
|
||||
|
||||
button_save.on_select = [&nav, this](Button&) {
|
||||
pmem::set_ui_override_batt_calc(checkbox_overridebatt.value());
|
||||
battery::BatteryManagement::set_calc_override(checkbox_overridebatt.value());
|
||||
@@ -976,6 +978,13 @@ SetBatteryView::SetBatteryView(NavigationView& nav) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
button_reset.on_select = [&nav, this](Button&) {
|
||||
if (battery::BatteryManagement::reset_learned())
|
||||
nav.display_modal("Reset", "Battery parameters reset");
|
||||
else
|
||||
nav.display_modal("Error", "Error parameter reset");
|
||||
};
|
||||
|
||||
checkbox_overridebatt.set_value(pmem::ui_override_batt_calc());
|
||||
|
||||
button_cancel.on_select = [&nav, this](Button&) {
|
||||
@@ -1017,7 +1026,7 @@ void SettingsMenuView::on_populate() {
|
||||
{"Theme", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push<SetThemeView>(); }},
|
||||
{"Autostart", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push<SetAutostartView>(); }},
|
||||
});
|
||||
if (battery::BatteryManagement::isDetected()) add_item({"Battery", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push<SetBatteryView>(); }});
|
||||
if (battery::BatteryManagement::isDetected()) add_item({"Battery", ui::Color::dark_cyan(), &bitmap_icon_batt_icon, [this]() { nav_.push<SetBatteryView>(); }});
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
@@ -906,13 +906,14 @@ class SetBatteryView : public View {
|
||||
Labels labels{
|
||||
{{1 * 8, 1 * 16}, "Override batt calculation", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 2 * 16}, "method to voltage based", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Labels labels2{
|
||||
{{1 * 8, 6 * 16}, "Reset IC's learned params.", Theme::getInstance()->fg_light->foreground}};
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Checkbox checkbox_overridebatt{
|
||||
{2 * 8, 6 * 16},
|
||||
{2 * 8, 4 * 16},
|
||||
23,
|
||||
"Override"};
|
||||
|
||||
@@ -920,6 +921,11 @@ class SetBatteryView : public View {
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
|
||||
Button button_reset{
|
||||
{2 * 8, 8 * 16, 12 * 8, 32},
|
||||
"Reset",
|
||||
};
|
||||
};
|
||||
|
||||
class SettingsMenuView : public BtnGridView {
|
||||
|
Reference in New Issue
Block a user