mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-24 16:07:47 +00:00
Dynamic baseband module loading from SD card
This commit is contained in:
@@ -149,6 +149,7 @@ CPPSRC = main.cpp \
|
||||
encoder.cpp \
|
||||
lcd_ili9341.cpp \
|
||||
ui.cpp \
|
||||
ui_alphanum.cpp \
|
||||
ui_text.cpp \
|
||||
ui_widget.cpp \
|
||||
ui_painter.cpp \
|
||||
@@ -170,6 +171,7 @@ CPPSRC = main.cpp \
|
||||
ui_console.cpp \
|
||||
ui_receiver.cpp \
|
||||
ui_spectrum.cpp \
|
||||
ui_loadmodule.cpp \
|
||||
receiver_model.cpp \
|
||||
transmitter_model.cpp \
|
||||
spectrum_color_lut.cpp \
|
||||
|
@@ -22,12 +22,14 @@
|
||||
#include "m4_startup.hpp"
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
#include "message.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
char * modhash;
|
||||
|
||||
/* TODO: OK, this is cool, but how do I put the M4 to sleep so I can switch to
|
||||
* a different image? Other than asking the old image to sleep while the M0
|
||||
* makes changes?
|
||||
@@ -37,6 +39,7 @@
|
||||
*/
|
||||
void m4_init(const portapack::spi_flash::region_t from, const portapack::memory::region_t to) {
|
||||
/* Initialize M4 code RAM */
|
||||
// DEBUG
|
||||
std::memcpy(reinterpret_cast<void*>(to.base()), from.base(), from.size);
|
||||
|
||||
/* M4 core is assumed to be sleeping with interrupts off, so we can mess
|
||||
@@ -48,6 +51,58 @@ void m4_init(const portapack::spi_flash::region_t from, const portapack::memory:
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 13);
|
||||
}
|
||||
|
||||
int m4_load_image(void) {
|
||||
uint32_t mod_size;
|
||||
UINT bw;
|
||||
uint8_t i;
|
||||
char md5sum[16];
|
||||
FILINFO modinfo;
|
||||
FIL modfile;
|
||||
DIR rootdir;
|
||||
FRESULT res;
|
||||
|
||||
// Scan SD card root directory for files with the right md5 fingerprint at the right location
|
||||
f_opendir(&rootdir, "/");
|
||||
for (;;) {
|
||||
res = f_readdir(&rootdir, &modinfo);
|
||||
if (res != FR_OK || modinfo.fname[0] == 0) break;
|
||||
if (!(modinfo.fattrib & AM_DIR)) {
|
||||
f_open(&modfile, modinfo.fname, FA_OPEN_EXISTING | FA_READ);
|
||||
f_lseek(&modfile, 26);
|
||||
f_read(&modfile, &md5sum, 16, &bw);
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (md5sum[i] != modhash[i]) break;
|
||||
}
|
||||
if (i == 16) {
|
||||
f_lseek(&modfile, 6);
|
||||
f_read(&modfile, &mod_size, 4, &bw);
|
||||
f_lseek(&modfile, 256);
|
||||
f_read(&modfile, reinterpret_cast<void*>(portapack::memory::map::m4_code.base()), mod_size, &bw);
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 13);
|
||||
f_close(&modfile);
|
||||
return 1;
|
||||
}
|
||||
f_close(&modfile);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void m4_switch(const char * hash) {
|
||||
modhash = const_cast<char*>(hash);
|
||||
|
||||
// Ask M4 to enter loop in RAM
|
||||
BasebandConfiguration baseband_switch {
|
||||
.mode = 0xFF,
|
||||
.sampling_rate = 0,
|
||||
.decimation_factor = 1,
|
||||
};
|
||||
|
||||
BasebandConfigurationMessage message { baseband_switch };
|
||||
shared_memory.baseband_queue.push(message);
|
||||
}
|
||||
|
||||
void m4_request_shutdown() {
|
||||
ShutdownMessage shutdown_message;
|
||||
shared_memory.baseband_queue.push(shutdown_message);
|
||||
|
@@ -24,10 +24,14 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "ff.h"
|
||||
#include "memory_map.hpp"
|
||||
#include "spi_image.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
void m4_init(const portapack::spi_flash::region_t from, const portapack::memory::region_t to);
|
||||
void m4_request_shutdown();
|
||||
void m4_switch(const char * hash);
|
||||
int m4_load_image(void);
|
||||
|
||||
#endif/*__M4_STARTUP_H__*/
|
||||
|
@@ -19,8 +19,12 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
//Reims ANFR 822519
|
||||
//TODO: UC/LC update buttons in keyboard view
|
||||
//TODO: Reset baseband if module not found (instead of lockup in RAM loop)
|
||||
//TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found
|
||||
//TODO: LCD backlight PWM
|
||||
//TODO: BUG: Crash after TX stop
|
||||
//TODO: Check bw setting in LCR TX
|
||||
//TODO: BUG: Crash after PSN entry in RDS TX
|
||||
//TODO: Dynamically load baseband code depending on mode (disable M4 & interrupts, load, reset)
|
||||
//TODO: Bodet :)
|
||||
//TODO: Whistler
|
||||
@@ -29,14 +33,8 @@
|
||||
//TODO: Persistent playdead !
|
||||
//TODO: LCR EC=A,J,N
|
||||
//TODO: LCR full message former (see norm)
|
||||
//TODO: See if receive still works
|
||||
//TODO: LCR repeats
|
||||
//TODO: LCR shared memory semaphore for doing/done
|
||||
//TODO: LCR address scan
|
||||
//TODO: LCR text showing status in LCRView
|
||||
//TODO: AFSK NRZI
|
||||
//TODO: AFSK volume
|
||||
//TODO: AFSK channel bandwidth
|
||||
//TODO: TX power
|
||||
|
||||
#include "ch.h"
|
||||
|
2
firmware/application/modules.h
Normal file
2
firmware/application/modules.h
Normal file
@@ -0,0 +1,2 @@
|
||||
const char md5_baseband[16] = {0xca,0x05,0xc3,0xbf,0x78,0x10,0xad,0xac,0x2a,0x2b,0x31,0x19,0xf9,0xe8,0x91,0x26,};
|
||||
const char md5_baseband_tx[16] = {0xe7,0x28,0x33,0x67,0x45,0x37,0x1e,0x13,0x3c,0x85,0xb5,0x91,0x51,0xaa,0xed,0x4f,};
|
173
firmware/application/ui_alphanum.cpp
Normal file
173
firmware/application/ui_alphanum.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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_alphanum.hpp"
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#include "ff.h"
|
||||
#include "portapack.hpp"
|
||||
#include "radio.hpp"
|
||||
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace hackrf::one;
|
||||
|
||||
namespace ui {
|
||||
|
||||
AlphanumView::AlphanumView(
|
||||
NavigationView& nav,
|
||||
char txt[],
|
||||
uint8_t max_len
|
||||
) {
|
||||
_max_len = max_len;
|
||||
_lowercase = false;
|
||||
|
||||
static constexpr Style style_alpha {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::red(),
|
||||
.foreground = Color::black(),
|
||||
};
|
||||
|
||||
static constexpr Style style_num {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::yellow(),
|
||||
.foreground = Color::black(),
|
||||
};
|
||||
|
||||
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 : buttons) {
|
||||
add_child(&button);
|
||||
button.on_select = button_fn;
|
||||
button.set_parent_rect({
|
||||
static_cast<Coord>((n % 5) * button_w),
|
||||
static_cast<Coord>((n / 5) * button_h + 18),
|
||||
button_w, button_h
|
||||
});
|
||||
if ((n < 10) || (n == 39))
|
||||
button.set_style(&style_num);
|
||||
else
|
||||
button.set_style(&style_alpha);
|
||||
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(&button_done);
|
||||
button_done.on_select = [this, &nav, txt, max_len](Button&) {
|
||||
memcpy(txt, txtinput, max_len+1);
|
||||
on_changed(this->value());
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
update_text();
|
||||
}
|
||||
|
||||
void AlphanumView::set_uppercase() {
|
||||
const char* const key_caps = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ. !<";
|
||||
|
||||
size_t n = 0;
|
||||
for(auto& button : buttons) {
|
||||
add_child(&button);
|
||||
const std::string label {
|
||||
key_caps[n]
|
||||
};
|
||||
button.set_text(label);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AlphanumView::set_lowercase() {
|
||||
const char* const key_caps = "0123456789abcdefghijklmnopqrstuvwxyz. !<";
|
||||
|
||||
size_t n = 0;
|
||||
for(auto& button : buttons) {
|
||||
add_child(&button);
|
||||
const std::string label {
|
||||
key_caps[n]
|
||||
};
|
||||
button.set_text(label);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
void AlphanumView::focus() {
|
||||
button_done.focus();
|
||||
}
|
||||
|
||||
char * AlphanumView::value() {
|
||||
return txtinput;
|
||||
}
|
||||
|
||||
void AlphanumView::on_button(Button& button) {
|
||||
const auto s = button.text();
|
||||
if( s == "<" ) {
|
||||
char_delete();
|
||||
} else {
|
||||
char_add(s[0]);
|
||||
}
|
||||
update_text();
|
||||
}
|
||||
|
||||
void AlphanumView::char_add(const char c) {
|
||||
if (txtidx < _max_len) {
|
||||
txtinput[txtidx] = c;
|
||||
txtidx++;
|
||||
}
|
||||
}
|
||||
|
||||
void AlphanumView::char_delete() {
|
||||
if (txtidx) {
|
||||
txtidx--;
|
||||
txtinput[txtidx] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
void AlphanumView::update_text() {
|
||||
text_input.set(txtinput);
|
||||
}
|
||||
|
||||
}
|
83
firmware/application/ui_alphanum.hpp
Normal file
83
firmware/application/ui_alphanum.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 AlphanumView : public View {
|
||||
public:
|
||||
std::function<void(char *)> on_changed;
|
||||
|
||||
AlphanumView(NavigationView& nav, char txt[], uint8_t max_len);
|
||||
|
||||
void focus() override;
|
||||
|
||||
char * value();
|
||||
|
||||
uint8_t txtidx;
|
||||
|
||||
void char_add(const char c);
|
||||
void char_delete();
|
||||
|
||||
private:
|
||||
uint8_t _max_len;
|
||||
bool _lowercase = false;
|
||||
static constexpr size_t button_w = 240 / 5;
|
||||
static constexpr size_t button_h = 28;
|
||||
char txtinput[9];
|
||||
|
||||
void set_lowercase();
|
||||
void set_uppercase();
|
||||
|
||||
Text text_input {
|
||||
{ 88, 0, 240, 16 }
|
||||
};
|
||||
|
||||
std::array<Button, 40> 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 */
|
@@ -144,10 +144,30 @@ void DebugSDView::paint(Painter& painter) {
|
||||
DebugSDView::DebugSDView(NavigationView& nav) {
|
||||
add_children({ {
|
||||
&text_title,
|
||||
&text_modules,
|
||||
&button_makefile,
|
||||
&button_done
|
||||
} });
|
||||
|
||||
FIL fdst;
|
||||
char buffer[256];
|
||||
uint8_t mods_version, mods_count;
|
||||
UINT bw;
|
||||
|
||||
const auto open_result = f_open(&fdst, "ppmods.bin", FA_OPEN_EXISTING | FA_READ);
|
||||
if (open_result == FR_OK) {
|
||||
f_read(&fdst, &mods_version, 1, &bw);
|
||||
if (mods_version == 1) {
|
||||
f_read(&fdst, &mods_count, 1, &bw);
|
||||
f_read(&fdst, buffer, 8, &bw);
|
||||
f_read(&fdst, buffer, 16, &bw);
|
||||
buffer[16] = 0;
|
||||
text_modules.set(buffer);
|
||||
} else {
|
||||
text_modules.set("Bad version");
|
||||
}
|
||||
}
|
||||
|
||||
button_makefile.on_select = [this](Button&){
|
||||
FATFS fs; /* Work area (file system object) for logical drives */
|
||||
FIL fdst; /* File objects */
|
||||
|
@@ -155,7 +155,12 @@ public:
|
||||
private:
|
||||
Text text_title {
|
||||
{ 32, 16, 128, 16 },
|
||||
"SD card debug",
|
||||
"SD card debug"
|
||||
};
|
||||
|
||||
Text text_modules {
|
||||
{ 8, 32, 28 * 8, 16 },
|
||||
"TESTTESTTESTTESTTESTTESTTEST"
|
||||
};
|
||||
|
||||
Button button_makefile {
|
||||
|
@@ -192,7 +192,8 @@ LCRView::LCRView(
|
||||
memset(litteral, 0, 5*8);
|
||||
memset(rgsb, 0, 5);
|
||||
|
||||
strcpy(rgsb, RGSB_list[0]);
|
||||
strcpy(rgsb, RGSB_list[29]);
|
||||
button_setrgsb.set_text(rgsb);
|
||||
|
||||
add_children({ {
|
||||
&text_recap,
|
||||
@@ -282,10 +283,10 @@ LCRView::LCRView(
|
||||
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()*(65536*1024)/2280;
|
||||
shared_memory.afsk_phase_inc_space = portapack::persistent_memory::afsk_space_freq()*(65536*1024)/2280;
|
||||
shared_memory.afsk_phase_inc_mark = portapack::persistent_memory::afsk_mark_freq()*(0x10000*256)/2280;
|
||||
shared_memory.afsk_phase_inc_space = portapack::persistent_memory::afsk_space_freq()*(0x10000*256)/2280;
|
||||
|
||||
shared_memory.afsk_fmmod = portapack::persistent_memory::afsk_bw()*33;
|
||||
shared_memory.afsk_fmmod = portapack::persistent_memory::afsk_bw() * 8;
|
||||
|
||||
memset(shared_memory.lcrdata, 0, 256);
|
||||
memcpy(shared_memory.lcrdata, lcrframe_f, 256);
|
||||
@@ -297,8 +298,10 @@ LCRView::LCRView(
|
||||
[this,&transmitter_model](Message* const p) {
|
||||
const auto message = static_cast<const TXDoneMessage*>(p);
|
||||
if (message->n > 0) {
|
||||
char str[8] = "0... ";
|
||||
str[0] = hexify(message->n);
|
||||
char str[8];
|
||||
strcpy(str, to_string_dec_int(message->n).c_str());
|
||||
strcat(str, "/");
|
||||
strcat(str, to_string_dec_int(shared_memory.afsk_repeat).c_str());
|
||||
text_status.set(str);
|
||||
} else {
|
||||
text_status.set("Done ! ");
|
||||
@@ -307,7 +310,10 @@ LCRView::LCRView(
|
||||
}
|
||||
);
|
||||
|
||||
text_status.set("0... ");
|
||||
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();
|
||||
};
|
||||
|
89
firmware/application/ui_loadmodule.cpp
Normal file
89
firmware/application/ui_loadmodule.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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_loadmodule.hpp"
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#include "ff.h"
|
||||
#include "hackrf_gpio.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
#include "hackrf_hal.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace hackrf::one;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void LoadModuleView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
void LoadModuleView::paint(Painter& painter) {
|
||||
|
||||
}
|
||||
|
||||
void LoadModuleView::on_hide() {
|
||||
auto& message_map = context().message_map();
|
||||
message_map.unregister_handler(Message::ID::ReadyForSwitch);
|
||||
}
|
||||
|
||||
void LoadModuleView::on_show() {
|
||||
auto& message_map = context().message_map();
|
||||
message_map.register_handler(Message::ID::ReadyForSwitch,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const ReadyForSwitchMessage*>(p);
|
||||
if (m4_load_image()) {
|
||||
text_info.set("Module loaded :)");
|
||||
_mod_loaded = true;
|
||||
} else {
|
||||
text_info.set("Module not found :(");
|
||||
_mod_loaded = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
m4_switch(_hash);
|
||||
}
|
||||
|
||||
LoadModuleView::LoadModuleView(
|
||||
NavigationView& nav,
|
||||
const char * hash,
|
||||
View* new_view
|
||||
)
|
||||
{
|
||||
add_children({ {
|
||||
&text_info,
|
||||
&button_ok
|
||||
} });
|
||||
|
||||
_hash = hash;
|
||||
|
||||
button_ok.on_select = [this,&nav,new_view](Button&){
|
||||
nav.pop();
|
||||
if (_mod_loaded == true) nav.push(new_view);
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
56
firmware/application/ui_loadmodule.hpp
Normal file
56
firmware/application/ui_loadmodule.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 "m4_startup.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class LoadModuleView : public View {
|
||||
public:
|
||||
LoadModuleView(NavigationView& nav, const char * hash, View* new_view);
|
||||
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
void focus() override;
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
private:
|
||||
const char * _hash;
|
||||
bool _mod_loaded = false;
|
||||
|
||||
Text text_info {
|
||||
{ 8, 64, 224, 16 },
|
||||
"Searching module..."
|
||||
};
|
||||
|
||||
Button button_ok {
|
||||
{ 88, 128, 64, 32 },
|
||||
"OK"
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
@@ -35,10 +35,14 @@
|
||||
#include "ui_lcr.hpp"
|
||||
#include "ui_whistle.hpp"
|
||||
#include "ui_jammer.hpp"
|
||||
#include "ui_loadmodule.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "m4_startup.hpp"
|
||||
#include "spi_image.hpp"
|
||||
|
||||
#include "modules.h"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
@@ -104,17 +108,20 @@ void NavigationView::focus() {
|
||||
/* SystemMenuView ********************************************************/
|
||||
|
||||
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||
add_items<10>({ {
|
||||
{ "Play dead", ui::Color::red(), [&nav](){ nav.push(new PlayDeadView { nav, false }); } },
|
||||
{ "Receiver", ui::Color::white(), [&nav](){ nav.push(new ReceiverView { nav, receiver_model }); } },
|
||||
{ "Jammer", ui::Color::white(), [&nav](){ nav.push(new JammerView { nav, transmitter_model }); } },
|
||||
{ "Whistle", ui::Color::white(), [&nav](){ nav.push(new WhistleView { nav, transmitter_model }); } },
|
||||
{ "RDS TX", ui::Color::yellow(), [&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 }); } },
|
||||
add_items<11>({ {
|
||||
{ "Play dead", ui::Color::red(), [&nav](){ nav.push(new PlayDeadView { nav, false }); } },
|
||||
{ "Receiver", ui::Color::cyan(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new ReceiverView { nav, receiver_model } }); } },
|
||||
//{ "Nordic/BTLE RX", ui::Color::cyan(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
|
||||
{ "Jammer", ui::Color::white(), [&nav](){ nav.push(new JammerView { nav, transmitter_model }); } },
|
||||
{ "Audio file TX", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
|
||||
//{ "Encoder TX", ui::Color::green(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
|
||||
{ "Whistle", ui::Color::purple(), [&nav](){ nav.push(new WhistleView { nav, transmitter_model }); } },
|
||||
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push(new RDSView { nav, transmitter_model }); } },
|
||||
{ "TEDI/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 }); } },
|
||||
} });
|
||||
}
|
||||
|
||||
|
@@ -36,140 +36,6 @@
|
||||
using namespace hackrf::one;
|
||||
|
||||
namespace ui {
|
||||
|
||||
AlphanumView::AlphanumView(
|
||||
NavigationView& nav,
|
||||
char txt[],
|
||||
uint8_t max_len
|
||||
) {
|
||||
_max_len = max_len;
|
||||
_lowercase = false;
|
||||
|
||||
static constexpr Style style_alpha {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::red(),
|
||||
.foreground = Color::black(),
|
||||
};
|
||||
|
||||
static constexpr Style style_num {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::yellow(),
|
||||
.foreground = Color::black(),
|
||||
};
|
||||
|
||||
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 : buttons) {
|
||||
add_child(&button);
|
||||
button.on_select = button_fn;
|
||||
button.set_parent_rect({
|
||||
static_cast<Coord>((n % 5) * button_w),
|
||||
static_cast<Coord>((n / 5) * button_h + 18),
|
||||
button_w, button_h
|
||||
});
|
||||
if ((n < 10) || (n == 39))
|
||||
button.set_style(&style_num);
|
||||
else
|
||||
button.set_style(&style_alpha);
|
||||
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(&button_done);
|
||||
button_done.on_select = [this, &nav, txt, max_len](Button&) {
|
||||
memcpy(txt, txtinput, max_len+1);
|
||||
on_changed(this->value());
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
update_text();
|
||||
}
|
||||
|
||||
void AlphanumView::set_uppercase() {
|
||||
const char* const key_caps = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ. !<";
|
||||
|
||||
size_t n = 0;
|
||||
for(auto& button : buttons) {
|
||||
add_child(&button);
|
||||
const std::string label {
|
||||
key_caps[n]
|
||||
};
|
||||
button.set_text(label);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AlphanumView::set_lowercase() {
|
||||
const char* const key_caps = "0123456789abcdefghijklmnopqrstuvwxyz. !<";
|
||||
|
||||
size_t n = 0;
|
||||
for(auto& button : buttons) {
|
||||
add_child(&button);
|
||||
const std::string label {
|
||||
key_caps[n]
|
||||
};
|
||||
button.set_text(label);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
void AlphanumView::focus() {
|
||||
button_done.focus();
|
||||
}
|
||||
|
||||
char * AlphanumView::value() {
|
||||
return txtinput;
|
||||
}
|
||||
|
||||
void AlphanumView::on_button(Button& button) {
|
||||
const auto s = button.text();
|
||||
if( s == "<" ) {
|
||||
char_delete();
|
||||
} else {
|
||||
char_add(s[0]);
|
||||
}
|
||||
update_text();
|
||||
}
|
||||
|
||||
void AlphanumView::char_add(const char c) {
|
||||
if (txtidx < _max_len) {
|
||||
txtinput[txtidx] = c;
|
||||
txtidx++;
|
||||
}
|
||||
}
|
||||
|
||||
void AlphanumView::char_delete() {
|
||||
if (txtidx) {
|
||||
txtidx--;
|
||||
txtinput[txtidx] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
void AlphanumView::update_text() {
|
||||
text_input.set(txtinput);
|
||||
}
|
||||
|
||||
void RDSView::focus() {
|
||||
button_setpsn.focus();
|
||||
|
@@ -24,12 +24,13 @@
|
||||
#include "ui_spectrum.hpp"
|
||||
#include "ui_console.hpp"
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
#include "portapack.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include "ais_baseband.hpp"
|
||||
|
||||
#include "ff.h"
|
||||
#include "m4_startup.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
|
Reference in New Issue
Block a user