From 58f113d15315a2bb99cbd58f8525f41948a7d858 Mon Sep 17 00:00:00 2001 From: furrtek Date: Tue, 18 Jul 2017 19:31:05 +0100 Subject: [PATCH] "CW generator" and "Whistle" merged in "Signal generator" Added wave shape selection and tone frequency auto-update Converted color icons to B&W --- firmware/application/CMakeLists.txt | 3 +- firmware/application/baseband_api.cpp | 15 + firmware/application/baseband_api.hpp | 2 + firmware/application/bitmap.hpp | 356 ++++++++++++++++++ .../application/bitmaps/bmp_bulb_ignore.hpp | 47 --- firmware/application/bitmaps/bmp_bulb_off.hpp | 43 --- firmware/application/bitmaps/bmp_bulb_on.hpp | 46 --- firmware/application/ui_about.hpp | 5 +- firmware/application/ui_bht_tx.hpp | 11 +- firmware/application/ui_cw.cpp | 84 ----- firmware/application/ui_cw.hpp | 58 --- firmware/application/ui_navigation.cpp | 12 +- .../{ui_whistle.cpp => ui_siggen.cpp} | 92 +++-- .../{ui_whistle.hpp => ui_siggen.hpp} | 84 +++-- firmware/application/ui_transmitter.hpp | 2 +- firmware/baseband/CMakeLists.txt | 7 + firmware/baseband/proc_capture.cpp | 4 +- firmware/baseband/proc_jammer.cpp | 6 +- firmware/baseband/proc_siggen.cpp | 124 ++++++ firmware/baseband/proc_siggen.hpp | 52 +++ firmware/common/message.hpp | 32 ++ firmware/common/spi_image.hpp | 1 + firmware/common/ui_widget.cpp | 32 +- firmware/common/ui_widget.hpp | 14 +- firmware/graphics/bulb_ignore.bmp | Bin 522 -> 0 bytes firmware/graphics/bulb_ignore.png | Bin 0 -> 186 bytes firmware/graphics/bulb_off.bmp | Bin 478 -> 0 bytes firmware/graphics/bulb_off.png | Bin 0 -> 178 bytes firmware/graphics/bulb_on.bmp | Bin 510 -> 0 bytes firmware/graphics/bulb_on.png | Bin 0 -> 206 bytes firmware/graphics/sig_cw.png | Bin 0 -> 107 bytes firmware/graphics/sig_noise.png | Bin 0 -> 194 bytes firmware/graphics/sig_saw_down.png | Bin 0 -> 205 bytes firmware/graphics/sig_saw_up.png | Bin 0 -> 197 bytes firmware/graphics/sig_sine.png | Bin 0 -> 171 bytes firmware/graphics/sig_square.png | Bin 0 -> 125 bytes firmware/graphics/sig_tri.png | Bin 0 -> 164 bytes sdcard/ADSB/airlines.db | Bin 0 -> 28928 bytes 38 files changed, 758 insertions(+), 374 deletions(-) delete mode 100644 firmware/application/bitmaps/bmp_bulb_ignore.hpp delete mode 100644 firmware/application/bitmaps/bmp_bulb_off.hpp delete mode 100644 firmware/application/bitmaps/bmp_bulb_on.hpp delete mode 100644 firmware/application/ui_cw.cpp delete mode 100644 firmware/application/ui_cw.hpp rename firmware/application/{ui_whistle.cpp => ui_siggen.cpp} (57%) rename firmware/application/{ui_whistle.hpp => ui_siggen.hpp} (55%) create mode 100644 firmware/baseband/proc_siggen.cpp create mode 100644 firmware/baseband/proc_siggen.hpp delete mode 100644 firmware/graphics/bulb_ignore.bmp create mode 100644 firmware/graphics/bulb_ignore.png delete mode 100644 firmware/graphics/bulb_off.bmp create mode 100644 firmware/graphics/bulb_off.png delete mode 100644 firmware/graphics/bulb_on.bmp create mode 100644 firmware/graphics/bulb_on.png create mode 100644 firmware/graphics/sig_cw.png create mode 100644 firmware/graphics/sig_noise.png create mode 100644 firmware/graphics/sig_saw_down.png create mode 100644 firmware/graphics/sig_saw_up.png create mode 100644 firmware/graphics/sig_sine.png create mode 100644 firmware/graphics/sig_square.png create mode 100644 firmware/graphics/sig_tri.png create mode 100644 sdcard/ADSB/airlines.db diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index ca340f64f..632cce8f5 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -172,7 +172,7 @@ set(CPPSRC ui_channel.cpp ui_scanner.cpp ui_coasterp.cpp - ui_cw.cpp + ui_siggen.cpp ui_debug.cpp ui_encoders.cpp ui_font_fixed_8x16.cpp @@ -204,7 +204,6 @@ set(CPPSRC ui_touch_calibration.cpp ui_transmitter.cpp ui_whipcalc.cpp - ui_whistle.cpp # ui_loadmodule.cpp recent_entries.cpp receiver_model.cpp diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index f35255f83..6e8e2de63 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -23,6 +23,7 @@ #include "baseband_api.hpp" #include "audio.hpp" +#include "tonesets.hpp" #include "dsp_iir_config.hpp" #include "portapack_shared_memory.hpp" @@ -228,6 +229,20 @@ void set_spectrum(const size_t sampling_rate, const size_t trigger) { send_message(&message); } +void set_siggen_tone(const uint32_t tone) { + const SigGenToneMessage message { + TONES_F2D(tone) + }; + send_message(&message); +} + +void set_siggen_config(const uint32_t bw, const uint32_t shape, const uint32_t duration) { + const SigGenConfigMessage message { + bw, shape, duration * TONES_SAMPLERATE + }; + send_message(&message); +} + static bool baseband_image_running = false; void run_image(const portapack::spi_flash::image_tag_t image_tag) { diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 39fb3ee53..5bd2cfc4d 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -76,6 +76,8 @@ void set_adsb(); void set_jammer(const bool run, const jammer::JammerType type, const uint32_t speed); void set_rds_data(const uint16_t message_length); void set_spectrum(const size_t sampling_rate, const size_t trigger); +void set_siggen_tone(const uint32_t tone); +void set_siggen_config(const uint32_t bw, const uint32_t shape, const uint32_t duration); void request_beep(); void run_image(const portapack::spi_flash::image_tag_t image_tag); diff --git a/firmware/application/bitmap.hpp b/firmware/application/bitmap.hpp index 67c0c6ef0..01b480658 100644 --- a/firmware/application/bitmap.hpp +++ b/firmware/application/bitmap.hpp @@ -241,6 +241,44 @@ static constexpr Bitmap bitmap_icon_sleep { { 16, 16 }, bitmap_icon_sleep_data }; +static constexpr uint8_t bitmap_sig_cw_data[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0x7F, + 0xFE, 0xFF, 0xFF, 0x7F, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +static constexpr Bitmap bitmap_sig_cw { + { 32, 32 }, bitmap_sig_cw_data +}; + static constexpr uint8_t bitmap_icon_speaker_data[] = { 0x00, 0x00, 0x00, 0x20, @@ -351,6 +389,44 @@ static constexpr Bitmap bitmap_icon_ais { { 16, 16 }, bitmap_icon_ais_data }; +static constexpr uint8_t bitmap_sig_square_data[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xFE, 0x83, 0xFF, 0x60, + 0xFE, 0x83, 0xFF, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0x83, 0xC1, 0x60, + 0x06, 0xFF, 0xC1, 0x7F, + 0x06, 0xFF, 0xC1, 0x7F, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +static constexpr Bitmap bitmap_sig_square { + { 32, 32 }, bitmap_sig_square_data +}; + static constexpr uint8_t bitmap_icon_nuoptix_data[] = { 0x80, 0x01, 0x80, 0x01, @@ -629,6 +705,44 @@ static constexpr Bitmap bitmap_icon_setup { { 16, 16 }, bitmap_icon_setup_data }; +static constexpr uint8_t bitmap_sig_saw_down_data[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x80, 0x00, 0x60, + 0x1E, 0x80, 0x01, 0x60, + 0x3E, 0x80, 0x03, 0x60, + 0x76, 0x80, 0x07, 0x60, + 0xE6, 0x80, 0x0F, 0x60, + 0xC6, 0x81, 0x1D, 0x60, + 0x86, 0x83, 0x39, 0x60, + 0x06, 0x87, 0x71, 0x60, + 0x06, 0x8E, 0xE1, 0x60, + 0x06, 0x9C, 0xC1, 0x61, + 0x06, 0xB8, 0x81, 0x63, + 0x06, 0xF0, 0x01, 0x67, + 0x06, 0xE0, 0x01, 0x6E, + 0x06, 0xC0, 0x01, 0x7C, + 0x06, 0x80, 0x01, 0x78, + 0x06, 0x00, 0x01, 0x70, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +static constexpr Bitmap bitmap_sig_saw_down { + { 32, 32 }, bitmap_sig_saw_down_data +}; + static constexpr uint8_t bitmap_icon_rds_data[] = { 0x00, 0x00, 0x00, 0x00, @@ -717,6 +831,36 @@ static constexpr Bitmap bitmap_icon_cwgen { { 16, 16 }, bitmap_icon_cwgen_data }; +static constexpr uint8_t bitmap_bulb_on_data[] = { + 0x04, 0x3C, 0x20, + 0x08, 0xFF, 0x10, + 0x90, 0xFF, 0x09, + 0xC0, 0xFF, 0x03, + 0xE0, 0xFF, 0x07, + 0xE0, 0xFF, 0x07, + 0xF0, 0xE7, 0x0F, + 0xF0, 0xBD, 0x0F, + 0xF7, 0xBD, 0xEF, + 0xF0, 0xDB, 0x0F, + 0xF0, 0xDB, 0x0F, + 0xE0, 0xDB, 0x07, + 0xE0, 0xCB, 0x07, + 0xC0, 0xD3, 0x03, + 0x90, 0xCB, 0x09, + 0x08, 0xFD, 0x10, + 0x04, 0xE3, 0x20, + 0x00, 0xBD, 0x00, + 0x00, 0xC3, 0x00, + 0x00, 0xBD, 0x00, + 0x00, 0xC3, 0x00, + 0x00, 0xBD, 0x00, + 0x00, 0x42, 0x00, + 0x00, 0x3C, 0x00, +}; +static constexpr Bitmap bitmap_bulb_on { + { 24, 24 }, bitmap_bulb_on_data +}; + static constexpr uint8_t bitmap_icon_receivers_data[] = { 0xC0, 0x07, 0x30, 0x18, @@ -783,6 +927,44 @@ static constexpr Bitmap bitmap_stop { { 16, 16 }, bitmap_stop_data }; +static constexpr uint8_t bitmap_sig_saw_up_data[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x01, 0x70, + 0x06, 0x80, 0x01, 0x78, + 0x06, 0xC0, 0x01, 0x7C, + 0x06, 0xE0, 0x01, 0x6E, + 0x06, 0xF0, 0x01, 0x67, + 0x06, 0xB8, 0x81, 0x63, + 0x06, 0x9C, 0xC1, 0x61, + 0x06, 0x8E, 0xE1, 0x60, + 0x06, 0x87, 0x71, 0x60, + 0x86, 0x83, 0x39, 0x60, + 0xC6, 0x81, 0x1D, 0x60, + 0xE6, 0x80, 0x0F, 0x60, + 0x76, 0x80, 0x07, 0x60, + 0x3E, 0x80, 0x03, 0x60, + 0x1E, 0x80, 0x01, 0x60, + 0x0E, 0x80, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +static constexpr Bitmap bitmap_sig_saw_up { + { 32, 32 }, bitmap_sig_saw_up_data +}; + static constexpr uint8_t bitmap_rssipwm_data[] = { 0x00, 0x00, 0x00, 0x8F, 0xE7, 0x7D, @@ -865,6 +1047,36 @@ static constexpr Bitmap bitmap_icon_tpms { { 16, 16 }, bitmap_icon_tpms_data }; +static constexpr uint8_t bitmap_bulb_ignore_data[] = { + 0x00, 0x3C, 0x00, + 0x00, 0xC3, 0x00, + 0x80, 0x00, 0x01, + 0x40, 0x3C, 0x02, + 0x20, 0x7E, 0x04, + 0x20, 0xE7, 0x04, + 0x10, 0xC3, 0x08, + 0x10, 0xE3, 0x08, + 0x10, 0x70, 0x08, + 0x10, 0x38, 0x08, + 0x10, 0x18, 0x08, + 0x20, 0x18, 0x04, + 0x20, 0x00, 0x04, + 0x40, 0x18, 0x02, + 0x80, 0x18, 0x01, + 0x00, 0xC3, 0x00, + 0x00, 0xFF, 0x00, + 0x00, 0xBD, 0x00, + 0x00, 0xC3, 0x00, + 0x00, 0xBD, 0x00, + 0x00, 0xC3, 0x00, + 0x00, 0xBD, 0x00, + 0x00, 0x42, 0x00, + 0x00, 0x3C, 0x00, +}; +static constexpr Bitmap bitmap_bulb_ignore { + { 24, 24 }, bitmap_bulb_ignore_data +}; + static constexpr uint8_t bitmap_icon_hackrf_data[] = { 0x80, 0x00, 0xC0, 0x01, @@ -1063,6 +1275,82 @@ static constexpr Bitmap bitmap_icon_replay { { 16, 16 }, bitmap_icon_replay_data }; +static constexpr uint8_t bitmap_sig_sine_data[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xC0, 0x00, + 0x80, 0x07, 0xE0, 0x01, + 0xC0, 0x0F, 0xF0, 0x03, + 0xC0, 0x0C, 0x30, 0x03, + 0x60, 0x18, 0x18, 0x06, + 0x60, 0x18, 0x18, 0x06, + 0x60, 0x18, 0x18, 0x06, + 0x60, 0x18, 0x18, 0x06, + 0x30, 0x30, 0x0C, 0x0C, + 0x30, 0x30, 0x0C, 0x0C, + 0x30, 0x30, 0x0C, 0x0C, + 0x30, 0x30, 0x0C, 0x0C, + 0x18, 0x60, 0x06, 0x18, + 0x1E, 0xE0, 0x07, 0x78, + 0x0E, 0xC0, 0x03, 0x70, + 0x06, 0x80, 0x01, 0x60, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +static constexpr Bitmap bitmap_sig_sine { + { 32, 32 }, bitmap_sig_sine_data +}; + +static constexpr uint8_t bitmap_sig_noise_data[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, + 0x00, 0x30, 0x80, 0x00, + 0x00, 0x30, 0x80, 0x01, + 0x40, 0x30, 0xC0, 0x03, + 0xC0, 0x30, 0xC0, 0x03, + 0xC0, 0x39, 0xC0, 0x72, + 0xC0, 0x7B, 0x60, 0x76, + 0x60, 0x6E, 0x60, 0x1E, + 0x60, 0xCE, 0x6C, 0x0C, + 0x66, 0xC4, 0x6E, 0x0C, + 0x66, 0xC0, 0x3E, 0x00, + 0x2C, 0xC0, 0x3B, 0x00, + 0x3C, 0xC0, 0x39, 0x00, + 0x3C, 0xC0, 0x18, 0x00, + 0x18, 0x40, 0x10, 0x00, + 0x18, 0x40, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +static constexpr Bitmap bitmap_sig_noise { + { 32, 32 }, bitmap_sig_noise_data +}; + static constexpr uint8_t bitmap_icon_aprs_data[] = { 0x00, 0x00, 0x00, 0x00, @@ -1085,6 +1373,44 @@ static constexpr Bitmap bitmap_icon_aprs { { 16, 16 }, bitmap_icon_aprs_data }; +static constexpr uint8_t bitmap_sig_tri_data[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xC0, 0x00, + 0x00, 0x03, 0xC0, 0x00, + 0x80, 0x07, 0xE0, 0x01, + 0x80, 0x07, 0xE0, 0x01, + 0xC0, 0x0C, 0x30, 0x03, + 0xC0, 0x0C, 0x30, 0x03, + 0x60, 0x18, 0x18, 0x06, + 0x60, 0x18, 0x18, 0x06, + 0x30, 0x30, 0x0C, 0x0C, + 0x30, 0x30, 0x0C, 0x0C, + 0x18, 0x60, 0x06, 0x18, + 0x18, 0x60, 0x06, 0x18, + 0x0E, 0xC0, 0x03, 0x70, + 0x0E, 0xC0, 0x03, 0x70, + 0x06, 0x80, 0x01, 0x60, + 0x06, 0x80, 0x01, 0x60, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +static constexpr Bitmap bitmap_sig_tri { + { 32, 32 }, bitmap_sig_tri_data +}; + static constexpr uint8_t bitmap_icon_soundboard_data[] = { 0x00, 0x00, 0xFF, 0xFF, @@ -1233,6 +1559,36 @@ static constexpr Bitmap bitmap_icon_jammer { { 16, 16 }, bitmap_icon_jammer_data }; +static constexpr uint8_t bitmap_bulb_off_data[] = { + 0x00, 0x3C, 0x00, + 0x00, 0xC3, 0x00, + 0x80, 0x00, 0x01, + 0x40, 0x00, 0x02, + 0x20, 0x00, 0x04, + 0x20, 0x00, 0x04, + 0x10, 0x00, 0x08, + 0x10, 0x42, 0x08, + 0x10, 0x42, 0x08, + 0x10, 0x24, 0x08, + 0x10, 0x24, 0x08, + 0x20, 0x24, 0x04, + 0x20, 0x2C, 0x04, + 0x40, 0x34, 0x02, + 0x80, 0x3C, 0x01, + 0x00, 0xFF, 0x00, + 0x00, 0xE3, 0x00, + 0x00, 0xBD, 0x00, + 0x00, 0xC3, 0x00, + 0x00, 0xBD, 0x00, + 0x00, 0xC3, 0x00, + 0x00, 0xBD, 0x00, + 0x00, 0x42, 0x00, + 0x00, 0x3C, 0x00, +}; +static constexpr Bitmap bitmap_bulb_off { + { 24, 24 }, bitmap_bulb_off_data +}; + } /* namespace ui */ diff --git a/firmware/application/bitmaps/bmp_bulb_ignore.hpp b/firmware/application/bitmaps/bmp_bulb_ignore.hpp deleted file mode 100644 index 35ac9ce78..000000000 --- a/firmware/application/bitmaps/bmp_bulb_ignore.hpp +++ /dev/null @@ -1,47 +0,0 @@ -const unsigned char bulb_ignore_bmp[] = { - 0x42, 0x4d, 0xc6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, - 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x70, 0x01, - 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x08, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x19, 0x19, 0x19, 0x00, 0x29, 0x2e, 0x21, 0x00, 0x1b, 0x1b, - 0x66, 0x00, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x55, 0x55, - 0x55, 0x00, 0x6c, 0x6c, 0x6c, 0x00, 0x95, 0x95, 0x95, 0x00, 0x0a, 0x44, - 0x02, 0x77, 0x02, 0x77, 0x0a, 0x44, 0x00, 0x00, 0x00, 0x18, 0x42, 0x24, - 0x44, 0x44, 0x47, 0x30, 0x03, 0x74, 0x44, 0x44, 0x42, 0x24, 0x00, 0x00, - 0x00, 0x18, 0x42, 0x22, 0x44, 0x44, 0x73, 0x66, 0x55, 0x37, 0x44, 0x44, - 0x22, 0x24, 0x00, 0x00, 0x00, 0x18, 0x44, 0x22, 0x24, 0x44, 0x76, 0x33, - 0x33, 0x57, 0x44, 0x42, 0x22, 0x44, 0x00, 0x00, 0x00, 0x18, 0x44, 0x42, - 0x22, 0x44, 0x73, 0x66, 0x55, 0x37, 0x44, 0x22, 0x24, 0x44, 0x00, 0x00, - 0x00, 0x18, 0x44, 0x44, 0x22, 0x24, 0x76, 0x33, 0x33, 0x57, 0x42, 0x22, - 0x44, 0x44, 0x00, 0x00, 0x00, 0x18, 0x44, 0x44, 0x42, 0x22, 0x73, 0x66, - 0x55, 0x37, 0x22, 0x24, 0x44, 0x44, 0x00, 0x00, 0x06, 0x44, 0x00, 0x0c, - 0x22, 0x26, 0x53, 0x35, 0x52, 0x22, 0x06, 0x44, 0x00, 0x00, 0x06, 0x44, - 0x00, 0x0c, 0x42, 0x22, 0x31, 0x13, 0x22, 0x24, 0x06, 0x44, 0x00, 0x00, - 0x06, 0x44, 0x00, 0x0c, 0x47, 0x22, 0x21, 0x12, 0x22, 0x74, 0x06, 0x44, - 0x00, 0x00, 0x06, 0x44, 0x00, 0x0c, 0x74, 0x42, 0x22, 0x22, 0x24, 0x47, - 0x06, 0x44, 0x00, 0x00, 0x00, 0x18, 0x44, 0x44, 0x47, 0x44, 0x44, 0x22, - 0x22, 0x44, 0x44, 0x74, 0x44, 0x44, 0x00, 0x00, 0x00, 0x18, 0x44, 0x44, - 0x47, 0x44, 0x64, 0x22, 0x22, 0x44, 0x44, 0x74, 0x44, 0x44, 0x00, 0x00, - 0x00, 0x18, 0x44, 0x44, 0x74, 0x44, 0x62, 0x22, 0x22, 0x24, 0x44, 0x47, - 0x44, 0x44, 0x00, 0x00, 0x00, 0x18, 0x44, 0x44, 0x74, 0x46, 0x22, 0x24, - 0x42, 0x22, 0x44, 0x47, 0x44, 0x44, 0x00, 0x00, 0x00, 0x18, 0x44, 0x44, - 0x74, 0x42, 0x22, 0x44, 0x44, 0x22, 0x24, 0x47, 0x44, 0x44, 0x00, 0x00, - 0x00, 0x18, 0x44, 0x44, 0x74, 0x22, 0x23, 0x44, 0x44, 0x32, 0x22, 0x47, - 0x44, 0x44, 0x00, 0x00, 0x00, 0x18, 0x44, 0x44, 0x72, 0x22, 0x60, 0x44, - 0x44, 0x00, 0x22, 0x27, 0x44, 0x44, 0x00, 0x00, 0x00, 0x18, 0x44, 0x44, - 0x22, 0x24, 0x66, 0x00, 0x00, 0x44, 0x42, 0x22, 0x44, 0x44, 0x00, 0x00, - 0x00, 0x0a, 0x44, 0x42, 0x22, 0x44, 0x46, 0x00, 0x08, 0x44, 0x00, 0x06, - 0x22, 0x24, 0x44, 0x00, 0x00, 0x00, 0x00, 0x08, 0x44, 0x22, 0x24, 0x74, - 0x08, 0x44, 0x00, 0x08, 0x47, 0x42, 0x22, 0x44, 0x00, 0x00, 0x00, 0x08, - 0x42, 0x22, 0x44, 0x47, 0x08, 0x44, 0x00, 0x08, 0x74, 0x44, 0x22, 0x24, - 0x00, 0x00, 0x00, 0x18, 0x42, 0x24, 0x44, 0x44, 0x74, 0x44, 0x44, 0x47, - 0x44, 0x44, 0x42, 0x24, 0x00, 0x00, 0x08, 0x44, 0x00, 0x08, 0x47, 0x77, - 0x77, 0x74, 0x08, 0x44, 0x00, 0x01 -}; -const unsigned int bulb_ignore_bmp_len = 522; diff --git a/firmware/application/bitmaps/bmp_bulb_off.hpp b/firmware/application/bitmaps/bmp_bulb_off.hpp deleted file mode 100644 index 679f8a583..000000000 --- a/firmware/application/bitmaps/bmp_bulb_off.hpp +++ /dev/null @@ -1,43 +0,0 @@ -const unsigned char bulb_off_bmp[] = { - 0x42, 0x4d, 0x9a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, - 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x01, - 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x07, 0x00, - 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x39, 0x39, 0x39, 0x00, 0xff, 0x00, 0xff, 0x00, 0x55, 0x5f, - 0x45, 0x00, 0x5b, 0x5b, 0x5b, 0x00, 0x7d, 0x7d, 0x7d, 0x00, 0x9d, 0x9d, - 0x9d, 0x00, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x11, 0x02, 0x66, 0x02, 0x66, - 0x0a, 0x11, 0x00, 0x00, 0x08, 0x11, 0x00, 0x08, 0x16, 0x30, 0x03, 0x61, - 0x08, 0x11, 0x00, 0x00, 0x08, 0x11, 0x00, 0x08, 0x63, 0x55, 0x44, 0x36, - 0x08, 0x11, 0x00, 0x00, 0x08, 0x11, 0x00, 0x08, 0x65, 0x33, 0x33, 0x46, - 0x08, 0x11, 0x00, 0x00, 0x08, 0x11, 0x00, 0x08, 0x63, 0x55, 0x44, 0x36, - 0x08, 0x11, 0x00, 0x00, 0x08, 0x11, 0x00, 0x08, 0x65, 0x33, 0x33, 0x46, - 0x08, 0x11, 0x00, 0x00, 0x08, 0x11, 0x00, 0x08, 0x63, 0x55, 0x44, 0x36, - 0x08, 0x11, 0x00, 0x00, 0x08, 0x11, 0x00, 0x08, 0x65, 0x43, 0x34, 0x46, - 0x08, 0x11, 0x00, 0x00, 0x08, 0x11, 0x00, 0x08, 0x63, 0x32, 0x23, 0x36, - 0x08, 0x11, 0x00, 0x00, 0x06, 0x11, 0x00, 0x0c, 0x16, 0x11, 0x22, 0x22, - 0x11, 0x61, 0x06, 0x11, 0x00, 0x00, 0x06, 0x11, 0x00, 0x0c, 0x61, 0x11, - 0x24, 0x22, 0x11, 0x16, 0x06, 0x11, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, - 0x16, 0x11, 0x11, 0x24, 0x22, 0x11, 0x11, 0x61, 0x11, 0x11, 0x00, 0x00, - 0x00, 0x18, 0x11, 0x11, 0x16, 0x11, 0x51, 0x34, 0x43, 0x11, 0x11, 0x61, - 0x11, 0x11, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, 0x61, 0x11, 0x51, 0x31, - 0x13, 0x11, 0x11, 0x16, 0x11, 0x11, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, - 0x61, 0x15, 0x51, 0x31, 0x13, 0x11, 0x11, 0x16, 0x11, 0x11, 0x00, 0x00, - 0x00, 0x18, 0x11, 0x11, 0x61, 0x15, 0x53, 0x11, 0x11, 0x31, 0x11, 0x16, - 0x11, 0x11, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, 0x61, 0x15, 0x53, 0x11, - 0x11, 0x31, 0x11, 0x16, 0x11, 0x11, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, - 0x61, 0x11, 0x50, 0x11, 0x11, 0x00, 0x11, 0x16, 0x11, 0x11, 0x00, 0x00, - 0x00, 0x18, 0x11, 0x11, 0x16, 0x11, 0x55, 0x00, 0x00, 0x11, 0x11, 0x61, - 0x11, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x11, 0x11, 0x16, 0x11, 0x15, 0x00, - 0x08, 0x11, 0x00, 0x06, 0x61, 0x11, 0x11, 0x00, 0x00, 0x00, 0x06, 0x11, - 0x02, 0x61, 0x08, 0x11, 0x02, 0x16, 0x06, 0x11, 0x00, 0x00, 0x06, 0x11, - 0x02, 0x16, 0x08, 0x11, 0x02, 0x61, 0x06, 0x11, 0x00, 0x00, 0x08, 0x11, - 0x00, 0x08, 0x61, 0x11, 0x11, 0x16, 0x08, 0x11, 0x00, 0x00, 0x08, 0x11, - 0x00, 0x08, 0x16, 0x66, 0x66, 0x61, 0x08, 0x11, 0x00, 0x01 -}; -const unsigned int bulb_off_bmp_len = 478; diff --git a/firmware/application/bitmaps/bmp_bulb_on.hpp b/firmware/application/bitmaps/bmp_bulb_on.hpp deleted file mode 100644 index 72d99d01c..000000000 --- a/firmware/application/bitmaps/bmp_bulb_on.hpp +++ /dev/null @@ -1,46 +0,0 @@ -const unsigned char bulb_on_bmp[] = { - 0x42, 0x4d, 0xba, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, - 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, - 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x09, 0x00, - 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x39, 0x39, 0x39, 0x00, 0xff, 0x00, 0xff, 0x00, 0x5b, 0x5b, - 0x5b, 0x00, 0x7d, 0x7d, 0x7d, 0x00, 0x90, 0xa0, 0x75, 0x00, 0x9d, 0x9d, - 0x9d, 0x00, 0x44, 0xe5, 0xff, 0x00, 0x85, 0xfe, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x0a, 0x11, 0x02, 0x88, 0x02, 0x88, 0x0a, 0x11, 0x00, 0x00, - 0x08, 0x11, 0x00, 0x08, 0x18, 0x20, 0x02, 0x81, 0x08, 0x11, 0x00, 0x00, - 0x08, 0x11, 0x00, 0x08, 0x82, 0x55, 0x33, 0x28, 0x08, 0x11, 0x00, 0x00, - 0x08, 0x11, 0x00, 0x08, 0x85, 0x22, 0x22, 0x38, 0x08, 0x11, 0x00, 0x00, - 0x08, 0x11, 0x00, 0x08, 0x82, 0x55, 0x33, 0x28, 0x08, 0x11, 0x00, 0x00, - 0x08, 0x11, 0x00, 0x08, 0x85, 0x22, 0x22, 0x38, 0x08, 0x11, 0x00, 0x00, - 0x08, 0x11, 0x00, 0x08, 0x82, 0x55, 0x32, 0x28, 0x08, 0x11, 0x00, 0x00, - 0x00, 0x18, 0x11, 0x61, 0x11, 0x11, 0x85, 0x33, 0x33, 0x28, 0x11, 0x11, - 0x16, 0x11, 0x00, 0x00, 0x00, 0x18, 0x11, 0x16, 0x11, 0x11, 0x83, 0x54, - 0x45, 0x38, 0x11, 0x11, 0x61, 0x11, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, - 0x61, 0x18, 0x77, 0x44, 0x44, 0x77, 0x81, 0x16, 0x11, 0x11, 0x00, 0x00, - 0x06, 0x11, 0x00, 0x0c, 0x87, 0x66, 0x48, 0x44, 0x66, 0x78, 0x06, 0x11, - 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, 0x18, 0x76, 0x66, 0x48, 0x44, 0x66, - 0x67, 0x81, 0x11, 0x11, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, 0x18, 0x66, - 0x86, 0x38, 0x83, 0x66, 0x66, 0x81, 0x11, 0x11, 0x00, 0x00, 0x00, 0x18, - 0x11, 0x11, 0x87, 0x67, 0x87, 0x37, 0x63, 0x76, 0x66, 0x78, 0x11, 0x11, - 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, 0x86, 0x78, 0x86, 0x36, 0x73, 0x67, - 0x67, 0x68, 0x11, 0x11, 0x00, 0x00, 0x00, 0x18, 0x66, 0x61, 0x86, 0x68, - 0x83, 0x67, 0x76, 0x36, 0x76, 0x68, 0x16, 0x66, 0x00, 0x00, 0x00, 0x18, - 0x11, 0x11, 0x86, 0x78, 0x85, 0x77, 0x77, 0x57, 0x77, 0x68, 0x11, 0x11, - 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, 0x87, 0x67, 0x88, 0x78, 0x77, 0x88, - 0x76, 0x78, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, 0x11, 0x11, 0x18, 0x66, - 0x06, 0x88, 0x00, 0x0a, 0x77, 0x77, 0x81, 0x11, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x11, 0x11, 0x18, 0x76, 0x78, 0x77, 0x77, 0x76, 0x76, 0x81, - 0x11, 0x11, 0x00, 0x00, 0x06, 0x11, 0x02, 0x87, 0x08, 0x67, 0x02, 0x68, - 0x06, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x11, 0x11, 0x61, 0x18, 0x76, 0x00, - 0x06, 0x66, 0x00, 0x08, 0x81, 0x16, 0x11, 0x11, 0x00, 0x00, 0x00, 0x18, - 0x11, 0x16, 0x11, 0x11, 0x87, 0x77, 0x77, 0x78, 0x11, 0x11, 0x61, 0x11, - 0x00, 0x00, 0x00, 0x18, 0x11, 0x61, 0x11, 0x11, 0x18, 0x88, 0x88, 0x81, - 0x11, 0x11, 0x16, 0x11, 0x00, 0x01 -}; -const unsigned int bulb_on_bmp_len = 510; diff --git a/firmware/application/ui_about.hpp b/firmware/application/ui_about.hpp index ef4f72c05..db8ac6ceb 100644 --- a/firmware/application/ui_about.hpp +++ b/firmware/application/ui_about.hpp @@ -86,14 +86,15 @@ private: flags flag; } credits_t; - const credits_t credits[14] = { {"Portapack|HAVOC", "Git hash " GIT_REVISION, SECTION}, + const credits_t credits[15] = { {"Portapack|HAVOC", "Git hash " GIT_REVISION, SECTION}, {"Gurus", "J. Boone", TITLE}, {"M. Ossmann", "", MEMBER_LF}, - {"Immaturity", "Furrtek", TITLE_LF}, + {"HAVOC", "Furrtek", TITLE_LF}, {"POCSAG rx", "T. Sailer", TITLE}, {"E. Oenal", "", MEMBER_LF}, {"RDS waveform", "C. Jacquet", TITLE_LF}, {"Xy. infos", "cLx", TITLE_LF}, + {"ADS-B map", "ShadeRelief", TITLE_LF}, {"Thanks", "", SECTION}, {"Rainer Matla", "Keld Norman", TITLE}, {"Giorgio C.", "DC1RDB", TITLE}, diff --git a/firmware/application/ui_bht_tx.hpp b/firmware/application/ui_bht_tx.hpp index b35e2a260..b9c80b301 100644 --- a/firmware/application/ui_bht_tx.hpp +++ b/firmware/application/ui_bht_tx.hpp @@ -26,11 +26,8 @@ #include "ui_transmitter.hpp" #include "ui_font_fixed_8x16.hpp" -#include "bmp_bulb_on.hpp" -#include "bmp_bulb_off.hpp" -#include "bmp_bulb_ignore.hpp" - #include "bht.hpp" +#include "bitmap.hpp" #include "message.hpp" #include "transmitter_model.hpp" #include "encoders.hpp" @@ -198,9 +195,9 @@ private: std::array relay_states { }; ImageOptionsField::options_t relay_options = { - { &bulb_ignore_bmp[0], 0 }, - { &bulb_off_bmp[0], 1 }, - { &bulb_on_bmp[0], 2 } + { &bitmap_bulb_ignore, 0 }, + { &bitmap_bulb_off, 1 }, + { &bitmap_bulb_on, 2 } }; ProgressBar progressbar { diff --git a/firmware/application/ui_cw.cpp b/firmware/application/ui_cw.cpp deleted file mode 100644 index 0bb043a3c..000000000 --- a/firmware/application/ui_cw.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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_cw.hpp" - -#include "portapack.hpp" -#include "baseband_api.hpp" - -#include -#include - -using namespace portapack; - -namespace ui { - -void CWTXView::focus() { - tx_view.focus(); -} - -CWTXView::~CWTXView() { - transmitter_model.disable(); - baseband::shutdown(); -} - -void CWTXView::start_tx() { - transmitter_model.set_sampling_rate(1536000U); // Not important - transmitter_model.set_rf_amp(true); - transmitter_model.set_baseband_bandwidth(1750000); // Not important - transmitter_model.enable(); -} - -void CWTXView::stop_tx() { - transmitter_model.disable(); -} - -CWTXView::CWTXView( - NavigationView& nav -) -{ - baseband::run_image(portapack::spi_flash::image_tag_noop); - - add_children({ - &tx_view - }); - - tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); - new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); - }; - }; - - tx_view.on_start = [this]() { - start_tx(); - tx_view.set_transmitting(true); - }; - - tx_view.on_stop = [this]() { - stop_tx(); - tx_view.set_transmitting(false); - }; - -} - -} /* namespace ui */ diff --git a/firmware/application/ui_cw.hpp b/firmware/application/ui_cw.hpp deleted file mode 100644 index b65833b0f..000000000 --- a/firmware/application/ui_cw.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 __CW_TX_H__ -#define __CW_TX_H__ - -#include "ui.hpp" -#include "ui_widget.hpp" -#include "ui_navigation.hpp" -#include "ui_transmitter.hpp" - -#include "portapack.hpp" -#include "message.hpp" - -namespace ui { - -class CWTXView : public View { -public: - CWTXView(NavigationView& nav); - ~CWTXView(); - - void focus() override; - - std::string title() const override { return "CW generator"; }; - -private: - void start_tx(); - void stop_tx(); - - TransmitterView tx_view { - 8 * 16, - 10000, - 12 - }; -}; - -} /* namespace ui */ - -#endif/*__CW_TX_H__*/ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index d25fa57f8..0ca659167 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -36,7 +36,7 @@ #include "ui_aprstx.hpp" #include "ui_bht_tx.hpp" #include "ui_coasterp.hpp" -#include "ui_cw.hpp" +#include "ui_siggen.hpp" #include "ui_debug.hpp" #include "ui_encoders.hpp" #include "ui_freqman.hpp" @@ -55,7 +55,6 @@ #include "ui_soundboard.hpp" #include "ui_sstvtx.hpp" #include "ui_whipcalc.hpp" -#include "ui_whistle.hpp" #include "analog_audio_app.hpp" #include "ais_app.hpp" @@ -283,17 +282,19 @@ void NavigationView::focus() { ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { add_items({ - { "ADS-B: Planes", ui::Color::orange(), &bitmap_icon_adsb, [&nav](){ nav.push(); }, }, + { "ADS-B: Planes", ui::Color::yellow(),&bitmap_icon_adsb, [&nav](){ nav.push(); }, }, { "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push(); } }, { "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push(); } }, - { "Audio", ui::Color::green(), nullptr, [&nav](){ nav.push(false); } }, + { "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push(false); } }, { "ERT: Utility Meters", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push(); } }, { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, { "SIGFOX", ui::Color::grey(), &bitmap_icon_fox, [&nav](){ nav.push(); } }, // SIGFRXView + { "LoRa", ui::Color::grey(), nullptr, [&nav](){ nav.push(); } }, { "SSTV", ui::Color::grey(), &bitmap_icon_sstv, [&nav](){ nav.push(); } }, { "TPMS: Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push(); } }, }); on_left = [&nav](){ nav.pop(); }; + //set_highlighted(3); // Default selection is "Audio" } /* TransmittersMenuView **************************************************/ @@ -312,10 +313,10 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { { "OOK remote encoders", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, { "RDS", ui::Color::green(), &bitmap_icon_rds, [&nav](){ nav.push(); } }, + { "Signal generator", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push(); } }, { "Soundboard", ui::Color::green(), &bitmap_icon_soundboard, [&nav](){ nav.push(); } }, { "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push(); } }, { "TEDI/LCR AFSK", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push(); } }, - { "Whistle", ui::Color::green(), &bitmap_icon_whistle, [&nav](){ nav.push(); } }, }); on_left = [&nav](){ nav.pop(); }; } @@ -325,7 +326,6 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) { add_items({ { "Frequency manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push(); } }, - { "CW generator", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push(); } }, { "Whip antenna length", ui::Color::yellow(),nullptr, [&nav](){ nav.push(); } }, { "Notepad", ui::Color::grey(), &bitmap_icon_notepad, [&nav](){ nav.push(); } }, { "Wipe SD card", ui::Color::red(), nullptr, [&nav](){ nav.push(); } }, diff --git a/firmware/application/ui_whistle.cpp b/firmware/application/ui_siggen.cpp similarity index 57% rename from firmware/application/ui_whistle.cpp rename to firmware/application/ui_siggen.cpp index 05648e785..23bc470f7 100644 --- a/firmware/application/ui_whistle.cpp +++ b/firmware/application/ui_siggen.cpp @@ -20,10 +20,10 @@ * Boston, MA 02110-1301, USA. */ -#include "ui_whistle.hpp" -#include "ui_receiver.hpp" -#include "tonesets.hpp" +#include "ui_siggen.hpp" +#include "tonesets.hpp" +#include "portapack.hpp" #include "baseband_api.hpp" #include @@ -33,57 +33,75 @@ using namespace portapack; namespace ui { -void WhistleView::start_tx() { - baseband::set_tone( - 0, - field_tone.value() * TONES_DELTA_COEF, - (checkbox_stop.value()) ? field_stop.value() * TONES_SAMPLERATE : 0xFFFFFFFF); // (Almost) infinite duration :) - - shared_memory.bb_data.tones_data.message[0] = 0; - +void SigGenView::focus() { + options_shape.focus(); +} + +SigGenView::~SigGenView() { + transmitter_model.disable(); + baseband::shutdown(); +} + +void SigGenView::start_tx() { transmitter_model.set_sampling_rate(1536000); transmitter_model.set_rf_amp(true); transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); - baseband::set_tones_config(transmitter_model.bandwidth(), 0, 1, false, false); + baseband::set_siggen_tone(symfield_tone.value_dec_u32()); - tx_mode = SINGLE; + auto duration = field_stop.value(); + if (!checkbox_auto.value()) + duration = 0; + baseband::set_siggen_config(transmitter_model.bandwidth(), options_shape.selected_index_value(), field_stop.value()); } -void WhistleView::on_tx_progress(const bool done) { - if (done) { - transmitter_model.disable(); +void SigGenView::update_tone() { + baseband::set_siggen_tone(symfield_tone.value_dec_u32()); +} + +void SigGenView::on_tx_progress(const bool done) { + if (done) tx_view.set_transmitting(false); - tx_mode = IDLE; - } } -void WhistleView::focus() { - tx_view.focus(); -} - -WhistleView::~WhistleView() { - transmitter_model.disable(); - baseband::shutdown(); -} - -WhistleView::WhistleView( +SigGenView::SigGenView( NavigationView& nav ) { - baseband::run_image(portapack::spi_flash::image_tag_tones); + baseband::run_image(portapack::spi_flash::image_tag_siggen); add_children({ &labels, - &field_tone, + &options_shape, + &text_shape, + &symfield_tone, + &button_update, + &checkbox_auto, &checkbox_stop, &field_stop, &tx_view }); - field_tone.set_value(1520); - field_stop.set_value(15); + options_shape.on_change = [this](size_t, OptionsField::value_t v) { + text_shape.set(shape_strings[v]); + }; + options_shape.set_selected_index(0); + text_shape.set(shape_strings[0]); + + symfield_tone.set_sym(1, 1); // Default: 1000 Hz + symfield_tone.on_change = [this]() { + if (auto_update) + update_tone(); + }; + + button_update.on_select = [this](Button&) { + update_tone(); + }; + + checkbox_auto.on_select = [this](Checkbox&, bool v) { + auto_update = v; + }; tx_view.on_edit_frequency = [this, &nav]() { auto new_view = nav.push(receiver_model.tuning_frequency()); @@ -93,15 +111,15 @@ WhistleView::WhistleView( }; tx_view.on_start = [this]() { - if (tx_mode == IDLE) { - tx_view.set_transmitting(true); - start_tx(); - } + start_tx(); + tx_view.set_transmitting(true); }; tx_view.on_stop = [this]() { - baseband::kill_tone(); + transmitter_model.disable(); + tx_view.set_transmitting(false); }; + } } /* namespace ui */ diff --git a/firmware/application/ui_whistle.hpp b/firmware/application/ui_siggen.hpp similarity index 55% rename from firmware/application/ui_whistle.hpp rename to firmware/application/ui_siggen.hpp index 9cec2bf50..ce8ce16fa 100644 --- a/firmware/application/ui_whistle.hpp +++ b/firmware/application/ui_siggen.hpp @@ -20,57 +20,97 @@ * Boston, MA 02110-1301, USA. */ +#ifndef __SIGGEN_H__ +#define __SIGGEN_H__ + #include "ui.hpp" #include "ui_widget.hpp" -#include "ui_painter.hpp" #include "ui_navigation.hpp" #include "ui_transmitter.hpp" + +#include "portapack.hpp" #include "message.hpp" -#include "transmitter_model.hpp" namespace ui { -class WhistleView : public View { +class SigGenView : public View { public: - WhistleView(NavigationView& nav); - ~WhistleView(); + SigGenView(NavigationView& nav); + ~SigGenView(); void focus() override; - std::string title() const override { return "Whistle"; }; + std::string title() const override { return "Signal generator"; }; private: void start_tx(); + void update_tone(); void on_tx_progress(const bool done); - - enum tx_modes { - IDLE = 0, - SINGLE + + const std::string shape_strings[7] = { + "CW", + "Sine", + "Triangle", + "Saw up", + "Saw down", + "Square", + "Noise" }; - tx_modes tx_mode = IDLE; - + bool auto_update { false }; + Labels labels { - { { 3 * 8, 4 * 8 }, "Tone frequency: Hz", Color::light_grey() }, - { { 22 * 8, 8 * 8 + 4 }, "s.", Color::light_grey() } + { { 6 * 8, 4 + 10 }, "Shape:", Color::light_grey() }, + { { 7 * 8, 7 * 8 }, "Tone: Hz", Color::light_grey() }, + { { 22 * 8, 15 * 8 + 4 }, "s.", Color::light_grey() }, + { { 8 * 8, 20 * 8 }, "Modulation: FM", Color::light_grey() } }; - NumberField field_tone { - { 19 * 8, 4 * 8 }, - 4, - { 1, 9999 }, + ImageOptionsField options_shape { + { 13 * 8, 4, 32, 32 }, + Color::white(), + Color::black(), + { + { &bitmap_sig_cw, 0 }, + { &bitmap_sig_sine, 1 }, + { &bitmap_sig_tri, 2 }, + { &bitmap_sig_saw_up, 3 }, + { &bitmap_sig_saw_down, 4 }, + { &bitmap_sig_square, 5 }, + { &bitmap_sig_noise, 6 } + } + }; + + Text text_shape { + { 18 * 8, 4 + 10, 8 * 8, 16 }, + "" + }; + + SymField symfield_tone { + { 13 * 8, 7 * 8 }, 5, - ' ' + SymField::SYMFIELD_DEC + }; + + Button button_update { + { 6 * 8, 10 * 8, 8 * 8, 3 * 8 }, + "Update" + }; + + Checkbox checkbox_auto { + { 16 * 8, 10 * 8 }, + 4, + "Auto" }; Checkbox checkbox_stop { - { 5 * 8, 8 * 8 }, + { 5 * 8, 15 * 8 }, 10, "Stop after" }; NumberField field_stop { - { 20 * 8, 8 * 8 + 4 }, + { 20 * 8, 15 * 8 + 4 }, 2, { 1, 99 }, 1, @@ -93,3 +133,5 @@ private: }; } /* namespace ui */ + +#endif/*__SIGGEN_H__*/ diff --git a/firmware/application/ui_transmitter.hpp b/firmware/application/ui_transmitter.hpp index 051cfd1a0..cbd581365 100644 --- a/firmware/application/ui_transmitter.hpp +++ b/firmware/application/ui_transmitter.hpp @@ -100,7 +100,7 @@ private: }; Text text_bw { - { 11 * 8, 2 * 8, 9 * 8, 1 * 16 }, + { 11 * 8, 1 * 8, 9 * 8, 1 * 16 }, "BW: kHz" }; NumberField field_bw { diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 02df31b09..1bf1297d4 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -387,6 +387,13 @@ set(MODE_CPPSRC ) DeclareTargets(PREP replay) +### Signal generator + +set(MODE_CPPSRC + proc_siggen.cpp +) +DeclareTargets(PSIG siggen) + ### SSTV TX set(MODE_CPPSRC diff --git a/firmware/baseband/proc_capture.cpp b/firmware/baseband/proc_capture.cpp index daa958d9d..04edf70a7 100644 --- a/firmware/baseband/proc_capture.cpp +++ b/firmware/baseband/proc_capture.cpp @@ -39,8 +39,8 @@ CaptureProcessor::CaptureProcessor() { decim_0.configure(decim_0_filter.taps, 33554432); decim_1.configure(decim_1_filter.taps, 131072); - channel_filter_pass_f = decim_1_filter.pass_frequency_normalized * decim_1_input_fs; - channel_filter_stop_f = decim_1_filter.stop_frequency_normalized * decim_1_input_fs; + channel_filter_pass_f = decim_1_filter.pass_frequency_normalized * decim_1_input_fs; // 162760.416666667 + channel_filter_stop_f = decim_1_filter.stop_frequency_normalized * decim_1_input_fs; // 337239.583333333 spectrum_interval_samples = decim_1_output_fs / spectrum_rate_hz; spectrum_samples = 0; diff --git a/firmware/baseband/proc_jammer.cpp b/firmware/baseband/proc_jammer.cpp index e6cc81e89..925267953 100644 --- a/firmware/baseband/proc_jammer.cpp +++ b/firmware/baseband/proc_jammer.cpp @@ -87,9 +87,9 @@ void JammerProcessor::execute(const buffer_c8_t& buffer) { }; void JammerProcessor::on_message(const Message* const msg) { - const auto message = *reinterpret_cast(msg); - - if (message.id == Message::ID::JammerConfigure) { + if (msg->id == Message::ID::JammerConfigure) { + const auto message = *reinterpret_cast(msg); + if (message.run) { jammer_channels = (JammerChannel*)shared_memory.bb_data.data; noise_type = message.type; diff --git a/firmware/baseband/proc_siggen.cpp b/firmware/baseband/proc_siggen.cpp new file mode 100644 index 000000000..a10c12410 --- /dev/null +++ b/firmware/baseband/proc_siggen.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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 "proc_siggen.hpp" +#include "portapack_shared_memory.hpp" +#include "sine_table_int8.hpp" +#include "event_m4.hpp" + +#include + +void SigGenProcessor::execute(const buffer_c8_t& buffer) { + if (!configured) return; + + for (size_t i = 0; i < buffer.count; i++) { + + if (!sample_count && auto_off) { + message.done = true; + shared_memory.application_queue.push(message); + } else + sample_count--; + + if (tone_shape == 0) { + // CW + re = 0; + im = 0; + } else { + + if (tone_shape == 1) { + // Sine + sample = (sine_table_i8[(tone_phase & 0xFF000000) >> 24]); + } else if (tone_shape == 2) { + // Tri + int8_t a = (tone_phase & 0xFF000000) >> 24; + sample = (a & 0x80) ? ((a << 1) ^ 0xFF) - 0x80 : (a << 1) + 0x80; + } else if (tone_shape == 3) { + // Saw up + sample = ((tone_phase & 0xFF000000) >> 24); + } else if (tone_shape == 4) { + // Saw down + sample = ((tone_phase & 0xFF000000) >> 24) ^ 0xFF; + } else if (tone_shape == 5) { + // Square + sample = (((tone_phase & 0xFF000000) >> 24) & 0x80) ? 127 : -128; + } else if (tone_shape == 6) { + // Noise + sample = (lfsr & 0xFF000000) >> 24; + feedback = ((lfsr >> 31) ^ (lfsr >> 29) ^ (lfsr >> 15) ^ (lfsr >> 11)) & 1; + lfsr = (lfsr << 1) | feedback; + if (!lfsr) lfsr = 0x1337; // Shouldn't do this :( + } + + tone_phase += tone_delta; + + // Do FM + delta = sample * fm_delta; + + phase += delta; + sphase = phase + (64 << 24); + + re = (sine_table_i8[(sphase & 0xFF000000) >> 24]); + im = (sine_table_i8[(phase & 0xFF000000) >> 24]); + } + + buffer.p[i] = {re, im}; + } +}; + +void SigGenProcessor::on_message(const Message* const msg) { + const auto message = *reinterpret_cast(msg); + + switch(msg->id) { + case Message::ID::SigGenConfig: + if (!message.bw) { + configured = false; + return; + } + + if (message.duration) { + sample_count = message.duration; + auto_off = true; + } else + auto_off = false; + + fm_delta = message.bw * (0xFFFFFFULL / 1536000); + tone_shape = message.shape; + + lfsr = 0x54DF0119; + + configured = true; + break; + + case Message::ID::SigGenTone: + tone_delta = reinterpret_cast(msg)->tone_delta; + break; + + default: + break; + } +} + +int main() { + EventDispatcher event_dispatcher { std::make_unique() }; + event_dispatcher.run(); + return 0; +} diff --git a/firmware/baseband/proc_siggen.hpp b/firmware/baseband/proc_siggen.hpp new file mode 100644 index 000000000..18a25bfd8 --- /dev/null +++ b/firmware/baseband/proc_siggen.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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 __PROC_SIGGEN_H__ +#define __PROC_SIGGEN_H__ + +#include "baseband_processor.hpp" +#include "baseband_thread.hpp" +#include "portapack_shared_memory.hpp" + +class SigGenProcessor : public BasebandProcessor { +public: + void execute(const buffer_c8_t& buffer) override; + + void on_message(const Message* const msg) override; + +private: + bool configured { false }; + + BasebandThread baseband_thread { 1536000, this, NORMALPRIO + 20, baseband::Direction::Transmit }; + + uint32_t tone_delta { 0 }, fm_delta { }; + uint32_t lfsr { }, feedback { }, tone_shape { }; + uint32_t sample_count { 0 }; + bool auto_off { }; + uint32_t tone_phase { 0 }, phase { 0 }, delta { 0 }, sphase { 0 }; + int8_t sample { 0 }; + int8_t re { 0 }, im { 0 }; + + TXDoneMessage message { }; +}; + +#endif diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 54ffdc7cf..b6b974c48 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -87,6 +87,8 @@ public: WidebandSpectrumConfig = 42, FSKConfigure = 43, SSTVConfigure = 44, + SigGenConfig = 43, + SigGenTone = 44, POCSAGPacket = 50, @@ -683,6 +685,36 @@ public: const bool ctcss_enabled; }; +class SigGenConfigMessage : public Message { +public: + constexpr SigGenConfigMessage( + const uint32_t bw, + const uint32_t shape, + const uint32_t duration + ) : Message { ID::SigGenConfig }, + bw(bw), + shape(shape), + duration(duration) + { + } + + const uint32_t bw; + const uint32_t shape; + const uint32_t duration; +}; + +class SigGenToneMessage : public Message { +public: + constexpr SigGenToneMessage( + const uint32_t tone_delta + ) : Message { ID::SigGenTone }, + tone_delta(tone_delta) + { + } + + const uint32_t tone_delta; +}; + class AFSKConfigureMessage : public Message { public: constexpr AFSKConfigureMessage( diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 1ead32792..64380a8b3 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -84,6 +84,7 @@ constexpr image_tag_t image_tag_replay { 'P', 'R', 'E', 'P' }; constexpr image_tag_t image_tag_fsktx { 'P', 'F', 'S', 'K' }; constexpr image_tag_t image_tag_mic_tx { 'P', 'M', 'T', 'X' }; constexpr image_tag_t image_tag_sstv_tx { 'P', 'S', 'T', 'X' }; +constexpr image_tag_t image_tag_siggen { 'P', 'S', 'I', 'G' }; constexpr image_tag_t image_tag_noop { 'P', 'N', 'O', 'P' }; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 4941c7102..dfaec8047 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -948,10 +948,14 @@ bool ImageButton::on_touch(const TouchEvent event) { /* ImageOptionsField *****************************************************/ ImageOptionsField::ImageOptionsField( - Rect parent_rect, - options_t options + const Rect parent_rect, + const Color foreground, + const Color background, + const options_t options ) : Widget { parent_rect }, - options { options } + options { options }, + foreground_ { foreground }, + background_ { background } { set_focusable(true); } @@ -994,14 +998,20 @@ void ImageOptionsField::set_options(options_t new_options) { } void ImageOptionsField::paint(Painter& painter) { - const auto paint_style = has_focus() ? style().invert() : style(); - - if( selected_index() < options.size() ) { - const auto bmp_ptr = options[selected_index()].first; - painter.fill_rectangle({screen_rect().location(), {screen_rect().size().width() + 4, screen_rect().size().height() + 4}}, ui::Color::black()); - painter.draw_rectangle({screen_rect().location(), {screen_rect().size().width() + 4, screen_rect().size().height() + 4}}, paint_style.background); - portapack::display.drawBMP({screen_pos().x() + 2, screen_pos().y() + 1}, bmp_ptr, true); - } + const bool selected = (has_focus() || highlighted()); + const auto paint_style = selected ? style().invert() : style(); + + painter.draw_rectangle( + { screen_rect().location(), { screen_rect().size().width() + 4, screen_rect().size().height() + 4 } }, + paint_style.background + ); + + painter.draw_bitmap( + {screen_pos().x() + 2, screen_pos().y() + 2}, + *options[selected_index_].first, + foreground_, + background_ + ); } void ImageOptionsField::on_focus() { diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 7f60f2387..72326fa34 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -406,18 +406,22 @@ public: class ImageOptionsField : public Widget { public: - using image_t = const unsigned char *; using value_t = int32_t; - using option_t = std::pair; + using option_t = std::pair; using options_t = std::vector; std::function on_change { }; std::function on_show_options { }; - ImageOptionsField(Rect parent_rect, options_t options); + ImageOptionsField( + const Rect parent_rect, + const Color foreground, + const Color background, + const options_t options + ); ImageOptionsField( - ) : ImageOptionsField { { }, { } } + ) : ImageOptionsField { { }, Color::white(), Color::black(), { } } { } @@ -438,6 +442,8 @@ public: private: options_t options; size_t selected_index_ { 0 }; + Color foreground_; + Color background_; }; class OptionsField : public Widget { diff --git a/firmware/graphics/bulb_ignore.bmp b/firmware/graphics/bulb_ignore.bmp deleted file mode 100644 index 1bcd2e875886f196d1058b63e2a9d4f5b698e69d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 522 zcmb7=F;BxV5QQ%RRZ(D~ORG+OSRfVzRERN>b*d+pqKFkClqmzE7WpMv_(A+Fc;_?) zMjV~*KELPFIsX1Lle9j#w~W~?GC7o-^(*!1(GUgM!iUY4>0irw{a*9=TrMt`vRE`y zRh4}4tLs|Yww1o`rPRF3yHa^)=ACM|I*6*?C5Gy@sqa*gm`UGPt4H-ne#=Scx%tg! zI*)hkVLD~>KvNOsoI^ diff --git a/firmware/graphics/bulb_ignore.png b/firmware/graphics/bulb_ignore.png new file mode 100644 index 0000000000000000000000000000000000000000..847922bee2fdfcec4e163706d7a3e25cc87579d2 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjjh-%!As(G?CmHe`P~c(y{NMlb z-mbZuXEiSL&}pbuDGa@;_Q`x%Zf>`8RGzKC(s>~;bE7d%%bnO5ANtjO)b z$8megQm2{g8Rq=dI&k;6<|2kUN=EJH8B{siUo*}%=ul(!+26J{g<)$LgRBO}VOHH= k+7j|BxjMucLs(Pnca+cWxBeYJ1?U(CPgg&ebxsLQ0Ob2ZDF6Tf literal 0 HcmV?d00001 diff --git a/firmware/graphics/bulb_off.bmp b/firmware/graphics/bulb_off.bmp deleted file mode 100644 index fbd18b704189a72951a941da7f20df6f5058e6d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 478 zcmb7AyKcfj5FB43W0^D~#EIJQ0pTGew~&xDNIc}qMRbaAMVH#Ykpjuz>g=9zKvb}& zy`8xojrMl2J_YdcEB8@yaLxeFFoHj&-|IHn5w5xT*!@U(DAemZ(lkXaC;NIwp64jb z5>-{9u4}|Jg(+eJ5fRzfCnwe8@9b^f;=^>hYVlp~%h^Rg8G4_Pc(F_pIzdq8I7(=h zVL)0crQ<)}&X!l)aXapLS)+ITTfQg9YSZ>_I5*O|^er=>^^euKum2940YVztgz?h} Twu1fKqKHHx{JgQE(2WIu2f8i+ diff --git a/firmware/graphics/bulb_off.png b/firmware/graphics/bulb_off.png new file mode 100644 index 0000000000000000000000000000000000000000..85807a162198a6da2454958e69b7522fcec5936b GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjm7Xq+As(G?C!FRxpuoZM{eS%~ zTT{cftB!9T2MFtN7)PqSRJdxtOPy=k-zg0Y2hLc@oV)fQ;d$agu9{8O@~gh=Q+)9| z<(VyG=X?u)zk;u)n=%%*?%qE|!OHu$LXA$x0lyG2iFVdQ&MBb@0O(Rg$^ZZW literal 0 HcmV?d00001 diff --git a/firmware/graphics/bulb_on.bmp b/firmware/graphics/bulb_on.bmp deleted file mode 100644 index 8ebc52f159c998e04748e9479428883aabe72ca9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 510 zcmb79u};J=40S71mBL~nRUOeyH&f|o*HaNJEC|HVg$gO@z;+_Z(xFssGV%jOd zCOTzVLen(x`u+^#I70C`LH|X{G(m*E@lAvPAwrm(`YpW{zucwkJ?>YlY>)qrpV@p! zutMz9bd4BOFXAy`cYBc`36^7($fA%f#Q_3@W6iD#rU=d1n24G3c2+HCL)J0&!!_6E zkAkVaKB!@{YSWDevW?BWiAxG{V(~^dAchL{hpB+yqKWA#5N( iUx(bU?Q{|CkO&AEgl>AbotBciE!$Pp(HN?w?Y(c})l!K7 diff --git a/firmware/graphics/bulb_on.png b/firmware/graphics/bulb_on.png new file mode 100644 index 0000000000000000000000000000000000000000..fb688ad1f6889ab62cb72bb94c1dedb8fa0cf62d GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjQ$1ZALp(a)PC3YRK!L~k^MCuh zbJ>D~guB~i)i^ev{gv~KrGY6RH1xgk>{^Sro2GF_-Dvdi;l7j@b3(`RZ3_2{zI=vB zOzi^v0mn_4mgvuAxMj6D zt;Hf-%ImAT!AZ|Gbxl`C#%JXQ1|~h06`~g|?HR|9Gv1td^F&`sRAX*OT;&(_Z44RBp?Ta4 rcZ&H|n0@&4j?KiDi9=z5_y-0P{iz#|y?fRRbQFW9tDnm{r-UW|^1nxe literal 0 HcmV?d00001 diff --git a/firmware/graphics/sig_saw_down.png b/firmware/graphics/sig_saw_down.png new file mode 100644 index 0000000000000000000000000000000000000000..c017062fc8675a819bb7af448b8b686f3bb5d0af GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJDV{ElArY-_r#f;q81S%s{_p?V zvqNh3-IRrLK`+ks9B#OH=FN>7_XHNV2kcD$3=Y5fTzBs5JywYfS1BQfg>#D*GH{Dd ztzPc3@NUt3rWG#R?*uV4mYrV8BpDK@CmP}C`gFs4%cibV54oRmicWoO7F9Cq>5r+W zI2fL0SuOPHWA?VlzWS9v`VMgP9EfWa=9YRBb#AZI4WRoNJYD@<);T3K F0RVzMQ;Prq literal 0 HcmV?d00001 diff --git a/firmware/graphics/sig_saw_up.png b/firmware/graphics/sig_saw_up.png new file mode 100644 index 0000000000000000000000000000000000000000..7e0630f157cbce07a70dd275e5e451aa0cd21ebe GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ9#0p?kcif|mmT>U6nI=N-ur)P zmysdc!~fS<#8neLpYtZU9NAcDzJQVU2jhdNnT+4=)J_Ew#ZwuY9kuqbR7kdLR6VeS zbKgpngo`Zo%S0GV4(7WsCkX#>5Opv)SkKOOLQO-4IY(Hkk6~LUXFQXUug?#W3Ass! t1Qje_NH@r)9BywoyPJ_W<3QX2PHw3;QJJ6pvw-em@O1TaS?83{1OPPUMHm18 literal 0 HcmV?d00001 diff --git a/firmware/graphics/sig_sine.png b/firmware/graphics/sig_sine.png new file mode 100644 index 0000000000000000000000000000000000000000..fbbb04b49058f3ea00d15103428f58d24e9328c5 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJB2O2`kcif|6Ak$eDDW_U{_j7% zlkY;3HOIt*9zF%fHC5Pv36xr<6$9FrzaMi(i0!-5M0H`bo{^kBvngx z5pIhwCtlrQY-O78YU9K(P>q6AoD}xTLyNE2YC+6-}-uX Utyt`^8E89$r>mdKI;Vst0BxB*MgRZ+ literal 0 HcmV?d00001 diff --git a/firmware/graphics/sig_square.png b/firmware/graphics/sig_square.png new file mode 100644 index 0000000000000000000000000000000000000000..16a64f2c7eca0a857e12cedfe7d716ec4cb62dbe GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz7f%<*kcif|=Pq(G81OhbevjW3 zyP(BEL#m=FzO!Ib$r)A#1_y=(ldo6oI?Ze{ul^2D4+FyiA&03C^%xTLfb2aD+|yfv UnE7JfKLJU3y85}Sb4q9e04qi$`v3p{ literal 0 HcmV?d00001 diff --git a/firmware/graphics/sig_tri.png b/firmware/graphics/sig_tri.png new file mode 100644 index 0000000000000000000000000000000000000000..3d2ff1b88c168652affe53c4de2eb5ca437a6595 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJY)==*kcif|mmIkcDDb#kyz~E3 zX{ZLHZ_?C1M_D#al9XRG^XBC}OdJXfG9Uc5?wG*L{3k@;|Ject`EyEUMGgmaM5g9G zOK9+(zUG``!;yB&Uyhay?_E^)z47m3KQS$2zTF8%hO^oY3`}2`*gp9tJ>hScl>l1H N;OXk;vd$@?2>??{I_Ura literal 0 HcmV?d00001 diff --git a/sdcard/ADSB/airlines.db b/sdcard/ADSB/airlines.db new file mode 100644 index 0000000000000000000000000000000000000000..88e5ade422853fc4f9341c48322bfc7247aa94bb GIT binary patch literal 28928 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 literal 0 HcmV?d00001