diff --git a/firmware/application/apps/ble_rx_app.cpp b/firmware/application/apps/ble_rx_app.cpp index f538d1fe..03c0b9c1 100644 --- a/firmware/application/apps/ble_rx_app.cpp +++ b/firmware/application/apps/ble_rx_app.cpp @@ -22,7 +22,6 @@ */ #include "ble_rx_app.hpp" -#include "ble_tx_app.hpp" #include "ui_modemsetup.hpp" @@ -65,8 +64,9 @@ void RecentEntriesTable::draw( Painter& painter, const Style& style) { std::string line{}; + line.reserve(30); - if (!entry.nameString.empty()) { + if (!entry.nameString.empty() && entry.include_name) { line = entry.nameString; if (line.length() < 17) { @@ -107,13 +107,16 @@ BleRecentEntryDetailView::BleRecentEntryDetailView(NavigationView& nav, const Bl text_mac_address.set(to_string_mac_address(entry.packetData.macAddress, 6, false)); - button_done.on_select = [this](const ui::Button&) { - nav_.pop(); + button_done.on_select = [&nav](const ui::Button&) { + nav.pop(); }; - button_send.on_select = [this](const ui::Button&) { - nav_.set_on_pop([this]() { launch_bletx(entry_); }); - nav_.pop(); + button_send.on_select = [this, &nav](const ui::Button&) { + auto packetToSend = build_packet(); + nav.set_on_pop([packetToSend, &nav]() { + nav.replace(packetToSend); + }); + nav.pop(); }; } @@ -199,18 +202,18 @@ void BleRecentEntryDetailView::set_entry(const BleRecentEntry& entry) { set_dirty(); } -void BleRecentEntryDetailView::launch_bletx(BleRecentEntry packetEntry) { +BLETxPacket BleRecentEntryDetailView::build_packet() { BLETxPacket bleTxPacket; memset(&bleTxPacket, 0, sizeof(BLETxPacket)); - std::string macAddressStr = to_string_mac_address(packetEntry.packetData.macAddress, 6, true); + std::string macAddressStr = to_string_mac_address(entry_.packetData.macAddress, 6, true); strncpy(bleTxPacket.macAddress, macAddressStr.c_str(), 12); - strncpy(bleTxPacket.advertisementData, packetEntry.dataString.c_str(), packetEntry.packetData.dataLen * 2); + strncpy(bleTxPacket.advertisementData, entry_.dataString.c_str(), entry_.packetData.dataLen * 2); strncpy(bleTxPacket.packetCount, "50", 3); bleTxPacket.packet_count = 50; - nav_.replace(bleTxPacket); + return bleTxPacket; } static std::uint64_t get_freq_by_channel_number(uint8_t channel_number) { @@ -255,28 +258,20 @@ BLERxView::BLERxView(NavigationView& nav) &options_channel, &field_frequency, &check_log, + &check_name, &label_sort, &options_sort, &button_filter, &button_switch, - &recent_entries_view, - &recent_entries_filter_view, - &recent_entry_detail_view}); - - recent_entry_detail_view.hidden(true); - recent_entries_filter_view.hidden(true); + &recent_entries_view}); recent_entries_view.on_select = [this](const BleRecentEntry& entry) { nav_.push(entry); }; - recent_entries_filter_view.on_select = [this](const BleRecentEntry& entry) { - nav_.push(entry); - }; - - button_filter.on_select = [this, &nav](Button&) { + button_filter.on_select = [this](Button&) { text_prompt( - nav, + nav_, filterBuffer, 64, [this](std::string& buffer) { @@ -284,9 +279,8 @@ BLERxView::BLERxView(NavigationView& nav) }); }; - button_switch.on_select = [this, &nav](Button&) { - nav_.set_on_pop([this]() { nav_.push(); }); - nav_.pop(); + button_switch.on_select = [&nav](Button&) { + nav.replace(); }; field_frequency.set_step(0); @@ -301,6 +295,13 @@ BLERxView::BLERxView(NavigationView& nav) logger->append(LOG_ROOT_DIR "/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT"); }; + check_name.set_value(true); + + check_name.on_select = [this](Checkbox&, bool v) { + setAllMembersToValue(recent, &BleRecentEntry::include_name, v); + recent_entries_view.set_dirty(); + }; + options_channel.on_change = [this](size_t, int32_t i) { field_frequency.set_value(get_freq_by_channel_number(i)); channel_number = i; @@ -308,44 +309,8 @@ BLERxView::BLERxView(NavigationView& nav) baseband::set_btlerx(channel_number); }; - options_sort.on_change = [this](size_t, int32_t i) { - switch (i) { - case 0: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.macAddress; }, true); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.macAddress; }, true); - break; - case 1: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.numHits; }, false); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.numHits; }, false); - break; - case 2: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.dbValue; }, true); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.dbValue; }, true); - break; - case 3: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.timestamp; }, false); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.timestamp; }, false); - break; - case 4: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.nameString; }, true); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.nameString; }, true); - break; - default: - break; - } - - recent_entries_view.set_dirty(); - recent_entries_filter_view.set_dirty(); + options_sort.on_change = [this](size_t, int32_t index) { + handle_entries_sort(index); }; options_channel.set_selected_index(0, true); @@ -428,42 +393,66 @@ void BLERxView::on_data(BlePacketData* packet) { // Start of Packet stuffing. // Masking off the top 2 bytes to avoid invalid keys. auto& entry = ::on_packet(recent, macAddressEncoded & 0xFFFFFFFFFFFF); - truncate_entries(recent, 32); updateEntry(packet, entry); + // Add entries if they meet the criteria. + auto value = filter; + resetFilteredEntries(recent, [&value](const BleRecentEntry& entry) { + return (entry.dataString.find(value) == std::string::npos) && (entry.nameString.find(value) == std::string::npos); + }); + + handle_entries_sort(options_sort.selected_index()); + // Log at End of Packet. if (logger && logging) { logger->log_raw_data(str_console); } } -void BLERxView::on_switch_table(const std::string value) { - filter = value; - - if (!value.empty()) { - removeEntriesWithoutKey(recent, filterEntries, [&value](const BleRecentEntry& entry) { - return entry.dataString.find(value) == std::string::npos; +void BLERxView::on_switch_table(std::string value) { + // New filter? Reset list from recent entries. + if (filter != value) { + resetFilteredEntries(recent, [&value](const BleRecentEntry& entry) { + return (entry.dataString.find(value) == std::string::npos) && (entry.nameString.find(value) == std::string::npos); }); + } - recent_entries_view.set_dirty(); + filter = value; +} - recent_entries_filter_view.hidden(false); - recent_entries_view.hidden(true); - } else { - recent_entries_view.hidden(false); - recent_entries_filter_view.hidden(true); +void BLERxView::handle_entries_sort(uint8_t index) { + switch (index) { + case 0: + sortEntriesBy( + recent, [](const BleRecentEntry& entry) { return entry.macAddress; }, true); + break; + case 1: + sortEntriesBy( + recent, [](const BleRecentEntry& entry) { return entry.numHits; }, false); + break; + case 2: + sortEntriesBy( + recent, [](const BleRecentEntry& entry) { return entry.dbValue; }, false); + break; + case 3: + sortEntriesBy( + recent, [](const BleRecentEntry& entry) { return entry.timestamp; }, false); + break; + case 4: + sortEntriesBy( + recent, [](const BleRecentEntry& entry) { return entry.nameString; }, true); + break; + default: + break; } recent_entries_view.set_dirty(); - recent_entries_filter_view.set_dirty(); } void BLERxView::set_parent_rect(const Rect new_parent_rect) { View::set_parent_rect(new_parent_rect); const Rect content_rect{0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height - switch_button_height}; recent_entries_view.set_parent_rect(content_rect); - recent_entry_detail_view.set_parent_rect(content_rect); - recent_entries_filter_view.set_parent_rect(content_rect); } BLERxView::~BLERxView() { @@ -502,6 +491,7 @@ void BLERxView::updateEntry(const BlePacketData* packet, BleRecentEntry& entry) } entry.nameString = ""; + entry.include_name = check_name.value(); uint8_t currentByte = 0; uint8_t length = 0; @@ -526,48 +516,6 @@ void BLERxView::updateEntry(const BlePacketData* packet, BleRecentEntry& entry) stringFound = true; } } - - switch (options_sort.selected_index()) { - case 0: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.macAddress; }, true); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.macAddress; }, true); - break; - case 1: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.numHits; }, false); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.numHits; }, false); - break; - case 2: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.dbValue; }, true); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.dbValue; }, true); - break; - case 3: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.timestamp; }, false); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.timestamp; }, false); - break; - case 4: - sortEntriesBy( - recent, [](const BleRecentEntry& entry) { return entry.nameString; }, true); - sortEntriesBy( - filterEntries, [](const BleRecentEntry& entry) { return entry.nameString; }, true); - break; - default: - break; - } - - on_switch_table(filter); - - // TODO: Crude hack, should be a more formal listener arrangement... - if (entry.key() == recent_entry_detail_view.entry().key()) { - recent_entry_detail_view.set_entry(entry); - } } } /* namespace ui */ diff --git a/firmware/application/apps/ble_rx_app.hpp b/firmware/application/apps/ble_rx_app.hpp index f30faa28..1599d484 100644 --- a/firmware/application/apps/ble_rx_app.hpp +++ b/firmware/application/apps/ble_rx_app.hpp @@ -24,6 +24,8 @@ #ifndef __BLE_RX_APP_H__ #define __BLE_RX_APP_H__ +#include "ble_tx_app.hpp" + #include "ui.hpp" #include "ui_navigation.hpp" #include "ui_receiver.hpp" @@ -79,6 +81,7 @@ struct BleRecentEntry { std::string timestamp; std::string dataString; std::string nameString; + bool include_name; uint16_t numHits; BleRecentEntry() @@ -93,6 +96,7 @@ struct BleRecentEntry { timestamp{}, dataString{}, nameString{}, + include_name{}, numHits{} { } @@ -118,7 +122,7 @@ class BleRecentEntryDetailView : public View { private: NavigationView& nav_; BleRecentEntry entry_{}; - void launch_bletx(BleRecentEntry packetEntry); + BLETxPacket build_packet(); static constexpr uint8_t total_data_lines{5}; @@ -167,7 +171,8 @@ class BLERxView : public View { private: void on_data(BlePacketData* packetData); - void on_switch_table(const std::string value); + void on_switch_table(std::string value); + void handle_entries_sort(uint8_t index); void updateEntry(const BlePacketData* packet, BleRecentEntry& entry); NavigationView& nav_; @@ -228,15 +233,21 @@ class BLERxView : public View { {"Name", 4}}}; Button button_filter{ - {12 * 8, 3 * 8, 4 * 8, 16}, + {11 * 8, 3 * 8, 4 * 8, 16}, "Filter"}; Checkbox check_log{ - {20 * 8, 3 * 8}, + {17 * 8, 3 * 8}, 3, "Log", true}; + Checkbox check_name{ + {23 * 8, 3 * 8}, + 3, + "Name", + true}; + Console console{ {0, 4 * 16, 240, 240}}; @@ -258,10 +269,7 @@ class BLERxView : public View { {"dB", 4}, }}; - BleRecentEntry entry_{}; BleRecentEntriesView recent_entries_view{columns, recent}; - BleRecentEntriesView recent_entries_filter_view{columns, filterEntries}; - BleRecentEntryDetailView recent_entry_detail_view{nav_, entry_}; MessageHandlerRegistration message_handler_packet{ Message::ID::BlePacket, diff --git a/firmware/application/apps/ble_tx_app.cpp b/firmware/application/apps/ble_tx_app.cpp index 5aa1ef07..199cffb0 100644 --- a/firmware/application/apps/ble_tx_app.cpp +++ b/firmware/application/apps/ble_tx_app.cpp @@ -219,17 +219,17 @@ void BLETxView::start() { return; } else { // Send first or single packet. - packet_counter = packets[current_packet].packet_count; - progressbar.set_max(packets[current_packet].packet_count); + progressbar.set_max(packets[0].packet_count); button_play.set_bitmap(&bitmap_stop); - baseband::set_btletx(channel_number, random_mac ? randomMac : packets[current_packet].macAddress, packets[current_packet].advertisementData, pduType); + baseband::set_btletx(channel_number, random_mac ? randomMac : packets[0].macAddress, packets[0].advertisementData, pduType); transmitter_model.enable(); is_running = true; } } else { // Send next packet. + progressbar.set_max(packets[current_packet].packet_count); baseband::set_btletx(channel_number, random_mac ? randomMac : packets[current_packet].macAddress, packets[current_packet].advertisementData, pduType); } @@ -238,7 +238,6 @@ void BLETxView::start() { } packet_counter--; - progressbar.set_value(packets[current_packet].packet_count - packet_counter); } @@ -248,10 +247,7 @@ void BLETxView::stop() { button_play.set_bitmap(&bitmap_play); check_loop.set_value(false); - current_packet = 0; - text_packets_sent.set(to_string_dec_uint(packets[0].packet_count)); - packet_counter = packets[0].packet_count; - update_packet_display(packets[0]); + update_current_packet(packets[0], 0); is_running = false; } @@ -265,16 +261,13 @@ void BLETxView::on_tx_progress(const bool done) { if (current_packet == (num_packets - 1)) { // If looping, restart from beginning. if (check_loop.value()) { - current_packet = 0; - packet_counter = packets[current_packet].packet_count; - update_packet_display(packets[current_packet]); + update_current_packet(packets[current_packet], 0); } else { stop(); } } else { current_packet++; - packet_counter = packets[current_packet].packet_count; - update_packet_display(packets[current_packet]); + update_current_packet(packets[current_packet], current_packet); } } else { if ((timer_count % timer_period) == 0) { @@ -344,8 +337,8 @@ BLETxView::BLETxView(NavigationView& nav) random_mac = v; }; - button_open.on_select = [this, &nav](Button&) { - auto open_view = nav.push(".TXT"); + button_open.on_select = [this](Button&) { + auto open_view = nav_.push(".TXT"); open_view->on_changed = [this](std::filesystem::path new_file_path) { on_file_changed(new_file_path); @@ -364,9 +357,8 @@ BLETxView::BLETxView(NavigationView& nav) }); }; - button_switch.on_select = [this, &nav](Button&) { - nav_.set_on_pop([this]() { nav_.push(); }); - nav_.pop(); + button_switch.on_select = [&nav](Button&) { + nav.replace(); }; } @@ -375,7 +367,8 @@ BLETxView::BLETxView( BLETxPacket packet) : BLETxView(nav) { packets[0] = packet; - update_packet_display(packets[0]); + + update_current_packet(packets[0], 0); num_packets = 1; file_override = true; @@ -404,7 +397,6 @@ void BLETxView::on_file_changed(const fs::path& new_file_path) { uint64_t packetCountSize = strlen(packets[num_packets].packetCount); packets[num_packets].packet_count = stringToUint32(packets[num_packets].packetCount); - packet_counter = packets[num_packets].packet_count; // Verify Data. if ((macAddressSize == mac_address_size_str) && (advertisementDataSize < max_packet_size_str) && (packetCountSize < max_packet_repeat_str) && @@ -425,7 +417,7 @@ void BLETxView::on_file_changed(const fs::path& new_file_path) { } while (num_packets < max_num_packets); - update_packet_display(packets[0]); + update_current_packet(packets[0], 0); } } @@ -447,7 +439,7 @@ void BLETxView::on_data(uint32_t value, bool is_data) { console.write(str_console); } -void BLETxView::update_packet_display(BLETxPacket packet) { +void BLETxView::update_current_packet(BLETxPacket packet, uint32_t currentIndex) { std::string formattedMacAddress = to_string_formatted_mac_address(packet.macAddress); std::vector strings = splitIntoStrings(packet.advertisementData); @@ -463,6 +455,9 @@ void BLETxView::update_packet_display(BLETxPacket packet) { for (const std::string& str : strings) { console.writeln(str); } + + packet_counter = packet.packet_count; + current_packet = currentIndex; } void BLETxView::set_parent_rect(const Rect new_parent_rect) { diff --git a/firmware/application/apps/ble_tx_app.hpp b/firmware/application/apps/ble_tx_app.hpp index 75612fb8..c102a9aa 100644 --- a/firmware/application/apps/ble_tx_app.hpp +++ b/firmware/application/apps/ble_tx_app.hpp @@ -85,10 +85,10 @@ class BLETxView : public View { private: void on_data(uint32_t value, bool is_data); - void on_tx_progress(const bool done); void on_file_changed(const std::filesystem::path& new_file_path); - void update_packet_display(BLETxPacket packet); void on_save_file(const std::string value); + void on_tx_progress(const bool done); + void update_current_packet(BLETxPacket packet, uint32_t currentIndex); NavigationView& nav_; TxRadioState radio_state_{ @@ -152,7 +152,7 @@ class BLETxView : public View { static constexpr uint8_t max_packet_size_str{62}; static constexpr uint8_t max_packet_repeat_str{10}; static constexpr uint32_t max_packet_repeat_count{UINT32_MAX}; - static constexpr uint32_t max_num_packets{256}; + static constexpr uint32_t max_num_packets{32}; BLETxPacket packets[max_num_packets]; diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 997cf8e3..83e6189b 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -103,19 +103,28 @@ void sortEntriesBy(ContainerType& entries, KeySelector keySelector, SortOrder as } template -void removeEntriesWithoutKey(ContainerType& entries, ContainerType& filteredEntries, KeySelector keySelector) { +void resetFilteredEntries(ContainerType& entries, KeySelector keySelector) { // Clear the filteredEntries container - filteredEntries.clear(); - auto it = entries.begin(); while (it != entries.end()) { - if (!keySelector(*it)) { - filteredEntries.emplace_back(*it); // Add a new entry to filteredEntries + if (keySelector(*it)) { + entries.erase(it); // Add a new entry to filteredEntries } ++it; // Move to the next element, outside of the if block } } +template +void setAllMembersToValue(ContainerType& entries, MemberPtr memberPtr, const KeyValue& keyValue) { + for (auto& entry : entries) { + // Check if the member specified by memberPtr is equal to keyValue + if (entry.*memberPtr != keyValue) { + // Update the member with keyValue + entry.*memberPtr = keyValue; + } + } +} + namespace ui { using RecentEntriesColumn = std::pair;