From d40016ffdabd2d1f14778a51c676a6409856ba4e Mon Sep 17 00:00:00 2001 From: furrtek Date: Mon, 9 May 2016 20:42:20 +0200 Subject: [PATCH] Fixed LCR and Xylos transmitters --- firmware/Makefile | 2 +- firmware/application/Makefile | 2 + firmware/application/touch.hpp | 6 +- firmware/application/ui_audiotx.hpp | 1 - firmware/application/ui_handwrite.cpp | 404 +++++++++++++++++++++ firmware/application/ui_handwrite.hpp | 105 ++++++ firmware/application/ui_lcr.cpp | 57 ++- firmware/application/ui_lcr.hpp | 11 +- firmware/application/ui_loadmodule.cpp | 14 +- firmware/application/ui_loadmodule.hpp | 2 +- firmware/application/ui_menu.cpp | 2 +- firmware/application/ui_navigation.cpp | 40 +- firmware/application/ui_soundboard.cpp | 145 ++++++++ firmware/application/ui_soundboard.hpp | 93 +++++ firmware/application/ui_xylos.cpp | 23 +- firmware/application/ui_xylos.hpp | 55 ++- firmware/baseband-tx.bin | Bin 33280 -> 33280 bytes firmware/baseband-tx/Makefile | 2 + firmware/baseband-tx/audio_compressor.cpp | 52 +++ firmware/baseband-tx/audio_compressor.hpp | 102 ++++++ firmware/baseband-tx/baseband_thread.cpp | 4 + firmware/baseband-tx/ook.hpp | 93 +++++ firmware/baseband-tx/phase_accumulator.hpp | 50 +++ firmware/baseband-tx/phase_detector.hpp | 68 ++++ firmware/baseband-tx/proc_audiotx.cpp | 56 +-- firmware/baseband-tx/proc_audiotx.hpp | 6 - firmware/baseband-tx/proc_tpms.cpp | 72 ++++ firmware/baseband-tx/proc_tpms.hpp | 125 +++++++ firmware/baseband-tx/proc_xylos.cpp | 6 +- firmware/baseband-tx/proc_xylos.hpp | 15 +- firmware/baseband-tx/stream_input.hpp | 73 ++++ firmware/baseband.bin | Bin 33280 -> 33280 bytes firmware/common/modules.h | 4 +- firmware/common/ui.hpp | 14 +- firmware/common/ui_widget.cpp | 46 ++- firmware/common/ui_widget.hpp | 15 + firmware/portapack-h1-firmware.bin | Bin 454488 -> 459560 bytes sdcard/baseband-tx.bin | Bin 33280 -> 33280 bytes sdcard/baseband.bin | Bin 33280 -> 33280 bytes 39 files changed, 1614 insertions(+), 151 deletions(-) create mode 100644 firmware/application/ui_handwrite.cpp create mode 100644 firmware/application/ui_handwrite.hpp create mode 100644 firmware/application/ui_soundboard.cpp create mode 100644 firmware/application/ui_soundboard.hpp create mode 100644 firmware/baseband-tx/audio_compressor.cpp create mode 100644 firmware/baseband-tx/audio_compressor.hpp create mode 100644 firmware/baseband-tx/ook.hpp create mode 100644 firmware/baseband-tx/phase_accumulator.hpp create mode 100644 firmware/baseband-tx/phase_detector.hpp create mode 100644 firmware/baseband-tx/proc_tpms.cpp create mode 100644 firmware/baseband-tx/proc_tpms.hpp create mode 100644 firmware/baseband-tx/stream_input.hpp diff --git a/firmware/Makefile b/firmware/Makefile index 18302e65..5bce1a9f 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -64,7 +64,7 @@ modules: $(TARGET_BASEBAND).bin $(TARGET_BASEBAND_TX).bin cp $(PATH_BASEBAND).bin ../sdcard/$(PATH_BASEBAND).bin cp $(PATH_BASEBAND_TX).bin ../sdcard/$(PATH_BASEBAND_TX).bin -$(TARGET).bin: modules $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND)_inc.bin $(TARGET_APPLICATION).bin +$(TARGET).bin: modules $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND_TX)_inc.bin $(TARGET_APPLICATION).bin $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND)_inc.bin $(TARGET_APPLICATION).bin $(TARGET).bin $(TARGET_BOOTSTRAP).bin: $(TARGET_BOOTSTRAP).elf diff --git a/firmware/application/Makefile b/firmware/application/Makefile index 4aeff3f0..caef1a99 100755 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -151,6 +151,7 @@ CPPSRC = main.cpp \ lcd_ili9341.cpp \ ui.cpp \ ui_alphanum.cpp \ + ui_handwrite.cpp \ ui_about.cpp \ ui_text.cpp \ ui_widget.cpp \ @@ -162,6 +163,7 @@ CPPSRC = main.cpp \ ui_channel.cpp \ ui_audio.cpp \ ui_audiotx.cpp \ + ui_soundboard.cpp \ ui_lcr.cpp \ ui_rds.cpp \ ui_jammer.cpp \ diff --git a/firmware/application/touch.hpp b/firmware/application/touch.hpp index 0402243a..c814db2c 100644 --- a/firmware/application/touch.hpp +++ b/firmware/application/touch.hpp @@ -180,12 +180,12 @@ private: static constexpr size_t touch_count_threshold { 4 }; static constexpr uint32_t touch_stable_bound { 4 }; - static constexpr float calib_x_low = 0.07f; - static constexpr float calib_x_high = 0.94f; + static constexpr float calib_x_low = 0.15f; + static constexpr float calib_x_high = 0.98f; static constexpr float calib_x_range = calib_x_high - calib_x_low; static constexpr float calib_y_low = 0.04f; - static constexpr float calib_y_high = 0.91f; + static constexpr float calib_y_high = 0.80f; //91 static constexpr float calib_y_range = calib_y_high - calib_y_low; // Ensure filter length is equal or less than touch_count_threshold, diff --git a/firmware/application/ui_audiotx.hpp b/firmware/application/ui_audiotx.hpp index 4cc7ede4..d9074cf5 100644 --- a/firmware/application/ui_audiotx.hpp +++ b/firmware/application/ui_audiotx.hpp @@ -40,7 +40,6 @@ public: AudioTXView(NavigationView& nav); ~AudioTXView(); - void focus() override; private: diff --git a/firmware/application/ui_handwrite.cpp b/firmware/application/ui_handwrite.cpp new file mode 100644 index 00000000..243ea88a --- /dev/null +++ b/firmware/application/ui_handwrite.cpp @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * + * 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_handwrite.hpp" + +#include "ch.h" + +#include "ff.h" +#include "portapack.hpp" +#include "event_m0.hpp" +#include "string_format.hpp" +#include "hackrf_hal.hpp" +#include "portapack_shared_memory.hpp" +#include "time.hpp" + +#include + +using namespace portapack; + +namespace ui { + +HandWriteView::~HandWriteView() { + time::signal_tick_second -= signal_token_tick_second; +} + +HandWriteView::HandWriteView( + NavigationView& nav, + char txt[], + uint8_t max_len +) { + _max_len = max_len; + _lowercase = false; + + txtidx = 0; + //memcpy(txtinput, txt, max_len+1); + + add_child(&text_input); + + const auto button_fn = [this](Button& button) { + this->on_button(button); + }; + + size_t n = 0; + for(auto& button : num_buttons) { + add_child(&button); + button.on_select = button_fn; + button.set_parent_rect({ + static_cast(n * 24), + static_cast(240), + 24, 20 + }); + const std::string label { + n + 0x30 + }; + button.set_text(label); + button.id = n; + n++; + } + //set_uppercase(); + + /*add_child(&button_lowercase); + button_lowercase.on_select = [this, &nav, txt, max_len](Button&) { + if (_lowercase == true) { + _lowercase = false; + button_lowercase.set_text("UC"); + set_uppercase(); + } else { + _lowercase = true; + button_lowercase.set_text("LC"); + set_lowercase(); + } + };*/ + + add_child(&text_debug_x); + add_child(&text_debug_y); + add_child(&text_debug_write); + add_child(&button_done); + button_done.on_select = [this, &nav, txt, max_len](Button&) { + //memcpy(txt, txtinput, max_len+1); + //on_changed(this->value()); + nav.pop(); + }; + + signal_token_tick_second = time::signal_tick_second += [this]() { + this->on_tick_second(); + }; + + //update_text(); +} + +bool HandWriteView::MM(uint8_t idx, char cmp) { + if (idx < move_index) { + if ((cmp == 'U') && ((move_list[idx] & 0xF0) == 0x00)) return true; + if ((cmp == 'D') && ((move_list[idx] & 0xF0) == 0x10)) return true; + if ((cmp == 'L') && ((move_list[idx] & 0x0F) == 0x00)) return true; + if ((cmp == 'R') && ((move_list[idx] & 0x0F) == 0x01)) return true; + } + return false; +} + +bool HandWriteView::MM(uint8_t idx, char cmpud, char cmplr) { + if (idx < move_index) { + if (cmpud == 'U') cmpud = 0; + if (cmpud == 'D') cmpud = 1; + if (cmpud == '?') cmpud = 2; + if (cmplr == 'L') cmplr = 0; + if (cmplr == 'R') cmplr = 1; + if (cmplr == '?') cmplr = 2; + if (((move_list[idx] >> 4) == cmpud) && ((move_list[idx] & 0x0F) == cmplr)) return true; + } + return false; +} + +bool HandWriteView::MI(uint8_t idx) { + if (move_index - 1 < idx) + return true; + else + return false; +} + +bool HandWriteView::MLAST(char cmp) { + if ((cmp == 'U') && ((move_list[move_index - 1] & 0xF0) == 0x00)) return true; + if ((cmp == 'D') && ((move_list[move_index - 1] & 0xF0) == 0x10)) return true; + if ((cmp == 'L') && ((move_list[move_index - 1] & 0x0F) == 0x00)) return true; + if ((cmp == 'R') && ((move_list[move_index - 1] & 0x0F) == 0x01)) return true; + return false; +} + +bool HandWriteView::on_touch(const TouchEvent event) { + char guess; + + if (event.type == ui::TouchEvent::Type::Start) { + move_index = 0; + move_wait = 4; + tracing = true; + } + if (event.type == ui::TouchEvent::Type::End) { + tracing = false; + + display.fill_rectangle( + {{0, 16}, {240, 230}}, + Color::black() + ); + + // Letter guessing + guess = '?'; + + if (MM(0, 'U')) { + if (MM(0, 'U', '?')) { + if (MI(1)) + guess = 'A'; + else + guess = 'F'; + } else if (MM(0, 'U', 'R')) { + if (MI(1)) { + guess = 'K'; + } else { + if (MM(1, 'L')) { + if (txt_idx > 0) txtinput[txt_idx--] = 0; // Erase + } else { + guess = 'N'; + } + } + } else if (MM(0, 'U', 'L')) { + if (MM(1, 'U', 'R')) guess = 'C'; + if (MM(1, 'D', 'L')) guess = 'M'; + } + } else if (MM(0, 'D')) { + if (MM(0, 'D', 'R') || MM(1, 'R')) + guess = 'P'; + else + guess = 'Q'; + if (MM(0, 'D', '?')) { + if (MI(1)) { + guess = 'I'; + } else { + if (MM(1, 'R') && MI(2)) { + guess = 'L'; + } else if (MM(1, 'L')) { + if (MI(2)) guess = 'J'; + } else if (MM(1, 'U', 'R')) { + if (MM(2, 'D')) guess = 'W'; + } + } + } + if (MM(0, 'D', 'R')) { + if (MI(1)) guess = 'R'; + if (MM(1, 'U', 'R') && MI(2)) guess = 'V'; + if (MM(1, 'D', 'L')) guess = 'B'; + } else if (MM(0, 'D', 'L')) { + if (MI(1)) guess = 'Y'; + if (MM(1, 'U', 'L') && MI(2)) guess = 'U'; + if (MM(1, 'D', 'R')) guess = 'D'; + } + } + + if (MM(0, 'L')) { + if (!MI(2) && (MLAST('U') || MLAST('L'))) guess = 'O'; + if (MM(0, '?', 'L')) { + if (MI(1)) + guess = 'E'; + else + guess = 'S'; + } + } else if (MM(0, 'R')) { + if (!MI(2) && (MLAST('U') || MLAST('R'))) guess = 'X'; + if (MM(0, '?', 'R')) { + if (MM(1, 'U') && MI(2)) { + guess = 'G'; + } else if (MM(1, 'D', '?') && MI(2)) { + guess = 'H'; + } else if (MM(1, 'L')) { + guess = 'Z'; + } else if (MI(1)) { + guess = 'T'; + } + } + } + + // if (guess = '?') guess = ' '; + if (guess != '!') txtinput[txt_idx++] = guess; + update_text(); + } + if (event.type == ui::TouchEvent::Type::Move) { + if (tracing) { + current_pos = event.point; + } + } + return true; +} + +void HandWriteView::sample_pen() { + int16_t diff_x, diff_y; + uint8_t dir, i; + + if (!(sample_skip & 1)) { + if (tracing) { + if (move_wait) { + move_wait--; // ~133ms delay + } else { + diff_x = current_pos.x - last_pos.x; + diff_y = current_pos.y - last_pos.y; + + text_debug_x.set(to_string_dec_int(diff_x)); + text_debug_y.set(to_string_dec_int(diff_y)); + + display.fill_rectangle( + {{current_pos.x, current_pos.y}, {4, 4}}, + Color::grey() + ); + + dir = 0; + if (abs(diff_x) > 7) { + if (diff_x > 0) + dir |= 0x01; // R + } else { + dir |= 0x02; // ? + } + if (abs(diff_y) > 7) { + if (diff_y > 0) + dir |= 0x10; // D + } else { + dir |= 0x20; // ? + } + + if ((dir & 0x11) == (dir_prev & 0x11)) + dir_cnt++; + else + dir_cnt = 0; + dir_prev = dir; + + // text_debug_d.set(to_string_dec_uint(dir)); + + if (dir_cnt > 1) { + dir_cnt = 0; + if (move_index) { + if ((move_list[move_index - 1] != dir) && (dir != 0x22)) { + if ((dir & 0xF0) == 0x20) { + if ((move_list[move_index - 1] & 0x0F) != (dir & 0x0F)) { + move_list[move_index] = dir; + move_index++; + } + } else if ((dir & 0x0F) == 0x02) { + if ((move_list[move_index - 1] & 0xF0) != (dir & 0xF0)) { + move_list[move_index] = dir; + move_index++; + } + } else { + // Replacement ? + if (((move_list[move_index - 1] & 0xF0) == 0x20) && ((dir & 0xF0) != 0x20)) { + if ((move_list[move_index - 1] & 0x0F) == (dir & 0x0F)) { + move_list[move_index - 1] = dir; + } else if ((dir & 0x0F) == 0x02) { + // Merge + move_list[move_index - 1] = (dir & 0xF0) | (move_list[move_index - 1] & 0x0F); + } else { + move_list[move_index] = dir; + move_index++; + } + } else if (((move_list[move_index - 1] & 0x0F) == 0x02) && ((dir & 0x0F) != 0x02)) { + if ((move_list[move_index - 1] & 0xF0) == (dir & 0xF0)) { + move_list[move_index - 1] = dir; + } else if ((dir & 0xF0) == 0x20) { + // Merge + move_list[move_index - 1] = (dir & 0x0F) | (move_list[move_index - 1] & 0xF0); + } else { + move_list[move_index] = dir; + move_index++; + } + } else { + move_list[move_index] = dir; + move_index++; + } + } + } + } else { + if (dir != 0x22) { + move_list[move_index] = dir; + move_index++; + } + } + + // DEBUG + /*if (move_index) { + memset(txtinput, 0, 20); + txtidx = 0; + for (i = 0; i < move_index; i++) { + if ((move_list[i] & 0x03) == 0) char_add('L'); + if ((move_list[i] & 0x03) == 1) char_add('R'); + if ((move_list[i] & 0x03) == 2) char_add('?'); + if ((move_list[i] >> 4) == 0) char_add('U'); + if ((move_list[i] >> 4) == 1) char_add('D'); + if ((move_list[i] >> 4) == 2) char_add('?'); + char_add(' '); + } + update_text(); + }*/ + + } + } + + last_pos = current_pos; + } + } + + sample_skip++; +} + +void HandWriteView::on_show() { + // Use screen refresh rate as sampling frequency + EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync); + EventDispatcher::message_map().register_handler(Message::ID::DisplayFrameSync, + [this](const Message* const) { + sample_pen(); + } + ); +} + +char * HandWriteView::value() { + return txtinput; +} + +void HandWriteView::on_button(Button& button) { + char_add(button.id + 0x30); + update_text(); +} + +void HandWriteView::char_add(const char c) { + if (txtidx < _max_len) { + txtinput[txtidx] = c; + txtidx++; + } +} + +void HandWriteView::char_delete() { + if (txtidx) { + txtidx--; + txtinput[txtidx] = ' '; + } +} + +void HandWriteView::update_text() { + text_input.set(txtinput); +} + +} diff --git a/firmware/application/ui_handwrite.hpp b/firmware/application/ui_handwrite.hpp new file mode 100644 index 00000000..25aee983 --- /dev/null +++ b/firmware/application/ui_handwrite.hpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * + * 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.hpp" +#include "ui_widget.hpp" +#include "ui_painter.hpp" +#include "ui_menu.hpp" +#include "ui_navigation.hpp" +#include "ui_font_fixed_8x16.hpp" +#include "clock_manager.hpp" +#include "message.hpp" +#include "signal.hpp" + +namespace ui { + +class HandWriteView : public View { +public: + std::function on_changed; + + HandWriteView(NavigationView& nav, char txt[], uint8_t max_len); + ~HandWriteView(); + + void on_show() override; + bool on_touch(const TouchEvent event) override; + + char * value(); + + uint8_t txtidx; + + void char_add(const char c); + void char_delete(); + +private: + SignalToken signal_token_tick_second; + + uint8_t _max_len, txt_idx = 0; + uint8_t dir_cnt = 0; + uint8_t dir_prev; + bool tracing = false; + uint8_t move_index; + uint8_t sample_skip, move_wait; + uint8_t move_list[32]; // TODO: Cap ! + Point start_pos, current_pos, last_pos; + bool _lowercase = false; + static constexpr size_t button_w = 240 / 5; + static constexpr size_t button_h = 28; + char txtinput[21] = {0}; // DEBUG + + bool MM(uint8_t idx, char cmp); + bool MM(uint8_t idx, char cmpud, char cmplr); + bool MI(uint8_t idx); + bool MLAST(char cmp); + + void sample_pen(); + + Text text_input { + { 0, 0, 240, 16 } + }; + + Text text_debug_x { + { 0, 16, 32, 16 } + }; + Text text_debug_y { + { 0, 32, 32, 16 } + }; + Text text_debug_write { + { 80, 24, 150, 16 } + }; + + std::array num_buttons; + + Button button_lowercase { + { 88+64+16, 270, 32, 24 }, + "UC" + }; + + Button button_done { + { 88, 270, 64, 24 }, + "Done" + }; + + void on_button(Button& button); + + void update_text(); +}; + +} /* namespace ui */ diff --git a/firmware/application/ui_lcr.cpp b/firmware/application/ui_lcr.cpp index a0d8f60d..fd333957 100644 --- a/firmware/application/ui_lcr.cpp +++ b/firmware/application/ui_lcr.cpp @@ -78,6 +78,10 @@ void LCRView::make_frame() { lcrframe[5] = 127; lcrframe[6] = 127; lcrframe[7] = 15; // SOM + + strcpy(rgsb, RGSB_list[adr_code.value()]); + button_setrgsb.set_text(rgsb); + strcat(lcrframe, rgsb); strcat(lcrframe, "PA "); if (checkbox_am_a.value() == true) { @@ -191,7 +195,7 @@ LCRView::LCRView( }; transmitter_model.set_baseband_configuration({ - .mode = 1, + .mode = 3, .sampling_rate = 2280000, // Is this right ? .decimation_factor = 1, }); @@ -200,11 +204,12 @@ LCRView::LCRView( memset(litteral, 0, 5*8); memset(rgsb, 0, 5); - strcpy(rgsb, RGSB_list[29]); + strcpy(rgsb, RGSB_list[adr_code.value()]); button_setrgsb.set_text(rgsb); add_children({ { &text_recap, + &adr_code, &button_setrgsb, &button_txsetup, &checkbox_am_a, @@ -290,7 +295,9 @@ LCRView::LCRView( memcpy(shared_memory.lcrdata, lcrframe_f, 256); shared_memory.afsk_transmit_done = false; - shared_memory.afsk_repeat = (portapack::persistent_memory::afsk_config() >> 8) & 0xFF; + shared_memory.afsk_repeat = 5; //(portapack::persistent_memory::afsk_config() >> 8) & 0xFF; + + EventDispatcher::message_map().unregister_handler(Message::ID::TXDone); EventDispatcher::message_map().register_handler(Message::ID::TXDone, [this,&transmitter_model](Message* const p) { @@ -316,7 +323,49 @@ LCRView::LCRView( transmitter_model.enable(); }; - + /* + button_transmit_scan.on_select() = [this,&transmitter_model](Button&){ + make_frame(); + + shared_memory.afsk_samples_per_bit = 228000/portapack::persistent_memory::afsk_bitrate(); + shared_memory.afsk_phase_inc_mark = portapack::persistent_memory::afsk_mark_freq()*(0x40000*256)/2280; + shared_memory.afsk_phase_inc_space = portapack::persistent_memory::afsk_space_freq()*(0x40000*256)/2280; + + shared_memory.afsk_fmmod = portapack::persistent_memory::afsk_bw() * 8; + + memset(shared_memory.lcrdata, 0, 256); + memcpy(shared_memory.lcrdata, lcrframe_f, 256); + + shared_memory.afsk_transmit_done = false; + shared_memory.afsk_repeat = 5; //(portapack::persistent_memory::afsk_config() >> 8) & 0xFF; + + EventDispatcher::message_map().unregister_handler(Message::ID::TXDone); + + EventDispatcher::message_map().register_handler(Message::ID::TXDone, + [this,&transmitter_model](Message* const p) { + char str[8]; + const auto message = static_cast(p); + if (message->n > 0) { + text_status.set(" "); + strcpy(str, to_string_dec_int(message->n).c_str()); + strcat(str, "/"); + strcat(str, to_string_dec_int((portapack::persistent_memory::afsk_config() >> 8) & 0xFF).c_str()); + text_status.set(str); + } else { + text_status.set("Done ! "); + transmitter_model.disable(); + } + } + ); + + char str[8]; + strcpy(str, "0/"); + strcat(str, to_string_dec_int(shared_memory.afsk_repeat).c_str()); + text_status.set(str); + + transmitter_model.enable(); + }; + */ button_txsetup.on_select = [&nav](Button&){ nav.push(); }; diff --git a/firmware/application/ui_lcr.hpp b/firmware/application/ui_lcr.hpp index 0d282ed4..11cfb8eb 100644 --- a/firmware/application/ui_lcr.hpp +++ b/firmware/application/ui_lcr.hpp @@ -44,6 +44,7 @@ public: void paint(Painter& painter) override; private: + uint8_t adri = 22; const char RGSB_list[37][5] = { "EAA0", "EAB0", "EAC0", "EAD0", "EbA0", "EbB0", "EbC0", "EbD0", @@ -70,9 +71,17 @@ private: }; Text text_recap { - { 32, 6, 192, 16 }, + { 8, 6, 18 * 8, 16 }, "-" }; + + NumberField adr_code { + { 220, 6 }, + 2, + { 0, 36 }, + 1, + '0' + }; Button button_setrgsb { { 16, 24, 96, 32 }, diff --git a/firmware/application/ui_loadmodule.cpp b/firmware/application/ui_loadmodule.cpp index a183a9a6..b045bee2 100644 --- a/firmware/application/ui_loadmodule.cpp +++ b/firmware/application/ui_loadmodule.cpp @@ -35,8 +35,10 @@ #include "ui_rds.hpp" #include "ui_xylos.hpp" #include "ui_lcr.hpp" -#include "ui_audiotx.hpp" +#include "analog_audio_app.hpp" +#include "ui_soundboard.hpp" #include "ui_debug.hpp" +#include "ui_audiotx.hpp" #include #include @@ -150,9 +152,12 @@ void LoadModuleView::loadmodule() { LoadModuleView::LoadModuleView( NavigationView& nav, const char * hash, - uint8_t ViewID + uint8_t ViewID, + bool loadplz ) { + if (loadplz == false) nav.pop(); // Useless, remove ! + add_children({ { &text_info, &text_infob, @@ -163,10 +168,11 @@ LoadModuleView::LoadModuleView( button_ok.on_select = [this, &nav, ViewID](Button&){ if (_mod_loaded == true) { - if (ViewID == 0) nav.push(); + if (ViewID == 0) nav.push(); //nav.push(); if (ViewID == 1) nav.push(); if (ViewID == 2) nav.push(); - if (ViewID == 3) nav.push(); + if (ViewID == 3) nav.push(); + if (ViewID == 10) nav.push(); } else { nav.pop(); } diff --git a/firmware/application/ui_loadmodule.hpp b/firmware/application/ui_loadmodule.hpp index 37b78cd2..fa7c05a8 100644 --- a/firmware/application/ui_loadmodule.hpp +++ b/firmware/application/ui_loadmodule.hpp @@ -32,7 +32,7 @@ namespace ui { class LoadModuleView : public View { public: - LoadModuleView(NavigationView& nav, const char * hash, uint8_t ViewID); + LoadModuleView(NavigationView& nav, const char * hash, uint8_t ViewID, bool loadplz); void loadmodule(); void on_show() override; diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 5f584eeb..30ec2c26 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -53,7 +53,7 @@ void MenuItemView::paint(Painter& painter) { paint_style.background ); - ui::Color final_item_color = item.color; + ui::Color final_item_color = (highlighted() && parent()->has_focus()) ? ui::Color::black() : item.color; if (final_item_color.v == paint_style.background.v) final_item_color = paint_style.foreground; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index a58e4fe0..077fc372 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -33,6 +33,9 @@ #include "ui_setup.hpp" #include "ui_debug.hpp" +#include "ui_handwrite.hpp" // DEBUG +#include "ui_soundboard.hpp" // DEBUG + #include "analog_audio_app.hpp" #include "ais_app.hpp" #include "ert_app.hpp" @@ -155,7 +158,7 @@ void NavigationView::focus() { } } -/* TransceiversMenuView **************************************************/ +/* TranspondersMenuView **************************************************/ TranspondersMenuView::TranspondersMenuView(NavigationView& nav) { add_items<3>({ { @@ -170,7 +173,9 @@ TranspondersMenuView::TranspondersMenuView(NavigationView& nav) { ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { add_items<2>({ { - { "Audio", ui::Color::white(), [&nav](){ nav.push(); } }, + { "Audio", ui::Color::white(), [&nav](){ nav.push(md5_baseband, 10, true); } }, + + //{ "Audio", ui::Color::white(), [&nav](){ nav.push(); } }, { "Transponders", ui::Color::white(), [&nav](){ nav.push(); } }, } }); on_left = [&nav](){ nav.pop(); }; @@ -180,18 +185,18 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { SystemMenuView::SystemMenuView(NavigationView& nav) { add_items<10>({ { - { "Play dead", ui::Color::red(), [&nav](){ nav.push(false); } }, - { "Receiver", ui::Color::cyan(), [&nav](){ nav.push(); } }, - { "RDS TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, 0); } }, - { "Xylos TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, 1); } }, - { "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, 2); } }, - { "Audio TX", ui::Color::orange(), [&nav](){ nav.push(md5_baseband_tx, 3); } }, - //{ "Capture", ui::Color::white(), [&nav](){ nav.push(); } }, - //{ "Analyze", ui::Color::white(), [&nav](){ nav.push(); } }, - { "Setup", ui::Color::white(), [&nav](){ nav.push(); } }, - { "About", ui::Color::white(), [&nav](){ nav.push(); } }, - { "Debug", ui::Color::white(), [&nav](){ nav.push(); } }, - { "HackRF", ui::Color::white(), [&nav](){ nav.push(); } }, + { "Play dead", ui::Color::red(), [&nav](){ nav.push(false); } }, + { "Receiver RX", ui::Color::cyan(), [&nav](){ nav.push(); } }, + { "Soundboard TX", ui::Color::orange(), [&nav](){ nav.push(md5_baseband_tx, 3, true); } }, + { "Audio TX TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, 0, true); } }, + { "Xylos TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, 1, true); } }, + { "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push(md5_baseband_tx, 2, true); } }, + //{ "Capture", ui::Color::white(), [&nav](){ nav.push(); } }, + //{ "Analyze", ui::Color::white(), [&nav](){ nav.push(); } }, + { "Setup", ui::Color::white(), [&nav](){ nav.push(); } }, + { "About", ui::Color::white(), [&nav](){ nav.push(); } }, + { "Debug", ui::Color::white(), [&nav](){ nav.push(); } }, + { "HackRF", ui::Color::white(), [&nav](){ nav.push(); } }, } }); /* @@ -224,7 +229,8 @@ SystemView::SystemView( set_style(&style_default); constexpr ui::Dim status_view_height = 16; - + char debugtxt[21] = {0}; + add_child(&status_view); status_view.set_parent_rect({ { 0, 0 }, @@ -255,7 +261,9 @@ SystemView::SystemView( if (portapack::persistent_memory::ui_config() & 1) navigation_view.push(); else - navigation_view.push(); + //navigation_view.push(); + //navigation_view.push(); + navigation_view.push(debugtxt, 20); } Context& SystemView::context() const { diff --git a/firmware/application/ui_soundboard.cpp b/firmware/application/ui_soundboard.cpp new file mode 100644 index 00000000..c45b2667 --- /dev/null +++ b/firmware/application/ui_soundboard.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * + * 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_soundboard.hpp" + +#include "ch.h" + +#include "ui_alphanum.hpp" +#include "ff.h" +#include "hackrf_gpio.hpp" +#include "portapack.hpp" +#include "radio.hpp" +#include "event_m0.hpp" +#include "string_format.hpp" + +#include "hackrf_hal.hpp" +#include "portapack_shared_memory.hpp" + +#include + +using namespace portapack; + +namespace ui { + +void SoundBoardView::on_show() { + /* + // Just in case + EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync); + + // "Vertical blank interrupt" + EventDispatcher::message_map().register_handler(Message::ID::DisplayFrameSync, + [this](const Message* const) { + pbar_test.set_value(testv/4); + testv++; + } + );*/ +} + +std::string SoundBoardView::title() const { + return "Sound board"; +}; + +void SoundBoardView::focus() { + buttons[0].focus(); +} + +void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) { + transmitter_model.set_tuning_frequency(f); +} + +void SoundBoardView::on_button(Button& button) { + text_test.set(to_string_dec_uint(button.id)); +} + +SoundBoardView::SoundBoardView( + NavigationView& nav +) +{ + size_t n; + + for (n = 0; n < 12; n++) { + sounds[n].filename = ""; + sounds[n].shortname = "Empty"; + sounds[n].min = 0; + sounds[n].sec = 0; + } + + add_children({ { + &text_test, + &field_frequency, + &number_bw, + &pbar_test, + &button_load, + &button_exit + } }); + + const auto button_fn = [this](Button& button) { + this->on_button(button); + }; + + for(auto& button : buttons) { + add_child(&button); + button.id = n; + button.on_select = button_fn; + button.set_parent_rect({ + static_cast((n % 3) * 70 + 15), + static_cast((n / 3) * 50 + 30), + 70, 50 + }); + button.set_text(sounds[n].shortname); + n++; + } + + field_frequency.set_value(transmitter_model.tuning_frequency()); + field_frequency.set_step(receiver_model.frequency_step()); + 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(receiver_model.tuning_frequency()); + new_view->on_changed = [this](rf::Frequency f) { + this->on_tuning_frequency_changed(f); + this->field_frequency.set_value(f); + }; + }; + + /*button_transmit.on_select = [](Button&){ + transmitter_model.set_baseband_configuration({ + .mode = 1, + .sampling_rate = 1536000, + .decimation_factor = 1, + }); + transmitter_model.set_rf_amp(true); + transmitter_model.enable(); + };*/ + + button_exit.on_select = [&nav](Button&){ + nav.pop(); + }; +} + +SoundBoardView::~SoundBoardView() { + transmitter_model.disable(); +} + +} diff --git a/firmware/application/ui_soundboard.hpp b/firmware/application/ui_soundboard.hpp new file mode 100644 index 00000000..398c5b0d --- /dev/null +++ b/firmware/application/ui_soundboard.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * + * 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.hpp" +#include "ui_widget.hpp" +#include "ui_painter.hpp" +#include "ui_menu.hpp" +#include "ui_navigation.hpp" +#include "ui_font_fixed_8x16.hpp" +#include "clock_manager.hpp" +#include "message.hpp" +#include "rf_path.hpp" +#include "max2837.hpp" +#include "volume.hpp" +#include "ui_receiver.hpp" +#include "transmitter_model.hpp" + +namespace ui { + +class SoundBoardView : public View { +public: + SoundBoardView(NavigationView& nav); + ~SoundBoardView(); + + std::string title() const; + void on_show() override; + void focus() override; + +private: + struct sound { + std::string filename; + std::string shortname; + uint8_t min; + uint8_t sec; + }; + + sound sounds[12]; + + std::array buttons; + void on_button(Button& button); + + void on_tuning_frequency_changed(rf::Frequency f); + + Text text_test { + { 120, 4, 64, 16 } + }; + + FrequencyField field_frequency { + { 1 * 8, 4 }, + }; + + NumberField number_bw { + { 16 * 8, 4 }, + 5, + {1000, 50000}, + 500, + ' ' + }; + + ProgressBar pbar_test { + { 45, 236, 150, 16 } + }; + + Button button_load { + { 8, 270, 64, 32 }, + "Load" + }; + + Button button_exit { + { 96, 270, 64, 32 }, + "Exit" + }; +}; + +} /* namespace ui */ diff --git a/firmware/application/ui_xylos.cpp b/firmware/application/ui_xylos.cpp index 22ff1b17..56de2e67 100644 --- a/firmware/application/ui_xylos.cpp +++ b/firmware/application/ui_xylos.cpp @@ -135,10 +135,10 @@ void XylosView::paint(Painter& painter) { void XylosView::upd_message() { uint8_t c; - ccirmessage[0] = '0'; - ccirmessage[1] = '0'; - ccirmessage[2] = '0'; - ccirmessage[3] = '0'; + ccirmessage[0] = (header_code_a.value() / 10) + 0x30; + ccirmessage[1] = (header_code_a.value() % 10) + 0x30; + ccirmessage[2] = (header_code_b.value() / 10) + 0x30; + ccirmessage[3] = (header_code_b.value() % 10) + 0x30; ccirmessage[4] = (city_code.value() / 10) + 0x30; ccirmessage[5] = (city_code.value() % 10) + 0x30; @@ -228,7 +228,7 @@ XylosView::XylosView( }; transmitter_model.set_baseband_configuration({ - .mode = 4, + .mode = 2, .sampling_rate = 1536000, .decimation_factor = 1, }); @@ -236,6 +236,9 @@ XylosView::XylosView( add_children({ { &text_title, &button_txtest, + &text_header, + &header_code_a, + &header_code_b, &text_city, &city_code, &text_family, @@ -265,11 +268,21 @@ XylosView::XylosView( family_code.set_value(1); subfamily_code.set_value(1); receiver_code.set_value(1); + header_code_a.set_value(0); + header_code_b.set_value(0); options_freq.set_selected_index(5); checkbox_wcsubfamily.set_value(true); checkbox_wcid.set_value(true); + header_code_a.on_change = [this](int32_t v) { + (void)v; + XylosView::upd_message(); + }; + header_code_b.on_change = [this](int32_t v) { + (void)v; + XylosView::upd_message(); + }; city_code.on_change = [this](int32_t v) { (void)v; XylosView::upd_message(); diff --git a/firmware/application/ui_xylos.hpp b/firmware/application/ui_xylos.hpp index 586dbb54..0d8d79c6 100644 --- a/firmware/application/ui_xylos.hpp +++ b/firmware/application/ui_xylos.hpp @@ -41,8 +41,6 @@ namespace ui { #define XYLOS_VOICE_RELAYS 21 #define XYLOS_VOICE_TRAILER 25 -void do_something(); - class XylosRXView : public View { public: XylosRXView(NavigationView& nav); @@ -152,47 +150,38 @@ public: private: bool txing = false; const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; - uint8_t xylos_voice_phrase[32] = { 0xFF }; - const char * xylos_voice_filenames[26] = { "zero.wav", - "one.wav", - "two.wav", - "three.wav", - "four.wav", - "five.wav", - "six.wav", - "seven.wav", - "eight.wav", - "nine.wav", - "a.wav", - "b.wav", - "c.wav", - "d.wav", - "e.wav", - "f.wav", - "header.wav", - "city.wav", - "family.wav", - "subfamily.wav", - "address.wav", - "relays.wav", - "ignored.wav", - "off.wav", - "on.wav", - "trailer.wav" - }; char ccirmessage[21]; char ccir_received[21]; Text text_title { - { 1 * 8, 1 * 16, 11, 16 }, + { 8, 8, 11, 16 }, "BH Xylos TX" }; Button button_txtest { - { 170, 1 * 16, 40, 24 }, + { 180, 8, 40, 24 }, "TEST" }; + Text text_header { + { 8 * 8, 2 * 16, 7 * 8, 16 }, + "Header:" + }; + NumberField header_code_a { + { 16 * 8, 2 * 16 }, + 2, + { 0, 99 }, + 1, + '0' + }; + NumberField header_code_b { + { 18 * 8, 2 * 16 }, + 2, + { 0, 99 }, + 1, + '0' + }; + Text text_city { { 4 * 8, 3 * 16, 11 * 8, 16 }, "Code ville:" @@ -256,7 +245,7 @@ private: "Frequence:" }; OptionsField options_freq { - { 16 * 8, 9 * 16 }, + { 16 * 8, 9 * 16 + 4}, 7, { { "31.3250", 0 }, diff --git a/firmware/baseband-tx.bin b/firmware/baseband-tx.bin index f456c721be28b4e5f21ebcb04db5527c0fe4ef42..3e65f73aba06c9806744978e5d16d24199b5488e 100644 GIT binary patch delta 3875 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 delta 1497 zcmZWpUvLve82|Qi7n&=i*FOnqTFNygX$UDzTJWKwlR!yJJG6l+qbPXQp&ldFBG5q} zB+OJteL-2liprEJLJ^#?gfazbQYk9Ts8k*p7=0*;v^8|h#o9gHU&UMVv0y&qut_O=bLZhUz|>(=H?JOFI6zxR^7z4cPYqg-#SSsm^5 z+(3M@6JRsNPG{84%tZWcl_7kRA#F+QGZgag(B&?Q&yskJVSmLBNp#c``Y2zN8S-5+ z{^xVMx@BW!w**Ai0`cKd@Ua09A;3T$^tb_P{n*7GV)B#tM|LlB-j7?j66B1&%hejH z5h;te)%06HI72Z=F-+t5XK?iea_*_rT+++db9HtJ5z9mSN1WJdD&i2C)DYfm%4No! zxWQD!A~K@kHj@Q8@mnU*hRBeHN=hVQV7fEaiDPNwVGaIg1Q)(%a#5nUH7xRTkPAP~ zr+8%zOKJ5D-kyUwiLHyH=@$$$?O7# zqqPpZqnC5dNO&^&&8-Y()-4W-Wked1cs#F~IXZ!>EG;aMH99_M@iFTrqL(cf5pv^0 zvlZly?zgogFOW@|7!n3j(U#pLjR(FohIHk));Jys0BK0crECa_f%I!QV3*CANpSx@ zY(0|M17uDTpR{k!0aC6BN7sf7w|FGVK-_d^L3oGSXV^GP{*)fi3N0QUlE3O*T$d{^ z8;51NlCDIwin>c`Ud6KU$O~tw1QNeLB16elfX*jamnvh2~2s4G?4+%#9o1FjFpW`M9`Q3n<3KrnG0fIK}#C1VWD4*?mP znqBLYjCUief{9Kr-tB0z`nO4al0O_NzS=zJdE?zTR|gXZ&A~(u1QW*$*5Z(A4lfSh z30tH@oI z!Hg@qvPH$bLk{hoFdZ>p$gf5p+i2N$O{5+t+J|Mn64Tn0tAY5bQ5qg-OFL;;goZbL z2z|7%WZnesceog70*^RE+%-Q^s4Fd}QxAHw6a;Y7bov^J?&oTCW$k^u#N!ckrRg-p zcg_W9rttZ3yJwKqm7!#`YC#TS-q&!0*UIeCaEn)(cP7a_xEfbg>YbcOe<4@Z4AEL~ zfzF!Jq~SljZl-+_=au!ibfrgS@5}_Q&bVS=ObF;oSHDCH`n7|8SQOVN4mj|yWw&!u zDXvVccBHoRD|E%J;*o`gjO54K!u8Be9j`C9`aVcCgJzS;9EE`TyPm%6|LMQ{t80oi zhEJ5Yx;16s6vVsIeWb@~HKmX0$EN9DP`%%e>wJ%N5Bdzp7ui^|zYriuv8n*z&g|&D qN(XCRMfC$kv`|#`7UA~F3jUf%%@n9OnyA*6L?g?)vW18L>AwI%N*xIR diff --git a/firmware/baseband-tx/Makefile b/firmware/baseband-tx/Makefile index 0b07fa9d..48f288b7 100755 --- a/firmware/baseband-tx/Makefile +++ b/firmware/baseband-tx/Makefile @@ -140,6 +140,8 @@ CPPSRC = main.cpp \ matched_filter.cpp \ proc_audiotx.cpp \ proc_playaudio.cpp \ + proc_xylos.cpp \ + proc_fsk_lcr.cpp \ dsp_squelch.cpp \ clock_recovery.cpp \ packet_builder.cpp \ diff --git a/firmware/baseband-tx/audio_compressor.cpp b/firmware/baseband-tx/audio_compressor.cpp new file mode 100644 index 00000000..95bbaee3 --- /dev/null +++ b/firmware/baseband-tx/audio_compressor.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * 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 "audio_compressor.hpp" + +float GainComputer::operator()(const float x) const { + const auto abs_x = std::abs(x); + const auto db = (abs_x < lin_floor) ? db_floor : log2_db_k * fast_log2(abs_x); + const auto overshoot_db = db - threshold_db; + if( knee_width_db > 0.0f ) { + const auto w2 = knee_width_db / 2.0f; + const auto a = w2 / (knee_width_db * knee_width_db); + const auto in_transition = (overshoot_db > -w2) && (overshoot_db < w2); + const auto rectified_overshoot = in_transition ? (a * std::pow(overshoot_db + w2, 2.0f)) : std::max(overshoot_db, 0.0f); + return rectified_overshoot * slope; + } else { + const auto rectified_overshoot = std::max(overshoot_db, 0.0f); + return rectified_overshoot * slope; + } +} + +void FeedForwardCompressor::execute_in_place(const buffer_f32_t& buffer) { + constexpr float makeup_gain = std::pow(10.0f, (threshold - (threshold / ratio)) / -20.0f); + for(size_t i=0; i + +/* Code based on article in Journal of the Audio Engineering Society + * Vol. 60, No. 6, 2012 June, by Dimitrios Giannoulis, Michael Massberg, + * Joshua D. Reiss "Digital Dynamic Range Compressor Design – A Tutorial + * and Analysis" + */ + +class GainComputer { +public: + constexpr GainComputer( + float ratio, + float threshold + ) : ratio { ratio }, + slope { 1.0f / ratio - 1.0f }, + threshold_db { threshold } + { + } + + float operator()(const float x) const; + +private: + const float ratio; + const float slope; + const float threshold_db; + + static constexpr float knee_width_db = 0.0f; + + static constexpr float db_floor = -120.0f; + static constexpr float lin_floor = std::pow(10.0f, db_floor / 20.0f); + static constexpr float log2_db_k = 20.0f * std::log10(2.0f); +}; + +class PeakDetectorBranchingSmooth { +public: + constexpr PeakDetectorBranchingSmooth( + float att_a, + float rel_a + ) : att_a { att_a }, + rel_a { rel_a } + { + } + + float operator()(const float db) { + const auto a = (db > state) ? att_a : rel_a; + state = db + a * (state - db); + return state; + } + +private: + float state { 0.0f }; + const float att_a; + const float rel_a; +}; + +class FeedForwardCompressor { +public: + void execute_in_place(const buffer_f32_t& buffer); + +private: + static constexpr float fs = 12000.0f; + static constexpr float ratio = 10.0f; + static constexpr float threshold = -30.0f; + + GainComputer gain_computer { ratio, threshold }; + PeakDetectorBranchingSmooth peak_detector { tau_alpha(0.010f, fs), tau_alpha(0.300f, fs) }; + + float execute_once(const float x); + + static constexpr float tau_alpha(const float tau, const float fs) { + return std::exp(-1.0f / (tau * fs)); + } +}; + +#endif/*__AUDIO_COMPRESSOR_H__*/ diff --git a/firmware/baseband-tx/baseband_thread.cpp b/firmware/baseband-tx/baseband_thread.cpp index d87f43b0..e6d77a70 100644 --- a/firmware/baseband-tx/baseband_thread.cpp +++ b/firmware/baseband-tx/baseband_thread.cpp @@ -33,6 +33,8 @@ #include "proc_playaudio.hpp" #include "proc_audiotx.hpp" +#include "proc_xylos.hpp" +#include "proc_fsk_lcr.hpp" #include "portapack_shared_memory.hpp" @@ -120,6 +122,8 @@ BasebandProcessor* BasebandThread::create_processor(const int32_t mode) { switch(mode) { case 0: return new PlayAudioProcessor(); case 1: return new AudioTXProcessor(); + case 2: return new XylosProcessor(); + case 3: return new LCRFSKProcessor(); default: return nullptr; } } diff --git a/firmware/baseband-tx/ook.hpp b/firmware/baseband-tx/ook.hpp new file mode 100644 index 00000000..27333922 --- /dev/null +++ b/firmware/baseband-tx/ook.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * 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 __OOK_HPP__ +#define __OOK_HPP__ + +#include "phase_detector.hpp" +#include "phase_accumulator.hpp" + +#include +#include +#include +#include + +class OOKSlicerMagSquaredInt { +public: + using symbol_t = bool; + + constexpr OOKSlicerMagSquaredInt( + const float samples_per_symbol + ) : mag2_threshold_leak_factor { + static_cast( + factor_sq(-1.0f / (8.0f * samples_per_symbol)) * float(1ULL << 32) + ) + } + { + } + + symbol_t operator()(const std::complex in) { + const uint32_t real2 = in.real() * in.real(); + const uint32_t imag2 = in.imag() * in.imag(); + const uint32_t mag2 = real2 + imag2; + + const uint32_t mag2_attenuated = mag2 >> 3; // Approximation of (-4.5dB)^2 + mag2_threshold = (uint64_t(mag2_threshold) * uint64_t(mag2_threshold_leak_factor)) >> 32; + mag2_threshold = std::max(mag2_threshold, mag2_attenuated); + const bool symbol = (mag2 > mag2_threshold); + return symbol; + } + +private: + const uint32_t mag2_threshold_leak_factor; + uint32_t mag2_threshold = 0; + + constexpr float factor_sq(float db) { + return std::pow(10.0f, db / (10.0f / 2)); + } +}; + +class OOKClockRecovery { +public: + constexpr OOKClockRecovery( + const float samples_per_symbol + ) : symbol_phase_inc_nominal { static_cast(std::round((1ULL << 32) / samples_per_symbol)) }, + phase_detector { samples_per_symbol }, + phase_accumulator { symbol_phase_inc_nominal } + { + } + + template + void operator()(const uint32_t slicer_history, SymbolHandler symbol_handler) { + if( phase_accumulator() ) { + const auto detector_result = phase_detector(slicer_history); + phase_accumulator.set_inc(symbol_phase_inc_nominal + detector_result.error * (symbol_phase_inc_nominal >> 3)); + symbol_handler(detector_result.symbol); + } + } + +private: + const uint32_t symbol_phase_inc_nominal; + PhaseDetectorEarlyLateGate phase_detector; + PhaseAccumulator phase_accumulator; +}; + +#endif/*__OOK_HPP__*/ diff --git a/firmware/baseband-tx/phase_accumulator.hpp b/firmware/baseband-tx/phase_accumulator.hpp new file mode 100644 index 00000000..bf3b331a --- /dev/null +++ b/firmware/baseband-tx/phase_accumulator.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * 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 __PHASE_ACCUMULATOR_HPP__ +#define __PHASE_ACCUMULATOR_HPP__ + +#include + +class PhaseAccumulator { +public: + constexpr PhaseAccumulator( + const uint32_t phase_inc + ) : phase_inc { phase_inc } + { + } + + bool operator()() { + const auto last_phase = phase; + phase += phase_inc; + return (phase < last_phase); + } + + void set_inc(const uint32_t new_phase_inc) { + phase_inc = new_phase_inc; + } + +private: + uint32_t phase { 0 }; + uint32_t phase_inc; +}; + +#endif/*__PHASE_ACCUMULATOR_HPP__*/ diff --git a/firmware/baseband-tx/phase_detector.hpp b/firmware/baseband-tx/phase_detector.hpp new file mode 100644 index 00000000..89cf4b5c --- /dev/null +++ b/firmware/baseband-tx/phase_detector.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * 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 __PHASE_DETECTOR_HPP__ +#define __PHASE_DETECTOR_HPP__ + +#include +#include +#include + +class PhaseDetectorEarlyLateGate { +public: + using history_t = uint32_t; + + using symbol_t = bool; + using error_t = int; + + struct result_t { + symbol_t symbol; + error_t error; + }; + + constexpr PhaseDetectorEarlyLateGate( + const float samples_per_symbol + ) : late_mask { (1U << static_cast(std::ceil(samples_per_symbol / 2))) - 1 }, + early_mask { late_mask << static_cast(std::floor(samples_per_symbol / 2)) }, + sample_bit { static_cast(std::floor(samples_per_symbol / 2)) } + { + } + + result_t operator()(const history_t symbol_history) const { + // history = ...0111, early + // history = ...1110, late + + const symbol_t symbol = (symbol_history >> sample_bit) & 1; + const int late_side = __builtin_popcount(symbol_history & late_mask); + const int early_side = __builtin_popcount(symbol_history & early_mask); + const int lateness = late_side - early_side; + const int direction = lateness; //std::min(std::max(lateness, -1), 1); + const error_t error = direction; + return { symbol, error }; + } + +private: + const history_t late_mask; + const history_t early_mask; + const size_t sample_bit; +}; + +#endif/*__PHASE_DETECTOR_HPP__*/ diff --git a/firmware/baseband-tx/proc_audiotx.cpp b/firmware/baseband-tx/proc_audiotx.cpp index a619a620..b47cd02c 100644 --- a/firmware/baseband-tx/proc_audiotx.cpp +++ b/firmware/baseband-tx/proc_audiotx.cpp @@ -23,63 +23,9 @@ #include "proc_audiotx.hpp" #include "portapack_shared_memory.hpp" #include "sine_table.hpp" -#include "audio_output.hpp" -#include "lfsr_random.hpp" #include -uint32_t lfsr(uint32_t v) { - - enum { - length = 31, - tap_0 = 31, - tap_1 = 18, - shift_amount_0 = 12, - shift_amount_1 = 12, - shift_amount_2 = 8 - }; - - const lfsr_word_t zero = 0; - v = ( - ( - v << shift_amount_0 - ) | ( - ( - (v >> (tap_0 - shift_amount_0)) ^ - (v >> (tap_1 - shift_amount_0)) - ) & ( - ~(~zero << shift_amount_0) - ) - ) - ); - v = ( - ( - v << shift_amount_1 - ) | ( - ( - (v >> (tap_0 - shift_amount_1)) ^ - (v >> (tap_1 - shift_amount_1)) - ) & ( - ~(~zero << shift_amount_1) - ) - ) - ); - v = ( - ( - v << shift_amount_2 - ) | ( - ( - (v >> (tap_0 - shift_amount_2)) ^ - (v >> (tap_1 - shift_amount_2)) - ) & ( - ~(~zero << shift_amount_2) - ) - ) - ); - - return v; -} - void AudioTXProcessor::execute(const buffer_c8_t& buffer){ for (size_t i = 0; i class AudioTXProcessor : public BasebandProcessor { diff --git a/firmware/baseband-tx/proc_tpms.cpp b/firmware/baseband-tx/proc_tpms.cpp new file mode 100644 index 00000000..9d401a1c --- /dev/null +++ b/firmware/baseband-tx/proc_tpms.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * + * 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_tpms.hpp" + +#include "dsp_fir_taps.hpp" + +TPMSProcessor::TPMSProcessor() { + decim_0.configure(taps_200k_decim_0.taps, 33554432); + decim_1.configure(taps_200k_decim_1.taps, 131072); +} + +void TPMSProcessor::execute(const buffer_c8_t& buffer) { + /* 2.4576MHz, 2048 samples */ + + const auto decim_0_out = decim_0.execute(buffer, dst_buffer); + const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); + const auto decimator_out = decim_1_out; + + /* 307.2kHz, 256 samples */ + feed_channel_stats(decimator_out); + + for(size_t i=0; ipacket_builder_ook_subaru.execute(symbol); + }); + ook_clock_recovery_gmc(slicer_history, [this](const bool symbol) { + this->packet_builder_ook_gmc.execute(symbol); + }); + } +} + +void TPMSProcessor::consume_symbol( + const float raw_symbol +) { + const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0; + packet_builder.execute(sliced_symbol); +} + +void TPMSProcessor::payload_handler( + const baseband::Packet& packet +) { + const TPMSPacketMessage message { tpms::SignalType::FLM, packet }; + shared_memory.application_queue.push(message); +} diff --git a/firmware/baseband-tx/proc_tpms.hpp b/firmware/baseband-tx/proc_tpms.hpp new file mode 100644 index 00000000..759f7383 --- /dev/null +++ b/firmware/baseband-tx/proc_tpms.hpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * + * 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_TPMS_H__ +#define __PROC_TPMS_H__ + +#include "baseband_processor.hpp" + +#include "channel_decimator.hpp" +#include "matched_filter.hpp" + +#include "clock_recovery.hpp" +#include "symbol_coding.hpp" +#include "packet_builder.hpp" +#include "baseband_packet.hpp" + +#include "ook.hpp" + +#include "message.hpp" +#include "portapack_shared_memory.hpp" + +#include +#include +#include + +// Translate+rectangular filter +// sample=307.2k, deviation=38400, symbol=19200 +// Length: 16 taps, 1 symbols, 2 cycles of sinusoid +constexpr std::array, 16> rect_taps_307k2_1t_p { { + { 6.2500000000e-02f, 0.0000000000e+00f }, { 4.4194173824e-02f, 4.4194173824e-02f }, + { 0.0000000000e+00f, 6.2500000000e-02f }, { -4.4194173824e-02f, 4.4194173824e-02f }, + { -6.2500000000e-02f, 0.0000000000e+00f }, { -4.4194173824e-02f, -4.4194173824e-02f }, + { 0.0000000000e+00f, -6.2500000000e-02f }, { 4.4194173824e-02f, -4.4194173824e-02f }, + { 6.2500000000e-02f, 0.0000000000e+00f }, { 4.4194173824e-02f, 4.4194173824e-02f }, + { 0.0000000000e+00f, 6.2500000000e-02f }, { -4.4194173824e-02f, 4.4194173824e-02f }, + { -6.2500000000e-02f, 0.0000000000e+00f }, { -4.4194173824e-02f, -4.4194173824e-02f }, + { 0.0000000000e+00f, -6.2500000000e-02f }, { 4.4194173824e-02f, -4.4194173824e-02f }, +} }; + +class TPMSProcessor : public BasebandProcessor { +public: + TPMSProcessor(); + + void execute(const buffer_c8_t& buffer) override; + +private: + std::array dst; + const buffer_c16_t dst_buffer { + dst.data(), + dst.size() + }; + + dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0; + dsp::decimate::FIRC16xR16x16Decim2 decim_1; + + dsp::matched_filter::MatchedFilter mf { rect_taps_307k2_1t_p, 8 }; + + clock_recovery::ClockRecovery clock_recovery { + 38400, 19200, { 0.0555f }, + [this](const float symbol) { this->consume_symbol(symbol); } + }; + PacketBuilder packet_builder { + { 0b010101010101010101010101010110, 30, 1 }, + { }, + { 256 }, + [this](const baseband::Packet& packet) { + this->payload_handler(packet); + } + }; + + static constexpr float channel_rate_in = 307200.0f; + static constexpr size_t channel_decimation = 8; + static constexpr float channel_sample_rate = channel_rate_in / channel_decimation; + OOKSlicerMagSquaredInt ook_slicer_5sps { 5 }; + uint32_t slicer_history { 0 }; + + OOKClockRecovery ook_clock_recovery_subaru { + channel_sample_rate / 8192.0f + }; + + PacketBuilder packet_builder_ook_subaru { + { 0b010101010101010101011110, 24, 0 }, + { }, + { 80 }, + [](const baseband::Packet& packet) { + const TPMSPacketMessage message { tpms::SignalType::Subaru, packet }; + shared_memory.application_queue.push(message); + } + }; + OOKClockRecovery ook_clock_recovery_gmc { + channel_sample_rate / 8400.0f + }; + + PacketBuilder packet_builder_ook_gmc { + { 0b01010101010101010101010101100101, 32, 0 }, + { }, + { 192 }, + [](const baseband::Packet& packet) { + const TPMSPacketMessage message { tpms::SignalType::GMC, packet }; + shared_memory.application_queue.push(message); + } + }; + void consume_symbol(const float symbol); + void payload_handler(const baseband::Packet& packet); +}; + +#endif/*__PROC_TPMS_H__*/ diff --git a/firmware/baseband-tx/proc_xylos.cpp b/firmware/baseband-tx/proc_xylos.cpp index b3da393d..61cdd241 100644 --- a/firmware/baseband-tx/proc_xylos.cpp +++ b/firmware/baseband-tx/proc_xylos.cpp @@ -23,7 +23,7 @@ #include "proc_xylos.hpp" #include "dsp_iir_config.hpp" -//#include "audio_output.hpp" +#include "audio_output.hpp" #include "portapack_shared_memory.hpp" #include "sine_table.hpp" @@ -75,7 +75,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { // Audio preview sample generation: 1536000/48000 = 32 if (as >= 31) { as = 0; - preview_audio_buffer.p[ai++] = sample * 128; + audio[ai++] = sample * 128; } else { as++; } @@ -92,5 +92,5 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) { buffer.p[i] = {(int8_t)re,(int8_t)im}; } - //audio_output.write(preview_audio_buffer); + //audio_output.write(audio_buffer); } diff --git a/firmware/baseband-tx/proc_xylos.hpp b/firmware/baseband-tx/proc_xylos.hpp index 0add6712..97695997 100644 --- a/firmware/baseband-tx/proc_xylos.hpp +++ b/firmware/baseband-tx/proc_xylos.hpp @@ -28,7 +28,7 @@ #include "dsp_decimate.hpp" #include "dsp_demodulate.hpp" -//#include "audio_output.hpp" +#include "audio_output.hpp" #include "baseband_processor.hpp" #define CCIR_TONELENGTH 15360-1 // 1536000/10/10 @@ -40,11 +40,12 @@ public: private: int16_t audio_data[64]; - - const buffer_s16_t preview_audio_buffer { - audio_data, - sizeof(int16_t)*64 - }; + + std::array audio; + /*const buffer_s16_t audio_buffer { + audio.data(), + audio.size() + };*/ uint32_t ccir_phases[16] = { (uint32_t)(1981*PHASEV), @@ -74,7 +75,7 @@ private: int32_t sample, frq; TXDoneMessage message; - //AudioOutput audio_output; + AudioOutput audio_output; }; #endif diff --git a/firmware/baseband-tx/stream_input.hpp b/firmware/baseband-tx/stream_input.hpp new file mode 100644 index 00000000..1b1ec552 --- /dev/null +++ b/firmware/baseband-tx/stream_input.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * 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 __STREAM_INPUT_H__ +#define __STREAM_INPUT_H__ + +#include "portapack_shared_memory.hpp" + +#include "fifo.hpp" + +#include +#include +#include + +class StreamInput { +public: + StreamInput(const size_t K) : + K { K }, + data { std::make_unique(1UL << K) }, + fifo { data.get(), K } + { + // TODO: Send stream creation message. + shared_memory.FIFO_HACK = &fifo; + } + + ~StreamInput() { + // TODO: Send stream distruction message. + shared_memory.FIFO_HACK = nullptr; + } + + size_t write(const void* const data, const size_t length) { + const auto written = fifo.in(reinterpret_cast(data), length); + + const auto last_bytes_written = bytes_written; + bytes_written += written; + if( (bytes_written & event_bytes_mask) < (last_bytes_written & event_bytes_mask) ) { + creg::m4txevent::assert(); + } + + return written; + } + + uint64_t written() const { + return bytes_written; + } + +private: + const size_t K; + const uint64_t event_bytes_mask = (1ULL << (K - 2)) - 1; + uint64_t bytes_written = 0; + std::unique_ptr data; + FIFO fifo; +}; + +#endif/*__STREAM_INPUT_H__*/ diff --git a/firmware/baseband.bin b/firmware/baseband.bin index ab19dc42d8862b65674f575fa305a3b8d9a2e020..7f9b8511d687d43282727ca37b7314cd379891a3 100644 GIT binary patch delta 70 zcmZo@VQOe$(h3OhRbXP6Qq8~+l$xBHS(aMF#Q*`H81?oadN-fXtdwtiyN2i9jatVV H1<(Zn{S_FB delta 70 zcmZo@VQOe$(h3OhRbXQHP|v^+l$xBHS(aMF#Q*{3EZ+k&(z+Ci7ktlL^k|FKMy+Fw H0_cJO5Cj?K diff --git a/firmware/common/modules.h b/firmware/common/modules.h index 5810db69..3cd201d0 100644 --- a/firmware/common/modules.h +++ b/firmware/common/modules.h @@ -1,2 +1,2 @@ -const char md5_baseband[16] = {0x37,0x04,0xf7,0x51,0x68,0x66,0x8a,0x20,0x73,0xa0,0xf7,0x69,0xa2,0xe2,0xb4,0x3a,}; -const char md5_baseband_tx[16] = {0x6c,0x1a,0x90,0x6b,0x68,0x78,0x6e,0xd2,0x08,0x3b,0x05,0xb1,0xbe,0x61,0xf8,0xe7,}; +const char md5_baseband[16] = {0xf2,0x01,0x2e,0xbf,0xc2,0xee,0x9f,0x0e,0x36,0x75,0x0e,0xb7,0x87,0x28,0x49,0xbd,}; +const char md5_baseband_tx[16] = {0xb1,0xe1,0xca,0x79,0x83,0x86,0x2f,0x20,0xba,0x94,0xd3,0x0c,0xc7,0x9d,0x43,0xe2,}; diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp index fa2f0fa5..bee55b86 100644 --- a/firmware/common/ui.hpp +++ b/firmware/common/ui.hpp @@ -30,12 +30,18 @@ using Coord = int16_t; using Dim = int16_t; struct Color { - uint16_t v; + uint16_t v; // rrrrrGGGGGGbbbbb constexpr Color( ) : v { 0 } { } + + constexpr Color( + uint16_t v + ) : v { v } + { + } constexpr Color( uint8_t r, @@ -49,6 +55,10 @@ struct Color { )} { } + + Color operator-() const { + return (v ^ 0xffff); + } static constexpr Color black() { return { 0, 0, 0 }; @@ -75,7 +85,7 @@ struct Color { } static constexpr Color cyan() { - return { 0, 128, 255 }; + return { 0, 255, 255 }; } static constexpr Color white() { diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 31d03ebf..d8a0aee9 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -292,6 +292,36 @@ void Text::paint(Painter& painter) { ); } +/* ProgressBar ***********************************************************/ + +ProgressBar::ProgressBar( + Rect parent_rect +) : Widget { parent_rect } +{ +} + +void ProgressBar::set_value(const uint16_t value) { + if (value > 100) + _value = 100; + else + _value = value; + set_dirty(); +} + +void ProgressBar::paint(Painter& painter) { + uint16_t v_sized; + + const auto rect = screen_rect(); + const auto s = style(); + + v_sized = (rect.size.w * _value) / 100; + + painter.fill_rectangle({rect.pos, {v_sized, rect.size.h}}, ui::Color::green()); + painter.fill_rectangle({{rect.pos.x + v_sized, rect.pos.y}, {rect.size.w - v_sized, rect.size.h}}, s.background); + + painter.draw_rectangle(rect, s.foreground); +} + /* Checkbox **************************************************************/ Checkbox::Checkbox( @@ -427,12 +457,16 @@ void Button::paint(Painter& painter) { paint_style.background ); - const auto label_r = paint_style.font.size_of(text_); - painter.draw_string( - { r.pos.x + (r.size.w - label_r.w) / 2, r.pos.y + (r.size.h - label_r.h) / 2 }, - paint_style, - text_ - ); + //char *token = strtok(text_.c_str(), "\n"); + //while(token) { + const auto label_r = paint_style.font.size_of(text_); + painter.draw_string( + { r.pos.x + (r.size.w - label_r.w) / 2, r.pos.y + (r.size.h - label_r.h) / 2 }, + paint_style, + text_ + ); + // token = strtok(NULL, " "); + //} } bool Button::on_key(const KeyEvent key) { diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index f154b86b..4a22f3f2 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -111,6 +111,8 @@ public: bool highlighted() const; void set_highlighted(const bool value); + + uint16_t id = 0; protected: void dirty_overlapping_children_in_rect(const Rect& child_rect); @@ -195,6 +197,19 @@ private: std::string text; }; +class ProgressBar : public Widget { +public: + ProgressBar(Rect parent_rect); + + void set_value(const uint16_t value); + uint16_t value() const; + + void paint(Painter& painter) override; + +private: + uint16_t _value = 0; +}; + class Checkbox : public Widget { public: std::function on_select; diff --git a/firmware/portapack-h1-firmware.bin b/firmware/portapack-h1-firmware.bin index a28ebe8f4a3254a0bb4747b48f79aff2a80d6b1b..47fe1947800134c5c042279fdfe56345be803f87 100644 GIT binary patch delta 70815 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 U&M3L))bc}{h20C}%$pqZe+;iH{{R30 delta 66208 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
  • ~3X#gv|)|cTjHJf0(DF;_J zE(+sWm>i^rf8nUMx2zKJr=yTNa9@GzcPen?SGybd*AymfJ!L8Kc1GR`zGTK z0~o-SYzB(`mO97hD~I(FaDd zFlCVTSc)~+9tfX{yQRF~kEYA|NHM3eJrYJhKzxAE2zt^53H1mQYfeLLmQWY^e!)-p zPVe`}y@V~%_v4V`I%@jGd=tV#=F`$L9Kncb(hbeGu>A!4Y3T=iBm)ZFQae7L2H%>9 zFSOwhVoLo>eNBB&V}Qm3jSt!{XrmzlP5+-3NNY%%1;Pd|CL+CFE>16ucJ~=@HT%8_ zLq6f3fb7ozpRn~4KCkEuET@r}ZX6Qn3SqAsoRm^CiKJG~N>~3)$%bCG`W?9#K4Kcl1TypV3xMjJTH-l(t6K*~%Q^cg=@eHsowwR<*J3JX5t zb8^l=x{YLw+UEV$EZW`s7t5y-b#5^WD_JP)L`>vwfK1kBu+(@?`r0FmI>3(@e@5ES zN47$dAy}lSJp(fQS!o3fVp8KhgJ)j^=C2lLatqHN;B`nd%OkvVfKNv`(<3G{sihov z&+7NS7w^ga-j(S1)1m4`8y8W1$>MEDdNZVD_0@TzzB(;^(nrP!x4cZRuRSY0;(mL= z=lmG?v^tERhx!s6g07LlE=n3C#15}&T%{i`Z{_rd9jlExhu%Ef(dek>HtOV!iY7k} zXG8X^Mnzp9VEUy8Lc#}M@~KgEW_S~p_6fgy$#0u=TH1l!FD2u3NrNtt6XV5!{p7@W z2o#0+Z@kzT;4b063BP{DXBryeN{AO#?*C0$Q;9o-jQ{XsGj7L7R*Hv1|0Jxb#J7bd z|KTr}y(nz@4{wRP-^;n~N}HWxu&KnQg6BVchU^1j@Ynos<#B0(N0|CGZywtPTszk$ zgD9uUlWXgeHU~jnX?GZ+Et+ZNTziEcw*Qr)&b^Tduqnl2Hk*osH@@bF*mL{!LwHiv z?tVIZ8#n1j%*J8rwr)v)H4f{I)z`vlU>mmH5V`*34Bb*IdUX>fIz7LFXU;&Kw$TGh z>)(DF8xbhDy!bXa*|9#2wPf$?bnavYu}nk4jBofT<#}n8TbTU~pU&68S!Abh|2Lpx zoRtOyg{E)#iTqjVy}%aXmv8ug-MIj#d>-Uog^SD2Z&=hj>6wST&cLoRmrvQVncje*4Hg$knP3oGN(_{^s7$xx4a>03aic{VFq4Mn>)Wn zZ6>nXfQ^e9l(5=d!D=&})kc(l2>q|x6h~_FVvuSBM~tXVL8LbG|3_^eMVhBzS-ZD3 zvm><`LN&?4H7rt_NvO?{w}hPUczxO?a{(7Ji_)qP$bQDG0$Uj`eiYiMSBgIhmEZA$ z0T2R+DBal)poIZ^C^*04vnPtkhJIn{Di*28@Lg@H#i|p}xi}Kq^~1FSS!aO%NG8s+ z5u#r3KN%GML@AV~q)xAp`d|3p2(zA*VigPlhFQ;kX|+4ddOk0`3iC_adXnyK#+QQJw8z7u!LjIA*Ds5XQp+3O?R=BG?j2Ufal+0c8;586mH{q+w`D(ca+Nq@29FqR+d%f~y*lxuE+$S?_F0ZLh$MbZb z+_b4Ye?F0u%6#V*#JrIQTXsd9J!XCE`Z(yj%<~m<8aP!`HFN`qAu|lsZWAWJGIu)u z?{N>r|6Qz<=71@iC3W-Ia|jga@_w_1$n$LCfE< z3T0uZP6vO{ei)3TwdYuciMtH+v8=)xyEVPA)v9z2-g?Sf4Hwe+mAorveNCmx^{}#dfsN0<|+<0)9lHgI!U#GBxWIvnyd z3xU}dWEmflakMeOASAN59*`+W<2oD>2sS89WUw(vWhTNVA#6q@tVeo>g$3XxASj); z2W6nrp+-oi44{hudR1RCX$dZ(-_3m-=)PK8G5rCrZ4~H z%|YZ-)@;^Ngd`u)1*9*qGMs|9wX@Rg*c8WM#dsHohkVTD3anp6Qz5j3>maTXcrT=H zxURrOvwemAU7S}i-B;|xfdh61Z~9DI zdU&ay3958&xmWpL#!|llMnS32N@V+6Z~zMZWh^4g8)49`Hf6%{+tG>+-ASn^M2iQh9)5`w&tP8@rI~o59Zr-M;i=h_JnbfKjrnLr z$b1sg$a?Nt7FLWfhbbOmlOkbqhQ*QYxt^;tUob$Ui7F7q3bwb5MkliSo<4aG>Fu?=_n#E4}s83O|`dd zZ;f#DH~xmCEL5xo=*UUwE&OZurl;S3^ zUzOqu9&#U+S0{Ko`OD-V1clt+`7C)$P?(AP%sA|i>d#B7i-05_#GnPbTu_1MZ`t#x z0vn#cf}yTF&QUmhWa$^B`{`PIhi!DKHE)@oOI>nKx-Hm?^$L4`=kHA|8VxR#L6l~r zS!IU1(LdKimh&9!e+w0V@VV3O9$jRHw7fJHUkR?zL%LV6{e$Y#;rX0&m!DD$BPGB0 zwWNrH%}w0C3c2Ngjx(H=7J7w`{@{z0ostJQW+Iuf`_bW zCBY1(S13Nlj~+=%k0dtN`xDXDySDRCXVPGJo|8fW%{Fzb>VRrLN#UH6t_}z<9piIk zmBQ!8_+nX+z<1$*QX!0{n@yPC#TUpNg3!emC#)(=vpqfaMp=1cyzZ%~tA!(7{I#;6 zP<;3~cy&fjqF!1V_%hi9yU>$y`^Vwj}Zn|iBF-7yTM%|0cOLfyTn1c)xUR-E6W0y6Zo#zx*PXbQH6I)U7!{_1zM5dwxC1TV-p7D^KCfb5xod60D~X;V9e^{uRN>B3y<(wD^RkQ;4u$ z@SWlxlr;$Vo#w|GsY^N3G71;fmRcbh_Y_>%nYql{-~RSAFPBX!soAhSjteg@&tdQd zL585EGLIt#hV^)s0U@fwjzv@ZQw;lNbg8VVX|fWkw6d1Fg@I@J8#B*Iw|c5qL3-cW zxeAio&T~?fS6Ro|UR`w-Qj)^zvwV6%H4=+zI4WHpjBichMo&}KC4P~(4_Y%#G}4p3 zcdhDK)l&1F&Q?PVg5=O5;m}!rY;0>yE(Zh-i^*LcA^jXb-F{B0_h=g*T~!4eR;YCFm$pi`?`TcA78IW04=t%@s-_{w4QEOK?*OW)MYT+yN7DrIZ2t8+c4svYIT{8#~ z2Zc22i}YkSKSPkiAe#b;5JiRB7L~Krs;N^zsMpL5a;2N2oVzMXE@W_vLVPTk;aXa) za%r}~AYfySRnd@-*4_teqR<4yK~w=@C@R8UuLyr_UBcVlyy3=Jte(RFrVnYD(4ZW4 zPRZFhmNf4|iw3CL0!u3{*PWzPK7Z;TlEusAT z&&=WuGhha2I9!|*Z!@4Y(#Z{&w@3qZx3x~hfFObbgH~vlar9ByosNp8OQG75rw&-T z#l3Bw)6Ndld8~HXvzgj;b~j_foWQift^U9a&Ux2doB@Z>PXF_~v*y37@BhBFzV)qd zt$$r&_D1Z9Y>I7s6jDd-iQU_c{a_!W>Pynt@NV%H%-8P5%62yTz$NL7jM;rrABP<{ zFMj6WQ-Tx;aQ0-oV=x!G2fNlJp(FSWbu2b=bgE@7_znv-XtsYz+b&^qjBc^S&iJ;h z2m*7jz!A&L`&T@indg0Ut39TvxT>TK+i&f8xk}b@xGZ*0x3~~wr{^8Olhdw0S%pl9 zX*}f8t=PsG=#~t+6${-`+b2Q@wx=QM9}#T5Xp_oX1=~G(jHnLX7i84DSCIKl>QYG+@Xa6%a4dJ9EEup%v;H5!fy|au~ zU}n*zi!X)R{*=JUKZTEqdzMcCgv|(fD0tR%MD`x6rgv}Abx76i+E{BQmI1yOHBl|_FwAKIm-5=`^Q+yR(ig>_ z29Kv;g&?>+PrKZnAX^!#;|;KL$Dt@1yyXnq@-uOs?kKIm&J)yd8O6L?tjFtWPBN*P zR7@iHX~!>1XNI~BN~oiR{&ZP7Bjj+20&Rm?*QoM}bc-t1Q91uW{TKCIvhdo0&2S7b zZ}E%G8Wro8yeLW>6HuYELv})g$qvgM^dDDHb)Ur`OFHK22!2oJI$C^Hnzh7j&w@~H z;_KdZS+!0lvuZX!t0vg4LN1?GV<{`a`Y9|OS3+{k0L8EDhXcpp95Cw)ek?V!{9rCCC(!&uQTE#!qtJNv{ zu0#4RpG~EMQguSAN?sIS#~+c`@CPN0SV00_GRtqi<}H2t`T61KIr-Dvzs!wt z_1!#@2gfEph}rjvK_#i_TgT@XZzbskyN`)drB)UK2`3GC)9*v(maO;8h| zW9GuMVuFL&&9K&p{Xd9r50a*c#)!R`CEFA^rE%IKOw`yDiDd?k4Nl67XgpZeSQgnB z(eOo8Sj(4Xkqtj!e$gb1nbi%_YrbuGlPg`PN0U40#lOx4__h1 zv~J`OI{6{4>|}ivJrYDzE4szs5A=xtYag?CI(Hy51IyF!|8?P|R5ETOT% zD)@}9;;xG1%DuUvU%Xnu->u@hih0|E__)AhGn`&)Q3cxkFh_5oTF_vqcfW(a z6ik*T{K4Th4;Qd?vDZ9Yz;GdE9uhMS54ep(bw4u>nqkIamCHD|ebAoDC*g&rzzc<8 zxSiI9ki_vvDi4=)%Dp$(h6~~m2eS?L=}$YnX5k_>N%oqBqu0&CF{=uWDLY*G=yFcS zUUyF2hWxn8J-y^-$a&i_$muiWEI#}gtQv~B)prK@Ovgfx?Reo@lYzOldOI9=M zF>$p9-$X_9B)Tn!gz~oC7|^~gUeXH7u}`q+;3>dz>_a7ol{8qP7Kuu#@6;2NELcWrcNYa_`J=!esSPLnkZcFauj<_0b(rxBR=v%A5wm*tY zlARTWK_M~39JVNY;W;e+K{Zh%RVc2eg;AtD+=?Nj3JmvDIc2m!BZ(br6`x13cDHh5 zCt{LA%g^)Q>5!6+ND`ESjWB ztfCyN@J1uPRW$d}qtPTG(JF3ow9jpi_O_@Aqd z!@j6ccrEN}$HHnFCMShx1i$5^Yvts!gssm&H=K}6r+Z?^e!`rFqG~!lmXz}jN@K~v z34e6%MyHsV&-9@c^LW{K`UVae_9UlhbMo|oG3218Qw*`6i(g-EDfl36+@embfAeQV zIv=Mi;`U(#XVch4adllQ+v7UL%LDGGV(`?(0jju-oD~jLQ!BqV@WX&e#;zmOdQb&vMjnJj*O4#6c_aK|DsYS)u570>J;DVqff<=Rk$88J&S$W-BJ zJIx$Nl)@V1$T(6Q=3V)@e;NI79QhpImoK94Vmzr;bYYadS9_e|mFt~REN{E80ID(b z4l%lfQ;Me!W(&z(;t6)PNwLX&b`;uCbMk{~`cNuqS=uH37K_27apF{Mtlc=5 zpS`Fl?r+Oya}C)9F&Ci1aAKziE@{%n3fxsMX^QK;epdq*3}Y*uv$>Luij8jS)17qr zMDm=n6PaoQWHm6?zz6uR&5q9IfN%1{1jVxgc&9|^asXxw(k)8zvY^;Wm3NX{L9^3X zaVJp*3GeST?nxu_`7zPE+-9Gx&Jlv)Cl-9sqd!g|`9l9rI%g_Mjs+{U(!!}^6aEPU z^lMxb?%8D=m`W7P+tBvY#Ob7rsnquAq>6=Cr{h&m?xI;UNSd&J7cHAX3WfGv#`k6r z!Y7=;;8oJZ-_sZuyAj_TYSdgmDpw)2m^z@?=RD)Q-%@Z7zUd|wd1z3(HS+P{28h@C?uFy~7 z99&}SHgvmtxecnSzcH5Nyy#O zws*9B*8LBY)Ft@~+-`}FB=Q2KLJP3`Fae(YaD{E)dKB|F$Ba^zg!sR#w9)q-hUwP| zhz|tfp&8ecBWzREiFC)egkVTIc(ZuZa@6wY%Z=r=+N$;I)@yfOjbGEZv3>6Sfr60dMp%p`=fx&bwgipCvBILyd;liC*==JOoyq1UEV-N>P38cODfW`UA2^46G~stu)8 zRa!;v8tr<;gVk#{Xjhlg#MNXCZ7(BP(aWnJL(_46No{Fq75Cdkbo*+uRNrLsiN!DfIF)ZR$&7U^Z9-T|>34?)9C z5VYVKUwNWq*N|j=1KVd4__g%a3|hT6Pj7U6?Jb01c+{P0Ng%97>irU<9AWcH`rcZS zo@GJq_Ih&IgoO6bVQmp|T#Ne%b8wHL0Pti;`Z|(cEMqi12lFjDv9{>&L%kk!Hn*=KvqeYB<`|v_(*R>YyK86;72w>256)(U{_zd2_%1b8)-D9qD+8u?TJV*Fo`7Z`490s=9}V>s>z`Sjp3 zWRG6=F_ahZGG+MASDKr@^5v8HYv>H_6(Aved3|HPXf5Cg&*hv3UBI6w9mcf`%lGIZ z1mz#o$Ms~U@eMsGk7%nr6)DTL6%9Z>q*a5tv@)vxf=KSEJXYN87 z`;i~Y8qD*n22!jq009$VfsArI=r3ObOP`-{*BbEr@WX7w%K$G^ram82NmqRIv{zA{ z`uL*JrR;?z0(cNrGa&UW9_?+zC%KlUJpHQB)hz&pSlLbIKxQ?`-oVU&Fn}Uox^EZ-1qBAIV;(mLW*9+~FRi0yIY8mix-AO0h~^B1 zMt-c)~x&5~qJT zoHbH>tjF@x+P%$2pOj_;@J5fuVzWaMqX8B)6ikK|H9$`q7sDK;HoLjY%znzK<%%UL zlF+tOl0oYze$NM`i%(7g#c9M@gbj7vJ0w|=#*kCuS=Gv9NtQ$yD8AxX?Yk1VP}y_| z#jhDA+y+?))sw(w%ce6FuNme_Wm8B3w?oE;QM_uHs8j|;$Hc*e1n!Kt(svl{tAs@E zt}F(LdR!bUpGFe7hvg#gB^PJ#7PrYGf+_y(_KA#PiQL=rsA!7k+QBlhf=wKo70C+2 zS=6+1J@N{qe8O)Xo3&MiScsCM8nhc!A6D{8C^nN#fcAow6i=c?boT z6mLrKZcP$b9F#+n+D-&TQWA`HuDb2ZkN~1M?!MS7r6%=CKxriWJ8o`pvX0s^!Y!Cm z%wTz#dt*uxHFu=#%PCg~QFDiu2frTvLe;8UAJx2PtYk!u?5Tq(9V)Y$8{GOb_g{6eQ zK2(?eQVyfX(nfLUC9b{LD)2Jn*ijL9G4S#j_V)zBc0}M6?cLFZK{KtwigQ+BeO?X^ z(j1CHNnsLn95D=@m zJ6eU>{H#I^HmXJJM(jh>BN`9~H;Q3Dcbie2yGh&afW4cygKE;83g{v*; zhkGSHq*p@w*hoUoBeac5SX&CV*GeDCvI-}uNTXFaP0^0?`HUlR6R1$mVyj?HwhCuA z!puMMeagXUjw^Tk1&=3lW zum=G$766>ZXL6$?PGUQ2RJ78@Z;WA!OBa_Or%NX3GmS4}-p{dJFn-V)wj{);9RzKN zVbmGx4qftvFgaN}Xf8UBSK!aMyNsZ^X%HD6Gd3(PF|z2O=RFI$48~TX^vf7^rn?C{ z>il8E*V|P!-Zg$2*W(L{c{O-0?EqG;0fj>I3JT=ji#o>S3|4LCo}PAwf@IDW9!0$| z+LkfBfkb$m#iOJ_)|hI%U^E;3bdeFVc;Bx*&OeNDuHPB;eID6c0Uw9!NK=>*c)NGQ zCXJj?p28VC&e&0n<&+&P0G>246iFD0iHG7it^{B1;ab=j>ZFIWv8+j&CCiL7Vp1%J zXvJ}2h%hjE8zzgi75Ge#ck{4_Tw-{|LzX4~&Gu?+4}6Tb*S$XCwgWTg-l2Axh1|R> z>Kl_GB=s9-d&igxGLzud*2`kjNz{#NG(rSe4AkDyb^EUz{5sr3z zyHeUeMcRNRk)Xz0FXXF7@$OACM59xcOz-pbHDRUls^G5<(V=hE7k+v{>w{0P-hrxm zAxFKgucc~wyt~g{HMMVFob}GCs=Q89y^yPBdbNNS3Lq(;lNv172szych24s4!WwnX z;QkF{m>LMt(f#IaNSS*1rx!Fnz1760*9`lR`f~(s3(D9&Y1O*E+NzGekE+B$_S_*= zpWUIVUKJR{tAdoR5tatk2+Nf7(S~c((3?)CZ%xmqEqa8m|yU+!DDULMN3wcW136->?dX=nS z0Uqa|yHoIIJ8|$%K?+opTo)W6i<^VFF5|lt8*( z?(xBAQXmUR5~bO-Vq6fLF`Y`LH0MpdMBd)-8`xm^q&I-Z&hV0j;s*2-$2d-uh3gf% zd_Bzp|EQa8q8i0|@jV25wp;vGLEZn6yH%s0_JE)#LRM1@_%7ys1 zJ`X7o#kSb7oHto5t*mX6Ixgmu`O;)*>CG}#d2nT6xxDgFk#wIFEDf$aNF? zqBF#I$3E}-X3RAl&zhq= z&VV!GpU6loC}0*Sq{nmkQMDw)z z$8p9QkqQrz;dVZP<)stK%doss%k7MPP}4VW5@c`lh3{Ryz?h|QWReWNX_i5zP7Z^8 za;W>8AFMC-2Pua4!4x0paRoqLlMjRi1;B2pFEpQxrNfqg#VlInTVWBe`02IC@7bl6 zzl3x@Tvsrs%^EkE2}qreaX=JI1L&XHb|NmC2`IpFD~qwh>p6Dp8Bt=~5Cw>P?KaE+ gs7BNw`loW6;*#ZcvjJX5w9anJPw^~N{Q8ggKja4-^Z)<= delta 1497 zcmZWpUvLve82|Qi7n&=i*FOnqTFNygX$UDzTJWKwlR!yJJG6l+qbPXQp&ldFBG5q} zB+OJteL-2liprEJLJ^#?gfazbQYk9Ts8k*p7=0*;v^8|h#o9gHU&UMVv0y&qut_O=bLZhUz|>(=H?JOFI6zxR^7z4cPYqg-#SSsm^5 z+(3M@6JRsNPG{84%tZWcl_7kRA#F+QGZgag(B&?Q&yskJVSmLBNp#c``Y2zN8S-5+ z{^xVMx@BW!w**Ai0`cKd@Ua09A;3T$^tb_P{n*7GV)B#tM|LlB-j7?j66B1&%hejH z5h;te)%06HI72Z=F-+t5XK?iea_*_rT+++db9HtJ5z9mSN1WJdD&i2C)DYfm%4No! zxWQD!A~K@kHj@Q8@mnU*hRBeHN=hVQV7fEaiDPNwVGaIg1Q)(%a#5nUH7xRTkPAP~ zr+8%zOKJ5D-kyUwiLHyH=@$$$?O7# zqqPpZqnC5dNO&^&&8-Y()-4W-Wked1cs#F~IXZ!>EG;aMH99_M@iFTrqL(cf5pv^0 zvlZly?zgogFOW@|7!n3j(U#pLjR(FohIHk));Jys0BK0crECa_f%I!QV3*CANpSx@ zY(0|M17uDTpR{k!0aC6BN7sf7w|FGVK-_d^L3oGSXV^GP{*)fi3N0QUlE3O*T$d{^ z8;51NlCDIwin>c`Ud6KU$O~tw1QNeLB16elfX*jamnvh2~2s4G?4+%#9o1FjFpW`M9`Q3n<3KrnG0fIK}#C1VWD4*?mP znqBLYjCUief{9Kr-tB0z`nO4al0O_NzS=zJdE?zTR|gXZ&A~(u1QW*$*5Z(A4lfSh z30tH@oI z!Hg@qvPH$bLk{hoFdZ>p$gf5p+i2N$O{5+t+J|Mn64Tn0tAY5bQ5qg-OFL;;goZbL z2z|7%WZnesceog70*^RE+%-Q^s4Fd}QxAHw6a;Y7bov^J?&oTCW$k^u#N!ckrRg-p zcg_W9rttZ3yJwKqm7!#`YC#TS-q&!0*UIeCaEn)(cP7a_xEfbg>YbcOe<4@Z4AEL~ zfzF!Jq~SljZl-+_=au!ibfrgS@5}_Q&bVS=ObF;oSHDCH`n7|8SQOVN4mj|yWw&!u zDXvVccBHoRD|E%J;*o`gjO54K!u8Be9j`C9`aVcCgJzS;9EE`TyPm%6|LMQ{t80oi zhEJ5Yx;16s6vVsIeWb@~HKmX0$EN9DP`%%e>wJ%N5Bdzp7ui^|zYriuv8n*z&g|&D qN(XCRMfC$kv`|#`7UA~F3jUf%%@n9OnyA*6L?g?)vW18L>AwI%N*xIR diff --git a/sdcard/baseband.bin b/sdcard/baseband.bin index ab19dc42d8862b65674f575fa305a3b8d9a2e020..7f9b8511d687d43282727ca37b7314cd379891a3 100644 GIT binary patch delta 70 zcmZo@VQOe$(h3OhRbXP6Qq8~+l$xBHS(aMF#Q*`H81?oadN-fXtdwtiyN2i9jatVV H1<(Zn{S_FB delta 70 zcmZo@VQOe$(h3OhRbXQHP|v^+l$xBHS(aMF#Q*{3EZ+k&(z+Ci7ktlL^k|FKMy+Fw H0_cJO5Cj?K