mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-10 08:39:29 +00:00
TPMS TX Application with Enhanced RX Integration (#3001)
* Add TPMS transmit application with editable fields and update linker script * Fix formatting in application information structure for TPMS TX * Implement TPMS recent entry detail view and enhance TPMS TX encoding logic * Refactor TPMS TX UI layout and streamline packet display updates * Fix formatting by removing unnecessary blank line in TPMSTXView constructor * Enhance TPMS transmission logic with signal type handling and update UI components * Add advanced mode toggle and auto-select signal type based on packet type * Enhance packet display and encoding logic with protocol-specific notes for temperature and ID handling * Implement baseband switching logic for TPMS transmission based on signal type * Implement application-level FSK repeat handling and initialize repeat counter * Add FSK termination function and improve transmission handling * Remove unused kill_fsk function and clean up whitespace in TPMS transmission logic * Add pressure and temperature unit conversion functionality in TPMSTXView * Add temperature and function field visibility handling in TPMSTXView * Add signal type handling and improve data loading in TPMSTXView * Fix formatting of pressure unit string in TPMSRecentEntryDetailView * Add pressure overflow checks and enhance transponder ID handling in TPMSTXView * Update application information and change icon color to green in TPMS TX * Update desired menu position for TPMS TX application
This commit is contained in:
+1
-1
@@ -75,7 +75,7 @@ __attribute__((section(".external_app.app_tpmsrx.application_information"), used
|
||||
},
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::RX,
|
||||
/*.desired_menu_position = */ -1,
|
||||
/*.desired_menu_position = */ 7,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_tpms */ {'P', 'T', 'P', 'M'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
|
||||
+137
-1
@@ -42,6 +42,25 @@ std::string type(tpms::Reading::Type type) {
|
||||
return to_string_dec_uint(toUType(type), 2);
|
||||
}
|
||||
|
||||
std::string type_name(tpms::Reading::Type type) {
|
||||
switch (type) {
|
||||
case tpms::Reading::Type::None:
|
||||
return "None";
|
||||
case tpms::Reading::Type::FLM_64:
|
||||
return "FLM_64";
|
||||
case tpms::Reading::Type::FLM_72:
|
||||
return "FLM_72";
|
||||
case tpms::Reading::Type::FLM_80:
|
||||
return "FLM_80";
|
||||
case tpms::Reading::Type::Schrader:
|
||||
return "Schrader";
|
||||
case tpms::Reading::Type::GMC_96:
|
||||
return "GMC_96";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string id(tpms::TransponderID id) {
|
||||
return to_string_hex(id.value(), 8);
|
||||
}
|
||||
@@ -101,7 +120,8 @@ void TPMSRecentEntry::update(const tpms::Reading& reading) {
|
||||
}
|
||||
}
|
||||
|
||||
TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
TPMSAppView::TPMSAppView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
// baseband::run_image(portapack::spi_flash::image_tag_tpms);
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
@@ -135,6 +155,11 @@ TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
};
|
||||
options_temperature.set_by_value(format::temp_unit);
|
||||
|
||||
// Add on_select handler for entries
|
||||
recent_entries_view.on_select = [this](const TPMSRecentEntry& entry) {
|
||||
on_show_detail(entry);
|
||||
};
|
||||
|
||||
logger = std::make_unique<TPMSLogger>();
|
||||
if (logger) {
|
||||
logger->append(logs_dir / u"TPMS.TXT");
|
||||
@@ -178,6 +203,7 @@ void TPMSAppView::on_packet(const tpms::Packet& packet) {
|
||||
const auto reading = reading_opt.value();
|
||||
auto& entry = ::on_packet(recent, TPMSRecentEntry::Key{reading.type(), reading.id()});
|
||||
entry.update(reading);
|
||||
entry.signal_type = packet.signal_type();
|
||||
recent_entries_view.set_dirty();
|
||||
}
|
||||
|
||||
@@ -191,6 +217,116 @@ void TPMSAppView::on_show_list() {
|
||||
recent_entries_view.focus();
|
||||
}
|
||||
|
||||
void TPMSAppView::on_show_detail(const TPMSRecentEntry& entry) {
|
||||
nav_.push<TPMSRecentEntryDetailView>(entry);
|
||||
}
|
||||
|
||||
// Detail view implementation
|
||||
TPMSRecentEntryDetailView::TPMSRecentEntryDetailView(NavigationView& nav, const TPMSRecentEntry& entry)
|
||||
: nav_{nav},
|
||||
entry_{entry} {
|
||||
add_children({&labels,
|
||||
&text_type,
|
||||
&text_id,
|
||||
&text_pressure,
|
||||
&text_temperature,
|
||||
&text_flags,
|
||||
&text_count,
|
||||
&button_done,
|
||||
&button_save});
|
||||
|
||||
// Display entry data
|
||||
text_type.set(format::type_name(entry.type));
|
||||
text_id.set(to_string_hex(entry.id.value(), 8));
|
||||
|
||||
if (entry.last_pressure.is_valid()) {
|
||||
std::string pressure_str = format::pressure(entry.last_pressure.value());
|
||||
std::string unit_str = format::pressure_unit == PRESSURE_UNIT_PSI ? " PSI" : format::pressure_unit == PRESSURE_UNIT_BAR ? " BAR"
|
||||
: " kPa";
|
||||
text_pressure.set(pressure_str + unit_str);
|
||||
} else {
|
||||
text_pressure.set("---");
|
||||
}
|
||||
|
||||
if (entry.last_temperature.is_valid()) {
|
||||
text_temperature.set(to_string_dec_int(entry.last_temperature.value().celsius(), 3) + " C");
|
||||
} else {
|
||||
text_temperature.set("---");
|
||||
}
|
||||
|
||||
if (entry.last_flags.is_valid()) {
|
||||
text_flags.set(to_string_hex(entry.last_flags.value(), 2));
|
||||
} else {
|
||||
text_flags.set("--");
|
||||
}
|
||||
|
||||
text_count.set(to_string_dec_uint(entry.received_count, 4));
|
||||
|
||||
button_done.on_select = [&nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
button_save.on_select = [this](Button&) {
|
||||
on_save();
|
||||
};
|
||||
}
|
||||
|
||||
void TPMSRecentEntryDetailView::focus() {
|
||||
button_done.focus();
|
||||
}
|
||||
|
||||
void TPMSRecentEntryDetailView::set_entry(const TPMSRecentEntry& entry) {
|
||||
entry_ = entry;
|
||||
}
|
||||
|
||||
void TPMSRecentEntryDetailView::on_save() {
|
||||
auto timestamp = to_string_timestamp(rtc_time::now());
|
||||
std::string file_name = "TPMS_" + timestamp + ".TXT";
|
||||
ensure_directory(tpms_dir);
|
||||
auto file_path = tpms_dir / file_name;
|
||||
|
||||
if (save_file(file_path)) {
|
||||
nav_.display_modal("Saved", "Packet saved to:\n" + file_name);
|
||||
} else {
|
||||
nav_.display_modal("Error", "Failed to save\npacket");
|
||||
}
|
||||
}
|
||||
|
||||
bool TPMSRecentEntryDetailView::save_file(const std::filesystem::path& path) {
|
||||
File f;
|
||||
auto error = f.create(path);
|
||||
if (error.is_valid())
|
||||
return false;
|
||||
|
||||
// Save in format compatible with TX app
|
||||
std::string content = "Type=" + to_string_dec_uint(toUType(entry_.type), 1) + "\n";
|
||||
content += "ID=" + to_string_hex(entry_.id.value(), 8) + "\n";
|
||||
|
||||
if (entry_.last_pressure.is_valid()) {
|
||||
content += "Pressure=" + to_string_dec_int(entry_.last_pressure.value().kilopascal(), 1) + "\n";
|
||||
} else {
|
||||
content += "Pressure=240\n"; // Default value
|
||||
}
|
||||
|
||||
if (entry_.last_temperature.is_valid()) {
|
||||
content += "Temperature=" + to_string_dec_int(entry_.last_temperature.value().celsius(), 1) + "\n";
|
||||
} else {
|
||||
content += "Temperature=25\n"; // Default value
|
||||
}
|
||||
|
||||
if (entry_.last_flags.is_valid()) {
|
||||
content += "Flags=" + to_string_hex(entry_.last_flags.value(), 2) + "\n";
|
||||
} else {
|
||||
content += "Flags=00\n";
|
||||
}
|
||||
|
||||
// Save signal type for proper retransmission
|
||||
content += "SignalType=" + to_string_dec_uint(toUType(entry_.signal_type), 1) + "\n";
|
||||
|
||||
f.write(content.c_str(), content.length());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::tpmsrx
|
||||
|
||||
namespace ui {
|
||||
|
||||
@@ -53,6 +53,7 @@ struct TPMSRecentEntry {
|
||||
|
||||
tpms::Reading::Type type{invalid_key.first};
|
||||
tpms::TransponderID id{invalid_key.second};
|
||||
tpms::SignalType signal_type{tpms::SignalType::OOK_8k192_Schrader};
|
||||
|
||||
size_t received_count{0};
|
||||
|
||||
@@ -89,6 +90,64 @@ class TPMSLogger {
|
||||
|
||||
using TPMSRecentEntriesView = RecentEntriesView<TPMSRecentEntries>;
|
||||
|
||||
class TPMSRecentEntryDetailView : public View {
|
||||
public:
|
||||
TPMSRecentEntryDetailView(NavigationView& nav, const TPMSRecentEntry& entry);
|
||||
|
||||
void set_entry(const TPMSRecentEntry& entry);
|
||||
const TPMSRecentEntry& entry() const { return entry_; }
|
||||
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
TPMSRecentEntry entry_;
|
||||
|
||||
void on_save();
|
||||
bool save_file(const std::filesystem::path& path);
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 1 * 16}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "ID:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 5 * 16}, "Pressure:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "Temperature:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 9 * 16}, "Flags:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 11 * 16}, "Count:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Text text_type{
|
||||
{8 * 8, 1 * 16, 20 * 8, 16},
|
||||
""};
|
||||
|
||||
Text text_id{
|
||||
{8 * 8, 3 * 16, 20 * 8, 16},
|
||||
""};
|
||||
|
||||
Text text_pressure{
|
||||
{12 * 8, 5 * 16, 16 * 8, 16},
|
||||
""};
|
||||
|
||||
Text text_temperature{
|
||||
{14 * 8, 7 * 16, 14 * 8, 16},
|
||||
""};
|
||||
|
||||
Text text_flags{
|
||||
{8 * 8, 9 * 16, 20 * 8, 16},
|
||||
""};
|
||||
|
||||
Text text_count{
|
||||
{8 * 8, 11 * 16, 20 * 8, 16},
|
||||
""};
|
||||
|
||||
Button button_save{
|
||||
{0 * 8, 13 * 16, 14 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Button button_done{
|
||||
{16 * 8, 13 * 16, 14 * 8, 32},
|
||||
"Done"};
|
||||
};
|
||||
|
||||
class TPMSAppView : public View {
|
||||
public:
|
||||
TPMSAppView(NavigationView& nav);
|
||||
@@ -105,6 +164,8 @@ class TPMSAppView : public View {
|
||||
std::string title() const override { return "TPMS RX"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
RxRadioState radio_state_{
|
||||
314900000 /* frequency*/
|
||||
,
|
||||
@@ -188,6 +249,7 @@ class TPMSAppView : public View {
|
||||
|
||||
void on_packet(const tpms::Packet& packet);
|
||||
void on_show_list();
|
||||
void on_show_detail(const TPMSRecentEntry& entry);
|
||||
void update_view();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user