Splash screen and Play Dead functionality

This commit is contained in:
furrtek 2015-09-04 20:37:27 +02:00
parent ec26f587f1
commit 30531a20f2
25 changed files with 1891 additions and 179 deletions

View File

@ -162,6 +162,7 @@ CPPSRC = main.cpp \
ui_debug.cpp \ ui_debug.cpp \
ui_rds.cpp \ ui_rds.cpp \
ui_lcr.cpp \ ui_lcr.cpp \
ui_afsksetup.cpp \
ui_console.cpp \ ui_console.cpp \
ui_receiver.cpp \ ui_receiver.cpp \
ui_spectrum.cpp \ ui_spectrum.cpp \

View File

@ -475,6 +475,8 @@ message_handlers[Message::ID::TestResults] = [&system_view](const Message* const
*/ */
int main(void) { int main(void) {
ui::Context context;
portapack::init(); portapack::init();
if( !cpld_update_if_necessary() ) { if( !cpld_update_if_necessary() ) {
@ -484,7 +486,7 @@ int main(void) {
init_message_queues(); init_message_queues();
portapack::io.init(); portapack::io.init();
ui::Context context;
portapack::display.init(); portapack::display.init();
sdcStart(&SDCD1, nullptr); sdcStart(&SDCD1, nullptr);
@ -503,13 +505,19 @@ int main(void) {
{ 0, 0, 240, 320 } { 0, 0, 240, 320 }
}; };
ui::Painter painter; ui::Painter painter;
EventDispatcher event_dispatcher { &system_view, painter, context };
context.message_map[Message::ID::FSKPacket] = [](const Message* const p) { context.message_map[Message::ID::FSKPacket] = [](const Message* const p) {
const auto message = static_cast<const FSKPacketMessage*>(p); const auto message = static_cast<const FSKPacketMessage*>(p);
(void)message; (void)message;
}; };
context.message_map[Message::ID::TXDone] = [](const Message* const p) {
const auto message = static_cast<const TXDoneMessage*>(p);
(void)message;
};
EventDispatcher event_dispatcher { &system_view, painter, context };
m4txevent_interrupt_enable(); m4txevent_interrupt_enable();
m4_init(portapack::spi_flash::baseband, portapack::spi_flash::m4_text_ram_base); m4_init(portapack::spi_flash::baseband, portapack::spi_flash::m4_text_ram_base);

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,121 @@
/*
* 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_rds.hpp"
#include "ui_afsksetup.hpp"
#include "ui_receiver.hpp"
#include "ch.h"
#include "ff.h"
#include "hackrf_gpio.hpp"
#include "portapack.hpp"
#include "radio.hpp"
#include "hackrf_hal.hpp"
#include "portapack_shared_memory.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include <stdio.h>
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 */

View File

@ -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 */

View File

@ -27,6 +27,7 @@
#include "led.hpp" #include "led.hpp"
#include "hackrf_gpio.hpp" #include "hackrf_gpio.hpp"
#include "portapack.hpp" #include "portapack.hpp"
#include "portapack_shared_memory.hpp"
#include "radio.hpp" #include "radio.hpp"
@ -229,15 +230,71 @@ void DebugSDView::focus() {
button_done.focus(); button_done.focus();
} }
// LCR debug view
void DebugLCRView::paint(Painter& painter) {
const Point offset = {
static_cast<Coord>(32),
static_cast<Coord>(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) { DebugMenuView::DebugMenuView(NavigationView& nav) {
add_items<7>({ { add_items<7>({ {
{ "Memory", [&nav](){ nav.push(new DebugMemoryView { nav }); } }, { "Memory", ui::Color::white(), [&nav](){ nav.push(new DebugMemoryView { nav }); } },
{ "Radio State", [&nav](){ nav.push(new NotImplementedView { nav }); } }, { "Radio State", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
{ "SD Card", [&nav](){ nav.push(new DebugSDView { nav }); } }, { "SD Card", ui::Color::white(), [&nav](){ nav.push(new DebugSDView { nav }); } },
{ "RFFC5072", [&nav](){ nav.push(new DebugRFFC5072View { nav }); } }, { "RFFC5072", ui::Color::white(), [&nav](){ nav.push(new DebugRFFC5072View { nav }); } },
{ "MAX2837", [&nav](){ nav.push(new NotImplementedView { nav }); } }, { "MAX2837", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
{ "Si5351C", [&nav](){ nav.push(new NotImplementedView { nav }); } }, { "Si5351C", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
{ "WM8731", [&nav](){ nav.push(new NotImplementedView { nav }); } }, { "WM8731", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
} }); } });
on_left = [&nav](){ nav.pop(); }; on_left = [&nav](){ nav.pop(); };
} }

View File

@ -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 { class DebugMenuView : public MenuView {
public: public:
DebugMenuView(NavigationView& nav); DebugMenuView(NavigationView& nav);

View File

@ -22,6 +22,8 @@
#include "ui_rds.hpp" #include "ui_rds.hpp"
#include "ui_lcr.hpp" #include "ui_lcr.hpp"
#include "ui_receiver.hpp" #include "ui_receiver.hpp"
#include "ui_afsksetup.hpp"
#include "ui_debug.hpp"
#include "ch.h" #include "ch.h"
@ -37,6 +39,12 @@
#include <cstring> #include <cstring>
#include <stdio.h> #include <stdio.h>
//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; using namespace hackrf::one;
namespace ui { namespace ui {
@ -49,18 +57,70 @@ LCRView::~LCRView() {
transmitter_model.disable(); transmitter_model.disable();
} }
char hexify(char in) { void LCRView::make_frame() {
if (in > 9) in += 7;
return in + 0x30;
}
void LCRView::paint(Painter& painter) {
char eom[3] = { 3, 0, 0 }; char eom[3] = { 3, 0, 0 };
uint8_t checksum = 0, i; uint8_t i;
char teststr[16];
uint16_t dp; uint16_t dp;
uint8_t cp, pp, cur_byte, new_byte; 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<strlen(lcrframe);dp++) {
pp = 0;
new_byte = 0;
cur_byte = lcrframe[dp];
for (cp=0;cp<7;cp++) {
if ((cur_byte>>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 { static constexpr Style style_orange {
.font = font::fixed_8x16, .font = font::fixed_8x16,
.background = Color::black(), .background = Color::black(),
@ -102,108 +162,65 @@ void LCRView::paint(Painter& painter) {
litteral[3] litteral[3]
); );
// Testing: 7 char pad for litterals offset.y += 40;
for (i = 0; i < 4; 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 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<strlen(lcrframe);dp++) {
pp = 0;
new_byte = 0;
cur_byte = lcrframe[dp];
for (cp=0;cp<7;cp++) {
if ((cur_byte>>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( painter.draw_string(
screen_pos() + offset, screen_pos() + offset,
style(), style_orange,
teststr 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( LCRView::LCRView(
NavigationView& nav, NavigationView& nav,
TransmitterModel& transmitter_model TransmitterModel& transmitter_model
) : transmitter_model(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_modulation(16);
transmitter_model.set_tuning_frequency(f); transmitter_model.set_tuning_frequency(persistent_memory::tuned_frequency());
memset(litteral, 0, 4*8); memset(litteral, 0, 5*8);
memset(rgsb, 0, 5); memset(rgsb, 0, 5);
strcpy(rgsb, RGSB_list[0]); strcpy(rgsb, RGSB_list[0]);
add_children({ { add_children({ {
&text_recap,
&button_setrgsb, &button_setrgsb,
&button_txsetup, &button_txsetup,
&button_setam_a, &button_setam_a,
&button_setam_b, &button_setam_b,
&button_setam_c, &button_setam_c,
&button_setam_d, &button_setam_d,
&button_setfreq, &button_setam_e,
&button_setbps, &text_status,
&button_lcrdebug,
&button_transmit, &button_transmit,
&button_transmit_scan, &button_transmit_scan,
&button_exit &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&){ button_setrgsb.on_select = [this,&nav](Button&){
auto an_view = new AlphanumView { nav, rgsb, 4 }; auto an_view = new AlphanumView { nav, rgsb, 4 };
an_view->on_changed = [this](char *rgsb) { an_view->on_changed = [this](char *rgsb) {
@ -211,13 +228,6 @@ LCRView::LCRView(
}; };
nav.push(an_view); 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&){ button_setam_a.on_select = [this,&nav](Button&){
auto an_view = new AlphanumView { nav, litteral[0], 7 }; auto an_view = new AlphanumView { nav, litteral[0], 7 };
@ -239,29 +249,47 @@ LCRView::LCRView(
an_view->on_changed = [this](char *) {}; an_view->on_changed = [this](char *) {};
nav.push(an_view); nav.push(an_view);
}; };
button_setbps.on_select = [this](Button&){ button_setam_e.on_select = [this,&nav](Button&){
if (persistent_memory::afsk_bitrate() == 1200) { auto an_view = new AlphanumView { nav, litteral[4], 7 };
persistent_memory::set_afsk_bitrate(2400); an_view->on_changed = [this](char *) {};
button_setbps.set_text("2400 bps"); nav.push(an_view);
} else { };
persistent_memory::set_afsk_bitrate(1200);
button_setbps.set_text("1200 bps"); button_lcrdebug.on_select = [this,&nav](Button&){
} make_frame();
nav.push(new DebugLCRView { nav, lcrstring, checksum });
}; };
button_transmit.on_select = [this,&transmitter_model](Button&){ button_transmit.on_select = [this,&transmitter_model](Button&){
uint16_t c; uint16_t c;
ui::Context context;
make_frame();
shared_memory.afsk_samples_per_bit = 228000/persistent_memory::afsk_bitrate(); 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_mark = persistent_memory::afsk_mark_freq()*(65536*1024)/2280;
shared_memory.afsk_phase_inc_space = persistent_memory::afsk_space_freq()*(65536*1024)/228000; shared_memory.afsk_phase_inc_space = persistent_memory::afsk_space_freq()*(65536*1024)/2280;
for (c = 0; c < 256; c++) { for (c = 0; c < 256; c++) {
shared_memory.lcrdata[c] = this->lcrframe[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(); transmitter_model.enable();
}; };
button_txsetup.on_select = [&nav, &transmitter_model](Button&){
nav.push(new AFSKSetupView { nav, transmitter_model });
};
button_exit.on_select = [&nav](Button&){ button_exit.on_select = [&nav](Button&){
nav.pop(); nav.pop();
}; };

View File

@ -39,7 +39,7 @@ public:
LCRView(NavigationView& nav, TransmitterModel& transmitter_model); LCRView(NavigationView& nav, TransmitterModel& transmitter_model);
~LCRView(); ~LCRView();
void updfreq(rf::Frequency f); void make_frame();
void focus() override; void focus() override;
void paint(Painter& painter) override; void paint(Painter& painter) override;
@ -56,12 +56,25 @@ private:
"AJ40", "AJ50", "AJ60", "AJ70", "AJ40", "AJ50", "AJ60", "AJ70",
"AK10" "AK10"
}; };
char litteral[4][8]; char litteral[5][8];
char rgsb[5]; char rgsb[5];
char lcrstring[256];
char checksum = 0;
char lcrframe[256]; char lcrframe[256];
char lcrframe_f[256];
rf::Frequency f = 162950000; rf::Frequency f = 162950000;
TransmitterModel& transmitter_model; TransmitterModel& transmitter_model;
Text text_status {
{ 136, 128, 64, 16 },
"Ready"
};
Text text_recap {
{ 32, 6, 192, 16 },
"-"
};
Button button_setrgsb { Button button_setrgsb {
{ 16, 24, 96, 32 }, { 16, 24, 96, 32 },
"Set RGSB" "Set RGSB"
@ -91,21 +104,22 @@ private:
"AM 4" "AM 4"
}; };
Button button_setfreq { Button button_setam_e {
{ 8, 232, 96, 32 }, { 16, 64+40+40+40+40, 48, 32 },
"162.9500" "AM 5"
}; };
Button button_setbps {
{ 128, 232, 96, 32 }, Button button_lcrdebug {
"1200bps" { 152, 224, 64, 32 },
"DEBUG"
}; };
Button button_transmit { Button button_transmit {
{ 8, 270, 48, 32 }, { 24, 270, 48, 32 },
"TX" "TX"
}; };
Button button_transmit_scan { Button button_transmit_scan {
{ 60, 270, 64, 32 }, { 76, 270, 72, 32 },
"SCAN TX" "SCAN TX"
}; };
Button button_exit { Button button_exit {

View File

@ -51,9 +51,19 @@ void MenuItemView::paint(Painter& painter) {
paint_style.background 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( painter.draw_string(
{ static_cast<Coord>(r.pos.x + 8), static_cast<Coord>(r.pos.y + (r.size.h - font_height) / 2) }, { static_cast<Coord>(r.pos.x + 8), static_cast<Coord>(r.pos.y + (r.size.h - font_height) / 2) },
paint_style, text_style,
item.text item.text
); );
} }

View File

@ -34,6 +34,7 @@ namespace ui {
struct MenuItem { struct MenuItem {
std::string text; std::string text;
ui::Color color;
std::function<void(void)> on_select; std::function<void(void)> on_select;
}; };

View File

@ -23,6 +23,9 @@
#include "receiver_model.hpp" #include "receiver_model.hpp"
#include "transmitter_model.hpp" #include "transmitter_model.hpp"
#include "portapack_persistent_memory.hpp"
#include "splash.hpp"
#include "ui_setup.hpp" #include "ui_setup.hpp"
#include "ui_debug.hpp" #include "ui_debug.hpp"
@ -98,16 +101,17 @@ void NavigationView::focus() {
/* SystemMenuView ********************************************************/ /* SystemMenuView ********************************************************/
SystemMenuView::SystemMenuView(NavigationView& nav) { SystemMenuView::SystemMenuView(NavigationView& nav) {
add_items<9>({ { add_items<10>({ {
{ "Receiver", [&nav](){ nav.push(new ReceiverView { nav, receiver_model }); } }, { "Play dead", ui::Color::red(), [&nav](){ nav.push(new PlayDeadView { nav }); } },
{ "Capture", [&nav](){ nav.push(new NotImplementedView { nav }); } }, { "Receiver", ui::Color::white(), [&nav](){ nav.push(new ReceiverView { nav, receiver_model }); } },
{ "Analyze", [&nav](){ nav.push(new NotImplementedView { nav }); } }, { "Capture", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
{ "RDS TX", [&nav](){ nav.push(new RDSView { nav, transmitter_model }); } }, { "Analyze", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
{ "LCR TX", [&nav](){ nav.push(new LCRView { nav, transmitter_model }); } }, { "RDS TX", ui::Color::orange(), [&nav](){ nav.push(new RDSView { nav, transmitter_model }); } },
{ "Setup", [&nav](){ nav.push(new SetupMenuView { nav }); } }, { "LCR TX", ui::Color::orange(), [&nav](){ nav.push(new LCRView { nav, transmitter_model }); } },
{ "About", [&nav](){ nav.push(new AboutView { nav }); } }, { "Setup", ui::Color::white(), [&nav](){ nav.push(new SetupMenuView { nav }); } },
{ "Debug", [&nav](){ nav.push(new DebugMenuView { nav }); } }, { "About", ui::Color::white(), [&nav](){ nav.push(new AboutView { nav }); } },
{ "HackRF", [&nav](){ nav.push(new HackRFFirmwareView { 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. // Initial view.
// TODO: Restore from non-volatile memory? // 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 { Context& SystemView::context() const {
return context_; 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<std::underlying_type<KeyEvent>::type>(key);
};
button_done.on_select = [this,&nav](Button&){
if (sequence == persistent_memory::playdead_sequence())
nav.pop();
else
sequence = 0;
};
}
/* HackRFFirmwareView ****************************************************/ /* HackRFFirmwareView ****************************************************/
HackRFFirmwareView::HackRFFirmwareView(NavigationView& nav) { HackRFFirmwareView::HackRFFirmwareView(NavigationView& nav) {

View File

@ -41,8 +41,8 @@ public:
private: private:
Text portapack { Text portapack {
{ 0, 0, 9 * 8, 1 * 16 }, { 0, 0, 15 * 8, 1 * 16 },
"PortaPack", "PortaPack/HAVOC"
}; };
}; };
@ -70,6 +70,25 @@ public:
SystemMenuView(NavigationView& nav); 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 { class SystemView : public View {
public: public:
SystemView( SystemView(
@ -85,6 +104,28 @@ private:
Context& context_; 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 { class HackRFFirmwareView : public View {
public: public:
HackRFFirmwareView(NavigationView& nav); HackRFFirmwareView(NavigationView& nav);

View File

@ -26,8 +26,10 @@
#include "lpc43xx_cpp.hpp" #include "lpc43xx_cpp.hpp"
#include <math.h> #include <math.h>
#include <cstring>
using namespace lpc43xx; using namespace lpc43xx;
using namespace portapack;
namespace ui { namespace ui {
@ -184,11 +186,56 @@ bool SetTouchCalibView::on_touch(const TouchEvent event) {
return true; 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<std::underlying_type<KeyEvent>::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) { SetupMenuView::SetupMenuView(NavigationView& nav) {
add_items<3>({ { add_items<4>({ {
{ "Date/Time", [&nav](){ nav.push(new SetDateTimeView { nav }); } }, { "Date/Time", ui::Color::white(), [&nav](){ nav.push(new SetDateTimeView { nav }); } },
{ "Frequency Correction", [&nav](){ nav.push(new SetFrequencyCorrectionView { nav }); } }, { "Frequency correction", ui::Color::white(), [&nav](){ nav.push(new SetFrequencyCorrectionView { nav }); } },
{ "Touch", [&nav](){ nav.push(new SetTouchCalibView { 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(); }; on_left = [&nav](){ nav.pop(); };
} }

View File

@ -25,6 +25,7 @@
#include "ui_widget.hpp" #include "ui_widget.hpp"
#include "ui_menu.hpp" #include "ui_menu.hpp"
#include "ui_navigation.hpp" #include "ui_navigation.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstdint> #include <cstdint>
@ -190,7 +191,7 @@ private:
Text text_firmware { Text text_firmware {
{ 0, 128, 240, 16 }, { 0, 128, 240, 16 },
"Firmware Version git-??????", "Firmware Version HAVOC 0.10",
}; };
Text text_cpld_hackrf { 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 { class SetupMenuView : public MenuView {
public: public:
SetupMenuView(NavigationView& nav); SetupMenuView(NavigationView& nav);

View File

@ -762,12 +762,6 @@ private:
class LCRFSKProcessor : public BasebandProcessor { class LCRFSKProcessor : public BasebandProcessor {
public: 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 { void execute(buffer_c8_t buffer) override {
for (size_t i = 0; i<buffer.count; i++) { for (size_t i = 0; i<buffer.count; i++) {
@ -776,14 +770,22 @@ public:
if (s >= 9) { if (s >= 9) {
s = 0; s = 0;
if (sample_count >= afsk_samples_per_bit) { if (sample_count >= shared_memory.afsk_samples_per_bit) {
cur_byte = shared_memory.lcrdata[byte_pos]; if (shared_memory.afsk_transmit_done == false)
cur_byte = shared_memory.lcrdata[byte_pos];
if (!cur_byte) { if (!cur_byte) {
bit_pos = 0; if (shared_memory.afsk_repeat) {
byte_pos = 0; shared_memory.afsk_repeat--;
cur_byte = shared_memory.lcrdata[0]; 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 //SdddddddpD
//0dddddddp1 //0dddddddp1
@ -808,9 +810,9 @@ public:
sample_count++; sample_count++;
} }
if (cur_bit) if (cur_bit)
aphase += phase_inc_mark; //(353205) aphase += shared_memory.afsk_phase_inc_mark; //(353205)
else else
aphase += phase_inc_space; //(647542) aphase += shared_memory.afsk_phase_inc_space; //(647542)
sample = sintab[(aphase & 0x03FF0000)>>16]; sample = sintab[(aphase & 0x03FF0000)>>16];
} else { } else {
@ -833,8 +835,6 @@ public:
} }
private: private:
uint32_t afsk_samples_per_bit;
uint32_t phase_inc_mark, phase_inc_space;
int8_t re, im; int8_t re, im;
uint8_t s; uint8_t s;
uint8_t bit_pos, byte_pos; uint8_t bit_pos, byte_pos;
@ -844,6 +844,7 @@ private:
uint32_t sample_count; uint32_t sample_count;
uint32_t aphase, phase, sphase; uint32_t aphase, phase, sphase;
int32_t sample, sig, frq; int32_t sample, sig, frq;
TXDoneMessage message;
}; };
static BasebandProcessor* baseband_processor { nullptr }; static BasebandProcessor* baseband_processor { nullptr };

View File

@ -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) { void ILI9341::draw_line(const ui::Point start, const ui::Point end, const ui::Color color) {
int x0 = start.x; int x0 = start.x;
int y0 = start.y; int y0 = start.y;

View File

@ -54,6 +54,7 @@ public:
); );
void draw_pixel(const ui::Point p, const ui::Color color); 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<size_t N> template<size_t N>
void draw_pixels( void draw_pixels(

View File

@ -42,6 +42,7 @@ public:
FSKConfiguration = 6, FSKConfiguration = 6,
FSKPacket = 7, FSKPacket = 7,
TestResults = 8, TestResults = 8,
TXDone = 9,
MAX MAX
}; };
@ -251,6 +252,14 @@ public:
FSKPacket packet; FSKPacket packet;
}; };
class TXDoneMessage : public Message {
public:
TXDoneMessage(
) : Message { ID::TXDone }
{
}
};
class MessageHandlerMap { class MessageHandlerMap {
public: public:
using MessageHandler = std::function<void(const Message* const p)>; using MessageHandler = std::function<void(const Message* const p)>;

View File

@ -55,14 +55,14 @@ using ppb_range_t = range_t<ppb_t>;
constexpr ppb_range_t ppb_range { -99000, 99000 }; constexpr ppb_range_t ppb_range { -99000, 99000 };
constexpr ppb_t ppb_reset_value { 0 }; constexpr ppb_t ppb_reset_value { 0 };
using afsk_freq_range_t = range_t<int16_t>; using afsk_freq_range_t = range_t<int32_t>;
constexpr afsk_freq_range_t afsk_freq_range { 100, 32000 }; constexpr afsk_freq_range_t afsk_freq_range { 1, 60 };
constexpr int16_t afsk_mark_reset_value { 1200 }; constexpr int32_t afsk_mark_reset_value { 12 };
constexpr int16_t afsk_space_reset_value { 2200 }; constexpr int32_t afsk_space_reset_value { 22 };
using afsk_bitrate_range_t = range_t<int16_t>; using afsk_bitrate_range_t = range_t<int32_t>;
constexpr afsk_bitrate_range_t afsk_bitrate_range { 600, 9600 }; 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 must pack the same way on M4 and M0 cores. */
struct data_t { struct data_t {
@ -71,10 +71,14 @@ struct data_t {
int32_t correction_ppb; int32_t correction_ppb;
// AFSK modem // AFSK modem
int16_t afsk_mark_freq; int32_t afsk_mark_freq;
int16_t afsk_space_freq; int32_t afsk_space_freq;
int16_t afsk_bitrate; int32_t afsk_bitrate;
uint8_t afsk_config; 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"); 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); 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); 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); 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); 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); 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); 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); 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; 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 persistent_memory */
} /* namespace portapack */ } /* namespace portapack */

View File

@ -37,18 +37,24 @@ void set_tuned_frequency(const rf::Frequency new_value);
ppb_t correction_ppb(); ppb_t correction_ppb();
void set_correction_ppb(const ppb_t new_value); void set_correction_ppb(const ppb_t new_value);
int16_t afsk_mark_freq(); int32_t afsk_mark_freq();
void set_afsk_mark(const int16_t new_value); void set_afsk_mark(const int32_t new_value);
int16_t afsk_space_freq(); int32_t afsk_space_freq();
void set_afsk_space(const int16_t new_value); void set_afsk_space(const int32_t new_value);
int16_t afsk_bitrate(); int32_t afsk_bitrate();
void set_afsk_bitrate(const int16_t new_value); void set_afsk_bitrate(const int32_t new_value);
uint8_t afsk_config(); uint8_t afsk_config();
void set_afsk_config(const uint8_t new_value); 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 persistent_memory */
} /* namespace portapack */ } /* namespace portapack */

View File

@ -47,6 +47,8 @@ struct SharedMemory {
uint32_t afsk_samples_per_bit; uint32_t afsk_samples_per_bit;
uint32_t afsk_phase_inc_mark; uint32_t afsk_phase_inc_mark;
uint32_t afsk_phase_inc_space; uint32_t afsk_phase_inc_space;
uint8_t afsk_repeat;
bool afsk_transmit_done;
}; };
extern SharedMemory& shared_memory; extern SharedMemory& shared_memory;

View File

@ -401,6 +401,11 @@ bool Button::on_key(const KeyEvent key) {
on_select(*this); on_select(*this);
return true; return true;
} }
} else {
if( on_dir ) {
on_dir(*this, key);
return false;
}
} }
return false; return false;

View File

@ -212,6 +212,7 @@ private:
class Button : public Widget { class Button : public Widget {
public: public:
std::function<void(Button&)> on_select; std::function<void(Button&)> on_select;
std::function<void(Button&,KeyEvent)> on_dir;
Button( Button(
Rect parent_rect, Rect parent_rect,