diff --git a/firmware/application/apps/ble_tx_app.cpp b/firmware/application/apps/ble_tx_app.cpp index 11b7df0c..bad77bb9 100644 --- a/firmware/application/apps/ble_tx_app.cpp +++ b/firmware/application/apps/ble_tx_app.cpp @@ -90,15 +90,10 @@ uint32_t stringToUint32(const std::string& str) { pos++; } - // Check if there are any non-digit characters left - if (pos < str.size()) { - return 0; - } - return result; } -void readUntilSpace(File& file, char* result, std::size_t maxBufferSize) { +void readUntil(File& file, char* result, std::size_t maxBufferSize, char delimiter) { std::size_t bytesRead = 0; while (true) { @@ -106,7 +101,7 @@ void readUntilSpace(File& file, char* result, std::size_t maxBufferSize) { File::Result readResult = file.read(&ch, 1); if (readResult.is_ok() && readResult.value() > 0) { - if (ch == ' ') { + if (ch == delimiter) { // Found a space character, stop reading break; } else if (bytesRead < maxBufferSize) { @@ -125,6 +120,17 @@ void readUntilSpace(File& file, char* result, std::size_t maxBufferSize) { result[bytesRead] = '\0'; } +void generateRandomMacAddress(char* macAddress) { + const char hexDigits[] = "0123456789ABCDEF"; + + // Generate 12 random hexadecimal characters + for (int i = 0; i < 12; i++) { + int randomIndex = rand() % 16; + macAddress[i] = hexDigits[randomIndex]; + } + macAddress[12] = '\0'; // Null-terminate the string +} + static std::uint64_t get_freq_by_channel_number(uint8_t channel_number) { uint64_t freq_hz; @@ -174,6 +180,9 @@ void BLETxView::toggle() { } void BLETxView::start() { + // Generate new random Mac Address. + generateRandomMacAddress(randomMac); + if (!is_active()) { // Check if file is present before continuing. File data_file; @@ -185,16 +194,18 @@ void BLETxView::start() { return; } else { // Send first or single packet. - progressbar.set_max(packet_count); + packet_counter = packets[current_packet].packet_count; + progressbar.set_max(packets[current_packet].packet_count); button_play.set_bitmap(&bitmap_stop); - baseband::set_btletx(channel_number, macAddress, advertisementData, pduType); + + baseband::set_btletx(channel_number, random_mac ? randomMac : packets[current_packet].macAddress, packets[current_packet].advertisementData, pduType); transmitter_model.enable(); is_running = true; } } else { // Send next packet. - baseband::set_btletx(channel_number, macAddress, advertisementData, pduType); + baseband::set_btletx(channel_number, random_mac ? randomMac : packets[current_packet].macAddress, packets[current_packet].advertisementData, pduType); } if ((packet_counter % 10) == 0) { @@ -203,7 +214,7 @@ void BLETxView::start() { packet_counter--; - progressbar.set_value(packet_count - packet_counter); + progressbar.set_value(packets[current_packet].packet_count - packet_counter); } void BLETxView::stop() { @@ -211,16 +222,32 @@ void BLETxView::stop() { progressbar.set_value(0); button_play.set_bitmap(&bitmap_play); check_loop.set_value(false); - text_packets_sent.set(to_string_dec_uint(packet_count)); - packet_counter = packet_count; + + 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]); + is_running = false; } void BLETxView::on_tx_progress(const bool done) { if (done) { - if (check_loop.value() && (packet_counter != 0) && is_active()) { - if ((timer_count % timer_period) == 0) { - start(); + if (check_loop.value() && is_active()) { + // Reached end of current packet repeats. + if (packet_counter == 0) { + // Done sending all packets. + if (current_packet == (num_packets - 1)) { + stop(); + } else { + current_packet++; + packet_counter = packets[current_packet].packet_count; + update_packet_display(packets[current_packet]); + } + } else { + if ((timer_count % timer_period) == 0) { + start(); + } } } else { if (is_active()) { @@ -239,6 +266,7 @@ BLETxView::BLETxView(NavigationView& nav) add_children({&button_open, &text_filename, &progressbar, + &check_rand_mac, &field_frequency, &tx_view, // now it handles previous rfgain, rfamp. &check_loop, @@ -247,6 +275,8 @@ BLETxView::BLETxView(NavigationView& nav) &options_speed, &options_channel, &options_adv_type, + &label_packet_index, + &text_packet_index, &label_packets_sent, &text_packets_sent, &label_mac_address, @@ -275,6 +305,11 @@ BLETxView::BLETxView(NavigationView& nav) options_speed.set_selected_index(0); + check_rand_mac.set_value(false); + check_rand_mac.on_select = [this](Checkbox&, bool v) { + random_mac = v; + }; + button_open.on_select = [this, &nav](Button&) { auto open_view = nav.push(".TXT"); open_view->on_changed = [this](std::filesystem::path new_file_path) { @@ -295,40 +330,38 @@ void BLETxView::on_file_changed(const fs::path& new_file_path) { return; } - readUntilSpace(data_file, macAddress, mac_address_size_str); - readUntilSpace(data_file, advertisementData, max_packet_size_str); - readUntilSpace(data_file, packetCount, max_packet_count_str); + do { + readUntil(data_file, packets[num_packets].macAddress, mac_address_size_str, ' '); + readUntil(data_file, packets[num_packets].advertisementData, max_packet_size_str, ' '); + readUntil(data_file, packets[num_packets].packetCount, max_packet_repeat_str, '\n'); - uint64_t macAddressSize = strlen(macAddress); - uint64_t advertisementDataSize = strlen(advertisementData); - uint64_t packetCountSize = strlen(packetCount); + uint64_t macAddressSize = strlen(packets[num_packets].macAddress); + uint64_t advertisementDataSize = strlen(packets[num_packets].advertisementData); + uint64_t packetCountSize = strlen(packets[num_packets].packetCount); - packet_count = stringToUint32(packetCount); - packet_counter = packet_count; + 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_count_str) && - hasValidHexPairs(macAddress, macAddressSize / 2) && hasValidHexPairs(advertisementData, advertisementDataSize / 2) && (packet_count > 0) && (packet_count < UINT32_MAX)) { - text_packets_sent.set(to_string_dec_uint(packet_count)); + // Verify Data. + if ((macAddressSize == mac_address_size_str) && (advertisementDataSize < max_packet_size_str) && (packetCountSize < max_packet_repeat_str) && + hasValidHexPairs(packets[num_packets].macAddress, macAddressSize / 2) && hasValidHexPairs(packets[num_packets].advertisementData, advertisementDataSize / 2) && (packets[num_packets].packet_count > 0) && (packets[num_packets].packet_count < max_packet_repeat_count)) { + text_filename.set(truncate(file_path.filename().string(), 12)); - std::string formattedMacAddress = to_string_formatted_mac_address(macAddress); + } else { + // Did not find any packets. + if (num_packets == 0) { + file_path = ""; + return; + } - text_mac_address.set(formattedMacAddress); - - std::vector strings = splitIntoStrings(advertisementData); - - console.clear(true); - - for (const std::string& str : strings) { - console.writeln(str); + break; } - text_filename.set(truncate(file_path.filename().string(), 12)); - } else { - // file_error(); - file_path = ""; - return; - } + num_packets++; + + } while (num_packets < max_num_packets); + + update_packet_display(packets[0]); } } @@ -342,6 +375,24 @@ void BLETxView::on_data(uint32_t value, bool is_data) { console.write(str_console); } +void BLETxView::update_packet_display(BLETxPacket packet) { + std::string formattedMacAddress = to_string_formatted_mac_address(packet.macAddress); + + std::vector strings = splitIntoStrings(packet.advertisementData); + + text_packet_index.set(to_string_dec_uint(current_packet)); + + text_packets_sent.set(to_string_dec_uint(packet.packet_count)); + + text_mac_address.set(formattedMacAddress); + + console.clear(true); + + for (const std::string& str : strings) { + console.writeln(str); + } +} + void BLETxView::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}; diff --git a/firmware/application/apps/ble_tx_app.hpp b/firmware/application/apps/ble_tx_app.hpp index 674fbb2c..144691ba 100644 --- a/firmware/application/apps/ble_tx_app.hpp +++ b/firmware/application/apps/ble_tx_app.hpp @@ -74,10 +74,18 @@ class BLETxView : public View { std::string title() const override { return "BLE TX"; }; + struct BLETxPacket { + char macAddress[13]; + char advertisementData[63]; + char packetCount[11]; + uint32_t packet_count; + }; + 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); NavigationView& nav_; TxRadioState radio_state_{ @@ -93,16 +101,17 @@ class BLETxView : public View { std::filesystem::path file_path{}; uint8_t channel_number = 37; - char macAddress[13] = "010203040506"; - char advertisementData[63] = "00112233445566778899AABBCCDDEEFF"; - char packetCount[11] = "0"; + + char randomMac[13] = "010203040506"; bool is_running = false; uint64_t timer_count{0}; uint64_t timer_period{256}; bool repeatLoop = false; - uint32_t packet_count{0}; uint32_t packet_counter{0}; + uint32_t num_packets{0}; + uint32_t current_packet{0}; + bool random_mac = false; enum PKT_TYPE { INVALID_TYPE, @@ -136,12 +145,15 @@ class BLETxView : public View { static constexpr uint8_t mac_address_size_str{12}; static constexpr uint8_t max_packet_size_str{62}; - static constexpr uint8_t max_packet_count_str{10}; - static constexpr uint32_t max_packet_count{UINT32_MAX}; + 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}; - PKT_TYPE pduType = {RAW}; + BLETxPacket packets[max_num_packets]; - static constexpr auto header_height = 8 * 16; + PKT_TYPE pduType = {DISCOVERY}; + + static constexpr auto header_height = 9 * 16; Button button_open{ {0 * 8, 0 * 16, 10 * 8, 2 * 16}, @@ -152,7 +164,13 @@ class BLETxView : public View { "-"}; ProgressBar progressbar{ - {11 * 8, 1 * 16, 12 * 8, 16}}; + {11 * 8, 1 * 16, 9 * 8, 16}}; + + Checkbox check_rand_mac{ + {21 * 8, 1 * 16}, + 6, + "Random", + true}; TxFrequencyField field_frequency{ {0 * 8, 2 * 16}, @@ -204,25 +222,32 @@ class BLETxView : public View { {"SCAN_RSP", SCAN_RSP}, {"CONNECT_REQ", CONNECT_REQ}}}; + Labels label_packet_index{ + {{0 * 8, 10 * 8}, "Packet Index:", Color::light_grey()}}; + + Text text_packet_index{ + {13 * 8, 5 * 16, 12 * 8, 16}, + "-"}; + Labels label_packets_sent{ - {{0 * 8, 10 * 8}, "Packets Left:", Color::light_grey()}}; + {{0 * 8, 12 * 8}, "Packets Left:", Color::light_grey()}}; Text text_packets_sent{ - {13 * 8, 5 * 16, 10 * 8, 16}, + {13 * 8, 6 * 16, 12 * 8, 16}, "-"}; Labels label_mac_address{ - {{0 * 8, 12 * 8}, "Mac Address:", Color::light_grey()}}; + {{0 * 8, 14 * 8}, "Mac Address:", Color::light_grey()}}; Text text_mac_address{ - {12 * 8, 6 * 16, 20 * 8, 16}, + {12 * 8, 7 * 16, 20 * 8, 16}, "-"}; Labels label_data_packet{ - {{0 * 8, 14 * 8}, "Packet Data:", Color::light_grey()}}; + {{0 * 8, 16 * 8}, "Packet Data:", Color::light_grey()}}; Console console{ - {0, 7 * 16, 240, 240}}; + {0, 8 * 16, 240, 240}}; std::string str_log{""}; bool logging{true};