From 30531a20f2c2ec7025aaa16e7f0422da036c961a Mon Sep 17 00:00:00 2001 From: furrtek Date: Fri, 4 Sep 2015 20:37:27 +0200 Subject: [PATCH] Splash screen and Play Dead functionality --- firmware/application/Makefile | 1 + firmware/application/main.cpp | 14 +- firmware/application/splash.bmp | Bin 0 -> 12840 bytes firmware/application/splash.hpp | 1075 +++++++++++++++++ firmware/application/ui_afsksetup.cpp | 121 ++ firmware/application/ui_afsksetup.hpp | 93 ++ firmware/application/ui_debug.cpp | 71 +- firmware/application/ui_debug.hpp | 45 + firmware/application/ui_lcr.cpp | 226 ++-- firmware/application/ui_lcr.hpp | 34 +- firmware/application/ui_menu.cpp | 14 +- firmware/application/ui_menu.hpp | 1 + firmware/application/ui_navigation.cpp | 117 +- firmware/application/ui_navigation.hpp | 45 +- firmware/application/ui_setup.cpp | 55 +- firmware/application/ui_setup.hpp | 28 +- firmware/baseband/main.cpp | 33 +- firmware/common/lcd_ili9341.cpp | 5 + firmware/common/lcd_ili9341.hpp | 1 + firmware/common/message.hpp | 9 + .../common/portapack_persistent_memory.cpp | 56 +- .../common/portapack_persistent_memory.hpp | 18 +- firmware/common/portapack_shared_memory.hpp | 2 + firmware/common/ui_widget.cpp | 5 + firmware/common/ui_widget.hpp | 1 + 25 files changed, 1891 insertions(+), 179 deletions(-) create mode 100644 firmware/application/splash.bmp create mode 100644 firmware/application/splash.hpp create mode 100644 firmware/application/ui_afsksetup.cpp create mode 100644 firmware/application/ui_afsksetup.hpp diff --git a/firmware/application/Makefile b/firmware/application/Makefile index 0ad8b72c8..cf743a829 100755 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -162,6 +162,7 @@ CPPSRC = main.cpp \ ui_debug.cpp \ ui_rds.cpp \ ui_lcr.cpp \ + ui_afsksetup.cpp \ ui_console.cpp \ ui_receiver.cpp \ ui_spectrum.cpp \ diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index d1e477395..2a96c512e 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -475,6 +475,8 @@ message_handlers[Message::ID::TestResults] = [&system_view](const Message* const */ int main(void) { + ui::Context context; + portapack::init(); if( !cpld_update_if_necessary() ) { @@ -484,7 +486,7 @@ int main(void) { init_message_queues(); portapack::io.init(); - ui::Context context; + portapack::display.init(); sdcStart(&SDCD1, nullptr); @@ -503,13 +505,19 @@ int main(void) { { 0, 0, 240, 320 } }; ui::Painter painter; - EventDispatcher event_dispatcher { &system_view, painter, context }; - + context.message_map[Message::ID::FSKPacket] = [](const Message* const p) { const auto message = static_cast(p); (void)message; }; +context.message_map[Message::ID::TXDone] = [](const Message* const p) { + const auto message = static_cast(p); + (void)message; +}; + + EventDispatcher event_dispatcher { &system_view, painter, context }; + m4txevent_interrupt_enable(); m4_init(portapack::spi_flash::baseband, portapack::spi_flash::m4_text_ram_base); diff --git a/firmware/application/splash.bmp b/firmware/application/splash.bmp new file mode 100644 index 0000000000000000000000000000000000000000..be597b1664a7c708553b1650d0c0db97eaa5961e GIT binary patch literal 12840 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 +#include + +using namespace hackrf::one; + +namespace ui { + +void AFSKSetupView::focus() { + button_setfreq.focus(); +} + +void AFSKSetupView::paint(Painter& painter) { + +} + +void AFSKSetupView::updfreq(rf::Frequency f) { + char finalstr[9] = {0}; + + persistent_memory::set_tuned_frequency(f); + transmitter_model.set_tuning_frequency(f); + + auto mhz = to_string_dec_int(f / 1000000, 3); + auto hz100 = to_string_dec_int((f / 100) % 10000, 4, '0'); + + strcat(finalstr, mhz.c_str()); + strcat(finalstr, "."); + strcat(finalstr, hz100.c_str()); + + this->button_setfreq.set_text(finalstr); +} + +AFSKSetupView::AFSKSetupView( + NavigationView& nav, + TransmitterModel& transmitter_model +) : transmitter_model(transmitter_model) +{ + + add_children({ { + &text_title, + &button_setfreq, + &button_setbps, + &text_mark, + &field_mark, + &text_space, + &field_space, + &button_done + } }); + + updfreq(persistent_memory::tuned_frequency()); + + field_mark.set_value(persistent_memory::afsk_mark_freq()*100); + field_space.set_value(persistent_memory::afsk_space_freq()*100); + + button_setfreq.on_select = [this,&nav](Button&){ + auto new_view = new FrequencyKeypadView { nav, this->transmitter_model.tuning_frequency() }; + new_view->on_changed = [this](rf::Frequency f) { + updfreq(f); + }; + nav.push(new_view); + }; + + if (persistent_memory::afsk_bitrate() == 1200) { + button_setbps.set_text("1200 bps"); + } else { + button_setbps.set_text("2400 bps"); + } + + button_setbps.on_select = [this](Button&){ + if (persistent_memory::afsk_bitrate() == 1200) { + persistent_memory::set_afsk_bitrate(2400); + button_setbps.set_text("2400 bps"); + } else { + persistent_memory::set_afsk_bitrate(1200); + button_setbps.set_text("1200 bps"); + } + }; + + button_done.on_select = [this,&nav](Button&){ + persistent_memory::set_afsk_mark(field_mark.value()/100); + persistent_memory::set_afsk_space(field_space.value()/100); + nav.pop(); + }; +} + +} /* namespace ui */ diff --git a/firmware/application/ui_afsksetup.hpp b/firmware/application/ui_afsksetup.hpp new file mode 100644 index 000000000..c9f36b063 --- /dev/null +++ b/firmware/application/ui_afsksetup.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 "transmitter_model.hpp" + +namespace ui { + +class AFSKSetupView : public View { +public: + AFSKSetupView(NavigationView& nav, TransmitterModel& transmitter_model); + + void updfreq(rf::Frequency f); + void focus() override; + void paint(Painter& painter) override; + +private: + //rf::Frequency f = 162950000; + TransmitterModel& transmitter_model; + + Text text_title { + { 40, 32, 160, 16 }, + "AFSK modulator setup" + }; + + Button button_setfreq { + { 8, 64, 104, 32 }, + "---.----M" + }; + Button button_setbps { + { 128, 64, 96, 32 }, + "----bps" + }; + + Text text_mark { + { 16, 104, 48, 16 }, + "Mark: Hz" + }; + NumberField field_mark { + { 64, 104 }, + 5, + { 100, 32000 }, + 100, + ' ' + }; + + Text text_space { + { 16, 120, 48, 16 }, + "Space: Hz" + }; + NumberField field_space { + { 64, 120 }, + 5, + { 100, 32000 }, + 100, + ' ' + }; + + Button button_done { + { 72, 200, 96, 48 }, + "Save" + }; +}; + +} /* namespace ui */ diff --git a/firmware/application/ui_debug.cpp b/firmware/application/ui_debug.cpp index 56b024071..d917d4347 100644 --- a/firmware/application/ui_debug.cpp +++ b/firmware/application/ui_debug.cpp @@ -27,6 +27,7 @@ #include "led.hpp" #include "hackrf_gpio.hpp" #include "portapack.hpp" +#include "portapack_shared_memory.hpp" #include "radio.hpp" @@ -229,15 +230,71 @@ void DebugSDView::focus() { button_done.focus(); } +// LCR debug view + +void DebugLCRView::paint(Painter& painter) { + const Point offset = { + static_cast(32), + static_cast(32) + }; + + const auto text = to_string_hex(fr, 2); + painter.draw_string( + screen_pos() + offset, + style(), + text + ); +} + +char hexify(char in) { + if (in > 9) in += 7; + return in + 0x30; +} + +DebugLCRView::DebugLCRView(NavigationView& nav, char* lcrstring, uint8_t checksum) { + char cstr[15] = "Checksum: 0x "; + + add_children({ { + &text_lcr1, + &text_lcr2, + &text_lcr3, + &text_lcr4, + &text_lcr5, + &text_lcr6, + &text_checksum, + &button_done + } }); + + std::string b = std::string(lcrstring); + + text_lcr1.set(b.substr(8+(0*26),26)); + text_lcr2.set(b.substr(8+(1*26),26)); + text_lcr3.set(b.substr(8+(2*26),26)); + text_lcr4.set(b.substr(8+(3*26),26)); + text_lcr5.set(b.substr(8+(4*26),26)); + text_lcr6.set(b.substr(8+(5*26),26)); + + cstr[12] = hexify(checksum >> 4); + cstr[13] = hexify(checksum & 15); + + text_checksum.set(cstr); + + button_done.on_select = [&nav](Button&){ nav.pop(); }; +} + +void DebugLCRView::focus() { + button_done.focus(); +} + DebugMenuView::DebugMenuView(NavigationView& nav) { add_items<7>({ { - { "Memory", [&nav](){ nav.push(new DebugMemoryView { nav }); } }, - { "Radio State", [&nav](){ nav.push(new NotImplementedView { nav }); } }, - { "SD Card", [&nav](){ nav.push(new DebugSDView { nav }); } }, - { "RFFC5072", [&nav](){ nav.push(new DebugRFFC5072View { nav }); } }, - { "MAX2837", [&nav](){ nav.push(new NotImplementedView { nav }); } }, - { "Si5351C", [&nav](){ nav.push(new NotImplementedView { nav }); } }, - { "WM8731", [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "Memory", ui::Color::white(), [&nav](){ nav.push(new DebugMemoryView { nav }); } }, + { "Radio State", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "SD Card", ui::Color::white(), [&nav](){ nav.push(new DebugSDView { nav }); } }, + { "RFFC5072", ui::Color::white(), [&nav](){ nav.push(new DebugRFFC5072View { nav }); } }, + { "MAX2837", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "Si5351C", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "WM8731", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, } }); on_left = [&nav](){ nav.pop(); }; } diff --git a/firmware/application/ui_debug.hpp b/firmware/application/ui_debug.hpp index ec976313b..b85fb7a18 100644 --- a/firmware/application/ui_debug.hpp +++ b/firmware/application/ui_debug.hpp @@ -188,6 +188,51 @@ private: }; }; +class DebugLCRView : public View { +public: + DebugLCRView(NavigationView& nav, char* lcrstring, uint8_t checksum); + + void focus() override; + + void paint(Painter& painter) override; + +private: + Text text_lcr1 { + { 16, 32, 208, 8 }, + "" + }; + Text text_lcr2 { + { 16, 32+16, 208, 8 }, + "" + }; + Text text_lcr3 { + { 16, 32+16+16, 208, 8 }, + "" + }; + Text text_lcr4 { + { 16, 32+16+16+16, 208, 8 }, + "" + }; + Text text_lcr5 { + { 16, 32+16+16+16+16, 208, 8 }, + "" + }; + Text text_lcr6 { + { 16, 32+16+16+16+16+16, 208, 8 }, + "" + }; + + Text text_checksum { + { 16, 32+16+16+16+16+16+32, 208, 8 }, + "" + }; + + Button button_done { + { 72, 240, 96, 24 }, + "Done" + }; +}; + class DebugMenuView : public MenuView { public: DebugMenuView(NavigationView& nav); diff --git a/firmware/application/ui_lcr.cpp b/firmware/application/ui_lcr.cpp index ec65f5faf..4b89f6e91 100644 --- a/firmware/application/ui_lcr.cpp +++ b/firmware/application/ui_lcr.cpp @@ -22,6 +22,8 @@ #include "ui_rds.hpp" #include "ui_lcr.hpp" #include "ui_receiver.hpp" +#include "ui_afsksetup.hpp" +#include "ui_debug.hpp" #include "ch.h" @@ -37,6 +39,12 @@ #include #include +//TODO: Repeats +//TODO: Shared memory semaphore for doing/done +//TODO: Scan +//TODO: Text showing status in LCRView +//TODO: Checkboxes for AMs + using namespace hackrf::one; namespace ui { @@ -49,18 +57,70 @@ LCRView::~LCRView() { transmitter_model.disable(); } -char hexify(char in) { - if (in > 9) in += 7; - return in + 0x30; -} - -void LCRView::paint(Painter& painter) { +void LCRView::make_frame() { char eom[3] = { 3, 0, 0 }; - uint8_t checksum = 0, i; - char teststr[16]; + uint8_t i; uint16_t dp; uint8_t cp, pp, cur_byte, new_byte; + // Testing: 7 char pad for litterals + for (i = 0; i < 5; i++) { + while (strlen(litteral[i]) < 7) { + strcat(litteral[i], " "); + } + } + + // Recreate LCR frame + memset(lcrframe, 0, 256); + lcrframe[0] = 127; + lcrframe[1] = 127; + lcrframe[2] = 127; + lcrframe[3] = 127; + lcrframe[4] = 127; + lcrframe[5] = 127; + lcrframe[6] = 127; + lcrframe[7] = 15; + strcat(lcrframe, rgsb); + strcat(lcrframe, "PA AM=1 AF=\""); + strcat(lcrframe, litteral[0]); + strcat(lcrframe, "\" CL=0 AM=2 AF=\""); + strcat(lcrframe, litteral[1]); + strcat(lcrframe, "\" CL=0 AM=3 AF=\""); + strcat(lcrframe, litteral[2]); + strcat(lcrframe, "\" CL=0 AM=4 AF=\""); + strcat(lcrframe, litteral[3]); + strcat(lcrframe, "\" CL=0 AM=5 AF=\""); + strcat(lcrframe, litteral[4]); + strcat(lcrframe, "\" CL=0 EC=A SAB=0"); //TODO: EC=A,J,N + + memcpy(lcrstring, lcrframe, 256); + + //Checksum + checksum = 0; + i = 7; + while (lcrframe[i]) { + checksum ^= lcrframe[i]; + i++; + } + checksum ^= 3; + checksum &= 0x7F; + eom[1] = checksum; + + strcat(lcrframe, eom); + + for (dp=0;dp>cp)&1) pp++; + new_byte |= ((cur_byte>>cp)&1)<<(7-cp); + } + lcrframe_f[dp] = new_byte|(pp&1); + } +} + +void LCRView::paint(Painter& painter) { static constexpr Style style_orange { .font = font::fixed_8x16, .background = Color::black(), @@ -102,108 +162,65 @@ void LCRView::paint(Painter& painter) { litteral[3] ); - // Testing: 7 char pad for litterals - for (i = 0; i < 4; i++) { - while (strlen(litteral[i]) < 7) { - strcat(litteral[i], " "); - } - } + offset.y += 40; - // Recreate LCR frame - memset(lcrframe, 0, 256); - lcrframe[0] = 127; - lcrframe[1] = 127; - lcrframe[2] = 127; - lcrframe[3] = 127; - lcrframe[4] = 127; - lcrframe[5] = 127; - lcrframe[6] = 127; - lcrframe[7] = 15; - strcat(lcrframe, rgsb); - strcat(lcrframe, "PA AM=1 AF=\""); - strcat(lcrframe, litteral[0]); - strcat(lcrframe, "\" CL=0 AM=2 AF=\""); - strcat(lcrframe, litteral[1]); - strcat(lcrframe, "\" CL=0 AM=3 AF=\""); - strcat(lcrframe, litteral[2]); - strcat(lcrframe, "\" CL=0 AM=4 AF=\""); - strcat(lcrframe, litteral[3]); - strcat(lcrframe, "\" CL=0 EC=A SAB=0"); //TODO: EC=A,J,N - - //Checksum - i = 7; - while (lcrframe[i]) { - checksum ^= lcrframe[i]; - i++; - } - checksum ^= 3; - checksum &= 0x7F; - eom[1] = checksum; - - strcat(lcrframe, eom); - - for (dp=0;dp>cp)&1) pp++; - new_byte |= ((cur_byte>>cp)&1)<<(7-cp); - } - lcrframe[dp] = new_byte|(pp&1); - } - - teststr[0] = hexify(eom[1] >> 4); - teststr[1] = hexify(eom[1] & 15); - teststr[2] = 0; - offset.x = 220; painter.draw_string( screen_pos() + offset, - style(), - teststr + style_orange, + litteral[4] ); } -void LCRView::updfreq(rf::Frequency f) { - char finalstr[9] = {0}; - transmitter_model.set_tuning_frequency(f); - - auto mhz = to_string_dec_int(f / 1000000, 3); - auto hz100 = to_string_dec_int((f / 100) % 10000, 4, '0'); - - strcat(finalstr, mhz.c_str()); - strcat(finalstr, "."); - strcat(finalstr, hz100.c_str()); - - this->button_setfreq.set_text(finalstr); -} - LCRView::LCRView( NavigationView& nav, TransmitterModel& transmitter_model ) : transmitter_model(transmitter_model) { + char finalstr[24] = {0}; + + static constexpr Style style_val { + .font = font::fixed_8x16, + .background = Color::green(), + .foreground = Color::black(), + }; + transmitter_model.set_modulation(16); - transmitter_model.set_tuning_frequency(f); - memset(litteral, 0, 4*8); + transmitter_model.set_tuning_frequency(persistent_memory::tuned_frequency()); + memset(litteral, 0, 5*8); memset(rgsb, 0, 5); strcpy(rgsb, RGSB_list[0]); add_children({ { + &text_recap, &button_setrgsb, &button_txsetup, &button_setam_a, &button_setam_b, &button_setam_c, &button_setam_d, - &button_setfreq, - &button_setbps, + &button_setam_e, + &text_status, + &button_lcrdebug, &button_transmit, &button_transmit_scan, &button_exit } }); + // Recap: tx freq @ bps + auto fstr = to_string_dec_int(persistent_memory::tuned_frequency() / 1000, 6); + auto bstr = to_string_dec_int(persistent_memory::afsk_bitrate(), 4); + + strcat(finalstr, fstr.c_str()); + strcat(finalstr, " @ "); + strcat(finalstr, bstr.c_str()); + strcat(finalstr, "bps"); + + text_recap.set(finalstr); + + button_transmit.set_style(&style_val); + button_transmit_scan.set_style(&style_val); + button_setrgsb.on_select = [this,&nav](Button&){ auto an_view = new AlphanumView { nav, rgsb, 4 }; an_view->on_changed = [this](char *rgsb) { @@ -211,13 +228,6 @@ LCRView::LCRView( }; nav.push(an_view); }; - button_setfreq.on_select = [this,&nav](Button&){ - auto new_view = new FrequencyKeypadView { nav, this->transmitter_model.tuning_frequency() }; - new_view->on_changed = [this](rf::Frequency f) { - updfreq(f); - }; - nav.push(new_view); - }; button_setam_a.on_select = [this,&nav](Button&){ auto an_view = new AlphanumView { nav, litteral[0], 7 }; @@ -239,28 +249,46 @@ LCRView::LCRView( an_view->on_changed = [this](char *) {}; nav.push(an_view); }; - button_setbps.on_select = [this](Button&){ - if (persistent_memory::afsk_bitrate() == 1200) { - persistent_memory::set_afsk_bitrate(2400); - button_setbps.set_text("2400 bps"); - } else { - persistent_memory::set_afsk_bitrate(1200); - button_setbps.set_text("1200 bps"); - } + button_setam_e.on_select = [this,&nav](Button&){ + auto an_view = new AlphanumView { nav, litteral[4], 7 }; + an_view->on_changed = [this](char *) {}; + nav.push(an_view); + }; + + button_lcrdebug.on_select = [this,&nav](Button&){ + make_frame(); + nav.push(new DebugLCRView { nav, lcrstring, checksum }); }; button_transmit.on_select = [this,&transmitter_model](Button&){ uint16_t c; + ui::Context context; + + make_frame(); shared_memory.afsk_samples_per_bit = 228000/persistent_memory::afsk_bitrate(); - shared_memory.afsk_phase_inc_mark = persistent_memory::afsk_mark_freq()*(65536*1024)/228000; - shared_memory.afsk_phase_inc_space = persistent_memory::afsk_space_freq()*(65536*1024)/228000; + shared_memory.afsk_phase_inc_mark = persistent_memory::afsk_mark_freq()*(65536*1024)/2280; + shared_memory.afsk_phase_inc_space = persistent_memory::afsk_space_freq()*(65536*1024)/2280; for (c = 0; c < 256; c++) { shared_memory.lcrdata[c] = this->lcrframe[c]; } + + shared_memory.afsk_transmit_done = false; + shared_memory.afsk_repeat = 5; // DEFAULT + + /*context.message_map[Message::ID::TXDone] = [this](const Message* const p) { + text_status.set("Sent ! "); + };*/ + + text_status.set("Send..."); + transmitter_model.enable(); }; + + button_txsetup.on_select = [&nav, &transmitter_model](Button&){ + nav.push(new AFSKSetupView { nav, transmitter_model }); + }; button_exit.on_select = [&nav](Button&){ nav.pop(); diff --git a/firmware/application/ui_lcr.hpp b/firmware/application/ui_lcr.hpp index 3e7e320fe..85b26b6b9 100644 --- a/firmware/application/ui_lcr.hpp +++ b/firmware/application/ui_lcr.hpp @@ -39,7 +39,7 @@ public: LCRView(NavigationView& nav, TransmitterModel& transmitter_model); ~LCRView(); - void updfreq(rf::Frequency f); + void make_frame(); void focus() override; void paint(Painter& painter) override; @@ -56,12 +56,25 @@ private: "AJ40", "AJ50", "AJ60", "AJ70", "AK10" }; - char litteral[4][8]; + char litteral[5][8]; char rgsb[5]; + char lcrstring[256]; + char checksum = 0; char lcrframe[256]; + char lcrframe_f[256]; rf::Frequency f = 162950000; TransmitterModel& transmitter_model; + Text text_status { + { 136, 128, 64, 16 }, + "Ready" + }; + + Text text_recap { + { 32, 6, 192, 16 }, + "-" + }; + Button button_setrgsb { { 16, 24, 96, 32 }, "Set RGSB" @@ -91,21 +104,22 @@ private: "AM 4" }; - Button button_setfreq { - { 8, 232, 96, 32 }, - "162.9500" + Button button_setam_e { + { 16, 64+40+40+40+40, 48, 32 }, + "AM 5" }; - Button button_setbps { - { 128, 232, 96, 32 }, - "1200bps" + + Button button_lcrdebug { + { 152, 224, 64, 32 }, + "DEBUG" }; Button button_transmit { - { 8, 270, 48, 32 }, + { 24, 270, 48, 32 }, "TX" }; Button button_transmit_scan { - { 60, 270, 64, 32 }, + { 76, 270, 72, 32 }, "SCAN TX" }; Button button_exit { diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 45468c2de..0924f0169 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -50,10 +50,20 @@ void MenuItemView::paint(Painter& painter) { r, paint_style.background ); - + + ui::Color final_item_color = item.color; + + if (final_item_color.v == paint_style.background.v) final_item_color = paint_style.foreground; + + Style text_style { + .font = paint_style.font, + .background = paint_style.background, + .foreground = final_item_color + }; + painter.draw_string( { static_cast(r.pos.x + 8), static_cast(r.pos.y + (r.size.h - font_height) / 2) }, - paint_style, + text_style, item.text ); } diff --git a/firmware/application/ui_menu.hpp b/firmware/application/ui_menu.hpp index 5863e0485..c52f2c3a3 100644 --- a/firmware/application/ui_menu.hpp +++ b/firmware/application/ui_menu.hpp @@ -34,6 +34,7 @@ namespace ui { struct MenuItem { std::string text; + ui::Color color; std::function on_select; }; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index aecf7eca6..d97901b27 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -23,6 +23,9 @@ #include "receiver_model.hpp" #include "transmitter_model.hpp" +#include "portapack_persistent_memory.hpp" + +#include "splash.hpp" #include "ui_setup.hpp" #include "ui_debug.hpp" @@ -98,16 +101,17 @@ void NavigationView::focus() { /* SystemMenuView ********************************************************/ SystemMenuView::SystemMenuView(NavigationView& nav) { - add_items<9>({ { - { "Receiver", [&nav](){ nav.push(new ReceiverView { nav, receiver_model }); } }, - { "Capture", [&nav](){ nav.push(new NotImplementedView { nav }); } }, - { "Analyze", [&nav](){ nav.push(new NotImplementedView { nav }); } }, - { "RDS TX", [&nav](){ nav.push(new RDSView { nav, transmitter_model }); } }, - { "LCR TX", [&nav](){ nav.push(new LCRView { nav, transmitter_model }); } }, - { "Setup", [&nav](){ nav.push(new SetupMenuView { nav }); } }, - { "About", [&nav](){ nav.push(new AboutView { nav }); } }, - { "Debug", [&nav](){ nav.push(new DebugMenuView { nav }); } }, - { "HackRF", [&nav](){ nav.push(new HackRFFirmwareView { nav }); } }, + add_items<10>({ { + { "Play dead", ui::Color::red(), [&nav](){ nav.push(new PlayDeadView { nav }); } }, + { "Receiver", ui::Color::white(), [&nav](){ nav.push(new ReceiverView { nav, receiver_model }); } }, + { "Capture", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "Analyze", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, + { "RDS TX", ui::Color::orange(), [&nav](){ nav.push(new RDSView { nav, transmitter_model }); } }, + { "LCR TX", ui::Color::orange(), [&nav](){ nav.push(new LCRView { nav, transmitter_model }); } }, + { "Setup", ui::Color::white(), [&nav](){ nav.push(new SetupMenuView { nav }); } }, + { "About", ui::Color::white(), [&nav](){ nav.push(new AboutView { nav }); } }, + { "Debug", ui::Color::white(), [&nav](){ nav.push(new DebugMenuView { nav }); } }, + { "HackRF", ui::Color::white(), [&nav](){ nav.push(new HackRFFirmwareView { nav }); } }, } }); } @@ -143,13 +147,104 @@ SystemView::SystemView( // Initial view. // TODO: Restore from non-volatile memory? - navigation_view.push(new SystemMenuView { navigation_view }); + navigation_view.push(new BMPView { navigation_view }); //SystemMenuView } Context& SystemView::context() const { return context_; } +/* ***********************************************************************/ + +void BMPView::focus() { + button_done.focus(); +} + +BMPView::BMPView(NavigationView& nav) { + add_children({ { + &text_info, + &button_done + } }); + + button_done.on_select = [this,&nav](Button&){ + nav.pop(); + nav.push(new SystemMenuView { nav }); + }; +} + +void BMPView::paint(Painter& painter) { + uint32_t pixel_data; + uint8_t p, by, c, count; + ui::Color linebuffer[185]; + ui::Coord px = 0, py = 302; + ui::Color palette[16]; + + // RLE_4 BMP loader with hardcoded size and no delta :( + + pixel_data = splash_bmp[0x0A]; + p = 0; + for (c = 0x36; c < (0x36+(16*4)); c+=4) { + palette[p++] = ui::Color(splash_bmp[c+2], splash_bmp[c+1], splash_bmp[c]); + } + + do { + by = splash_bmp[pixel_data++]; + if (by) { + count = by; + by = splash_bmp[pixel_data++]; + for (c = 0; c < count; c+=2) { + linebuffer[px++] = palette[by >> 4]; + if (px < 185) linebuffer[px++] = palette[by & 15]; + } + if (pixel_data & 1) pixel_data++; + } else { + by = splash_bmp[pixel_data++]; + if (by == 0) { + portapack::display.render_line({27, py}, 185, linebuffer); + py--; + px = 0; + } else if (by == 1) { + break; + } else if (by == 2) { + // Delta + } else { + count = by; + for (c = 0; c < count; c+=2) { + by = splash_bmp[pixel_data++]; + linebuffer[px++] = palette[by >> 4]; + if (px < 185) linebuffer[px++] = palette[by & 15]; + } + if (pixel_data & 1) pixel_data++; + } + } + } while (1); +} + +/* PlayDeadView **********************************************************/ + +void PlayDeadView::focus() { + button_done.focus(); +} + +PlayDeadView::PlayDeadView(NavigationView& nav) { + add_children({ { + &text_playdead1, + &text_playdead2, + &button_done, + } }); + + button_done.on_dir = [this,&nav](Button&, KeyEvent key){ + sequence = (sequence<<3) | static_cast::type>(key); + }; + + button_done.on_select = [this,&nav](Button&){ + if (sequence == persistent_memory::playdead_sequence()) + nav.pop(); + else + sequence = 0; + }; +} + /* HackRFFirmwareView ****************************************************/ HackRFFirmwareView::HackRFFirmwareView(NavigationView& nav) { diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index ee816a042..3dcbb4749 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -41,8 +41,8 @@ public: private: Text portapack { - { 0, 0, 9 * 8, 1 * 16 }, - "PortaPack", + { 0, 0, 15 * 8, 1 * 16 }, + "PortaPack/HAVOC" }; }; @@ -70,6 +70,25 @@ public: SystemMenuView(NavigationView& nav); }; +class BMPView : public View { +public: + BMPView(NavigationView& nav); + void paint(Painter& painter) override; + void focus() override; + +private: + Text text_info { + { 5 * 8, 284, 20 * 8, 16 }, + "shrbrnd-sig-ftk 2015" + }; + + Button button_done { + { 240, 0, 1, 1 }, + "" + }; +}; + + class SystemView : public View { public: SystemView( @@ -85,6 +104,28 @@ private: Context& context_; }; +class PlayDeadView : public View { +public: + PlayDeadView(NavigationView& nav); + void focus() override; + +private: + uint32_t sequence = 0; + Text text_playdead1 { + { 6 * 8, 7 * 16, 14 * 8, 16 }, + "Firmware error" + }; + Text text_playdead2 { + { 6 * 8, 9 * 16, 16 * 8, 16 }, + "0x1400_0000 : 2C" + }; + + Button button_done { + { 240, 0, 1, 1 }, + "" + }; +}; + class HackRFFirmwareView : public View { public: HackRFFirmwareView(NavigationView& nav); diff --git a/firmware/application/ui_setup.cpp b/firmware/application/ui_setup.cpp index 08b29272c..003697bb9 100644 --- a/firmware/application/ui_setup.cpp +++ b/firmware/application/ui_setup.cpp @@ -26,8 +26,10 @@ #include "lpc43xx_cpp.hpp" #include +#include using namespace lpc43xx; +using namespace portapack; namespace ui { @@ -184,11 +186,56 @@ bool SetTouchCalibView::on_touch(const TouchEvent event) { return true; } +SetPlayDeadView::SetPlayDeadView(NavigationView& nav) { + add_children({{ + &text_sequence, + &button_enter, + &button_cancel + }}); + + button_enter.on_select = [this,&nav](Button&){ + if (entermode == false) { + sequence = 0; + memset(sequence_txt,0,11); + text_sequence.set(""); + keycount = 0; + entermode = true; + button_cancel.hidden(true); + } else { + persistent_memory::set_playdead_sequence(sequence); + nav.pop(); + } + }; + button_enter.on_dir = [this,&nav](Button&, KeyEvent key){ + if ((entermode == true) && (keycount < 10)) { + key_code = static_cast::type>(key); + if (key_code == 0) + sequence_txt[keycount] = 'R'; + else if (key_code == 1) + sequence_txt[keycount] = 'L'; + else if (key_code == 2) + sequence_txt[keycount] = 'D'; + else if (key_code == 3) + sequence_txt[keycount] = 'U'; + text_sequence.set(sequence_txt); + sequence = (sequence<<3) | key_code; + keycount++; + + } + }; + button_cancel.on_select = [&nav](Button&){ nav.pop(); }; +} + +void SetPlayDeadView::focus() { + button_enter.focus(); +} + SetupMenuView::SetupMenuView(NavigationView& nav) { - add_items<3>({ { - { "Date/Time", [&nav](){ nav.push(new SetDateTimeView { nav }); } }, - { "Frequency Correction", [&nav](){ nav.push(new SetFrequencyCorrectionView { nav }); } }, - { "Touch", [&nav](){ nav.push(new SetTouchCalibView { nav }); } }, + add_items<4>({ { + { "Date/Time", ui::Color::white(), [&nav](){ nav.push(new SetDateTimeView { nav }); } }, + { "Frequency correction", ui::Color::white(), [&nav](){ nav.push(new SetFrequencyCorrectionView { nav }); } }, + { "Touch", ui::Color::white(), [&nav](){ nav.push(new SetTouchCalibView { nav }); } }, + { "Play dead", ui::Color::white(), [&nav](){ nav.push(new SetPlayDeadView { nav }); } }, } }); on_left = [&nav](){ nav.pop(); }; } diff --git a/firmware/application/ui_setup.hpp b/firmware/application/ui_setup.hpp index fd8370f75..21bee9a17 100644 --- a/firmware/application/ui_setup.hpp +++ b/firmware/application/ui_setup.hpp @@ -25,6 +25,7 @@ #include "ui_widget.hpp" #include "ui_menu.hpp" #include "ui_navigation.hpp" +#include "portapack_persistent_memory.hpp" #include @@ -190,7 +191,7 @@ private: Text text_firmware { { 0, 128, 240, 16 }, - "Firmware Version git-??????", + "Firmware Version HAVOC 0.10", }; Text text_cpld_hackrf { @@ -237,6 +238,31 @@ private: }; }; +class SetPlayDeadView : public View { +public: + SetPlayDeadView(NavigationView& nav); + void focus() override; +private: + bool entermode = false; + uint32_t sequence = 0; + uint8_t keycount, key_code; + char sequence_txt[11]; + + Text text_sequence { + { 64, 32, 14 * 8, 16 }, + "Enter sequence", + }; + + Button button_enter { + { 16, 192, 96, 24 }, + "Enter" + }; + Button button_cancel { + { 128, 192, 96, 24 }, + "Cancel" + }; +}; + class SetupMenuView : public MenuView { public: SetupMenuView(NavigationView& nav); diff --git a/firmware/baseband/main.cpp b/firmware/baseband/main.cpp index a1e626199..c1e6f2759 100755 --- a/firmware/baseband/main.cpp +++ b/firmware/baseband/main.cpp @@ -762,12 +762,6 @@ private: class LCRFSKProcessor : public BasebandProcessor { public: - void BasebandProcessor() { - afsk_samples_per_bit = shared_memory.afsk_samples_per_bit; - phase_inc_mark = shared_memory.afsk_phase_inc_mark; - phase_inc_space = shared_memory.afsk_phase_inc_space; - } - void execute(buffer_c8_t buffer) override { for (size_t i = 0; i= 9) { s = 0; - if (sample_count >= afsk_samples_per_bit) { - cur_byte = shared_memory.lcrdata[byte_pos]; + if (sample_count >= shared_memory.afsk_samples_per_bit) { + if (shared_memory.afsk_transmit_done == false) + cur_byte = shared_memory.lcrdata[byte_pos]; if (!cur_byte) { - bit_pos = 0; - byte_pos = 0; - cur_byte = shared_memory.lcrdata[0]; + if (shared_memory.afsk_repeat) { + shared_memory.afsk_repeat--; + bit_pos = 0; + byte_pos = 0; + cur_byte = shared_memory.lcrdata[0]; + } else { + shared_memory.afsk_transmit_done = true; // TODO: Remove, unused + //shared_memory.application_queue.push(&message); + cur_byte = 0; + } } - cur_byte = (0x55<<1); //DEBUG + //cur_byte = (0x55<<1); //DEBUG //SdddddddpD //0dddddddp1 @@ -808,9 +810,9 @@ public: sample_count++; } if (cur_bit) - aphase += phase_inc_mark; //(353205) + aphase += shared_memory.afsk_phase_inc_mark; //(353205) else - aphase += phase_inc_space; //(647542) + aphase += shared_memory.afsk_phase_inc_space; //(647542) sample = sintab[(aphase & 0x03FF0000)>>16]; } else { @@ -833,8 +835,6 @@ public: } private: - uint32_t afsk_samples_per_bit; - uint32_t phase_inc_mark, phase_inc_space; int8_t re, im; uint8_t s; uint8_t bit_pos, byte_pos; @@ -844,6 +844,7 @@ private: uint32_t sample_count; uint32_t aphase, phase, sphase; int32_t sample, sig, frq; + TXDoneMessage message; }; static BasebandProcessor* baseband_processor { nullptr }; diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index a470d4173..6d916e9af 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -241,6 +241,11 @@ void ILI9341::fill_rectangle(ui::Rect r, const ui::Color c) { } } +void ILI9341::render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer) { + lcd_start_ram_write(p, { count, 1 }); + io.lcd_write_pixels(line_buffer, count); +} + void ILI9341::draw_line(const ui::Point start, const ui::Point end, const ui::Color color) { int x0 = start.x; int y0 = start.y; diff --git a/firmware/common/lcd_ili9341.hpp b/firmware/common/lcd_ili9341.hpp index 415dbd533..ebabc8620 100644 --- a/firmware/common/lcd_ili9341.hpp +++ b/firmware/common/lcd_ili9341.hpp @@ -54,6 +54,7 @@ public: ); void draw_pixel(const ui::Point p, const ui::Color color); + void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer); template void draw_pixels( diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 2910f80ec..0cad72be1 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -42,6 +42,7 @@ public: FSKConfiguration = 6, FSKPacket = 7, TestResults = 8, + TXDone = 9, MAX }; @@ -251,6 +252,14 @@ public: FSKPacket packet; }; +class TXDoneMessage : public Message { +public: + TXDoneMessage( + ) : Message { ID::TXDone } + { + } +}; + class MessageHandlerMap { public: using MessageHandler = std::function; diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 06f01177b..4c133cecd 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -55,14 +55,14 @@ using ppb_range_t = range_t; constexpr ppb_range_t ppb_range { -99000, 99000 }; constexpr ppb_t ppb_reset_value { 0 }; -using afsk_freq_range_t = range_t; -constexpr afsk_freq_range_t afsk_freq_range { 100, 32000 }; -constexpr int16_t afsk_mark_reset_value { 1200 }; -constexpr int16_t afsk_space_reset_value { 2200 }; +using afsk_freq_range_t = range_t; +constexpr afsk_freq_range_t afsk_freq_range { 1, 60 }; +constexpr int32_t afsk_mark_reset_value { 12 }; +constexpr int32_t afsk_space_reset_value { 22 }; -using afsk_bitrate_range_t = range_t; +using afsk_bitrate_range_t = range_t; constexpr afsk_bitrate_range_t afsk_bitrate_range { 600, 9600 }; -constexpr int16_t afsk_bitrate_reset_value { 1200 }; +constexpr int32_t afsk_bitrate_reset_value { 1200 }; /* struct must pack the same way on M4 and M0 cores. */ struct data_t { @@ -71,10 +71,14 @@ struct data_t { int32_t correction_ppb; // AFSK modem - int16_t afsk_mark_freq; - int16_t afsk_space_freq; - int16_t afsk_bitrate; + int32_t afsk_mark_freq; + int32_t afsk_space_freq; + int32_t afsk_bitrate; uint8_t afsk_config; + + // Play dead unlock + bool playing_dead; + uint32_t playdead_sequence; }; static_assert(sizeof(data_t) <= 0x100, "Persistent memory structure too large for VBAT-maintained region"); @@ -99,30 +103,30 @@ void set_correction_ppb(const ppb_t new_value) { data->correction_ppb = ppb_range.clip(new_value); } -int16_t afsk_mark_freq() { +int32_t afsk_mark_freq() { afsk_freq_range.reset_if_outside(data->afsk_mark_freq, afsk_mark_reset_value); - return data->correction_ppb; + return data->afsk_mark_freq; } -void set_afsk_mark(const int16_t new_value) { +void set_afsk_mark(const int32_t new_value) { data->afsk_mark_freq = afsk_freq_range.clip(new_value); } -int16_t afsk_space_freq() { +int32_t afsk_space_freq() { afsk_freq_range.reset_if_outside(data->afsk_space_freq, afsk_space_reset_value); - return data->correction_ppb; + return data->afsk_space_freq; } -void set_afsk_space(const int16_t new_value) { +void set_afsk_space(const int32_t new_value) { data->afsk_space_freq = afsk_freq_range.clip(new_value); } -int16_t afsk_bitrate() { +int32_t afsk_bitrate() { afsk_bitrate_range.reset_if_outside(data->afsk_bitrate, afsk_bitrate_reset_value); - return data->correction_ppb; + return data->afsk_bitrate; } -void set_afsk_bitrate(const int16_t new_value) { +void set_afsk_bitrate(const int32_t new_value) { data->afsk_bitrate = afsk_bitrate_range.clip(new_value); } @@ -134,5 +138,21 @@ void set_afsk_config(const uint8_t new_value) { data->afsk_config = new_value; } +bool playing_dead() { + return data->playing_dead; +} + +void set_playing_dead(const bool new_value) { + data->playing_dead = new_value; +} + +uint32_t playdead_sequence() { + return data->playdead_sequence; +} + +void set_playdead_sequence(const uint32_t new_value) { + data->playdead_sequence = new_value; +} + } /* namespace persistent_memory */ } /* namespace portapack */ diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 947947cc6..08aabe06e 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -37,18 +37,24 @@ void set_tuned_frequency(const rf::Frequency new_value); ppb_t correction_ppb(); void set_correction_ppb(const ppb_t new_value); -int16_t afsk_mark_freq(); -void set_afsk_mark(const int16_t new_value); +int32_t afsk_mark_freq(); +void set_afsk_mark(const int32_t new_value); -int16_t afsk_space_freq(); -void set_afsk_space(const int16_t new_value); +int32_t afsk_space_freq(); +void set_afsk_space(const int32_t new_value); -int16_t afsk_bitrate(); -void set_afsk_bitrate(const int16_t new_value); +int32_t afsk_bitrate(); +void set_afsk_bitrate(const int32_t new_value); uint8_t afsk_config(); void set_afsk_config(const uint8_t new_value); +bool playing_dead(); +void set_playing_dead(const bool new_value); + +uint32_t playdead_sequence(); +void set_playdead_sequence(const uint32_t new_value); + } /* namespace persistent_memory */ } /* namespace portapack */ diff --git a/firmware/common/portapack_shared_memory.hpp b/firmware/common/portapack_shared_memory.hpp index 289cbf30a..1d387f136 100644 --- a/firmware/common/portapack_shared_memory.hpp +++ b/firmware/common/portapack_shared_memory.hpp @@ -47,6 +47,8 @@ struct SharedMemory { uint32_t afsk_samples_per_bit; uint32_t afsk_phase_inc_mark; uint32_t afsk_phase_inc_space; + uint8_t afsk_repeat; + bool afsk_transmit_done; }; extern SharedMemory& shared_memory; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 83b7e7055..a193e9a19 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -401,6 +401,11 @@ bool Button::on_key(const KeyEvent key) { on_select(*this); return true; } + } else { + if( on_dir ) { + on_dir(*this, key); + return false; + } } return false; diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index c5293cdb3..341aa0c8e 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -212,6 +212,7 @@ private: class Button : public Widget { public: std::function on_select; + std::function on_dir; Button( Rect parent_rect,