diff --git a/firmware/application/apps/ble_rx_app.cpp b/firmware/application/apps/ble_rx_app.cpp index 45aac6f5..6be25a49 100644 --- a/firmware/application/apps/ble_rx_app.cpp +++ b/firmware/application/apps/ble_rx_app.cpp @@ -22,19 +22,22 @@ */ #include "ble_rx_app.hpp" - +#include "ble_rx_app.hpp" #include "ui_modemsetup.hpp" #include "modems.hpp" #include "audio.hpp" +#include "io_file.hpp" #include "rtc_time.hpp" #include "baseband_api.hpp" #include "string_format.hpp" #include "portapack_persistent_memory.hpp" +#include "ui_fileman.hpp" #include "ui_textentry.hpp" using namespace portapack; using namespace modems; +namespace fs = std::filesystem; void BLELogger::log_raw_data(const std::string& data) { log_file.write_entry(data); @@ -199,8 +202,6 @@ BleRecentEntryDetailView::BleRecentEntryDetailView(NavigationView& nav, const Bl } void BleRecentEntryDetailView::on_save_file(const std::string value, BLETxPacket packetToSave) { - std::filesystem::path packet_save_path{u"BLERX/Packets/????.TXT"}; - ensure_directory(packet_save_path); auto folder = packet_save_path.parent_path(); auto ext = packet_save_path.extension(); @@ -403,6 +404,10 @@ void BLERxView::focus() { options_channel.focus(); } +void BLERxView::file_error() { + nav_.display_modal("Error", "File read error."); +} + BLERxView::BLERxView(NavigationView& nav) : nav_{nav} { baseband::run_image(portapack::spi_flash::image_tag_btle_rx); @@ -415,9 +420,12 @@ BLERxView::BLERxView(NavigationView& nav) &options_channel, &field_frequency, &check_log, + &button_find, &check_name, &label_sort, &options_sort, + &label_found, + &text_found_count, &button_filter, &button_save_list, &button_clear_list, @@ -428,6 +436,10 @@ BLERxView::BLERxView(NavigationView& nav) nav_.push(entry); }; + ensure_directory(find_packet_path); + ensure_directory(log_packets_path); + ensure_directory(packet_save_path); + filterBuffer = filter; button_filter.on_select = [this](Button&) { @@ -440,6 +452,21 @@ BLERxView::BLERxView(NavigationView& nav) }); }; + logger = std::make_unique(); + + check_log.set_value(logging); + + check_log.on_select = [this](Checkbox&, bool v) { + str_log = ""; + logging = v; + + if (logger && logging) + logger->append( + "BLERX/Logs" + "/BLELOG_" + + to_string_timestamp(rtc_time::now()) + ".TXT"); + }; + button_save_list.on_select = [this, &nav](const ui::Button&) { listFileBuffer = ""; text_prompt( @@ -461,16 +488,6 @@ BLERxView::BLERxView(NavigationView& nav) field_frequency.set_step(0); - check_log.set_value(logging); - - check_log.on_select = [this](Checkbox&, bool v) { - str_log = ""; - logging = v; - - if (logger && logging) - logger->append(LOG_ROOT_DIR "/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT"); - }; - check_name.set_value(name_enable); check_name.on_select = [this](Checkbox&, bool v) { @@ -504,7 +521,14 @@ BLERxView::BLERxView(NavigationView& nav) options_channel.set_selected_index(channel_index, true); options_sort.set_selected_index(sort_index, true); - logger = std::make_unique(); + button_find.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); + + // nav_.set_on_pop([this]() { button_play.focus(); }); + }; + }; // Auto-configure modem for LCR RX (will be removed later) baseband::set_btlerx(channel_number); @@ -529,9 +553,6 @@ std::string BLERxView::build_line_str(BleRecentEntry entry) { } void BLERxView::on_save_file(const std::string value) { - std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"}; - - ensure_directory(packet_save_path); auto folder = packet_save_path.parent_path(); auto ext = packet_save_path.extension(); auto new_path = folder / value + ext; @@ -709,6 +730,24 @@ void BLERxView::on_data(BlePacketData* packet) { if (logger && logging) { logger->log_raw_data(str_console); } + + if (!searchList.empty()) { + auto it = searchList.begin(); + + while (it != searchList.end()) { + std::string searchStr = (std::string)*it; + + if (entry.dataString.find(searchStr) != std::string::npos) { + searchList.erase(it); + found_count++; + break; + } + + it++; + } + + text_found_count.set(to_string_dec_uint(found_count) + "/" + to_string_dec_uint(total_count)); + } } void BLERxView::on_filter_change(std::string value) { @@ -722,6 +761,48 @@ void BLERxView::on_filter_change(std::string value) { filter = value; } +void BLERxView::on_file_changed(const std::filesystem::path& new_file_path) { + file_path = fs::path(u"/") + new_file_path; + found_count = 0; + total_count = 0; + searchList.clear(); + + { // Get the size of the data file. + File data_file; + auto error = data_file.open(file_path, true, false); + if (error) { + file_error(); + file_path = ""; + return; + } + + uint64_t bytesRead = 0; + uint64_t bytePos = 0; + char currentLine[maxLineLength]; + + do { + memset(currentLine, 0, maxLineLength); + + bytesRead = readUntil(data_file, currentLine, maxLineLength, '\n'); + + // Remove return if found. + if (currentLine[strlen(currentLine)] == '\r') { + currentLine[strlen(currentLine)] = '\0'; + } + + if (!bytesRead) { + break; + } + + searchList.push_back(currentLine); + total_count++; + + bytePos += bytesRead; + + } while (bytePos <= data_file.size()); + } +} + // called each 1/60th of second, so 6 = 100ms void BLERxView::on_timer() { if (++timer_count == timer_period) { diff --git a/firmware/application/apps/ble_rx_app.hpp b/firmware/application/apps/ble_rx_app.hpp index 4416e74d..3e84b2d8 100644 --- a/firmware/application/apps/ble_rx_app.hpp +++ b/firmware/application/apps/ble_rx_app.hpp @@ -132,6 +132,7 @@ class BleRecentEntryDetailView : public View { void on_save_file(const std::string value, BLETxPacket packetToSave); bool saveFile(const std::filesystem::path& path, BLETxPacket packetToSave); std::string packetFileBuffer{}; + std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"}; static constexpr uint8_t total_data_lines{5}; @@ -195,6 +196,8 @@ class BLERxView : public View { bool saveFile(const std::filesystem::path& path); void on_data(BlePacketData* packetData); void on_filter_change(std::string value); + void on_file_changed(const std::filesystem::path& new_file_path); + void file_error(); void on_timer(); void handle_entries_sort(uint8_t index); void updateEntry(const BlePacketData* packet, BleRecentEntry& entry, ADV_PDU_TYPE pdu_type); @@ -235,7 +238,16 @@ class BLERxView : public View { std::string headerStr = "Timestamp, MAC Address, Name, Packet Type, Data, Hits, dB, Channel"; uint16_t maxLineLength = 140; - static constexpr auto header_height = 3 * 16; + std::filesystem::path file_path{}; + uint64_t found_count = 0; + uint64_t total_count = 0; + std::vector searchList{}; + + std::filesystem::path find_packet_path{u"BLERX/Find/????.TXT"}; + std::filesystem::path log_packets_path{u"BLERX/Logs/????.TXT"}; + std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"}; + + static constexpr auto header_height = 4 * 16; static constexpr auto switch_button_height = 3 * 16; OptionsField options_channel{ @@ -293,6 +305,17 @@ class BLERxView : public View { "Name", true}; + Button button_find{ + {0 * 8, 6 * 8, 4 * 8, 16}, + "Find"}; + + Labels label_found{ + {{5 * 8, 6 * 8}, "Found:", Color::light_grey()}}; + + Text text_found_count{ + {11 * 8, 3 * 16, 20 * 8, 16}, + "0/0"}; + Console console{ {0, 4 * 16, 240, 240}}; @@ -309,7 +332,6 @@ class BLERxView : public View { "Tx"}; std::string str_log{""}; - std::unique_ptr logger{}; BleRecentEntries recent{}; diff --git a/firmware/application/bitmap.hpp b/firmware/application/bitmap.hpp index 51a711ff..d700f3a9 100644 --- a/firmware/application/bitmap.hpp +++ b/firmware/application/bitmap.hpp @@ -1169,20 +1169,20 @@ static constexpr uint8_t bitmap_icon_tpms_data[] = { 0xEC, 0x37, 0x36, - 0x6C, - 0x1A, - 0x58, - 0x0B, - 0xD0, - 0x0B, - 0xD0, - 0x0B, - 0xD0, - 0x0B, - 0xD0, - 0x1A, - 0x58, - 0x36, + 0x6D, + 0x3A, + 0x59, + 0x4B, + 0xD5, + 0x8B, + 0xD3, + 0xCB, + 0xD1, + 0xAB, + 0xD2, + 0x9A, + 0x5C, + 0xB6, 0x6C, 0xEC, 0x37, @@ -5721,6 +5721,44 @@ static constexpr Bitmap bitmap_icon_hide{ {16, 16}, bitmap_icon_hide_data}; +static constexpr uint8_t bitmap_icon_thermometer_data[] = { + 0xC0, + 0x00, + 0x20, + 0x01, + 0x10, + 0x02, + 0x10, + 0x3A, + 0x10, + 0x02, + 0x10, + 0x1A, + 0x10, + 0x02, + 0xD0, + 0x3A, + 0xD0, + 0x02, + 0xD0, + 0x1A, + 0xD0, + 0x02, + 0xE8, + 0x05, + 0xE8, + 0x05, + 0xC8, + 0x04, + 0x10, + 0x02, + 0xE0, + 0x01, +}; +static constexpr Bitmap bitmap_icon_thermometer{ + {16, 16}, + bitmap_icon_thermometer_data}; + } /* namespace ui */ #endif /*__BITMAP_HPP__*/ diff --git a/firmware/application/external/blespam/ui_blespam.cpp b/firmware/application/external/blespam/ui_blespam.cpp index 49e96a9e..15679a95 100644 --- a/firmware/application/external/blespam/ui_blespam.cpp +++ b/firmware/application/external/blespam/ui_blespam.cpp @@ -104,7 +104,7 @@ BLESpamView::BLESpamView(NavigationView& nav) console.writeln("Based on work of:"); console.writeln("@Willy-JL, @ECTO-1A,"); console.writeln("@Spooks4576, @iNetro"); - + console.writeln(""); changePacket(true); // init } @@ -140,6 +140,15 @@ void BLESpamView::randomizeMac() { mac[12] = '\0'; // Null-terminate the string } +void BLESpamView::on_tx_progress(const bool done) { + if (done) { + if (is_running) { + changePacket(false); + baseband::set_btletx(channel_number, mac, advertisementData, pduType); + } + } +} + void BLESpamView::furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) { for (uint32_t i = 0; i < len; i += 4) { const uint32_t random_val = rand(); @@ -473,23 +482,38 @@ void BLESpamView::createIosPacket(bool crash = false) { } void BLESpamView::createFastPairPacket() { - uint32_t model; - model = fastpairModels[rand() % fastpairModels_count].value; + uint32_t model = fastpairModels[rand() % fastpairModels_count].value; + uint8_t size = 14; + uint8_t* packet = (uint8_t*)malloc(size); + uint8_t i = 0; + + packet[i++] = 3; // Size + packet[i++] = 0x03; // AD Type (Service UUID List) + packet[i++] = 0x2C; // Service UUID (Google LLC, FastPair) + packet[i++] = 0xFE; // ... + + packet[i++] = 6; // Size + packet[i++] = 0x16; // AD Type (Service Data) + packet[i++] = 0x2C; // Service UUID (Google LLC, FastPair) + packet[i++] = 0xFE; // ... + packet[i++] = (model >> 0x10) & 0xFF; // Device Model + packet[i++] = (model >> 0x08) & 0xFF; // ... + packet[i++] = (model >> 0x00) & 0xFF; // ... + + packet[i++] = 2; // Size + packet[i++] = 0x0A; // AD Type (Tx Power Level) + packet[i++] = (rand() % 120) - 100; // -100 to +20 dBm + + // size, packet + std::string res = to_string_hex_array(packet, size); memset(advertisementData, 0, sizeof(advertisementData)); - // 0 0 6 - const char* source = "03032CFE06162CFED5A59E020AB4\0"; - memcpy(advertisementData, source, 28); - advertisementData[16] = uint_to_char((model >> 20) & 0x0F, 16); - advertisementData[17] = uint_to_char((model >> 16) & 0x0F, 16); - advertisementData[18] = uint_to_char((model >> 12) & 0x0F, 16); - advertisementData[19] = uint_to_char((model >> 8) & 0x0F, 16); - advertisementData[20] = uint_to_char((model >> 4) & 0x0F, 16); - advertisementData[21] = uint_to_char((model >> 0) & 0x0F, 16); + std::copy(res.begin(), res.end(), advertisementData); + free(packet); } void BLESpamView::changePacket(bool forced = false) { counter++; // need to send it multiple times to be accepted - if (counter >= 3 || forced) { + if (counter >= 4 || forced) { // really change packet and mac. counter = 0; randomizeMac(); @@ -516,21 +540,15 @@ void BLESpamView::changePacket(bool forced = false) { } // rate limit console display displayCounter++; - if (displayCounter > 5) { + if (displayCounter > 25) { displayCounter = 0; console.writeln(advertisementData); } } } -// called each 1/60th of second, so 6 = 100ms -void BLESpamView::on_timer() { - if (is_running) { - changePacket(); - reset(); - } -} BLESpamView::~BLESpamView() { + is_running = false; stop(); } diff --git a/firmware/application/external/blespam/ui_blespam.hpp b/firmware/application/external/blespam/ui_blespam.hpp index dce485e1..39ec2059 100644 --- a/firmware/application/external/blespam/ui_blespam.hpp +++ b/firmware/application/external/blespam/ui_blespam.hpp @@ -145,17 +145,19 @@ class BLESpamView : public View { void createSamsungPacket(); void createWindowsPacket(); void changePacket(bool forced); - void on_timer(); + void on_tx_progress(const bool done); + uint64_t get_freq_by_channel_number(uint8_t channel_number); void randomizeMac(); void randomChn(); void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len); - MessageHandlerRegistration message_handler_frame_sync{ - Message::ID::DisplayFrameSync, - [this](const Message* const) { - this->on_timer(); + MessageHandlerRegistration message_handler_tx_progress{ + Message::ID::TXProgress, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + this->on_tx_progress(message.done); }}; // continuity diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index 6e9c1941..d555cefd 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -61,7 +61,7 @@ static constexpr SPIConfig ssp_config_max283x = { .ssport = gpio_max283x_select.port(), .sspad = gpio_max283x_select.pad(), .cr0 = - CR0_CLOCKRATE(ssp_scr(ssp1_pclk_f, ssp1_cpsr, max283x_spi_f) + 1) | CR0_FRFSPI | CR0_DSS16BIT, + CR0_CLOCKRATE(ssp_scr(ssp1_pclk_f, ssp1_cpsr, max283x_spi_f) + 3) | CR0_FRFSPI | CR0_DSS16BIT, .cpsr = ssp1_cpsr, }; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 34d33dc7..0f3515b5 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -567,7 +567,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { {"Recon", Color::green(), &bitmap_icon_scanner, [&nav]() { nav.push(); }}, {"Search", Color::yellow(), &bitmap_icon_search, [&nav]() { nav.push(); }}, {"TPMS Cars", Color::green(), &bitmap_icon_tpms, [&nav]() { nav.push(); }}, - {"Weather", Color::yellow(), &bitmap_icon_lge, [&nav]() { nav.push(); }}, + {"Weather", Color::green(), &bitmap_icon_thermometer, [&nav]() { nav.push(); }}, {"SubGhzD", Color::yellow(), &bitmap_icon_remote, [&nav]() { nav.push(); }}, // {"FSK RX", Color::yellow(), &bitmap_icon_remote, [&nav]() { nav.push(); }}, // {"DMR", Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push(); }}, diff --git a/firmware/graphics/icon_thermometer.png b/firmware/graphics/icon_thermometer.png new file mode 100644 index 00000000..9e0cb33f Binary files /dev/null and b/firmware/graphics/icon_thermometer.png differ diff --git a/firmware/graphics/icon_tpms.png b/firmware/graphics/icon_tpms.png index 93afb7a5..fa66aa4a 100644 Binary files a/firmware/graphics/icon_tpms.png and b/firmware/graphics/icon_tpms.png differ