diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 197dc5bb..b61c2227 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -174,6 +174,7 @@ set(CPPSRC ui_navigation.cpp ui_numbers.cpp ui_nuoptix.cpp + ui_playdead.cpp ui_pocsag_tx.cpp ui_rds.cpp ui_receiver.cpp diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 95069669..5d3013d8 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -180,6 +180,19 @@ std::vector scan_root_files(const std::filesystem::path& return file_list; } +std::vector scan_root_directories(const std::filesystem::path& directory) { + + std::vector directory_list { }; + + for(const auto& entry : std::filesystem::directory_iterator(directory, "*")) { + if( std::filesystem::is_directory(entry.status()) ) { + directory_list.push_back(entry.path()); + } + } + + return directory_list; +} + namespace std { namespace filesystem { diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index ddeb4e65..f011252d 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -234,6 +234,7 @@ space_info space(const path& p); } /* namespace std */ std::vector scan_root_files(const std::filesystem::path& directory, const std::filesystem::path& extension); +std::vector scan_root_directories(const std::filesystem::path& directory); std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_stem_pattern); /* Values added to FatFs FRESULT enum, values outside the FRESULT data type */ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 660e56d7..aec15a9a 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -21,19 +21,16 @@ */ #include "ui_navigation.hpp" -//#include "ui_loadmodule.hpp" #include "modules.h" #include "portapack.hpp" #include "event_m0.hpp" -#include "portapack_persistent_memory.hpp" #include "bmp_splash.hpp" #include "bmp_modal_warning.hpp" #include "ui_about.hpp" #include "ui_adsbtx.hpp" -#include "ui_mictx.hpp" #include "ui_bht_tx.hpp" #include "ui_closecall.hpp" #include "ui_cw.hpp" @@ -42,9 +39,11 @@ #include "ui_freqman.hpp" #include "ui_jammer.hpp" #include "ui_lcr.hpp" +#include "ui_mictx.hpp" #include "ui_morse.hpp" #include "ui_numbers.hpp" #include "ui_nuoptix.hpp" +#include "ui_playdead.hpp" #include "ui_pocsag_tx.hpp" #include "ui_rds.hpp" #include "ui_sd_wipe.hpp" @@ -354,13 +353,14 @@ void SystemMenuView::hackrf_mode(NavigationView& nav) { } SystemMenuView::SystemMenuView(NavigationView& nav) { - add_items<12>({ { + add_items<13>({ { { "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push(); } }, { "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push(); } }, { "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push(); } }, { "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push(); } }, - { "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push(); } }, { "Audio transmitters", ui::Color::green(), &bitmap_icon_audiotx, [&nav](){ nav.push(); } }, + { "Code transmitters", ui::Color::green(), &bitmap_icon_codetx, [&nav](){ nav.push(); } }, + { "SSTV transmitter", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, { "Close Call", ui::Color::orange(),&bitmap_icon_closecall, [&nav](){ nav.push(); } }, { "Jammer", ui::Color::orange(),&bitmap_icon_jammer, [&nav](){ nav.push(); } }, { "Utilities", ui::Color::purple(),&bitmap_icon_utilities, [&nav](){ nav.push(); } }, @@ -450,60 +450,6 @@ void BMPView::paint(Painter&) { portapack::display.drawBMP({(240 - 185) / 2, 0}, splash_bmp, false); } -/* PlayDeadView **********************************************************/ - -void PlayDeadView::focus() { - button_seq_entry.focus(); -} - -void PlayDeadView::paint(Painter& painter) { - if (!(portapack::persistent_memory::ui_config() & 16)) { - // Blank the whole display - painter.fill_rectangle( - portapack::display.screen_rect(), - style().background - ); - } -} - -PlayDeadView::PlayDeadView(NavigationView& nav) { - rtc::RTC datetime; - - portapack::persistent_memory::set_playing_dead(0x5920C1DF); // Enable - - add_children({ - &text_playdead1, - &text_playdead2, - &text_playdead3, - &button_seq_entry, - }); - - // Seed from RTC - rtcGetTime(&RTCD1, &datetime); - text_playdead2.set("0x" + to_string_hex(lfsr_iterate(datetime.second()), 6) + "00"); - - text_playdead3.hidden(true); - - button_seq_entry.on_dir = [this](Button&, KeyEvent key){ - sequence = (sequence << 3) | (static_cast::type>(key) + 1); - return true; - }; - - button_seq_entry.on_select = [this, &nav](Button&){ - if (sequence == portapack::persistent_memory::playdead_sequence()) { - portapack::persistent_memory::set_playing_dead(0x82175E23); // Disable - if (!(portapack::persistent_memory::ui_config() & 16)) { - text_playdead3.hidden(false); - } else { - nav.pop(); - nav.push(); - } - } else { - sequence = 0; - } - }; -} - /* NotImplementedView ****************************************************/ NotImplementedView::NotImplementedView(NavigationView& nav) { diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index aa3a98ad..ba587bce 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -181,35 +181,6 @@ private: }; }; -class PlayDeadView : public View { -public: - PlayDeadView(NavigationView& nav); - - void focus() override; - void paint(Painter& painter) override; - -private: - uint32_t sequence = 0; - - Text text_playdead1 { - { 6 * 8, 7 * 16, 14 * 8, 16 }, - "\x46irmwa" "re " "er\x72o\x72" - }; - Text text_playdead2 { - { 6 * 8, 9 * 16, 16 * 8, 16 }, - "" - }; - Text text_playdead3 { - { 6 * 8, 12 * 16, 16 * 8, 16 }, - "Please reset" - }; - - Button button_seq_entry { - { 240, 0, 1, 1 }, - "" - }; -}; - class ReceiverMenuView : public MenuView { public: ReceiverMenuView(NavigationView& nav); diff --git a/firmware/application/ui_numbers.cpp b/firmware/application/ui_numbers.cpp index e6c9db77..f6ad29ef 100644 --- a/firmware/application/ui_numbers.cpp +++ b/firmware/application/ui_numbers.cpp @@ -21,6 +21,7 @@ */ #include "ui_numbers.hpp" +#include "string_format.hpp" #include "portapack.hpp" #include "hackrf_hal.hpp" @@ -29,17 +30,15 @@ #include #include -// TODO: Total transmission time (all durations / 44100) - using namespace portapack; namespace ui { void NumbersStationView::focus() { - button_exit.focus(); - if (file_error) - nav_.display_modal("No files", "Missing files in /numbers/", ABORT, nullptr); + nav_.display_modal("No voices", "No valid voices found in\nthe /numbers directory.", ABORT, nullptr); + else + button_exit.focus(); } NumbersStationView::~NumbersStationView() { @@ -54,7 +53,7 @@ void NumbersStationView::on_tuning_frequency_changed(rf::Frequency f) { void NumbersStationView::prepare_audio() { uint8_t code; - if (sample_counter >= sample_duration) { + /*if (sample_counter >= sample_duration) { if (segment == ANNOUNCE) { if (!announce_loop) { segment = MESSAGE; @@ -108,11 +107,11 @@ void NumbersStationView::prepare_audio() { } } - baseband::set_fifo_data(audio_buffer); + baseband::set_fifo_data(audio_buffer);*/ } void NumbersStationView::start_tx() { - sample_duration = sound_sizes[10]; // Announce + //sample_duration = sound_sizes[10]; // Announce sample_counter = sample_duration; code_index = 0; @@ -130,7 +129,7 @@ void NumbersStationView::start_tx() { baseband::set_audiotx_data( (1536000 / 44100) - 1, - number_bw.value(), + 12000, 1, false, 0 @@ -150,56 +149,99 @@ void NumbersStationView::on_tick_second() { } } +void NumbersStationView::on_voice_changed(size_t index) { + std::string flags_string = ""; + + if (voices[index].accent) { + flags_string = "^"; + } + if (voices[index].announce) { + flags_string += "A"; + } + text_voice_flags.set(flags_string); +} + NumbersStationView::NumbersStationView( NavigationView& nav ) : nav_ (nav) { - uint8_t c; + std::vector directory_list; + using option_t = std::pair; + using options_t = std::vector; + options_t voice_options; + uint32_t c, i, ia; + bool valid; //uint8_t y, m, d, dayofweek; reader = std::make_unique(); - c = 0; - for (auto& file_name : file_names) { - if (reader->open("/numbers/" + file_name + ".wav")) { - if ((reader->channels() == 1) && (reader->sample_rate() == 44100) && (reader->bits_per_sample() == 8)) { - sound_sizes[c] = reader->data_size(); - c++; + // Search for valid voice directories + directory_list = scan_root_directories("/numbers"); + if (!directory_list.size()) { + file_error = true; + return; + } + // This is awfully repetitive + for (const auto& dir : directory_list) { + i = 0; + for (const auto& file_name : file_names) { + valid = false; + if (reader->open("/numbers/" + dir.string() + "/" + file_name + ".wav")) { + // Check format (mono, 8 bits) + if ((reader->channels() == 1) && (reader->bits_per_sample() == 8)) + valid = true; } + if (!valid) { + if (i < 10) + i = 0; // Missingno, invalid voice + break; + } + i++; + } + if (i) { + // Voice ok, are there accent files ? + ia = 0; + for (const auto& file_name : file_names) { + valid = false; + if (reader->open("/numbers/" + dir.string() + "/" + file_name + "a.wav")) { + // Check format (mono, 8 bits) + if ((reader->channels() == 1) && (reader->bits_per_sample() == 8)) + valid = true; + } + if (!valid) + break; + ia++; + } + + voices.push_back({ dir.string(), (ia >= 10), (i == 11) }); } } - - if (c != 11) file_error = true; + if (!voices.size()) { + file_error = true; + return; + } baseband::run_image(portapack::spi_flash::image_tag_audio_tx); add_children({ - &text_title, - &field_frequency, - &number_bw, - &text_code, &symfield_code, &check_armed, - &button_tx_now, + &options_voices, + &text_voice_flags, + //&button_tx_now, &button_exit }); + + for (const auto& voice : voices) + voice_options.emplace_back(voice.dir.substr(0, 4), c); + + options_voices.set_options(voice_options); + options_voices.on_change = [this](size_t i, int32_t) { + this->on_voice_changed(i); + }; + options_voices.set_selected_index(0); - number_bw.set_value(75); check_armed.set_value(false); - - field_frequency.set_value(transmitter_model.tuning_frequency()); - field_frequency.set_step(50000); - field_frequency.on_change = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); - }; - field_frequency.on_edit = [this, &nav]() { - // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(transmitter_model.tuning_frequency()); - new_view->on_changed = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); - this->field_frequency.set_value(f); - }; - }; check_armed.on_select = [this](Checkbox&, bool v) { if (v) { @@ -213,6 +255,9 @@ NumbersStationView::NumbersStationView( } }; + for (c = 0; c < 25; c++) + symfield_code.set_symbol_list(c, "0123456789pPE"); + // DEBUG symfield_code.set_sym(0, 10); symfield_code.set_sym(1, 3); @@ -226,9 +271,6 @@ NumbersStationView::NumbersStationView( symfield_code.set_sym(9, 0); symfield_code.set_sym(10, 12); // End - for (c = 0; c < 25; c++) - symfield_code.set_symbol_list(c, "0123456789pPE"); - /* rtc::RTC datetime; rtcGetTime(&RTCD1, &datetime); @@ -243,10 +285,6 @@ NumbersStationView::NumbersStationView( text_title.set(day_of_week[dayofweek]); */ - button_tx_now.on_select = [this, &nav](Button&){ - this->start_tx(); - }; - button_exit.on_select = [&nav](Button&){ nav.pop(); }; diff --git a/firmware/application/ui_numbers.hpp b/firmware/application/ui_numbers.hpp index 3aacb453..306e2fc8 100644 --- a/firmware/application/ui_numbers.hpp +++ b/firmware/application/ui_numbers.hpp @@ -33,6 +33,7 @@ #include "baseband_api.hpp" #include "utility.hpp" #include "message.hpp" +#include "file.hpp" #include "io_wave.hpp" namespace ui { @@ -47,9 +48,12 @@ public: std::string title() const override { return "Numbers station"; }; private: + NavigationView& nav_; + // Sequencing state machine enum segments { - ANNOUNCE = 0, + IDLE = 0, + ANNOUNCE, MESSAGE, SIGNOFF }; @@ -60,12 +64,16 @@ private: .foreground = Color::red() }; - NavigationView& nav_; + struct voice_t { + std::string dir; + bool accent; + bool announce; + }; - segments segment; - bool armed = false; - bool file_error = false; - uint32_t sound_sizes[11]; + segments segment { IDLE }; + bool armed { false }; + bool file_error { false }; + std::vector voices; const std::vector file_names = { { "0" }, @@ -84,16 +92,17 @@ private: // const uint8_t month_table[12] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 }; // const char * day_of_week[7] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; - std::unique_ptr reader; + std::unique_ptr reader { }; uint8_t code_index, announce_loop; uint32_t sample_counter; uint32_t sample_duration; int8_t audio_buffer[1024]; uint32_t pause = 0; - bool armed_blink; - SignalToken signal_token_tick_second; + bool armed_blink { false }; + SignalToken signal_token_tick_second { }; + void on_voice_changed(size_t index); void on_tick_second(); void on_tuning_frequency_changed(rf::Frequency f); void prepare_audio(); @@ -109,28 +118,23 @@ private: // End // Frequency list and sequence - Text text_title { - { 1 * 8, 8 * 16, 11, 16 }, - "Schedule:" + Labels labels { + { { 2 * 8, 5 * 8 }, "Voice: Flags:", Color::light_grey() }, + { { 1 * 8, 8 * 8 }, "Code:", Color::light_grey() } }; - FrequencyField field_frequency { - { 1 * 8, 4 }, + OptionsField options_voices { + { 8 * 8, 1 * 8 }, + 4, + { } }; - NumberField number_bw { - { 12 * 8, 4 }, - 3, - {1, 150}, - 1, - ' ' - }; - - Text text_code { - { 20, 4 * 16, 5 * 8, 16 }, - "Code:" + Text text_voice_flags { + { 19 * 8, 1 * 8, 2 * 8, 16 }, + "" }; + SymField symfield_code { - { 20, 5 * 16 }, + { 1 * 8, 10 * 8 }, 25, SymField::SYMFIELD_DEF }; @@ -140,10 +144,10 @@ private: 5, "Armed" }; - Button button_tx_now { + /*Button button_tx_now { { 18 * 8, 13 * 16, 10 * 8, 32 }, "TX now" - }; + };*/ Button button_exit { { 21 * 8, 16 * 16, 64, 32 }, "Exit" diff --git a/firmware/application/ui_playdead.cpp b/firmware/application/ui_playdead.cpp new file mode 100644 index 00000000..36896d93 --- /dev/null +++ b/firmware/application/ui_playdead.cpp @@ -0,0 +1,81 @@ +/* + * 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_playdead.hpp" +#include "portapack_persistent_memory.hpp" +#include "string_format.hpp" + +namespace ui { + +void PlayDeadView::focus() { + button_seq_entry.focus(); +} + +void PlayDeadView::paint(Painter& painter) { + if (!(portapack::persistent_memory::ui_config() & 16)) { + // Blank the whole display + painter.fill_rectangle( + portapack::display.screen_rect(), + style().background + ); + } +} + +PlayDeadView::PlayDeadView(NavigationView& nav) { + rtc::RTC datetime; + + portapack::persistent_memory::set_playing_dead(0x5920C1DF); // Enable + + add_children({ + &text_playdead1, + &text_playdead2, + &text_playdead3, + &button_seq_entry, + }); + + // Seed from RTC + rtcGetTime(&RTCD1, &datetime); + text_playdead2.set("0x" + to_string_hex(lfsr_iterate(datetime.second()), 6) + "00"); + + text_playdead3.hidden(true); + + button_seq_entry.on_dir = [this](Button&, KeyEvent key){ + sequence = (sequence << 3) | (static_cast::type>(key) + 1); + return true; + }; + + button_seq_entry.on_select = [this, &nav](Button&){ + if (sequence == portapack::persistent_memory::playdead_sequence()) { + portapack::persistent_memory::set_playing_dead(0x82175E23); // Disable + if (!(portapack::persistent_memory::ui_config() & 16)) { + text_playdead3.hidden(false); + } else { + nav.pop(); + nav.push(); + } + } else { + sequence = 0; + } + }; +} + +} /* namespace ui */ diff --git a/firmware/application/ui_playdead.hpp b/firmware/application/ui_playdead.hpp new file mode 100644 index 00000000..2169dbe6 --- /dev/null +++ b/firmware/application/ui_playdead.hpp @@ -0,0 +1,62 @@ +/* + * 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 __UI_PLAYDEAD_H__ +#define __UI_PLAYDEAD_H__ + +#include "ui.hpp" +#include "ui_navigation.hpp" + +namespace ui { + +class PlayDeadView : public View { +public: + PlayDeadView(NavigationView& nav); + + void focus() override; + void paint(Painter& painter) override; + +private: + uint32_t sequence = 0; + + Text text_playdead1 { + { 6 * 8, 7 * 16, 14 * 8, 16 }, + "\x46irmwa" "re " "er\x72o\x72" + }; + Text text_playdead2 { + { 6 * 8, 9 * 16, 16 * 8, 16 }, + "" + }; + Text text_playdead3 { + { 6 * 8, 12 * 16, 16 * 8, 16 }, + "Please reset" + }; + + Button button_seq_entry { + { 240, 0, 1, 1 }, + "" + }; +}; + +} /* namespace ui */ + +#endif/*__UI_PLAYDEAD_H__*/ diff --git a/firmware/baseband/proc_tones.cpp b/firmware/baseband/proc_tones.cpp index 375291ac..27aa1921 100644 --- a/firmware/baseband/proc_tones.cpp +++ b/firmware/baseband/proc_tones.cpp @@ -130,7 +130,7 @@ void TonesProcessor::on_message(const Message* const p) { tone_deltas[c] = shared_memory.bb_data.tones_data.tone_defs[c].delta; tone_durations[c] = shared_memory.bb_data.tones_data.tone_defs[c].duration; } - fm_delta = message.fm_delta * (0xFFFFFFFFULL / 1536000) * 2; + fm_delta = message.fm_delta * (0xFFFFFFULL / 1536000); audio_out = message.audio_out; dual_tone = message.dual_tone; diff --git a/firmware/common/bmp.hpp b/firmware/common/bmp.hpp new file mode 100644 index 00000000..8081ee26 --- /dev/null +++ b/firmware/common/bmp.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 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. + */ + +#pragma pack(push, 1) +struct bmp_header_t { + uint16_t signature; + uint32_t size; + uint16_t reserved_1; + uint16_t reserved_2; + uint32_t image_data; + uint32_t BIH_size; + uint32_t width; + uint32_t height; + uint16_t planes; + uint16_t bpp; + uint32_t compression; + uint32_t data_size; + uint32_t h_res; + uint32_t v_res; + uint32_t colors_count; + uint32_t icolors_count; +}; +#pragma pack(pop) + +#pragma pack(push, 1) +struct bmp_palette_t { + struct color_t { + uint8_t B; + uint8_t G; + uint8_t R; + uint8_t A; + } color[16]; +}; +#pragma pack(pop) diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index fe273264..07efcdbf 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -20,6 +21,7 @@ */ #include "lcd_ili9341.hpp" +#include "bmp.hpp" #include "portapack_io.hpp" using namespace portapack; diff --git a/firmware/common/lcd_ili9341.hpp b/firmware/common/lcd_ili9341.hpp index 06f0dac3..99153640 100644 --- a/firmware/common/lcd_ili9341.hpp +++ b/firmware/common/lcd_ili9341.hpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * @@ -110,38 +111,6 @@ private: uint16_t current_position; }; - #pragma pack(push, 1) - struct bmp_header_t { - uint16_t signature; - uint32_t size; - uint16_t reserved_1; - uint16_t reserved_2; - uint32_t image_data; - uint32_t BIH_size; - uint32_t width; - uint32_t height; - uint16_t planes; - uint16_t bpp; - uint32_t compression; - uint32_t data_size; - uint32_t h_res; - uint32_t v_res; - uint32_t colors_count; - uint32_t icolors_count; - }; - #pragma pack(pop) - - #pragma pack(push, 1) - struct bmp_palette_t { - struct color_t { - uint8_t B; - uint8_t G; - uint8_t R; - uint8_t A; - } color[16]; - }; - #pragma pack(pop) - scroll_t scroll_state; void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count); diff --git a/firmware/hackrf_one_usb.dfu b/firmware/hackrf_one_usb.dfu new file mode 100644 index 00000000..49e0eee1 Binary files /dev/null and b/firmware/hackrf_one_usb.dfu differ diff --git a/sdcard/NUMBERS/UA2/0.wav b/sdcard/NUMBERS/UA/0a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/0.wav rename to sdcard/NUMBERS/UA/0a.wav diff --git a/sdcard/NUMBERS/UA2/1.wav b/sdcard/NUMBERS/UA/1a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/1.wav rename to sdcard/NUMBERS/UA/1a.wav diff --git a/sdcard/NUMBERS/UA2/2.wav b/sdcard/NUMBERS/UA/2a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/2.wav rename to sdcard/NUMBERS/UA/2a.wav diff --git a/sdcard/NUMBERS/UA2/3.wav b/sdcard/NUMBERS/UA/3a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/3.wav rename to sdcard/NUMBERS/UA/3a.wav diff --git a/sdcard/NUMBERS/UA2/4.wav b/sdcard/NUMBERS/UA/4a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/4.wav rename to sdcard/NUMBERS/UA/4a.wav diff --git a/sdcard/NUMBERS/UA2/5.wav b/sdcard/NUMBERS/UA/5a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/5.wav rename to sdcard/NUMBERS/UA/5a.wav diff --git a/sdcard/NUMBERS/UA2/6.wav b/sdcard/NUMBERS/UA/6a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/6.wav rename to sdcard/NUMBERS/UA/6a.wav diff --git a/sdcard/NUMBERS/UA2/7.wav b/sdcard/NUMBERS/UA/7a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/7.wav rename to sdcard/NUMBERS/UA/7a.wav diff --git a/sdcard/NUMBERS/UA2/8.wav b/sdcard/NUMBERS/UA/8a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/8.wav rename to sdcard/NUMBERS/UA/8a.wav diff --git a/sdcard/NUMBERS/UA2/9.wav b/sdcard/NUMBERS/UA/9a.wav similarity index 100% rename from sdcard/NUMBERS/UA2/9.wav rename to sdcard/NUMBERS/UA/9a.wav