Merge fixing, commit to catch up on recent files

This commit is contained in:
furrtek 2016-02-04 10:27:53 +01:00
parent 44638e504b
commit 6e496e2b26
90 changed files with 2257 additions and 1428 deletions

View File

@ -148,6 +148,8 @@ CPPSRC = main.cpp \
encoder.cpp \
lcd_ili9341.cpp \
ui.cpp \
ui_alphanum.cpp \
ui_about.cpp \
ui_text.cpp \
ui_widget.cpp \
ui_painter.cpp \
@ -157,6 +159,9 @@ CPPSRC = main.cpp \
ui_rssi.cpp \
ui_channel.cpp \
ui_audio.cpp \
ui_lcr.cpp \
ui_rds.cpp \
ui_jammer.cpp \
ui_font_fixed_8x16.cpp \
ui_setup.cpp \
ui_debug.cpp \

View File

@ -19,36 +19,34 @@
* Boston, MA 02110-1301, USA.
*/
#include "irq_ipc.hpp"
#ifndef __FILE_H__
#define __FILE_H__
#include "event.hpp"
#include "ff.h"
#include "ch.h"
#include "hal.h"
#include <cstddef>
#include <string>
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
class File {
public:
~File();
void m4txevent_interrupt_enable() {
nvicEnableVector(M4CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M4TXEVENT_IRQ_PRIORITY));
}
bool open_for_append(const std::string file_path);
bool close();
void m4txevent_interrupt_disable() {
nvicDisableVector(M4CORE_IRQn);
}
bool is_ready();
extern "C" {
bool read(void* const data, const size_t bytes_to_read);
bool write(const void* const data, const size_t bytes_to_write);
CH_IRQ_HANDLER(M4Core_IRQHandler) {
CH_IRQ_PROLOGUE();
bool puts(const std::string string);
chSysLockFromIsr();
events_flag_isr(EVT_MASK_APPLICATION);
chSysUnlockFromIsr();
bool sync();
creg::m4txevent::clear();
private:
const std::string file_path;
FIL f;
};
CH_IRQ_EPILOGUE();
}
}
#endif/*__FILE_H__*/

View File

@ -106,7 +106,7 @@ void m4_switch(const char * hash) {
// Ask M4 to enter wait loop in RAM
BasebandConfiguration baseband_switch {
.mode = SWITCH,
.mode = 255, // DEBUG
.sampling_rate = 0,
.decimation_factor = 1,
};

View File

@ -62,7 +62,6 @@
#include "ui_painter.hpp"
#include "ui_navigation.hpp"
#include "irq_ipc.hpp"
#include "irq_lcd_frame.hpp"
#include "irq_controls.hpp"
#include "irq_rtc.hpp"

View File

@ -75,31 +75,8 @@ uint32_t TransmitterModel::sampling_rate() const {
return baseband_configuration.sampling_rate;
}
void TransmitterModel::set_sampling_rate(uint32_t hz) {
baseband_configuration.sampling_rate = hz;
update_baseband_configuration();
}
mode_type TransmitterModel::modulation() const {
return baseband_configuration.mode;
}
void TransmitterModel::set_modulation(mode_type v) {
baseband_configuration.mode = v;
update_modulation();
}
uint32_t TransmitterModel::baseband_oversampling() const {
// TODO: Rename decimation_factor.
return baseband_configuration.decimation_factor;
}
void TransmitterModel::set_baseband_oversampling(uint32_t v) {
baseband_configuration.decimation_factor = v;
update_baseband_configuration();
}
void TransmitterModel::enable() {
enabled_ = true;
radio::set_direction(rf::Direction::Transmit);
update_tuning_frequency();
update_rf_amp();
@ -107,23 +84,30 @@ void TransmitterModel::enable() {
update_vga();
update_baseband_bandwidth();
update_baseband_configuration();
radio::streaming_enable();
}
void TransmitterModel::baseband_disable() {
shared_memory.baseband_queue.push_and_wait(
BasebandConfigurationMessage {
.configuration = { },
}
);
}
void TransmitterModel::disable() {
/* TODO: This is a dumb hack to stop baseband from working so hard. */
BasebandConfigurationMessage message {
.configuration = {
.mode = NONE,
.sampling_rate = 0,
.decimation_factor = 1,
}
};
shared_memory.baseband_queue.push(message);
enabled_ = false;
baseband_disable();
// TODO: Responsibility for enabling/disabling the radio is muddy.
// Some happens in ReceiverModel, some inside radio namespace.
radio::disable();
}
uint32_t TransmitterModel::baseband_oversampling() const {
// TODO: Rename decimation_factor.
return baseband_configuration.decimation_factor;
}
int32_t TransmitterModel::tuning_offset() {
return -(sampling_rate() / 4);
}
@ -148,8 +132,8 @@ void TransmitterModel::update_vga() {
radio::set_vga_gain(vga_gain_db_);
}
void TransmitterModel::update_modulation() {
update_baseband_configuration();
uint32_t TransmitterModel::modulation() const {
return baseband_configuration.mode;
}
void TransmitterModel::set_baseband_configuration(const BasebandConfiguration config) {
@ -158,7 +142,12 @@ void TransmitterModel::set_baseband_configuration(const BasebandConfiguration co
}
void TransmitterModel::update_baseband_configuration() {
radio::streaming_disable();
// TODO: Move more low-level radio control stuff to M4. It'll enable tighter
// synchronization for things like wideband (sweeping) spectrum analysis, and
// protocols that need quick RX/TX turn-around.
// Disabling baseband while changing sampling rates seems like a good idea...
baseband_disable();
clock_manager.set_sampling_frequency(sampling_rate() * baseband_oversampling());
update_tuning_frequency();
@ -166,7 +155,5 @@ void TransmitterModel::update_baseband_configuration() {
BasebandConfigurationMessage message { baseband_configuration };
shared_memory.baseband_queue.push(message);
radio::streaming_enable();
}

View File

@ -38,7 +38,7 @@ public:
) : clock_manager(clock_manager)
{
}
rf::Frequency tuning_frequency() const;
void set_tuning_frequency(rf::Frequency f);
@ -55,13 +55,10 @@ public:
void set_vga(int32_t v_db);
uint32_t sampling_rate() const;
void set_sampling_rate(uint32_t hz);
mode_type modulation() const;
void set_modulation(mode_type v);
uint32_t modulation() const;
uint32_t baseband_oversampling() const;
void set_baseband_oversampling(uint32_t v);
void enable();
void disable();
@ -69,12 +66,14 @@ public:
void set_baseband_configuration(const BasebandConfiguration config);
private:
rf::Frequency frequency_step_ { 25000 };
bool enabled_ { false };
bool rf_amp_ { true };
int32_t lna_gain_db_ { 0 };
uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum };
int32_t vga_gain_db_ { 8 };
BasebandConfiguration baseband_configuration {
.mode = NONE,
.mode = 1,
.sampling_rate = 2280000,
.decimation_factor = 1,
};
@ -89,6 +88,8 @@ private:
void update_vga();
void update_modulation();
void update_baseband_configuration();
void baseband_disable();
};
#endif/*__TRANSMITTER_MODEL_H__*/

View File

@ -26,6 +26,7 @@
#include "ymdata.hpp"
#include "portapack.hpp"
#include "event_m0.hpp"
#include "ui_about.hpp"
#include "touch.hpp"
@ -44,23 +45,21 @@ using namespace portapack;
namespace ui {
void AboutView::on_show() {
auto& message_map = context().message_map();
// Just in case
message_map.unregister_handler(Message::ID::DisplayFrameSync);
EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync);
// "Vertical blank interrupt"
message_map.register_handler(Message::ID::DisplayFrameSync,
EventDispatcher::message_map().register_handler(Message::ID::DisplayFrameSync,
[this](const Message* const) {
update();
}
);
// Just in case
message_map.unregister_handler(Message::ID::FIFOSignal);
EventDispatcher::message_map().unregister_handler(Message::ID::FIFOSignal);
// Handle baseband asking to fill up FIFO
message_map.register_handler(Message::ID::FIFOSignal,
EventDispatcher::message_map().register_handler(Message::ID::FIFOSignal,
[this](Message* const p) {
FIFODataMessage datamessage;
const auto message = static_cast<const FIFOSignalMessage*>(p);
@ -349,6 +348,7 @@ void AboutView::update() {
refresh_cnt++;
}
// Slowly increase volume to avoid jumpscare
if (headphone_vol < (70<<2)) {
portapack::audio_codec.set_headphone_volume(volume_t::decibel((headphone_vol/4) - 99) + wolfson::wm8731::headphone_gain_range.max);
headphone_vol++;
@ -370,14 +370,13 @@ void AboutView::ym_init() {
}
AboutView::AboutView(
NavigationView& nav,
TransmitterModel& transmitter_model
) : transmitter_model(transmitter_model)
NavigationView& nav
)
{
uint8_t p, c;
transmitter_model.set_baseband_configuration({
.mode = PLAY_AUDIO,
.mode = 5,
.sampling_rate = 1536000,
.decimation_factor = 1,
});
@ -412,8 +411,7 @@ AboutView::AboutView(
ym_init();
button_ok.on_select = [this,&nav](Button&){
auto& message_map = context().message_map();
message_map.unregister_handler(Message::ID::DisplayFrameSync);
EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync);
if (framebuffer) chHeapFree(framebuffer); // Do NOT forget this
nav.pop();
};

View File

@ -34,7 +34,7 @@ namespace ui {
class AboutView : public View {
public:
AboutView(NavigationView& nav, TransmitterModel& transmitter_model);
AboutView(NavigationView& nav);
~AboutView();
void on_show() override;
@ -54,8 +54,6 @@ private:
bool same;
} ymreg_t;
TransmitterModel& transmitter_model;
uint16_t headphone_vol = 5<<2;
ymreg_t ym_regs[14];

View File

@ -24,19 +24,17 @@
#include "ui_spectrum.hpp"
#include "ui_console.hpp"
#include "event_m0.hpp"
#include "ff.h"
#include "portapack.hpp"
using namespace portapack;
#include "ui_receiver.hpp"
namespace ui {
AFSKRXView::AFSKRXView(
NavigationView& nav,
ReceiverModel& receiver_model
) : receiver_model(receiver_model)
NavigationView& nav
)
{
add_children({ {
&button_done,
@ -48,7 +46,7 @@ AFSKRXView::AFSKRXView(
};
receiver_model.set_baseband_configuration({
.mode = RX_AFSK,
.mode = 6,
.sampling_rate = 3072000,
.decimation_factor = 4,
});
@ -60,8 +58,7 @@ AFSKRXView::~AFSKRXView() {
}
void AFSKRXView::on_show() {
auto& message_map = context().message_map();
message_map.register_handler(Message::ID::AFSKData,
EventDispatcher::message_map().register_handler(Message::ID::AFSKData,
[this](Message* const p) {
const auto message = static_cast<const AFSKDataMessage*>(p);
this->on_data_afsk(*message);
@ -72,8 +69,7 @@ void AFSKRXView::on_show() {
}
void AFSKRXView::on_hide() {
auto& message_map = context().message_map();
message_map.unregister_handler(Message::ID::AFSKData);
EventDispatcher::message_map().unregister_handler(Message::ID::AFSKData);
}
void AFSKRXView::on_data_afsk(const AFSKDataMessage& message) {

View File

@ -42,7 +42,7 @@ namespace ui {
class AFSKRXView : public View {
public:
AFSKRXView(NavigationView& nav, ReceiverModel& receiver_model);
AFSKRXView(NavigationView& nav);
~AFSKRXView();
void focus() override;
@ -51,8 +51,6 @@ public:
void on_hide() override;
private:
ReceiverModel& receiver_model;
std::unique_ptr<Widget> widget_content;
Button button_done {

View File

@ -66,9 +66,8 @@ void AFSKSetupView::updfreq(rf::Frequency f) {
}
AFSKSetupView::AFSKSetupView(
NavigationView& nav,
TransmitterModel& transmitter_model
) : transmitter_model(transmitter_model)
NavigationView& nav
)
{
uint8_t rpt;

View File

@ -36,15 +36,13 @@ namespace ui {
class AFSKSetupView : public View {
public:
AFSKSetupView(NavigationView& nav, TransmitterModel& transmitter_model);
AFSKSetupView(NavigationView& nav);
void updfreq(rf::Frequency f);
void focus() override;
void paint(Painter& painter) override;
private:
TransmitterModel& transmitter_model;
Text text_title {
{ 40, 32, 160, 16 },
"AFSK modulator setup"

View File

@ -110,7 +110,7 @@ void AlphanumView::set_uppercase() {
size_t n = 0;
for(auto& button : buttons) {
add_child(&button);
//add_child(&button);
const std::string label {
key_caps[n]
};
@ -125,7 +125,7 @@ void AlphanumView::set_lowercase() {
size_t n = 0;
for(auto& button : buttons) {
add_child(&button);
//add_child(&button);
const std::string label {
key_caps[n]
};

View File

@ -245,20 +245,6 @@ void RegistersView::focus() {
button_done.focus();
}
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;
@ -301,26 +287,26 @@ void DebugLCRView::focus() {
DebugMenuView::DebugMenuView(NavigationView& nav) {
add_items<8>({ {
{ "Memory", [&nav](){ nav.push<DebugMemoryView>(); } },
{ "Radio State", [&nav](){ nav.push<NotImplementedView>(); } },
{ "SD Card", [&nav](){ nav.push<NotImplementedView>(); } },
{ "RFFC5072", [&nav](){ nav.push<RegistersView>(
{ "Memory", ui::Color::white(), [&nav](){ nav.push<DebugMemoryView>(); } },
{ "Radio State", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "SD Card", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "RFFC5072", ui::Color::white(), [&nav](){ nav.push<RegistersView>(
"RFFC5072", RegistersWidgetConfig { 31, 2, 4, 4 },
[](const size_t register_number) { return radio::first_if.read(register_number); }
); } },
{ "MAX2837", [&nav](){ nav.push<RegistersView>(
{ "MAX2837", ui::Color::white(), [&nav](){ nav.push<RegistersView>(
"MAX2837", RegistersWidgetConfig { 32, 2, 3, 4 },
[](const size_t register_number) { return radio::second_if.read(register_number); }
); } },
{ "Si5351C", [&nav](){ nav.push<RegistersView>(
{ "Si5351C", ui::Color::white(), [&nav](){ nav.push<RegistersView>(
"Si5351C", RegistersWidgetConfig { 96, 2, 2, 8 },
[](const size_t register_number) { return portapack::clock_generator.read_register(register_number); }
); } },
{ "WM8731", [&nav](){ nav.push<RegistersView>(
{ "WM8731", ui::Color::white(), [&nav](){ nav.push<RegistersView>(
"WM8731", RegistersWidgetConfig { wolfson::wm8731::reg_count, 1, 3, 4 },
[](const size_t register_number) { return portapack::audio_codec.read(register_number); }
); } },
{ "Temperature", [&nav](){ nav.push<TemperatureView>(); } },
{ "Temperature", ui::Color::white(), [&nav](){ nav.push<TemperatureView>(); } },
} });
on_left = [&nav](){ nav.pop(); };
}

View File

@ -246,8 +246,6 @@ public:
void focus() override;
void paint(Painter& painter) override;
private:
Text text_lcr1 {
{ 16, 32, 208, 8 },

View File

@ -29,6 +29,8 @@
#include "hackrf_gpio.hpp"
#include "portapack.hpp"
#include "radio.hpp"
#include "string_format.hpp"
#include "event_m0.hpp"
#include "hackrf_hal.hpp"
#include "portapack_shared_memory.hpp"
@ -37,7 +39,7 @@
#include <cstring>
#include <stdio.h>
using namespace hackrf::one;
using namespace portapack;
namespace ui {
@ -146,9 +148,8 @@ void JammerView::updfreq(uint8_t id, rf::Frequency f) {
}
JammerView::JammerView(
NavigationView& nav,
TransmitterModel& transmitter_model
) : transmitter_model(transmitter_model)
NavigationView& nav
)
{
static constexpr Style style_val {
@ -169,7 +170,11 @@ JammerView::JammerView(
.foreground = Color::grey(),
};
transmitter_model.set_modulation(TX_JAMMER);
transmitter_model.set_baseband_configuration({
.mode = 3,
.sampling_rate = 1536000, // ?
.decimation_factor = 1,
});
add_children({ {
&text_type,
@ -232,11 +237,9 @@ JammerView::JammerView(
button_transmit.on_select = [this,&transmitter_model](Button&) {
uint8_t i = 0;
rf::Frequency t, range_lower;
auto& message_map = context().message_map();
EventDispatcher::message_map().unregister_handler(Message::ID::Retune);
message_map.unregister_handler(Message::ID::Retune);
message_map.register_handler(Message::ID::Retune,
EventDispatcher::message_map().register_handler(Message::ID::Retune,
[this,&transmitter_model](Message* const p) {
const auto message = static_cast<const RetuneMessage*>(p);
if (message->freq > 0) {

View File

@ -36,7 +36,7 @@ namespace ui {
class JammerView : public View {
public:
JammerView(NavigationView& nav, TransmitterModel& transmitter_model);
JammerView(NavigationView& nav);
~JammerView();
void updfreq(uint8_t id, rf::Frequency f);
@ -117,7 +117,6 @@ private:
bool jamming = false;
rf::Frequency f;
TransmitterModel& transmitter_model;
Text text_type {
{ 1 * 8, 1 * 16, 40, 16 },

View File

@ -31,8 +31,11 @@
#include "ff.h"
#include "hackrf_gpio.hpp"
#include "portapack.hpp"
#include "event_m0.hpp"
#include "radio.hpp"
#include "string_format.hpp"
#include "hackrf_hal.hpp"
#include "portapack_shared_memory.hpp"
#include "portapack_persistent_memory.hpp"
@ -40,7 +43,7 @@
#include <cstring>
#include <stdio.h>
using namespace hackrf::one;
using namespace portapack;
namespace ui {
@ -176,9 +179,8 @@ void LCRView::paint(Painter& painter) {
}
LCRView::LCRView(
NavigationView& nav,
TransmitterModel& transmitter_model
) : transmitter_model(transmitter_model)
NavigationView& nav
)
{
char finalstr[24] = {0};
@ -188,7 +190,12 @@ LCRView::LCRView(
.foreground = Color::black(),
};
transmitter_model.set_modulation(TX_LCR);
transmitter_model.set_baseband_configuration({
.mode = 1,
.sampling_rate = 1536000, // Is this right ?
.decimation_factor = 1,
});
transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
memset(litteral, 0, 5*8);
memset(rgsb, 0, 5);
@ -277,8 +284,6 @@ LCRView::LCRView(
};
button_transmit.on_select = [this,&transmitter_model](Button&){
auto& message_map = context().message_map();
make_frame();
shared_memory.afsk_samples_per_bit = 228000/portapack::persistent_memory::afsk_bitrate();
@ -293,7 +298,7 @@ LCRView::LCRView(
shared_memory.afsk_transmit_done = false;
shared_memory.afsk_repeat = (portapack::persistent_memory::afsk_config() >> 8) & 0xFF;
message_map.register_handler(Message::ID::TXDone,
EventDispatcher::message_map().register_handler(Message::ID::TXDone,
[this,&transmitter_model](Message* const p) {
char str[8];
const auto message = static_cast<const TXDoneMessage*>(p);
@ -319,7 +324,7 @@ LCRView::LCRView(
};
button_txsetup.on_select = [&nav, &transmitter_model](Button&){
nav.push(new AFSKSetupView { nav, transmitter_model });
nav.push(new AFSKSetupView { nav });
};
button_exit.on_select = [&nav](Button&){

View File

@ -36,7 +36,7 @@ namespace ui {
class LCRView : public View {
public:
LCRView(NavigationView& nav, TransmitterModel& transmitter_model);
LCRView(NavigationView& nav);
~LCRView();
void make_frame();
@ -63,7 +63,6 @@ private:
char lcrframe[256];
char lcrframe_f[256];
rf::Frequency f;
TransmitterModel& transmitter_model;
Text text_status {
{ 168, 196, 64, 16 },

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
@ -24,10 +25,12 @@
#include "ch.h"
#include "ff.h"
#include "event_m0.hpp"
#include "hackrf_gpio.hpp"
#include "portapack.hpp"
#include "portapack_shared_memory.hpp"
#include "hackrf_hal.hpp"
#include "string_format.hpp"
#include <cstring>
#include <stdio.h>
@ -45,18 +48,17 @@ void LoadModuleView::paint(Painter& painter) {
}
void LoadModuleView::on_hide() {
auto& message_map = context().message_map();
message_map.unregister_handler(Message::ID::ReadyForSwitch);
EventDispatcher::message_map().unregister_handler(Message::ID::ReadyForSwitch);
EventDispatcher::message_map().unregister_handler(Message::ID::ModuleID);
}
void LoadModuleView::on_show() {
// Ask for MD5 signature and compare
ModuleIDMessage message;
auto& message_map = context().message_map();
//message_map.unregister_handler(Message::ID::ModuleID);
message_map.unregister_handler(Message::ID::ModuleID);
message_map.register_handler(Message::ID::ModuleID,
EventDispatcher::message_map().register_handler(Message::ID::ModuleID,
[this](Message* const p) {
uint8_t c;
const auto message = static_cast<const ModuleIDMessage*>(p);
@ -78,13 +80,66 @@ void LoadModuleView::on_show() {
shared_memory.baseband_queue.push(message);
}
int LoadModuleView::load_image() {
const char magic[6] = {'P', 'P', 'M', ' ', 0x02, 0x00};
UINT bw;
uint8_t i;
uint32_t cnt;
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
if (f_opendir(&rootdir, "/") == FR_OK) {
for (;;) {
res = f_readdir(&rootdir, &modinfo);
if (res != FR_OK || modinfo.fname[0] == 0) break; // Reached last file, abort
// Only care about files with .bin extension
if ((!(modinfo.fattrib & AM_DIR)) && (modinfo.fname[9] == 'B') && (modinfo.fname[10] == 'I') && (modinfo.fname[11] == 'N')) {
res = f_open(&modfile, modinfo.fname, FA_OPEN_EXISTING | FA_READ);
if (res != FR_OK) return 0;
// Magic bytes and version check
f_read(&modfile, &md5sum, 6, &bw);
for (i = 0; i < 6; i++)
if (md5sum[i] != magic[i]) break;
if (i == 6) {
f_lseek(&modfile, 26);
f_read(&modfile, &md5sum, 16, &bw);
for (i = 0; i < 16; i++)
if (md5sum[i] != _hash[i]) break;
// f_read can't read more than 512 bytes at a time ?
if (i == 16) {
f_lseek(&modfile, 512);
for (cnt = 0; cnt < 64; cnt++) {
if (f_read(&modfile, reinterpret_cast<void*>(portapack::memory::map::m4_code.base() + (cnt * 512)), 512, &bw)) return 0;
}
f_close(&modfile);
f_closedir(&rootdir);
LPC_RGU->RESET_CTRL[0] = (1 << 13);
return 1;
}
}
f_close(&modfile);
}
}
f_closedir(&rootdir);
}
return 0;
}
void LoadModuleView::loadmodule() {
auto& message_map = context().message_map();
message_map.register_handler(Message::ID::ReadyForSwitch,
//message_map.unregister_handler(Message::ID::ReadyForSwitch);
EventDispatcher::message_map().register_handler(Message::ID::ReadyForSwitch,
[this](Message* const p) {
(void)p;
if (m4_load_image()) {
text_info.set("Module loaded :)");
if (load_image()) {
text_info.set(to_string_hex(*((unsigned int*)0x10080000),8));
//text_infob.set(to_string_hex(*((unsigned int*)0x10080004),8));
text_infob.set("Module loaded :)");
_mod_loaded = true;
} else {
text_info.set("Module not found :(");
@ -104,6 +159,7 @@ LoadModuleView::LoadModuleView(
{
add_children({ {
&text_info,
&text_infob,
&button_ok
} });

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
@ -31,7 +32,7 @@ namespace ui {
class LoadModuleView : public View {
public:
LoadModuleView(NavigationView& nav, const char * hash, View* new_view);
LoadModuleView(NavigationView& nav, const char * hash, View * new_view);
void loadmodule();
void on_show() override;
@ -40,12 +41,17 @@ public:
void paint(Painter& painter) override;
private:
int load_image(void);
const char * _hash;
bool _mod_loaded = false;
Text text_info {
{ 8, 64, 224, 16 },
"Searching module..."
"-"
};
Text text_infob {
{ 8, 64+16, 224, 16 },
"-"
};
Button button_ok {

View File

@ -108,6 +108,10 @@ View* NavigationView::push_view(std::unique_ptr<View> new_view) {
return p;
}
void NavigationView::push(View* v) {
push_view(std::unique_ptr<View>(v));
}
void NavigationView::pop() {
// Can't pop last item from stack.
if( view_stack.size() > 1 ) {
@ -149,9 +153,9 @@ void NavigationView::focus() {
TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
add_items<3>({ {
{ "AIS: Boats", [&nav](){ nav.push<AISAppView>(); } },
{ "ERT: Utility Meters", [&nav](){ nav.push<ERTAppView>(); } },
{ "TPMS: Cars", [&nav](){ nav.push<TPMSAppView>(); } },
{ "AIS: Boats", ui::Color::white(), [&nav](){ nav.push<AISAppView>(); } },
{ "ERT: Utility Meters", ui::Color::white(), [&nav](){ nav.push<ERTAppView>(); } },
{ "TPMS: Cars", ui::Color::white(), [&nav](){ nav.push<TPMSAppView>(); } },
} });
}
@ -159,8 +163,8 @@ TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
add_items<2>({ {
{ "Audio", [&nav](){ nav.push<ReceiverView>(); } },
{ "Transponders", [&nav](){ nav.push<TranspondersMenuView>(); } },
{ "Audio", ui::Color::white(), [&nav](){ nav.push<ReceiverView>(); } },
{ "Transponders", ui::Color::white(), [&nav](){ nav.push<TranspondersMenuView>(); } },
} });
}
@ -168,24 +172,24 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
SystemMenuView::SystemMenuView(NavigationView& nav) {
add_items<10>({ {
{ "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 ReceiverMenuView { nav, receiver_model }}); } },
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } },
{ "Receiver", ui::Color::cyan(), [&nav](){ nav.push<LoadModuleView>(md5_baseband, new ReceiverMenuView(nav)); } },
//{ "Nordic/BTLE RX", ui::Color::cyan(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
{ "Jammer", ui::Color::white(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new JammerView { nav, transmitter_model }}); } },
{ "Jammer", ui::Color::white(), [&nav](){ nav.push<LoadModuleView>(md5_baseband, new JammerView(nav)); } },
//{ "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 LoadModuleView { nav, md5_baseband, new WhistleView { nav, transmitter_model }}); } },
//{ "SIGFOX RX", ui::Color::orange(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new SIGFRXView { nav, receiver_model }}); } },
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new RDSView { nav, transmitter_model }}); } },
{ "Xylos TX", ui::Color::orange(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new XylosView { nav, transmitter_model }}); } },
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, new RDSView(nav)); } },
{ "Xylos TX", ui::Color::orange(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, new XylosView(nav)); } },
//{ "Xylos RX", ui::Color::green(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new XylosRXView { nav, receiver_model }}); } },
//{ "AFSK RX", ui::Color::cyan(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new AFSKRXView { nav, receiver_model }}); } },
{ "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new LCRView { nav, transmitter_model }}); } },
{ "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, new LCRView(nav)); } },
//{ "Numbers station", ui::Color::purple(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new NumbersStationView { nav, transmitter_model }}); } },
{ "Setup", ui::Color::white(), [&nav](){ nav.push(new SetupMenuView { nav }); } },
{ "About", ui::Color::white(), [&nav](){ nav.push(new AboutView { nav, transmitter_model }); } },
{ "Debug", ui::Color::white(), [&nav](){ nav.push(new DebugMenuView { nav }); } },
{ "HackRF", ui::Color::white(), [&nav](){ nav.push(new HackRFFirmwareView { nav }); } },
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } },
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
{ "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } },
} });
}
@ -266,6 +270,41 @@ HackRFFirmwareView::HackRFFirmwareView(NavigationView& nav) {
} });
}
/* PlayDeadView **********************************************************/
void PlayDeadView::focus() {
button_done.focus();
}
PlayDeadView::PlayDeadView(NavigationView& nav, bool booting) {
_booting = booting;
persistent_memory::set_playing_dead(0x59);
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()) {
persistent_memory::set_playing_dead(0);
if (_booting) {
nav.pop();
nav.push<SystemMenuView>();
} else {
nav.pop();
}
} else {
sequence = 0;
}
};
}
void HackRFFirmwareView::focus() {
button_no.focus();
}

View File

@ -82,6 +82,8 @@ public:
T* push(Args&&... args) {
return reinterpret_cast<T*>(push_view(std::unique_ptr<View>(new T(*this, std::forward<Args>(args)...))));
}
void push(View* v);
void pop();
@ -120,6 +122,29 @@ private:
};
};
class PlayDeadView : public View {
public:
PlayDeadView(NavigationView& nav, bool booting);
void focus() override;
private:
bool _booting;
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 ReceiverMenuView : public MenuView {
public:
ReceiverMenuView(NavigationView& nav);

View File

@ -34,7 +34,7 @@
#include <cstring>
using namespace hackrf::one;
using namespace portapack;
namespace ui {
@ -134,9 +134,8 @@ void RDSView::paint(Painter& painter) {
}
RDSView::RDSView(
NavigationView& nav,
TransmitterModel& transmitter_model
) : transmitter_model(transmitter_model)
NavigationView& nav
)
{
transmitter_model.set_tuning_frequency(93000000);
strcpy(psname, "TEST1234");

View File

@ -86,7 +86,7 @@ private:
*/
class RDSView : public View {
public:
RDSView(NavigationView& nav, TransmitterModel& transmitter_model);
RDSView(NavigationView& nav);
~RDSView();
void focus() override;
@ -94,7 +94,6 @@ public:
private:
char psname[9];
TransmitterModel& transmitter_model;
Text text_title {
{ 76, 16, 88, 16 },

View File

@ -20,13 +20,16 @@
*/
#include "ui_setup.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
#include "portapack.hpp"
using portapack::receiver_model;
using namespace portapack;
namespace ui {
@ -167,12 +170,6 @@ void AntennaBiasSetupView::focus() {
button_done.focus();
}
void AboutView::focus() {
button_ok.focus();
}
void SetTouchCalibView::focus() {
button_ok.focus();
}
@ -433,13 +430,13 @@ void ModInfoView::focus() {
SetupMenuView::SetupMenuView(NavigationView& nav) {
add_items<7>({ {
{ "SD card modules", ui::Color::white(), [&nav](){ nav.push(new ModInfoView { nav }); } },
{ "Date/Time", ui::Color::white(), [&nav](){ nav.push(new SetDateTimeView { nav }); } },
{ "SD card modules", ui::Color::white(), [&nav](){ nav.push<ModInfoView>(); } },
{ "Date/Time", ui::Color::white(), [&nav](){ nav.push<SetDateTimeView>(); } },
{ "Frequency correction", ui::Color::white(), [&nav](){ nav.push<SetFrequencyCorrectionView>(); } },
{ "Antenna Bias Voltage", [&nav](){ nav.push<AntennaBiasSetupView>(); } },
{ "Touch screen", ui::Color::white(), [&nav](){ nav.push(new SetTouchCalibView { nav }); } },
{ "Play dead", ui::Color::red(), [&nav](){ nav.push(new SetPlayDeadView { nav }); } },
{ "UI", ui::Color::white(), [&nav](){ nav.push(new SetUIView { nav }); } },
{ "Antenna Bias Voltage", ui::Color::white(), [&nav](){ nav.push<AntennaBiasSetupView>(); } },
{ "Touch screen", ui::Color::white(), [&nav](){ nav.push<SetTouchCalibView>(); } },
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<SetPlayDeadView>(); } },
{ "UI", ui::Color::white(), [&nav](){ nav.push<SetUIView>(); } },
} });
on_left = [&nav](){ nav.pop(); };
}

View File

@ -25,6 +25,7 @@
#include "ui_widget.hpp"
#include "ui_menu.hpp"
#include "ui_navigation.hpp"
#include "ff.h"
#include <cstdint>
@ -252,6 +253,132 @@ private:
};
};
class SetUIView : public View {
public:
SetUIView(NavigationView& nav);
void focus() override;
private:
Checkbox checkbox_showsplash {
{ 3 * 8, 2 * 16},
"Show splash"
};
Checkbox checkbox_bloff {
{ 3 * 8, 4 * 16},
"Backlight off after:"
};
OptionsField options_bloff {
{ 10 * 8, 5 * 16 + 4 },
10,
{
{ "5 seconds ", 0 },
{ "15 seconds", 1 },
{ "1 minute ", 2 },
{ "5 minutes ", 3 },
{ "10 minutes", 4 }
}
};
Button button_ok {
{ 4 * 8, 272, 64, 24 },
"Ok"
};
};
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 ModInfoView : public View {
public:
ModInfoView(NavigationView& nav);
void focus() override;
void on_show() override;
private:
void update_infos(uint8_t modn);
typedef struct moduleinfo_t{
char filename[9];
uint16_t version;
uint32_t size;
char md5[16];
char name[16];
char description[214];
} moduleinfo_t;
moduleinfo_t module_list[8]; // 8 max for now
Text text_modcount {
{ 2 * 8, 1 * 16, 18 * 8, 16 },
"Searching..."
};
OptionsField option_modules {
{ 2 * 8, 2 * 16 },
24,
{ { "-", 0 }
}
};
Text text_name {
{ 2 * 8, 4 * 16, 5 * 8, 16 },
"Name:"
};
Text text_namestr {
{ 8 * 8, 4 * 16, 16 * 8, 16 },
"..."
};
Text text_size {
{ 2 * 8, 5 * 16, 5 * 8, 16 },
"Size:"
};
Text text_sizestr {
{ 8 * 8, 5 * 16, 16 * 8, 16 },
"..."
};
Text text_md5 {
{ 2 * 8, 6 * 16, 4 * 8, 16 },
"MD5:"
};
Text text_md5_a {
{ 7 * 8, 6 * 16, 16 * 8, 16 },
"..."
};
Text text_md5_b {
{ 7 * 8, 7 * 16, 16 * 8, 16 },
"..."
};
Button button_ok {
{ 4 * 8, 272, 64, 24 },
"Ok"
};
};
class SetupMenuView : public MenuView {
public:
SetupMenuView(NavigationView& nav);

View File

@ -25,11 +25,13 @@
#include "ch.h"
#include "evtimer.h"
#include "event_m0.hpp"
#include "ff.h"
#include "hackrf_gpio.hpp"
#include "portapack.hpp"
#include "radio.hpp"
//#include "fox_bmp.hpp"
#include "string_format.hpp"
#include "hackrf_hal.hpp"
#include "portapack_shared_memory.hpp"
@ -38,7 +40,7 @@
#include <cstring>
#include <stdio.h>
using namespace hackrf::one;
using namespace portapack;
namespace ui {
@ -98,20 +100,23 @@ void SIGFRXView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
}
void SIGFRXView::on_show() {
context().message_map().register_handler(Message::ID::ChannelSpectrum,
/*EventDispatcher::message_map().register_handler(Message::ID::ChannelSpectrum,
[this](const Message* const p) {
this->on_channel_spectrum(reinterpret_cast<const ChannelSpectrumMessage*>(p)->spectrum);
}
);
);*/
}
void SIGFRXView::on_hide() {
//EventDispatcher::message_map().unregister_handler(Message::ID::ChannelSpectrum);
}
SIGFRXView::SIGFRXView(
NavigationView& nav,
ReceiverModel& receiver_model
) : receiver_model(receiver_model)
NavigationView& nav
)
{
receiver_model.set_baseband_configuration({
.mode = RX_SIGFOX,
.mode = 255, // DEBUG
.sampling_rate = 3072000,
.decimation_factor = 4,
});

View File

@ -36,17 +36,16 @@ namespace ui {
class SIGFRXView : public View {
public:
SIGFRXView(NavigationView& nav, ReceiverModel& receiver_model);
SIGFRXView(NavigationView& nav);
~SIGFRXView();
void on_channel_spectrum(const ChannelSpectrum& spectrum);
void on_show() override;
void on_hide() override;
void focus() override;
void paint(Painter& painter) override;
private:
ReceiverModel& receiver_model;
private:
uint8_t last_channel;
uint8_t detect_counter = 0;

View File

@ -25,6 +25,7 @@
#include "ch.h"
#include "hackrf_hal.hpp"
#include "event_m0.hpp"
#include "ui_alphanum.hpp"
#include "ff.h"
#include "hackrf_gpio.hpp"
@ -38,7 +39,7 @@
#include <cstring>
#include <stdio.h>
using namespace hackrf::one;
using namespace portapack;
namespace ui {
@ -91,9 +92,8 @@ void XylosRXView::on_show() {
}
XylosRXView::XylosRXView(
NavigationView& nav,
ReceiverModel& receiver_model
) : receiver_model(receiver_model)
NavigationView& nav
)
{
char ccirdebug[21] = { 0,0,0,0,1,8,1,10,10,10,11,1,1,2,0,11,0,0,0,0,0xFF };
@ -211,9 +211,8 @@ void XylosView::journuit() {
}
XylosView::XylosView(
NavigationView& nav,
TransmitterModel& transmitter_model
) : transmitter_model(transmitter_model)
NavigationView& nav
)
{
static constexpr Style style_val {
.font = font::fixed_8x16,
@ -228,13 +227,11 @@ XylosView::XylosView(
};
transmitter_model.set_baseband_configuration({
.mode = TX_XYLOS,
.mode = 4,
.sampling_rate = 1536000,
.decimation_factor = 1,
});
transmitter_model.set_modulation(TX_XYLOS); // Useless ?
add_children({ {
&text_title,
&button_txtest,
@ -323,11 +320,9 @@ XylosView::XylosView(
button_txtest.on_select = [this,&transmitter_model](Button&) {
const uint8_t ccirtest[21] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,0xFF };
if (txing == false) {
auto& message_map = context().message_map();
EventDispatcher::message_map().unregister_handler(Message::ID::TXDone);
message_map.unregister_handler(Message::ID::TXDone);
message_map.register_handler(Message::ID::TXDone,
EventDispatcher::message_map().register_handler(Message::ID::TXDone,
[this,&transmitter_model](Message* const p) {
const auto message = static_cast<const TXDoneMessage*>(p);
if (message->n == 25) {
@ -359,11 +354,9 @@ XylosView::XylosView(
if (txing == false) {
upd_message();
auto& message_map = context().message_map();
EventDispatcher::message_map().unregister_handler(Message::ID::TXDone);
message_map.unregister_handler(Message::ID::TXDone);
message_map.register_handler(Message::ID::TXDone,
EventDispatcher::message_map().register_handler(Message::ID::TXDone,
[this,&transmitter_model](Message* const p) {
uint8_t c;
char progress[21];

View File

@ -45,7 +45,7 @@ void do_something();
class XylosRXView : public View {
public:
XylosRXView(NavigationView& nav, ReceiverModel& receiver_model);
XylosRXView(NavigationView& nav);
~XylosRXView();
void talk();
@ -91,8 +91,6 @@ private:
"trailer.wav"
};
char ccir_received[21];
ReceiverModel& receiver_model;
Text text_title {
{ 1 * 8, 1 * 16, 11, 16 },
@ -142,7 +140,7 @@ private:
class XylosView : public View {
public:
XylosView(NavigationView& nav, TransmitterModel& transmitter_model);
XylosView(NavigationView& nav);
~XylosView();
void journuit();
@ -184,8 +182,6 @@ private:
};
char ccirmessage[21];
char ccir_received[21];
TransmitterModel& transmitter_model;
Text text_title {
{ 1 * 8, 1 * 16, 11, 16 },

Binary file not shown.

View File

@ -124,16 +124,20 @@ CSRC = $(PORTSRC) \
# setting.
CPPSRC = main.cpp \
message_queue.cpp \
event.cpp \
event_m4.cpp \
irq_ipc_m4.cpp \
gpdma.cpp \
baseband_dma.cpp \
baseband_sgpio.cpp \
portapack_shared_memory.cpp \
baseband_thread.cpp \
baseband_processor.cpp \
channel_decimator.cpp \
baseband_stats_collector.cpp \
dsp_decimate.cpp \
dsp_demodulate.cpp \
matched_filter.cpp \
spectrum_collector.cpp \
proc_rds.cpp \
proc_jammer.cpp \
proc_fsk_lcr.cpp \
proc_xylos.cpp \
@ -144,11 +148,15 @@ CPPSRC = main.cpp \
packet_builder.cpp \
dsp_fft.cpp \
dsp_fir_taps.cpp \
dsp_iir.cpp \
fxpt_atan2.cpp \
rssi.cpp \
rssi_dma.cpp \
rssi_thread.cpp \
audio.cpp \
audio_output.cpp \
audio_dma.cpp \
audio_stats_collector.cpp \
touch_dma.cpp \
../common/utility.cpp \
../common/chibios_cpp.cpp \

View File

@ -121,7 +121,7 @@ constexpr gpdma::channel::Config config_rx() {
/* TODO: Clean up terminology around "buffer", "transfer", "samples" */
constexpr size_t buffer_samples_log2n = 8; // Bumped to 8, to allow filling at 750Hz
constexpr size_t buffer_samples_log2n = 7;
constexpr size_t buffer_samples = (1 << buffer_samples_log2n);
constexpr size_t transfers_per_buffer_log2n = 2;
constexpr size_t transfers_per_buffer = (1 << transfers_per_buffer_log2n);
@ -208,8 +208,8 @@ void enable() {
}
void disable() {
gpdma_channel_i2s0_tx.disable_force();
gpdma_channel_i2s0_rx.disable_force();
gpdma_channel_i2s0_tx.disable();
gpdma_channel_i2s0_rx.disable();
}
buffer_t tx_empty_buffer() {

View File

@ -0,0 +1,100 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "audio_output.hpp"
#include "portapack_shared_memory.hpp"
#include "audio_dma.hpp"
#include "message.hpp"
#include <cstdint>
#include <cstddef>
#include <array>
void AudioOutput::configure(
const iir_biquad_config_t& hpf_config,
const iir_biquad_config_t& deemph_config,
const float squelch_threshold
) {
hpf.configure(hpf_config);
deemph.configure(deemph_config);
squelch.set_threshold(squelch_threshold);
}
void AudioOutput::write(
const buffer_s16_t& audio
) {
std::array<float, 32> audio_f;
for(size_t i=0; i<audio.count; i++) {
audio_f[i] = audio.p[i];
}
write(buffer_f32_t {
audio_f.data(),
audio.count,
audio.sampling_rate
});
}
void AudioOutput::write(
const buffer_f32_t& audio
) {
const auto audio_present_now = squelch.execute(audio);
hpf.execute_in_place(audio);
deemph.execute_in_place(audio);
audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0);
const bool audio_present = (audio_present_history != 0);
if( audio_present ) {
i2s::i2s0::tx_unmute();
} else {
i2s::i2s0::tx_mute();
for(size_t i=0; i<audio.count; i++) {
audio.p[i] = 0;
}
}
fill_audio_buffer(audio);
}
void AudioOutput::fill_audio_buffer(const buffer_f32_t& audio) {
auto audio_buffer = audio::dma::tx_empty_buffer();
for(size_t i=0; i<audio_buffer.count; i++) {
const int32_t sample_int = audio.p[i];
const int32_t sample_saturated = __SSAT(sample_int, 16);
audio_buffer.p[i].left = audio_buffer.p[i].right = sample_saturated;
}
feed_audio_stats(audio);
}
void AudioOutput::feed_audio_stats(const buffer_f32_t& audio) {
audio_stats.feed(
audio,
[](const AudioStatistics& statistics) {
const AudioStatisticsMessage audio_stats_message { statistics };
shared_memory.application_queue.push(audio_stats_message);
}
);
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __AUDIO_OUTPUT_H__
#define __AUDIO_OUTPUT_H__
#include "dsp_types.hpp"
#include "dsp_iir.hpp"
#include "dsp_squelch.hpp"
#include "audio_stats_collector.hpp"
#include <cstdint>
class AudioOutput {
public:
void configure(
const iir_biquad_config_t& hpf_config,
const iir_biquad_config_t& deemph_config = iir_config_passthrough,
const float squelch_threshold = 0.0f
);
void write(const buffer_s16_t& audio);
void write(const buffer_f32_t& audio);
private:
IIRBiquadFilter hpf;
IIRBiquadFilter deemph;
FMSquelch squelch;
AudioStatsCollector audio_stats;
uint64_t audio_present_history = 0;
void fill_audio_buffer(const buffer_f32_t& audio);
void feed_audio_stats(const buffer_f32_t& audio);
};
#endif/*__AUDIO_OUTPUT_H__*/

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "audio_stats_collector.hpp"
#include "utility.hpp"
void AudioStatsCollector::consume_audio_buffer(const buffer_f32_t& src) {
auto src_p = src.p;
const auto src_end = &src.p[src.count];
while(src_p < src_end) {
const auto sample = *(src_p++);
const auto sample_squared = sample * sample;
squared_sum += sample_squared;
if( sample_squared > max_squared ) {
max_squared = sample_squared;
}
}
}
bool AudioStatsCollector::update_stats(const size_t sample_count, const size_t sampling_rate) {
count += sample_count;
const size_t samples_per_update = sampling_rate * update_interval;
if( count >= samples_per_update ) {
statistics.rms_db = complex16_mag_squared_to_dbv_norm(squared_sum / count);
statistics.max_db = complex16_mag_squared_to_dbv_norm(max_squared);
statistics.count = count;
squared_sum = 0;
max_squared = 0;
count = 0;
return true;
} else {
return false;
}
}
bool AudioStatsCollector::feed(const buffer_f32_t& src) {
consume_audio_buffer(src);
return update_stats(src.count, src.sampling_rate);
}
bool AudioStatsCollector::mute(const size_t sample_count, const size_t sampling_rate) {
return update_stats(sample_count, sampling_rate);
}

View File

@ -22,9 +22,8 @@
#ifndef __AUDIO_STATS_COLLECTOR_H__
#define __AUDIO_STATS_COLLECTOR_H__
#include "buffer.hpp"
#include "dsp_types.hpp"
#include "message.hpp"
#include "utility.hpp"
#include <cstdint>
#include <cstddef>
@ -32,64 +31,33 @@
class AudioStatsCollector {
public:
template<typename Callback>
void feed(buffer_s16_t src, Callback callback) {
consume_audio_buffer(src);
if( update_stats(src.count, src.sampling_rate) ) {
void feed(const buffer_f32_t& src, Callback callback) {
if( feed(src) ) {
callback(statistics);
}
}
template<typename Callback>
void mute(const size_t sample_count, const size_t sampling_rate, Callback callback) {
if( update_stats(sample_count, sampling_rate) ) {
if( mute(sample_count, sampling_rate) ) {
callback(statistics);
}
}
private:
static constexpr float update_interval { 0.1f };
uint64_t squared_sum { 0 };
uint32_t max_squared { 0 };
float squared_sum { 0 };
float max_squared { 0 };
size_t count { 0 };
AudioStatistics statistics;
void consume_audio_buffer(buffer_s16_t src) {
auto src_p = src.p;
const auto src_end = &src.p[src.count];
while(src_p < src_end) {
const auto sample = *(src_p++);
const uint64_t sample_squared = sample * sample;
squared_sum += sample_squared;
if( sample_squared > max_squared ) {
max_squared = sample_squared;
}
}
}
void consume_audio_buffer(const buffer_f32_t& src);
bool update_stats(const size_t sample_count, const size_t sampling_rate) {
count += sample_count;
bool update_stats(const size_t sample_count, const size_t sampling_rate);
const size_t samples_per_update = sampling_rate * update_interval;
if( count >= samples_per_update ) {
const float squared_sum_f = squared_sum;
const float max_squared_f = max_squared;
const float squared_avg_f = squared_sum_f / count;
statistics.rms_db = complex16_mag_squared_to_dbv_norm(squared_avg_f);
statistics.max_db = complex16_mag_squared_to_dbv_norm(max_squared_f);
statistics.count = count;
squared_sum = 0;
max_squared = 0;
count = 0;
return true;
} else {
return false;
}
}
bool feed(const buffer_f32_t& src);
bool mute(const size_t sample_count, const size_t sampling_rate);
};
#endif/*__AUDIO_STATS_COLLECTOR_H__*/

View File

@ -20,7 +20,6 @@
*/
#include "baseband_dma.hpp"
#include "portapack_shared_memory.hpp"
#include <cstdint>
#include <cstddef>
@ -35,8 +34,6 @@ using namespace lpc43xx;
namespace baseband {
namespace dma {
int quitt = 0;
constexpr uint32_t gpdma_ahb_master_sgpio = 0;
constexpr uint32_t gpdma_ahb_master_memory = 1;
@ -102,17 +99,12 @@ constexpr size_t msg_count = transfers_per_buffer - 1;
static std::array<gpdma::channel::LLI, transfers_per_buffer> lli_loop;
static constexpr auto& gpdma_channel_sgpio = gpdma::channels[portapack::sgpio_gpdma_channel_number];
//static Mailbox mailbox;
//static std::array<msg_t, msg_count> messages;
static Semaphore semaphore;
static volatile const gpdma::channel::LLI* next_lli = nullptr;
void transfer_complete() {
static void transfer_complete() {
next_lli = gpdma_channel_sgpio.next_lli();
quitt = 0;
/* TODO: Is Mailbox the proper synchronization mechanism for this? */
//chMBPostI(&mailbox, 0);
chSemSignalI(&semaphore);
}
@ -121,7 +113,6 @@ static void dma_error() {
}
void init() {
//chMBInit(&mailbox, messages.data(), messages.size());
chSemInit(&semaphore, 0);
gpdma_channel_sgpio.set_handlers(transfer_complete, dma_error);
@ -148,7 +139,6 @@ void enable(const baseband::Direction direction) {
const auto gpdma_config = config(direction);
gpdma_channel_sgpio.configure(lli_loop[0], gpdma_config);
//chMBReset(&mailbox);
chSemReset(&semaphore, 0);
gpdma_channel_sgpio.enable();
@ -159,14 +149,11 @@ bool is_enabled() {
}
void disable() {
gpdma_channel_sgpio.disable_force();
gpdma_channel_sgpio.disable();
}
baseband::buffer_t wait_for_rx_buffer() {
//msg_t msg;
//const auto status = chMBFetch(&mailbox, &msg, TIME_INFINITE);
const auto status = chSemWait(&semaphore);
if (quitt) return { nullptr, 0 };
if( status == RDY_OK ) {
const auto next = next_lli;
if( next ) {
@ -174,28 +161,10 @@ baseband::buffer_t wait_for_rx_buffer() {
const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask;
return { reinterpret_cast<sample_t*>(lli_loop[free_index].destaddr), transfer_samples };
} else {
return { nullptr, 0 };
return { };
}
} else {
return { nullptr, 0 };
}
}
baseband::buffer_t wait_for_tx_buffer() {
//msg_t msg;
//const auto status = chMBFetch(&mailbox, &msg, TIME_INFINITE);
const auto status = chSemWait(&semaphore);
if( status == RDY_OK ) {
const auto next = next_lli;
if( next ) {
const size_t next_index = next - &lli_loop[0];
const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask;
return { reinterpret_cast<sample_t*>(lli_loop[free_index].srcaddr), transfer_samples };
} else {
return { nullptr, 0 };
}
} else {
return { nullptr, 0 };
return { };
}
}

View File

@ -23,104 +23,14 @@
#include "portapack_shared_memory.hpp"
#include "dsp_fft.hpp"
#include "audio_dma.hpp"
#include "message.hpp"
#include "event_m4.hpp"
#include "utility.hpp"
#include <cstddef>
#include <algorithm>
void BasebandProcessor::update_spectrum() {
// Called from idle thread (after EVT_MASK_SPECTRUM is flagged)
if( channel_spectrum_request_update ) {
/* Decimated buffer is full. Compute spectrum. */
channel_spectrum_request_update = false;
fft_c_preswapped(channel_spectrum);
ChannelSpectrumMessage spectrum_message;
for(size_t i=0; i<spectrum_message.spectrum.db.size(); i++) {
const auto mag2 = magnitude_squared(channel_spectrum[i]);
const float db = complex16_mag_squared_to_dbv_norm(mag2);
constexpr float mag_scale = 5.0f;
const unsigned int v = (db * mag_scale) + 255.0f;
spectrum_message.spectrum.db[i] = std::max(0U, std::min(255U, v));
}
/* TODO: Rename .db -> .magnitude, or something more (less!) accurate. */
spectrum_message.spectrum.db_count = spectrum_message.spectrum.db.size();
spectrum_message.spectrum.sampling_rate = channel_spectrum_sampling_rate;
spectrum_message.spectrum.channel_filter_pass_frequency = channel_filter_pass_frequency;
spectrum_message.spectrum.channel_filter_stop_frequency = channel_filter_stop_frequency;
shared_memory.application_queue.push(spectrum_message);
}
}
void BasebandProcessor::feed_channel_stats(const buffer_c16_t channel) {
void BasebandProcessor::feed_channel_stats(const buffer_c16_t& channel) {
channel_stats.feed(
channel,
[this](const ChannelStatistics statistics) {
this->post_channel_stats_message(statistics);
[](const ChannelStatistics& statistics) {
const ChannelStatisticsMessage channel_stats_message { statistics };
shared_memory.application_queue.push(channel_stats_message);
}
);
}
void BasebandProcessor::feed_channel_spectrum(
const buffer_c16_t channel,
const uint32_t filter_pass_frequency,
const uint32_t filter_stop_frequency
) {
channel_filter_pass_frequency = filter_pass_frequency;
channel_filter_stop_frequency = filter_stop_frequency;
channel_spectrum_decimator.feed(
channel,
[this](const buffer_c16_t data) {
this->post_channel_spectrum_message(data);
}
);
}
void BasebandProcessor::fill_audio_buffer(const buffer_s16_t audio) {
auto audio_buffer = audio::dma::tx_empty_buffer();;
for(size_t i=0; i<audio_buffer.count; i++) {
audio_buffer.p[i].left = audio_buffer.p[i].right = audio.p[i];
}
i2s::i2s0::tx_unmute();
feed_audio_stats(audio);
}
void BasebandProcessor::post_channel_stats_message(const ChannelStatistics statistics) {
channel_stats_message.statistics = statistics;
shared_memory.application_queue.push(channel_stats_message);
}
void BasebandProcessor::post_channel_spectrum_message(const buffer_c16_t data) {
if( !channel_spectrum_request_update ) {
fft_swap(data, channel_spectrum);
channel_spectrum_sampling_rate = data.sampling_rate;
channel_spectrum_request_update = true;
events_flag(EVT_MASK_SPECTRUM);
}
}
void BasebandProcessor::feed_audio_stats(const buffer_s16_t audio) {
audio_stats.feed(
audio,
[this](const AudioStatistics statistics) {
this->post_audio_stats_message(statistics);
}
);
}
void BasebandProcessor::post_audio_stats_message(const AudioStatistics statistics) {
audio_stats_message.statistics = statistics;
shared_memory.application_queue.push(audio_stats_message);
}
void BasebandProcessor::fill_buffer(int8_t * inptr) {
(void)inptr;
}

View File

@ -23,55 +23,24 @@
#define __BASEBAND_PROCESSOR_H__
#include "dsp_types.hpp"
#include "complex.hpp"
#include "block_decimator.hpp"
#include "channel_stats_collector.hpp"
#include "audio_stats_collector.hpp"
#include <array>
#include <cstdint>
#include <complex>
#include "message.hpp"
class BasebandProcessor {
public:
virtual ~BasebandProcessor() = default;
virtual void execute(buffer_c8_t buffer) = 0;
virtual void fill_buffer(int8_t * inptr);
virtual void execute(const buffer_c8_t& buffer) = 0;
void update_spectrum();
virtual void on_message(const Message* const) { };
protected:
void feed_channel_stats(const buffer_c16_t channel);
void feed_channel_spectrum(
const buffer_c16_t channel,
const uint32_t filter_pass_frequency,
const uint32_t filter_stop_frequency
);
void fill_audio_buffer(const buffer_s16_t audio);
volatile bool channel_spectrum_request_update { false };
std::array<std::complex<float>, 256> channel_spectrum;
uint32_t channel_spectrum_sampling_rate { 0 };
uint32_t channel_filter_pass_frequency { 0 };
uint32_t channel_filter_stop_frequency { 0 };
void feed_channel_stats(const buffer_c16_t& channel);
private:
BlockDecimator<256> channel_spectrum_decimator { 4 };
ChannelStatsCollector channel_stats;
ChannelStatisticsMessage channel_stats_message;
AudioStatsCollector audio_stats;
AudioStatisticsMessage audio_stats_message;
void post_channel_stats_message(const ChannelStatistics statistics);
void post_channel_spectrum_message(const buffer_c16_t data);
void feed_audio_stats(const buffer_s16_t audio);
void post_audio_stats_message(const AudioStatistics statistics);
};
#endif/*__BASEBAND_PROCESSOR_H__*/

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2014 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 "baseband_stats_collector.hpp"
#include "lpc43xx_cpp.hpp"
bool BasebandStatsCollector::process(const buffer_c8_t& buffer) {
samples += buffer.count;
const size_t report_samples = buffer.sampling_rate * report_interval;
const auto report_delta = samples - samples_last_report;
return report_delta >= report_samples;
}
BasebandStatistics BasebandStatsCollector::capture_statistics() {
BasebandStatistics statistics;
const auto idle_ticks = thread_idle->total_ticks;
statistics.idle_ticks = (idle_ticks - last_idle_ticks);
last_idle_ticks = idle_ticks;
const auto main_ticks = thread_main->total_ticks;
statistics.main_ticks = (main_ticks - last_main_ticks);
last_main_ticks = main_ticks;
const auto rssi_ticks = thread_rssi->total_ticks;
statistics.rssi_ticks = (rssi_ticks - last_rssi_ticks);
last_rssi_ticks = rssi_ticks;
const auto baseband_ticks = thread_baseband->total_ticks;
statistics.baseband_ticks = (baseband_ticks - last_baseband_ticks);
last_baseband_ticks = baseband_ticks;
statistics.saturation = lpc43xx::m4::flag_saturation();
lpc43xx::m4::clear_flag_saturation();
samples_last_report = samples;
return statistics;
}

View File

@ -26,7 +26,6 @@
#include "dsp_types.hpp"
#include "message.hpp"
#include "utility_m4.hpp"
#include <cstdint>
#include <cstddef>
@ -46,36 +45,9 @@ public:
}
template<typename Callback>
void process(buffer_c8_t buffer, Callback callback) {
samples += buffer.count;
const size_t report_samples = buffer.sampling_rate * report_interval;
const auto report_delta = samples - samples_last_report;
if( report_delta >= report_samples ) {
BasebandStatistics statistics;
const auto idle_ticks = thread_idle->total_ticks;
statistics.idle_ticks = (idle_ticks - last_idle_ticks);
last_idle_ticks = idle_ticks;
const auto main_ticks = thread_main->total_ticks;
statistics.main_ticks = (main_ticks - last_main_ticks);
last_main_ticks = main_ticks;
const auto rssi_ticks = thread_rssi->total_ticks;
statistics.rssi_ticks = (rssi_ticks - last_rssi_ticks);
last_rssi_ticks = rssi_ticks;
const auto baseband_ticks = thread_baseband->total_ticks;
statistics.baseband_ticks = (baseband_ticks - last_baseband_ticks);
last_baseband_ticks = baseband_ticks;
statistics.saturation = m4_flag_saturation();
clear_m4_flag_saturation();
callback(statistics);
samples_last_report = samples;
void process(const buffer_c8_t& buffer, Callback callback) {
if( process(buffer) ) {
callback(capture_statistics());
}
}
@ -91,6 +63,9 @@ private:
uint32_t last_rssi_ticks { 0 };
const Thread* const thread_baseband;
uint32_t last_baseband_ticks { 0 };
bool process(const buffer_c8_t& buffer);
BasebandStatistics capture_statistics();
};
#endif/*__BASEBAND_STATS_COLLECTOR_H__*/

View File

@ -0,0 +1,155 @@
/*
* Copyright (C) 2014 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 "baseband_thread.hpp"
#include "dsp_types.hpp"
#include "baseband.hpp"
#include "baseband_stats_collector.hpp"
#include "baseband_sgpio.hpp"
#include "baseband_dma.hpp"
#include "rssi.hpp"
#include "i2s.hpp"
#include "proc_xylos.hpp"
#include "proc_fsk_lcr.hpp"
#include "proc_jammer.hpp"
#include "proc_rds.hpp"
#include "proc_playaudio.hpp"
#include "portapack_shared_memory.hpp"
#include <array>
static baseband::SGPIO baseband_sgpio;
WORKING_AREA(baseband_thread_wa, 4096);
Thread* BasebandThread::start(const tprio_t priority) {
return chThdCreateStatic(baseband_thread_wa, sizeof(baseband_thread_wa),
priority, ThreadBase::fn,
this
);
}
void BasebandThread::set_configuration(const BasebandConfiguration& new_configuration) {
if( new_configuration.mode != baseband_configuration.mode ) {
disable();
// TODO: Timing problem around disabling DMA and nulling and deleting old processor
auto old_p = baseband_processor;
baseband_processor = nullptr;
delete old_p;
baseband_processor = create_processor(new_configuration.mode);
enable();
}
baseband_configuration = new_configuration;
}
void BasebandThread::on_message(const Message* const message) {
if( message->id == Message::ID::BasebandConfiguration ) {
set_configuration(reinterpret_cast<const BasebandConfigurationMessage*>(message)->configuration);
} else {
if( baseband_processor ) {
baseband_processor->on_message(message);
}
}
}
void BasebandThread::run() {
baseband_sgpio.init();
baseband::dma::init();
const auto baseband_buffer = new std::array<baseband::sample_t, 8192>();
baseband::dma::configure(
baseband_buffer->data(),
direction()
);
//baseband::dma::allocate(4, 2048);
BasebandStatsCollector stats {
chSysGetIdleThread(),
thread_main,
thread_rssi,
chThdSelf()
};
while(true) {
// TODO: Place correct sampling rate into buffer returned here:
const auto buffer_tmp = baseband::dma::wait_for_rx_buffer();
if( buffer_tmp ) {
buffer_c8_t buffer {
buffer_tmp.p, buffer_tmp.count, baseband_configuration.sampling_rate
};
if( baseband_processor ) {
baseband_processor->execute(buffer);
}
stats.process(buffer,
[](const BasebandStatistics& statistics) {
const BasebandStatisticsMessage message { statistics };
shared_memory.application_queue.push(message);
}
);
}
}
delete baseband_buffer;
}
BasebandProcessor* BasebandThread::create_processor(const int32_t mode) {
switch(mode) {
case 0: return new RDSProcessor();
case 1: return new LCRFSKProcessor();
case 2: return nullptr; //new ToneProcessor();
case 3: return new JammerProcessor();
case 4: return new XylosProcessor();
case 5: return new PlayAudioProcessor();
case 6: return nullptr; //new AFSKRXProcessor();
default: return nullptr;
}
}
void BasebandThread::disable() {
if( baseband_processor ) {
i2s::i2s0::tx_mute();
baseband::dma::disable();
baseband_sgpio.streaming_disable();
rf::rssi::stop();
}
}
void BasebandThread::enable() {
if( baseband_processor ) {
if( direction() == baseband::Direction::Receive ) {
rf::rssi::start();
}
baseband_sgpio.configure(direction());
baseband::dma::enable(direction());
baseband_sgpio.streaming_enable();
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BASEBAND_THREAD_H__
#define __BASEBAND_THREAD_H__
#include "thread_base.hpp"
#include "message.hpp"
#include "baseband_processor.hpp"
#include <ch.h>
class BasebandThread : public ThreadBase {
public:
BasebandThread(
) : ThreadBase { "baseband" }
{
}
Thread* start(const tprio_t priority);
void on_message(const Message* const message);
// This getter should die, it's just here to leak information to code that
// isn't in the right place to begin with.
baseband::Direction direction() const {
return baseband::Direction::Receive;
}
Thread* thread_main { nullptr };
Thread* thread_rssi { nullptr };
BasebandProcessor* baseband_processor { nullptr };
private:
BasebandConfiguration baseband_configuration;
void run() override;
BasebandProcessor* create_processor(const int32_t mode);
void disable();
void enable();
void set_configuration(const BasebandConfiguration& new_configuration);
};
#endif/*__BASEBAND_THREAD_H__*/

View File

@ -1 +1 @@
More specific stuff for testing :o
More or less experimental stuff, mainly TX.

View File

@ -0,0 +1,57 @@
/*
* 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 "dsp_iir.hpp"
#include <hal.h>
void IIRBiquadFilter::configure(const iir_biquad_config_t& new_config) {
config = new_config;
}
void IIRBiquadFilter::execute(const buffer_f32_t& buffer_in, const buffer_f32_t& buffer_out) {
const auto a_ = config.a;
const auto b_ = config.b;
auto x_ = x;
auto y_ = y;
// TODO: Assert that buffer_out.count == buffer_in.count.
for(size_t i=0; i<buffer_out.count; i++) {
x_[0] = x_[1];
x_[1] = x_[2];
x_[2] = buffer_in.p[i];
y_[0] = y_[1];
y_[1] = y_[2];
y_[2] = b_[0] * x_[2] + b_[1] * x_[1] + b_[2] * x_[0]
- a_[1] * y_[1] - a_[2] * y_[0];
buffer_out.p[i] = y_[2];
}
x = x_;
y = y_;
}
void IIRBiquadFilter::execute_in_place(const buffer_f32_t& buffer) {
execute(buffer, buffer);
}

View File

@ -27,13 +27,27 @@
#include "dsp_types.hpp"
struct iir_biquad_config_t {
const std::array<float, 3> b;
const std::array<float, 3> a;
std::array<float, 3> b;
std::array<float, 3> a;
};
constexpr iir_biquad_config_t iir_config_passthrough {
{ { 1.0f, 0.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f } },
};
constexpr iir_biquad_config_t iir_config_no_pass {
{ { 0.0f, 0.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f } },
};
class IIRBiquadFilter {
public:
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
constexpr IIRBiquadFilter(
) : IIRBiquadFilter(iir_config_no_pass)
{
}
// Assume all coefficients are normalized so that a0=1.0
constexpr IIRBiquadFilter(
@ -42,34 +56,15 @@ public:
{
}
void execute(buffer_s16_t buffer_in, buffer_s16_t buffer_out) {
// TODO: Assert that buffer_out.count == buffer_in.count.
for(size_t i=0; i<buffer_out.count; i++) {
buffer_out.p[i] = execute_sample(buffer_in.p[i]);
}
}
void configure(const iir_biquad_config_t& new_config);
void execute_in_place(buffer_s16_t buffer) {
execute(buffer, buffer);
}
void execute(const buffer_f32_t& buffer_in, const buffer_f32_t& buffer_out);
void execute_in_place(const buffer_f32_t& buffer);
private:
const iir_biquad_config_t config;
iir_biquad_config_t config;
std::array<float, 3> x { { 0.0f, 0.0f, 0.0f } };
std::array<float, 3> y { { 0.0f, 0.0f, 0.0f } };
float execute_sample(const float in) {
x[0] = x[1];
x[1] = x[2];
x[2] = in;
y[0] = y[1];
y[1] = y[2];
y[2] = config.b[0] * x[2] + config.b[1] * x[1] + config.b[2] * x[0]
- config.a[1] * y[1] - config.a[2] * y[0];
return y[2];
}
};
#endif/*__DSP_IIR_H__*/

View File

@ -24,22 +24,30 @@
#include <cstdint>
#include <array>
bool FMSquelch::execute(buffer_s16_t audio) {
bool FMSquelch::execute(const buffer_f32_t& audio) {
if( threshold_squared == 0.0f ) {
return true;
}
// TODO: No hard-coded array size.
std::array<int16_t, N> squelch_energy_buffer;
const buffer_s16_t squelch_energy {
std::array<float, N> squelch_energy_buffer;
const buffer_f32_t squelch_energy {
squelch_energy_buffer.data(),
squelch_energy_buffer.size()
};
non_audio_hpf.execute(audio, squelch_energy);
uint64_t max_squared = 0;
float non_audio_max_squared = 0;
for(const auto sample : squelch_energy_buffer) {
const uint64_t sample_squared = sample * sample;
if( sample_squared > max_squared ) {
max_squared = sample_squared;
const float sample_squared = sample * sample;
if( sample_squared > non_audio_max_squared ) {
non_audio_max_squared = sample_squared;
}
}
return (max_squared < (threshold * threshold));
return (non_audio_max_squared < threshold_squared);
}
void FMSquelch::set_threshold(const float new_value) {
threshold_squared = new_value * new_value;
}

View File

@ -31,14 +31,14 @@
class FMSquelch {
public:
bool execute(buffer_s16_t audio);
bool execute(const buffer_f32_t& audio);
void set_threshold(const float new_value);
private:
static constexpr size_t N = 32;
static constexpr int16_t threshold = 3072;
float threshold_squared { 0.0f };
// nyquist = 48000 / 2.0
// scipy.signal.iirdesign(wp=8000 / nyquist, ws= 4000 / nyquist, gpass=1, gstop=18, ftype='ellip')
IIRBiquadFilter non_audio_hpf { non_audio_hpf_config };
};

View File

@ -21,10 +21,99 @@
#include "event_m4.hpp"
#include "portapack_shared_memory.hpp"
#include "message_queue.hpp"
#include "ch.h"
Thread* thread_event_loop = nullptr;
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
void events_initialize(Thread* const event_loop_thread) {
thread_event_loop = event_loop_thread;
#include <cstdint>
#include <array>
extern "C" {
CH_IRQ_HANDLER(MAPP_IRQHandler) {
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
EventDispatcher::events_flag_isr(EVT_MASK_BASEBAND);
chSysUnlockFromIsr();
creg::m0apptxevent::clear();
CH_IRQ_EPILOGUE();
}
}
Thread* EventDispatcher::thread_event_loop = nullptr;
void EventDispatcher::run() {
thread_event_loop = chThdSelf();
lpc43xx::creg::m0apptxevent::enable();
baseband_thread.thread_main = chThdSelf();
baseband_thread.thread_rssi = rssi_thread.start(NORMALPRIO + 10);
baseband_thread.start(NORMALPRIO + 20);
while(is_running) {
const auto events = wait();
dispatch(events);
}
lpc43xx::creg::m0apptxevent::disable();
}
void EventDispatcher::request_stop() {
is_running = false;
}
eventmask_t EventDispatcher::wait() {
return chEvtWaitAny(ALL_EVENTS);
}
void EventDispatcher::dispatch(const eventmask_t events) {
if( events & EVT_MASK_BASEBAND ) {
handle_baseband_queue();
}
if( events & EVT_MASK_SPECTRUM ) {
handle_spectrum();
}
}
void EventDispatcher::handle_baseband_queue() {
std::array<uint8_t, Message::MAX_SIZE> message_buffer;
while(Message* const message = shared_memory.baseband_queue.peek(message_buffer)) {
on_message(message);
shared_memory.baseband_queue.skip();
}
}
void EventDispatcher::on_message(const Message* const message) {
switch(message->id) {
case Message::ID::Shutdown:
on_message_shutdown(*reinterpret_cast<const ShutdownMessage*>(message));
break;
default:
on_message_default(message);
break;
}
}
void EventDispatcher::on_message_shutdown(const ShutdownMessage&) {
request_stop();
}
void EventDispatcher::on_message_default(const Message* const message) {
baseband_thread.on_message(message);
}
void EventDispatcher::handle_spectrum() {
const UpdateSpectrumMessage message;
baseband_thread.on_message(&message);
}

View File

@ -22,25 +22,54 @@
#ifndef __EVENT_M4_H__
#define __EVENT_M4_H__
#include "event.hpp"
#include "baseband_thread.hpp"
#include "rssi_thread.hpp"
#include "message.hpp"
#include "ch.h"
constexpr auto EVT_MASK_BASEBAND = EVENT_MASK(0);
constexpr auto EVT_MASK_SPECTRUM = EVENT_MASK(1);
void events_initialize(Thread* const event_loop_thread);
class EventDispatcher {
public:
void run();
void request_stop();
extern Thread* thread_event_loop;
inline void events_flag(const eventmask_t events) {
if( thread_event_loop ) {
chEvtSignal(thread_event_loop, events);
static inline void events_flag(const eventmask_t events) {
if( thread_event_loop ) {
chEvtSignal(thread_event_loop, events);
}
}
}
inline void events_flag_isr(const eventmask_t events) {
if( thread_event_loop ) {
chEvtSignalI(thread_event_loop, events);
static inline void events_flag_isr(const eventmask_t events) {
if( thread_event_loop ) {
chEvtSignalI(thread_event_loop, events);
}
}
}
private:
static Thread* thread_event_loop;
BasebandThread baseband_thread;
RSSIThread rssi_thread;
bool is_running = true;
eventmask_t wait();
void dispatch(const eventmask_t events);
void handle_baseband_queue();
void on_message(const Message* const message);
void on_message_shutdown(const ShutdownMessage&);
void on_message_default(const Message* const message);
void handle_spectrum();
};
#endif/*__EVENT_M4_H__*/

View File

@ -15,13 +15,11 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* 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 "ch.h"
#include "test.h"
#include "lpc43xx_cpp.hpp"
@ -30,34 +28,13 @@
#include "gpdma.hpp"
#include "baseband.hpp"
#include "baseband_dma.hpp"
#include "event_m4.hpp"
#include "irq_ipc_m4.hpp"
#include "touch_dma.hpp"
#include "modules.h"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "dsp_fft.hpp"
#include "dsp_fir_taps.hpp"
#include "dsp_iir.hpp"
#include "dsp_iir_config.hpp"
#include "dsp_squelch.hpp"
#include "channel_decimator.hpp"
#include "baseband_thread.hpp"
#include "rssi_thread.hpp"
#include "baseband_processor.hpp"
#include "proc_fsk_lcr.hpp"
#include "proc_jammer.hpp"
#include "proc_xylos.hpp"
#include "proc_playaudio.hpp"
#include "clock_recovery.hpp"
#include "packet_builder.hpp"
#include "message_queue.hpp"
@ -73,55 +50,87 @@
#include <cstdint>
#include <cstddef>
#include <array>
#include <string>
#include <bitset>
#include <math.h>
static baseband::Direction direction = baseband::Direction::Receive;
extern "C" {
class ThreadBase {
public:
constexpr ThreadBase(
const char* const name
) : name { name }
{
void __late_init(void) {
/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
* - Kernel initialization, the main() function becomes a thread and the
* RTOS is active.
*/
halInit();
/* After this call, scheduler, systick, heap, etc. are available. */
/* By doing chSysInit() here, it runs before C++ constructors, which may
* require the heap.
*/
chSysInit();
}
}
static void init() {
i2s::i2s0::configure(
audio::i2s0_config_tx,
audio::i2s0_config_rx,
audio::i2s0_config_dma
);
audio::dma::init();
audio::dma::configure();
audio::dma::enable();
i2s::i2s0::tx_start();
i2s::i2s0::rx_start();
LPC_CREG->DMAMUX = portapack::gpdma_mux;
gpdma::controller.enable();
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
touch::dma::init();
touch::dma::allocate();
touch::dma::enable();
}
static void halt() {
port_disable();
while(true) {
port_wait_for_interrupt();
}
}
static msg_t fn(void* arg) {
auto obj = static_cast<ThreadBase*>(arg);
chRegSetThreadName(obj->name);
obj->run();
static void shutdown() {
// TODO: Is this complete?
nvicDisableVector(DMA_IRQn);
chSysDisable();
return 0;
}
systick_stop();
virtual void run() = 0;
ShutdownMessage shutdown_message;
shared_memory.application_queue.push(shutdown_message);
private:
const char* const name;
};
halt();
}
class BasebandThread : public ThreadBase {
public:
BasebandThread(
) : ThreadBase { "baseband" }
{
}
int main(void) {
init();
Thread* start(const tprio_t priority) {
return chThdCreateStatic(wa, sizeof(wa),
priority, ThreadBase::fn,
this
);
}
/* TODO: Ensure DMAs are configured to point at first LLI in chain. */
Thread* thread_main { nullptr };
BasebandProcessor* baseband_processor { nullptr };
BasebandConfiguration baseband_configuration;
EventDispatcher event_dispatcher;
event_dispatcher.run();
private:
WORKING_AREA(wa, 2048);
shutdown();
return 0;
}
/*
void run() override {
while(true) {
if (direction == baseband::Direction::Transmit) {
@ -149,167 +158,6 @@ private:
}
};
#define SAMPLES_PER_BIT 192
#define FILTER_SIZE 576
#define SAMPLE_BUFFER_SIZE SAMPLES_PER_BIT + FILTER_SIZE
static int32_t waveform_biphase[] = {
165,167,168,168,167,166,163,160,
157,152,147,141,134,126,118,109,
99,88,77,66,53,41,27,14,
0,-14,-29,-44,-59,-74,-89,-105,
-120,-135,-150,-165,-179,-193,-206,-218,
-231,-242,-252,-262,-271,-279,-286,-291,
-296,-299,-301,-302,-302,-300,-297,-292,
-286,-278,-269,-259,-247,-233,-219,-202,
-185,-166,-145,-124,-101,-77,-52,-26,
0,27,56,85,114,144,175,205,
236,266,296,326,356,384,412,439,
465,490,513,535,555,574,590,604,
616,626,633,637,639,638,633,626,
616,602,586,565,542,515,485,451,
414,373,329,282,232,178,121,62,
0,-65,-132,-202,-274,-347,-423,-500,
-578,-656,-736,-815,-894,-973,-1051,-1128,
-1203,-1276,-1347,-1415,-1479,-1540,-1596,-1648,
-1695,-1736,-1771,-1799,-1820,-1833,-1838,-1835,
-1822,-1800,-1767,-1724,-1670,-1605,-1527,-1437,
-1334,-1217,-1087,-943,-785,-611,-423,-219,
0,235,487,755,1040,1341,1659,1994,
2346,2715,3101,3504,3923,4359,4811,5280,
5764,6264,6780,7310,7856,8415,8987,9573,
10172,10782,11404,12036,12678,13329,13989,14656,
15330,16009,16694,17382,18074,18767,19461,20155,
20848,21539,22226,22909,23586,24256,24918,25571,
26214,26845,27464,28068,28658,29231,29787,30325,
30842,31339,31814,32266,32694,33097,33473,33823,
34144,34437,34699,34931,35131,35299,35434,35535,
35602,35634,35630,35591,35515,35402,35252,35065,
34841,34579,34279,33941,33566,33153,32702,32214,
31689,31128,30530,29897,29228,28525,27788,27017,
26214,25379,24513,23617,22693,21740,20761,19755,
18725,17672,16597,15501,14385,13251,12101,10935,
9755,8563,7360,6148,4927,3701,2470,1235,
0,-1235,-2470,-3701,-4927,-6148,-7360,-8563,
-9755,-10935,-12101,-13251,-14385,-15501,-16597,-17672,
-18725,-19755,-20761,-21740,-22693,-23617,-24513,-25379,
-26214,-27017,-27788,-28525,-29228,-29897,-30530,-31128,
-31689,-32214,-32702,-33153,-33566,-33941,-34279,-34579,
-34841,-35065,-35252,-35402,-35515,-35591,-35630,-35634,
-35602,-35535,-35434,-35299,-35131,-34931,-34699,-34437,
-34144,-33823,-33473,-33097,-32694,-32266,-31814,-31339,
-30842,-30325,-29787,-29231,-28658,-28068,-27464,-26845,
-26214,-25571,-24918,-24256,-23586,-22909,-22226,-21539,
-20848,-20155,-19461,-18767,-18074,-17382,-16694,-16009,
-15330,-14656,-13989,-13329,-12678,-12036,-11404,-10782,
-10172,-9573,-8987,-8415,-7856,-7310,-6780,-6264,
-5764,-5280,-4811,-4359,-3923,-3504,-3101,-2715,
-2346,-1994,-1659,-1341,-1040,-755,-487,-235,
0,219,423,611,785,943,1087,1217,
1334,1437,1527,1605,1670,1724,1767,1800,
1822,1835,1838,1833,1820,1799,1771,1736,
1695,1648,1596,1540,1479,1415,1347,1276,
1203,1128,1051,973,894,815,736,656,
578,500,423,347,274,202,132,65,
0,-62,-121,-178,-232,-282,-329,-373,
-414,-451,-485,-515,-542,-565,-586,-602,
-616,-626,-633,-638,-639,-637,-633,-626,
-616,-604,-590,-574,-555,-535,-513,-490,
-465,-439,-412,-384,-356,-326,-296,-266,
-236,-205,-175,-144,-114,-85,-56,-27,
0,26,52,77,101,124,145,166,
185,202,219,233,247,259,269,278,
286,292,297,300,302,302,301,299,
296,291,286,279,271,262,252,242,
231,218,206,193,179,165,150,135,
120,105,89,74,59,44,29,14,
0,-14,-27,-41,-53,-66,-77,-88,
-99,-109,-118,-126,-134,-141,-147,-152,
-157,-160,-163,-166,-167,-168,-168,-167
};
class RDSProcessor : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override {
for (size_t i = 0; i<buffer.count; i++) {
//Sample generation 2.28M/10=228kHz
if(s >= 9) {
s = 0;
if(sample_count >= SAMPLES_PER_BIT) {
cur_bit = (shared_memory.rdsdata[(bit_pos / 26) & 15]>>(25-(bit_pos % 26))) & 1;
prev_output = cur_output;
cur_output = prev_output ^ cur_bit;
int32_t *src = waveform_biphase;
int idx = in_sample_index;
for(int j=0; j<FILTER_SIZE; j++) {
val = (*src++);
if (cur_output) val = -val;
sample_buffer[idx++] += val;
if (idx >= SAMPLE_BUFFER_SIZE) idx = 0;
}
in_sample_index += SAMPLES_PER_BIT;
if (in_sample_index >= SAMPLE_BUFFER_SIZE) in_sample_index -= SAMPLE_BUFFER_SIZE;
bit_pos++;
sample_count = 0;
}
sample = sample_buffer[out_sample_index];
sample_buffer[out_sample_index] = 0;
out_sample_index++;
if (out_sample_index >= SAMPLE_BUFFER_SIZE) out_sample_index = 0;
//AM @ 228k/4=57kHz
switch (mphase) {
case 0:
case 2: sample = 0; break;
case 1: break;
case 3: sample = -sample; break;
}
mphase++;
if (mphase >= 4) mphase = 0;
sample_count++;
} else {
s++;
}
//FM
frq = (sample>>16) * 386760;
phase = (phase + frq);
sphase = phase + (256<<16);
//re = sintab[(sphase & 0x03FF0000)>>16];
//im = sintab[(phase & 0x03FF0000)>>16];
buffer.p[i] = {(int8_t)re,(int8_t)im};
}
}
private:
int8_t re, im;
uint8_t mphase, s;
uint32_t bit_pos;
int32_t sample_buffer[SAMPLE_BUFFER_SIZE] = {0};
int32_t val;
uint8_t prev_output = 0;
uint8_t cur_output = 0;
uint8_t cur_bit = 0;
int sample_count = SAMPLES_PER_BIT;
int in_sample_index = 0;
int32_t sample;
int out_sample_index = SAMPLE_BUFFER_SIZE-1;
uint32_t phase, sphase;
int32_t sig, frq, frq_im, rdsc;
int32_t k;
};
class ToneProcessor : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override {
@ -348,130 +196,6 @@ private:
int32_t sample, sig, frq;
};
extern "C" {
void __late_init(void) {
/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
* - Kernel initialization, the main() function becomes a thread and the
* RTOS is active.
*/
halInit();
/* After this call, scheduler, systick, heap, etc. are available. */
/* By doing chSysInit() here, it runs before C++ constructors, which may
* require the heap.
*/
chSysInit();
}
}
static BasebandThread baseband_thread;
static void init() {
i2s::i2s0::configure(
audio::i2s0_config_tx,
audio::i2s0_config_rx,
audio::i2s0_config_dma
);
audio::dma::init();
audio::dma::configure();
audio::dma::enable();
i2s::i2s0::tx_start();
i2s::i2s0::rx_start();
LPC_CREG->DMAMUX = portapack::gpdma_mux;
gpdma::controller.enable();
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
baseband::dma::init();
touch::dma::init();
const auto thread_main = chThdSelf();
baseband_thread.thread_main = thread_main;
baseband_thread.start(NORMALPRIO + 20);
}
static void shutdown() {
// TODO: Is this complete?
nvicDisableVector(DMA_IRQn);
m0apptxevent_interrupt_disable();
chSysDisable();
systick_stop();
}
static void halt() {
port_disable();
while(true) {
port_wait_for_interrupt();
}
}
class EventDispatcher {
public:
MessageHandlerMap& message_handlers() {
return message_map;
}
void run() {
while(is_running) {
const auto events = wait();
dispatch(events);
}
}
void request_stop() {
is_running = false;
}
private:
MessageHandlerMap message_map;
bool is_running = true;
eventmask_t wait() {
return chEvtWaitAny(ALL_EVENTS);
}
void dispatch(const eventmask_t events) {
if( events & EVT_MASK_BASEBAND ) {
handle_baseband_queue();
}
if( events & EVT_MASK_SPECTRUM ) {
handle_spectrum();
}
}
void handle_baseband_queue() {
std::array<uint8_t, Message::MAX_SIZE> message_buffer;
while(Message* const message = shared_memory.baseband_queue.pop(message_buffer)) {
message_map.send(message);
}
}
void handle_spectrum() {
if( baseband_thread.baseband_processor ) {
baseband_thread.baseband_processor->update_spectrum();
}
}
};
const auto baseband_buffer =
new std::array<baseband::sample_t, 8192>();
char ram_loop[32];
typedef int (*fn_ptr)(void);
fn_ptr loop_ptr;
@ -586,27 +310,4 @@ int main(void) {
event_dispatcher.request_stop();
}
);
/* TODO: Ensure DMAs are configured to point at first LLI in chain. */
touch::dma::allocate();
touch::dma::enable();
baseband::dma::configure(
baseband_buffer->data(),
direction
);
//baseband::dma::allocate(4, 2048);
event_dispatcher.run();
shutdown();
ShutdownMessage shutdown_message;
shared_memory.application_queue.push(shutdown_message);
halt();
return 0;
}
*/

View File

@ -1 +1 @@
Second module
Experimental

View File

@ -26,6 +26,6 @@
#include <cstdint>
void AudioTXProcessor::execute(buffer_c8_t buffer) {
void AudioTXProcessor::execute(const buffer_c8_t& buffer) {
}

View File

@ -29,7 +29,8 @@
class AudioTXProcessor : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override;
void execute(const buffer_c8_t& buffer) override;
private:
int8_t audio_fifo[SAMPLERATE];

View File

@ -25,7 +25,7 @@
#include <cstdint>
void LCRFSKProcessor::execute(buffer_c8_t buffer) {
void LCRFSKProcessor::execute(const buffer_c8_t& buffer) {
for (size_t i = 0; i<buffer.count; i++) {

View File

@ -26,7 +26,7 @@
class LCRFSKProcessor : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override;
void execute(const buffer_c8_t& buffer) override;
private:
int8_t re, im;

View File

@ -27,33 +27,9 @@
#define POLY_MASK_32 0xB4BCD35C
void JammerProcessor::execute(buffer_c8_t buffer) {
void JammerProcessor::execute(const buffer_c8_t& buffer) {
for (size_t i = 0; i<buffer.count; i++) {
/*if (s > 3000000) {
s = 0;
feedback = lfsr & 1;
lfsr >>= 1;
if (feedback == 1)
lfsr ^= POLY_MASK_32;
} else {
s++;
}
aphase += lfsr;*/
/*if (s >= 10) {
s = 0;
aphase += 353205; // DEBUG
} else {
s++;
}
sample = sintab[(aphase & 0x03FF0000)>>16];*/
// Duration timer
//
if (s >= 10000) { //shared_memory.jammer_ranges[ir].duration
s = 0;
for (;;) {

View File

@ -26,7 +26,7 @@
class JammerProcessor : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override;
void execute(const buffer_c8_t& buffer) override;
private:
int32_t lfsr32 = 0xABCDE;

View File

@ -33,7 +33,7 @@ void PlayAudioProcessor::fill_buffer(int8_t * inptr) {
asked = false;
}
void PlayAudioProcessor::execute(buffer_c8_t buffer) {
void PlayAudioProcessor::execute(const buffer_c8_t& buffer){
// This is called at 1536000/2048 = 750Hz
@ -69,5 +69,5 @@ void PlayAudioProcessor::execute(buffer_c8_t buffer) {
buffer.p[i] = {(int8_t)re,(int8_t)im};
}
fill_audio_buffer(preview_audio_buffer);
//fill_audio_buffer(preview_audio_buffer);
}

View File

@ -27,7 +27,7 @@
class PlayAudioProcessor : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override;
void execute(const buffer_c8_t& buffer) override;
void fill_buffer(int8_t * inptr);
private:

View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_rds.hpp"
#include "portapack_shared_memory.hpp"
#include "sine_table.hpp"
#include <cstdint>
void RDSProcessor::execute(const buffer_c8_t& buffer) {
for (size_t i = 0; i<buffer.count; i++) {
//Sample generation 2.28M/10=228kHz
if(s >= 9) {
s = 0;
if(sample_count >= SAMPLES_PER_BIT) {
cur_bit = (shared_memory.rdsdata[(bit_pos / 26) & 15]>>(25-(bit_pos % 26))) & 1;
prev_output = cur_output;
cur_output = prev_output ^ cur_bit;
int32_t *src = waveform_biphase;
int idx = in_sample_index;
for(int j=0; j<FILTER_SIZE; j++) {
val = (*src++);
if (cur_output) val = -val;
sample_buffer[idx++] += val;
if (idx >= SAMPLE_BUFFER_SIZE) idx = 0;
}
in_sample_index += SAMPLES_PER_BIT;
if (in_sample_index >= SAMPLE_BUFFER_SIZE) in_sample_index -= SAMPLE_BUFFER_SIZE;
bit_pos++;
sample_count = 0;
}
sample = sample_buffer[out_sample_index];
sample_buffer[out_sample_index] = 0;
out_sample_index++;
if (out_sample_index >= SAMPLE_BUFFER_SIZE) out_sample_index = 0;
//AM @ 228k/4=57kHz
switch (mphase) {
case 0:
case 2: sample = 0; break;
case 1: break;
case 3: sample = -sample; break;
}
mphase++;
if (mphase >= 4) mphase = 0;
sample_count++;
} else {
s++;
}
//FM
frq = (sample>>16) * 386760;
phase = (phase + frq);
sphase = phase + (256<<16);
//re = sintab[(sphase & 0x03FF0000)>>16];
//im = sintab[(phase & 0x03FF0000)>>16];
buffer.p[i] = {(int8_t)re,(int8_t)im};
}
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_RDS_H__
#define __PROC_RDS_H__
#include "baseband_processor.hpp"
#define SAMPLES_PER_BIT 192
#define FILTER_SIZE 576
#define SAMPLE_BUFFER_SIZE SAMPLES_PER_BIT + FILTER_SIZE
class RDSProcessor : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
private:
int8_t re, im;
uint8_t mphase, s;
uint32_t bit_pos;
int32_t sample_buffer[SAMPLE_BUFFER_SIZE] = {0};
int32_t val;
uint8_t prev_output = 0;
uint8_t cur_output = 0;
uint8_t cur_bit = 0;
int sample_count = SAMPLES_PER_BIT;
int in_sample_index = 0;
int32_t sample;
int out_sample_index = SAMPLE_BUFFER_SIZE-1;
uint32_t phase, sphase;
int32_t sig, frq, frq_im, rdsc;
int32_t k;
int32_t waveform_biphase[576] = {
165,167,168,168,167,166,163,160,
157,152,147,141,134,126,118,109,
99,88,77,66,53,41,27,14,
0,-14,-29,-44,-59,-74,-89,-105,
-120,-135,-150,-165,-179,-193,-206,-218,
-231,-242,-252,-262,-271,-279,-286,-291,
-296,-299,-301,-302,-302,-300,-297,-292,
-286,-278,-269,-259,-247,-233,-219,-202,
-185,-166,-145,-124,-101,-77,-52,-26,
0,27,56,85,114,144,175,205,
236,266,296,326,356,384,412,439,
465,490,513,535,555,574,590,604,
616,626,633,637,639,638,633,626,
616,602,586,565,542,515,485,451,
414,373,329,282,232,178,121,62,
0,-65,-132,-202,-274,-347,-423,-500,
-578,-656,-736,-815,-894,-973,-1051,-1128,
-1203,-1276,-1347,-1415,-1479,-1540,-1596,-1648,
-1695,-1736,-1771,-1799,-1820,-1833,-1838,-1835,
-1822,-1800,-1767,-1724,-1670,-1605,-1527,-1437,
-1334,-1217,-1087,-943,-785,-611,-423,-219,
0,235,487,755,1040,1341,1659,1994,
2346,2715,3101,3504,3923,4359,4811,5280,
5764,6264,6780,7310,7856,8415,8987,9573,
10172,10782,11404,12036,12678,13329,13989,14656,
15330,16009,16694,17382,18074,18767,19461,20155,
20848,21539,22226,22909,23586,24256,24918,25571,
26214,26845,27464,28068,28658,29231,29787,30325,
30842,31339,31814,32266,32694,33097,33473,33823,
34144,34437,34699,34931,35131,35299,35434,35535,
35602,35634,35630,35591,35515,35402,35252,35065,
34841,34579,34279,33941,33566,33153,32702,32214,
31689,31128,30530,29897,29228,28525,27788,27017,
26214,25379,24513,23617,22693,21740,20761,19755,
18725,17672,16597,15501,14385,13251,12101,10935,
9755,8563,7360,6148,4927,3701,2470,1235,
0,-1235,-2470,-3701,-4927,-6148,-7360,-8563,
-9755,-10935,-12101,-13251,-14385,-15501,-16597,-17672,
-18725,-19755,-20761,-21740,-22693,-23617,-24513,-25379,
-26214,-27017,-27788,-28525,-29228,-29897,-30530,-31128,
-31689,-32214,-32702,-33153,-33566,-33941,-34279,-34579,
-34841,-35065,-35252,-35402,-35515,-35591,-35630,-35634,
-35602,-35535,-35434,-35299,-35131,-34931,-34699,-34437,
-34144,-33823,-33473,-33097,-32694,-32266,-31814,-31339,
-30842,-30325,-29787,-29231,-28658,-28068,-27464,-26845,
-26214,-25571,-24918,-24256,-23586,-22909,-22226,-21539,
-20848,-20155,-19461,-18767,-18074,-17382,-16694,-16009,
-15330,-14656,-13989,-13329,-12678,-12036,-11404,-10782,
-10172,-9573,-8987,-8415,-7856,-7310,-6780,-6264,
-5764,-5280,-4811,-4359,-3923,-3504,-3101,-2715,
-2346,-1994,-1659,-1341,-1040,-755,-487,-235,
0,219,423,611,785,943,1087,1217,
1334,1437,1527,1605,1670,1724,1767,1800,
1822,1835,1838,1833,1820,1799,1771,1736,
1695,1648,1596,1540,1479,1415,1347,1276,
1203,1128,1051,973,894,815,736,656,
578,500,423,347,274,202,132,65,
0,-62,-121,-178,-232,-282,-329,-373,
-414,-451,-485,-515,-542,-565,-586,-602,
-616,-626,-633,-638,-639,-637,-633,-626,
-616,-604,-590,-574,-555,-535,-513,-490,
-465,-439,-412,-384,-356,-326,-296,-266,
-236,-205,-175,-144,-114,-85,-56,-27,
0,26,52,77,101,124,145,166,
185,202,219,233,247,259,269,278,
286,292,297,300,302,302,301,299,
296,291,286,279,271,262,252,242,
231,218,206,193,179,165,150,135,
120,105,89,74,59,44,29,14,
0,-14,-27,-41,-53,-66,-77,-88,
-99,-109,-118,-126,-134,-141,-147,-152,
-157,-160,-163,-166,-167,-168,-168,-167
};
};
#endif

View File

@ -21,6 +21,10 @@
*/
#include "proc_xylos.hpp"
#include "dsp_iir_config.hpp"
//#include "audio_output.hpp"
#include "portapack_shared_memory.hpp"
#include "sine_table.hpp"
@ -31,7 +35,7 @@
// 14 13 12 11:
// 2108 989 2259 931
void XylosProcessor::execute(buffer_c8_t buffer) {
void XylosProcessor::execute(const buffer_c8_t& buffer) {
// This is called at 1536000/2048 = 750Hz
@ -88,5 +92,5 @@ void XylosProcessor::execute(buffer_c8_t buffer) {
buffer.p[i] = {(int8_t)re,(int8_t)im};
}
fill_audio_buffer(preview_audio_buffer);
//audio_output.write(preview_audio_buffer);
}

View File

@ -25,12 +25,18 @@
#include "baseband_processor.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
//#include "audio_output.hpp"
#include "baseband_processor.hpp"
#define CCIR_TONELENGTH 15360-1 // 1536000/10/10
#define PHASEV 436.91 // (65536*1024)/1536000*10
class XylosProcessor : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override;
void execute(const buffer_c8_t& buffer) override;
private:
int16_t audio_data[64];
@ -67,6 +73,8 @@ private:
uint32_t aphase, phase, sphase;
int32_t sample, frq;
TXDoneMessage message;
//AudioOutput audio_output;
};
#endif

View File

@ -157,7 +157,7 @@ bool is_enabled() {
}
void disable() {
gpdma_channel.disable_force();
gpdma_channel.disable();
}
rf::rssi::buffer_t wait_for_buffer() {

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2014 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 "rssi_thread.hpp"
#include "rssi.hpp"
#include "rssi_dma.hpp"
#include "rssi_stats_collector.hpp"
#include "message.hpp"
#include "portapack_shared_memory.hpp"
WORKING_AREA(rssi_thread_wa, 128);
Thread* RSSIThread::start(const tprio_t priority) {
return chThdCreateStatic(rssi_thread_wa, sizeof(rssi_thread_wa),
priority, ThreadBase::fn,
this
);
}
void RSSIThread::run() {
rf::rssi::init();
rf::rssi::dma::allocate(4, 400);
RSSIStatisticsCollector stats;
while(true) {
// TODO: Place correct sampling rate into buffer returned here:
const auto buffer_tmp = rf::rssi::dma::wait_for_buffer();
const rf::rssi::buffer_t buffer {
buffer_tmp.p, buffer_tmp.count, sampling_rate
};
stats.process(
buffer,
[](const RSSIStatistics& statistics) {
const RSSIStatisticsMessage message { statistics };
shared_memory.application_queue.push(message);
}
);
}
rf::rssi::dma::free();
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __RSSI_THREAD_H__
#define __RSSI_THREAD_H__
#include "thread_base.hpp"
#include <ch.h>
#include <cstdint>
class RSSIThread : public ThreadBase {
public:
RSSIThread(
) : ThreadBase { "rssi" }
{
}
Thread* start(const tprio_t priority);
private:
void run() override;
const uint32_t sampling_rate { 400000 };
};
#endif/*__RSSI_THREAD_H__*/

View File

@ -0,0 +1,130 @@
/*
* 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 "spectrum_collector.hpp"
#include "dsp_fft.hpp"
#include "utility.hpp"
#include "event_m4.hpp"
#include "portapack_shared_memory.hpp"
#include "event_m4.hpp"
#include <algorithm>
void SpectrumCollector::on_message(const Message* const message) {
switch(message->id) {
case Message::ID::UpdateSpectrum:
update();
break;
case Message::ID::SpectrumStreamingConfig:
set_state(*reinterpret_cast<const SpectrumStreamingConfigMessage*>(message));
break;
default:
break;
}
}
void SpectrumCollector::set_state(const SpectrumStreamingConfigMessage& message) {
if( message.mode == SpectrumStreamingConfigMessage::Mode::Running ) {
start();
} else {
stop();
}
}
void SpectrumCollector::start() {
streaming = true;
ChannelSpectrumConfigMessage message { &fifo };
shared_memory.application_queue.push(message);
}
void SpectrumCollector::stop() {
streaming = false;
fifo.reset_in();
}
void SpectrumCollector::set_decimation_factor(
const size_t decimation_factor
) {
channel_spectrum_decimator.set_factor(decimation_factor);
}
/* TODO: Refactor to register task with idle thread?
* It's sad that the idle thread has to call all the way back here just to
* perform the deferred task on the buffer of data we prepared.
*/
void SpectrumCollector::feed(
const buffer_c16_t& channel,
const uint32_t filter_pass_frequency,
const uint32_t filter_stop_frequency
) {
// Called from baseband processing thread.
channel_filter_pass_frequency = filter_pass_frequency;
channel_filter_stop_frequency = filter_stop_frequency;
channel_spectrum_decimator.feed(
channel,
[this](const buffer_c16_t& data) {
this->post_message(data);
}
);
}
void SpectrumCollector::post_message(const buffer_c16_t& data) {
// Called from baseband processing thread.
if( streaming && !channel_spectrum_request_update ) {
fft_swap(data, channel_spectrum);
channel_spectrum_sampling_rate = data.sampling_rate;
channel_spectrum_request_update = true;
EventDispatcher::events_flag(EVT_MASK_SPECTRUM);
}
}
void SpectrumCollector::update() {
// Called from idle thread (after EVT_MASK_SPECTRUM is flagged)
if( streaming && channel_spectrum_request_update ) {
/* Decimated buffer is full. Compute spectrum. */
fft_c_preswapped(channel_spectrum);
ChannelSpectrum spectrum;
spectrum.sampling_rate = channel_spectrum_sampling_rate;
spectrum.channel_filter_pass_frequency = channel_filter_pass_frequency;
spectrum.channel_filter_stop_frequency = channel_filter_stop_frequency;
for(size_t i=0; i<spectrum.db.size(); i++) {
// Three point Hamming window.
const auto corrected_sample = channel_spectrum[i] * 0.54f
+ (channel_spectrum[(i-1) & 0xff] + channel_spectrum[(i+1) & 0xff]) * -0.23f;
const auto mag2 = magnitude_squared(corrected_sample);
const float db = complex16_mag_squared_to_dbv_norm(mag2);
constexpr float mag_scale = 5.0f;
const unsigned int v = (db * mag_scale) + 255.0f;
spectrum.db[i] = std::max(0U, std::min(255U, v));
}
fifo.in(spectrum);
}
channel_spectrum_request_update = false;
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPECTRUM_COLLECTOR_H__
#define __SPECTRUM_COLLECTOR_H__
#include "dsp_types.hpp"
#include "complex.hpp"
#include "block_decimator.hpp"
#include <cstdint>
#include <array>
#include "message.hpp"
class SpectrumCollector {
public:
constexpr SpectrumCollector(
) : channel_spectrum_decimator { 1 }
{
}
void on_message(const Message* const message);
void set_decimation_factor(const size_t decimation_factor);
void feed(
const buffer_c16_t& channel,
const uint32_t filter_pass_frequency,
const uint32_t filter_stop_frequency
);
private:
BlockDecimator<256> channel_spectrum_decimator;
ChannelSpectrumFIFO fifo;
volatile bool channel_spectrum_request_update { false };
bool streaming { false };
std::array<std::complex<float>, 256> channel_spectrum;
uint32_t channel_spectrum_sampling_rate { 0 };
uint32_t channel_filter_pass_frequency { 0 };
uint32_t channel_filter_stop_frequency { 0 };
void post_message(const buffer_c16_t& data);
void set_state(const SpectrumStreamingConfigMessage& message);
void start();
void stop();
void update();
};
#endif/*__SPECTRUM_COLLECTOR_H__*/

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __THREAD_BASE_H__
#define __THREAD_BASE_H__
#include <ch.h>
class ThreadBase {
public:
constexpr ThreadBase(
const char* const name
) : name { name }
{
}
protected:
static msg_t fn(void* arg) {
auto obj = static_cast<ThreadBase*>(arg);
chRegSetThreadName(obj->name);
obj->run();
return 0;
}
private:
const char* const name;
virtual void run() = 0;
};
#endif/*__THREAD_BASE_H__*/

View File

@ -122,7 +122,7 @@ bool is_enabled() {
}
void disable() {
gpdma_channel.disable_force();
gpdma_channel.disable();
}
} /* namespace dma */

Binary file not shown.

View File

@ -1 +1 @@
Basic RX/TX stuff for testing :)
Original firmware's functionalities: Receiver.

View File

@ -50,121 +50,6 @@
#include <cstdint>
#include <cstddef>
#include <array>
#include <string>
#include <bitset>
class ThreadBase {
public:
constexpr ThreadBase(
const char* const name
) : name { name }
{
}
static msg_t fn(void* arg) {
auto obj = static_cast<ThreadBase*>(arg);
chRegSetThreadName(obj->name);
obj->run();
return 0;
}
virtual void run() = 0;
private:
const char* const name;
};
class BasebandThread : public ThreadBase {
public:
BasebandThread(
) : ThreadBase { "baseband" }
{
}
Thread* start(const tprio_t priority) {
return chThdCreateStatic(wa, sizeof(wa),
priority, ThreadBase::fn,
this
);
}
Thread* thread_main { nullptr };
Thread* thread_rssi { nullptr };
BasebandProcessor* baseband_processor { nullptr };
BasebandConfiguration baseband_configuration;
private:
WORKING_AREA(wa, 2048);
void run() override {
BasebandStatsCollector stats {
chSysGetIdleThread(),
thread_main,
thread_rssi,
chThdSelf()
};
while(true) {
// TODO: Place correct sampling rate into buffer returned here:
const auto buffer_tmp = baseband::dma::wait_for_rx_buffer();
const buffer_c8_t buffer {
buffer_tmp.p, buffer_tmp.count, baseband_configuration.sampling_rate
};
if( baseband_processor ) {
baseband_processor->execute(buffer);
}
stats.process(buffer,
[](const BasebandStatistics statistics) {
const BasebandStatisticsMessage message { statistics };
shared_memory.application_queue.push(message);
}
);
}
}
};
class RSSIThread : public ThreadBase {
public:
RSSIThread(
) : ThreadBase { "rssi" }
{
}
Thread* start(const tprio_t priority) {
return chThdCreateStatic(wa, sizeof(wa),
priority, ThreadBase::fn,
this
);
}
uint32_t sampling_rate { 400000 };
private:
WORKING_AREA(wa, 128);
void run() override {
RSSIStatisticsCollector stats;
while(true) {
// TODO: Place correct sampling rate into buffer returned here:
const auto buffer_tmp = rf::rssi::dma::wait_for_buffer();
const rf::rssi::buffer_t buffer {
buffer_tmp.p, buffer_tmp.count, sampling_rate
};
stats.process(
buffer,
[](const RSSIStatistics statistics) {
const RSSIStatisticsMessage message { statistics };
shared_memory.application_queue.push(message);
}
);
}
}
};
extern "C" {
@ -187,9 +72,6 @@ void __late_init(void) {
}
static BasebandThread baseband_thread;
static RSSIThread rssi_thread;
static void init() {
i2s::i2s0::configure(
audio::i2s0_config_tx,
@ -208,31 +90,9 @@ static void init() {
gpdma::controller.enable();
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
baseband::dma::init();
rf::rssi::init();
touch::dma::init();
const auto thread_main = chThdSelf();
const auto thread_rssi = rssi_thread.start(NORMALPRIO + 10);
baseband_thread.thread_main = thread_main;
baseband_thread.thread_rssi = thread_rssi;
baseband_thread.start(NORMALPRIO + 20);
}
static void shutdown() {
// TODO: Is this complete?
nvicDisableVector(DMA_IRQn);
m0apptxevent_interrupt_disable();
chSysDisable();
systick_stop();
touch::dma::allocate();
touch::dma::enable();
}
static void halt() {
@ -242,146 +102,27 @@ static void halt() {
}
}
class EventDispatcher {
public:
MessageHandlerMap& message_handlers() {
return message_map;
}
static void shutdown() {
// TODO: Is this complete?
nvicDisableVector(DMA_IRQn);
chSysDisable();
void run() {
while(is_running) {
const auto events = wait();
dispatch(events);
}
}
systick_stop();
void request_stop() {
is_running = false;
}
ShutdownMessage shutdown_message;
shared_memory.application_queue.push(shutdown_message);
private:
MessageHandlerMap message_map;
bool is_running = true;
eventmask_t wait() {
return chEvtWaitAny(ALL_EVENTS);
}
void dispatch(const eventmask_t events) {
if( events & EVT_MASK_BASEBAND ) {
handle_baseband_queue();
}
if( events & EVT_MASK_SPECTRUM ) {
handle_spectrum();
}
}
void handle_baseband_queue() {
std::array<uint8_t, Message::MAX_SIZE> message_buffer;
while(Message* const message = shared_memory.baseband_queue.pop(message_buffer)) {
message_map.send(message);
}
}
void handle_spectrum() {
if( baseband_thread.baseband_processor ) {
baseband_thread.baseband_processor->update_spectrum();
}
}
};
static constexpr auto direction = baseband::Direction::Receive;
halt();
}
int main(void) {
init();
events_initialize(chThdSelf());
m0apptxevent_interrupt_enable();
EventDispatcher event_dispatcher;
auto& message_handlers = event_dispatcher.message_handlers();
message_handlers.register_handler(Message::ID::BasebandConfiguration,
[&message_handlers](const Message* const p) {
auto message = reinterpret_cast<const BasebandConfigurationMessage*>(p);
if( message->configuration.mode != baseband_thread.baseband_configuration.mode ) {
if( baseband_thread.baseband_processor ) {
i2s::i2s0::tx_mute();
baseband::dma::disable();
rf::rssi::stop();
}
// TODO: Timing problem around disabling DMA and nulling and deleting old processor
auto old_p = baseband_thread.baseband_processor;
baseband_thread.baseband_processor = nullptr;
delete old_p;
switch(message->configuration.mode) {
case 0:
baseband_thread.baseband_processor = new NarrowbandAMAudio();
break;
case 1:
baseband_thread.baseband_processor = new NarrowbandFMAudio();
break;
case 2:
baseband_thread.baseband_processor = new WidebandFMAudio();
break;
case 3:
baseband_thread.baseband_processor = new AISProcessor();
break;
case 4:
baseband_thread.baseband_processor = new WidebandSpectrum();
break;
case 5:
baseband_thread.baseband_processor = new TPMSProcessor();
break;
default:
break;
}
if( baseband_thread.baseband_processor ) {
if( direction == baseband::Direction::Receive ) {
rf::rssi::start();
}
baseband::dma::enable(direction);
}
}
baseband_thread.baseband_configuration = message->configuration;
}
);
message_handlers.register_handler(Message::ID::Shutdown,
[&event_dispatcher](const Message* const) {
event_dispatcher.request_stop();
}
);
/* TODO: Ensure DMAs are configured to point at first LLI in chain. */
if( direction == baseband::Direction::Receive ) {
rf::rssi::dma::allocate(4, 400);
}
touch::dma::allocate();
touch::dma::enable();
const auto baseband_buffer =
new std::array<baseband::sample_t, 8192>();
baseband::dma::configure(
baseband_buffer->data(),
direction
);
EventDispatcher event_dispatcher;
event_dispatcher.run();
shutdown();

View File

@ -1 +1 @@
First module
Receiver

View File

@ -25,30 +25,17 @@
using namespace lpc43xx;
void AFSKRXProcessor::execute(buffer_c8_t buffer) {
void AFSKRXProcessor::execute(const buffer_c8_t& buffer) {
if( !configured ) {
return;
}
/* Called every 2048/3072000 second -- 1500Hz. */
auto decimator_out = decimator.execute(buffer);
const buffer_c16_t work_baseband_buffer {
(complex16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 96kHz complex<int16_t>[64]
* -> FIR filter, <6kHz (0.063fs) pass, gain 1.0
* -> 48kHz int16_t[32] */
auto channel = channel_filter.execute(decimator_out, work_baseband_buffer);
const buffer_s16_t work_audio_buffer {
(int16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 48kHz complex<int16_t>[32]
* -> FM demodulation
* -> 48kHz int16_t[32] */
auto audio = demod.execute(channel, work_audio_buffer);
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer);
auto audio = demod.execute(channel_out, work_audio_buffer);
/*static uint64_t audio_present_history = 0;
const auto audio_present_now = squelch.execute(audio);
@ -65,7 +52,7 @@ void AFSKRXProcessor::execute(buffer_c8_t buffer) {
}*/
//}
audio_hpf.execute_in_place(audio);
//audio_hpf.execute_in_place(audio);
for(size_t i=0; i<audio.count; i++) {
if (spur > 10) {
@ -97,9 +84,9 @@ void AFSKRXProcessor::execute(buffer_c8_t buffer) {
if (sc >= 600) {
sc = 0;
AFSKDataMessage message;
memcpy(message.data,aud,128*2);
shared_memory.application_queue.push(message);
//AFSKDataMessage message;
//memcpy(message.data,aud,128*2);
//shared_memory.application_queue.push(message);
audc = 0;
} else {
sc++;
@ -110,7 +97,7 @@ void AFSKRXProcessor::execute(buffer_c8_t buffer) {
audc++;
}
fill_audio_buffer(audio);
audio_output.write(audio);
}
void AFSKRXProcessor::data_handler(

View File

@ -24,38 +24,35 @@
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "dsp_fir_taps.hpp"
#include "dsp_iir.hpp"
#include "dsp_iir_config.hpp"
#include "dsp_squelch.hpp"
#include "audio_output.hpp"
#include "message.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
class AFSKRXProcessor : public BasebandProcessor {
public:
AFSKRXProcessor() {
decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By32);
channel_filter.configure(channel_filter_taps.taps, 2);
}
void execute(buffer_c8_t buffer) override;
void execute(const buffer_c8_t& buffer) override;
private:
ChannelDecimator decimator;
const fir_taps_real<64>& channel_filter_taps = taps_64_lp_042_078_tfilter;
dsp::decimate::FIRAndDecimateComplex channel_filter;
dsp::demodulate::FM demod { 48000, 5000 };
IIRBiquadFilter audio_hpf { audio_hpf_config };
//FMSquelch squelch;
std::array<complex16_t, 512> dst;
const buffer_c16_t dst_buffer {
dst.data(),
dst.size()
};
const buffer_f32_t work_audio_buffer {
(float*)dst.data(),
sizeof(dst) / sizeof(float)
};
dsp::decimate::FIRAndDecimateComplex channel_filter;
dsp::demodulate::FM demod; // 48000 5000
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0;
dsp::decimate::FIRC16xR16x32Decim8 decim_1;
AudioOutput audio_output;
uint16_t bit_timer = 0, freq_timer = 0;
uint16_t sc;
uint8_t audc, spur, sign, prev_sign, bit = 0;
@ -63,6 +60,9 @@ private:
int16_t aud[128];
void data_handler(const double data);
bool configured { false };
void configure(const NBFMConfigureMessage& message);
};
#endif/*__PROC_TPMS_H__*/

View File

@ -24,46 +24,6 @@
#include <cstdint>
#include <cstddef>
void SIGFRXProcessor::execute(buffer_c8_t buffer) {
void SIGFRXProcessor::execute(const buffer_c8_t& buffer) {
/* Called every 2048/3072000 second -- 1500Hz. */
auto decimator_out = decimator.execute(buffer);
const buffer_c16_t work_baseband_buffer {
(complex16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 192kHz complex<int16_t>[64]
* -> 96kHz int16_t[32] */
//auto channel = channel_filter.execute(decimator_out, work_baseband_buffer);
// TODO: Feed channel_stats post-decimation data?
feed_channel_spectrum(
decimator_out,
41000, //decimator_out.sampling_rate * channel_filter_taps.pass_frequency_normalized,
70000 //decimator_out.sampling_rate * channel_filter_taps.stop_frequency_normalized
);
/*const buffer_s16_t work_audio_buffer {
(int16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
*
auto audio = demod.execute(channel, work_audio_buffer);
static uint64_t audio_present_history = 0;
const auto audio_present_now = squelch.execute(audio);
audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0);
const bool audio_present = (audio_present_history != 0);
if( !audio_present ) {
// Zero audio buffer.
for(size_t i=0; i<audio.count; i++) {
audio.p[i] = 0;
}
}
audio_hpf.execute_in_place(audio);
fill_audio_buffer(audio);*/
}

View File

@ -24,31 +24,15 @@
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "dsp_fir_taps.hpp"
#include "dsp_iir.hpp"
#include "dsp_iir_config.hpp"
#include "dsp_squelch.hpp"
class SIGFRXProcessor : public BasebandProcessor {
public:
SIGFRXProcessor() {
decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By16);
//channel_filter.configure(channel_filter_taps.taps, 1);
}
void execute(buffer_c8_t buffer) override;
void execute(const buffer_c8_t& buffer) override;
private:
ChannelDecimator decimator;
//const fir_taps_real<64>& channel_filter_taps = taps_64_lp_410_700_tfilter; //taps_64_lp_104_140_tfilter
//dsp::decimate::FIRAndDecimateComplex channel_filter;
dsp::demodulate::FM demod { 48000, 7500 };
IIRBiquadFilter audio_hpf { audio_hpf_config };
FMSquelch squelch;
};
#endif

BIN
firmware/bootstrap/bootstrap.bin Executable file

Binary file not shown.

View File

@ -2579,7 +2579,6 @@ FRESULT f_read (
UINT rcnt, cc;
BYTE csect, *rbuff = (BYTE*)buff;
*br = 0; /* Clear read byte counter */
res = validate(fp); /* Check validity */

View File

@ -619,7 +619,7 @@ void sdc_lld_start_clk(SDCDriver *sdcp) {
(void)sdcp;
sdio_cclk_set_400khz();
/* TODO: Reset card using CMD0 + init flag? */
sdio_send_command(sdcp, 0 | (1U << 15), 0);
if (sdio_send_command(sdcp, 0 | (1U << 15), 0) != CH_SUCCESS) for(;;);
}
/**

View File

@ -419,12 +419,14 @@ public:
int64_t freq = 0;
};
class DisplayFrameSyncMessage : public Message {
class AFSKDataMessage : public Message {
public:
constexpr DisplayFrameSyncMessage(
) : Message { ID::DisplayFrameSync }
constexpr AFSKDataMessage(
) : Message { ID::AFSKData }
{
}
int16_t data[128] = {0};
};
class FIFOSignalMessage : public Message {

View File

@ -1,2 +1,2 @@
const char md5_baseband[16] = {0x0f,0xf7,0xa8,0x6f,0x0f,0xb3,0x88,0x4c,0xec,0x45,0xcf,0x8d,0xd5,0xf8,0x11,0x92,};
const char md5_baseband_tx[16] = {0x77,0xa8,0x27,0xec,0xb4,0xcb,0xe6,0x17,0x06,0x70,0x49,0x01,0xed,0x48,0x1f,0x54,};
const char md5_baseband[16] = {0xf8,0xf3,0x7b,0x36,0x68,0xd3,0xa1,0x85,0x26,0xb1,0x76,0x99,0x46,0x95,0xfd,0xec,};
const char md5_baseband_tx[16] = {0xfc,0xe9,0x57,0x6b,0xfb,0xac,0x72,0x61,0x65,0x4e,0x3d,0x7f,0xb4,0x78,0xbd,0xd2,};

View File

@ -1,24 +1,3 @@
/*
* Copyright (C) 2014 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_widget.hpp"
#include "ui_painter.hpp"
@ -305,77 +284,91 @@ void Text::set(const std::string value) {
}
void Text::paint(Painter& painter) {
if (style_ == nullptr) style_ = &style();
const auto rect = screen_rect();
const auto s = style();
painter.fill_rectangle(rect, s.background);
painter.draw_string(
rect.pos,
(*style_),
s,
text
);
}
/* Button ****************************************************************/
/* Checkbox **************************************************************/
Button::Button(
Rect parent_rect,
std::string text
) : Widget { parent_rect },
text_ { text }
{
flags.focusable = true;
}
void Button::set_text(const std::string value) {
void Checkbox::set_text(const std::string value) {
text_ = value;
set_dirty();
}
std::string Button::text() const {
std::string Checkbox::text() const {
return text_;
}
void Button::paint(Painter& painter) {
void Checkbox::set_value(const bool value) {
value_ = value;
set_dirty();
}
bool Checkbox::value() const {
return value_;
}
void Checkbox::paint(Painter& painter) {
const auto r = screen_rect();
if (style_ == nullptr) style_ = &style();
const auto paint_style = (has_focus() || flags.highlighted) ? style_->invert() : *(style_);
painter.draw_rectangle(r, style().foreground);
const auto paint_style = (has_focus() || flags.highlighted) ? style().invert() : style();
painter.draw_rectangle({ r.pos.x, r.pos.y, 24, 24 }, style().foreground);
painter.fill_rectangle(
{ r.pos.x + 1, r.pos.y + 1, r.size.w - 2, r.size.h - 2 },
paint_style.background
{
static_cast<Coord>(r.pos.x + 1), static_cast<Coord>(r.pos.y + 1),
static_cast<Dim>(24 - 2), static_cast<Dim>(24 - 2)
},
style().background
);
painter.draw_rectangle({ r.pos.x+2, r.pos.y+2, 24-4, 24-4 }, paint_style.background);
if (value_ == true) {
// Check
portapack::display.draw_line( {r.pos.x+2, r.pos.y+14}, {r.pos.x+6, r.pos.y+18}, ui::Color::green());
portapack::display.draw_line( {r.pos.x+6, r.pos.y+18}, {r.pos.x+20, r.pos.y+4}, ui::Color::green());
} else {
// Cross
portapack::display.draw_line( {r.pos.x+1, r.pos.y+1}, {r.pos.x+24-2, r.pos.y+24-2}, ui::Color::red());
portapack::display.draw_line( {r.pos.x+24-2, r.pos.y+1}, {r.pos.x+1, r.pos.y+24-2}, ui::Color::red());
}
const auto label_r = paint_style.font.size_of(text_);
painter.draw_string(
{ r.pos.x + (r.size.w - label_r.w) / 2, r.pos.y + (r.size.h - label_r.h) / 2 },
{
static_cast<Coord>(r.pos.x + 24 + 4),
static_cast<Coord>(r.pos.y + (24 - label_r.h) / 2)
},
paint_style,
text_
);
}
bool Button::on_key(const KeyEvent key) {
bool Checkbox::on_key(const KeyEvent key) {
if( key == KeyEvent::Select ) {
value_ = not value_;
set_dirty();
if( on_select ) {
on_select(*this);
return true;
}
} else {
if( on_dir ) {
on_dir(*this, key);
return false;
}
}
return false;
}
bool Button::on_touch(const TouchEvent event) {
bool Checkbox::on_touch(const TouchEvent event) {
switch(event.type) {
case TouchEvent::Type::Start:
flags.highlighted = true;
@ -385,6 +378,7 @@ bool Button::on_touch(const TouchEvent event) {
case TouchEvent::Type::End:
flags.highlighted = false;
value_ = not value_;
set_dirty();
if( on_select ) {
on_select(*this);
@ -427,6 +421,199 @@ bool Button::on_touch(const TouchEvent event) {
#endif
}
/* Button ****************************************************************/
Button::Button(
Rect parent_rect,
std::string text
) : Widget { parent_rect },
text_ { text }
{
flags.focusable = true;
}
void Button::set_text(const std::string value) {
text_ = value;
set_dirty();
}
std::string Button::text() const {
return text_;
}
void Button::paint(Painter& painter) {
const auto r = screen_rect();
const auto paint_style = (has_focus() || flags.highlighted) ? style().invert() : style();
painter.draw_rectangle(r, style().foreground);
painter.fill_rectangle(
{ r.pos.x + 1, r.pos.y + 1, r.size.w - 2, r.size.h - 2 },
paint_style.background
);
const auto label_r = paint_style.font.size_of(text_);
painter.draw_string(
{ r.pos.x + (r.size.w - label_r.w) / 2, r.pos.y + (r.size.h - label_r.h) / 2 },
paint_style,
text_
);
}
bool Button::on_key(const KeyEvent key) {
if( key == KeyEvent::Select ) {
if( on_select ) {
on_select(*this);
return true;
}
}
return false;
}
bool Button::on_touch(const TouchEvent event) {
switch(event.type) {
case TouchEvent::Type::Start:
flags.highlighted = true;
set_dirty();
return true;
case TouchEvent::Type::End:
flags.highlighted = false;
set_dirty();
if( on_select ) {
on_select(*this);
}
return true;
default:
return false;
}
#if 0
switch(event.type) {
case TouchEvent::Type::Start:
flags.highlighted = true;
set_dirty();
return true;
case TouchEvent::Type::Move:
{
const bool new_highlighted = screen_rect().contains(event.point);
if( flags.highlighted != new_highlighted ) {
flags.highlighted = new_highlighted;
set_dirty();
}
}
return true;
case TouchEvent::Type::End:
if( flags.highlighted ) {
flags.highlighted = false;
set_dirty();
if( on_select ) {
on_select(*this);
}
}
return true;
default:
return false;
}
#endif
}
/* Image *****************************************************************/
Image::Image(
) : Image { { }, nullptr, Color::white(), Color::black() }
{
}
Image::Image(
const Rect parent_rect,
const Bitmap* bitmap,
const Color foreground,
const Color background
) : Widget { parent_rect },
bitmap_ { bitmap },
foreground_ { foreground },
background_ { background }
{
}
void Image::set_bitmap(const Bitmap* bitmap) {
bitmap_ = bitmap;
set_dirty();
}
void Image::set_foreground(const Color color) {
foreground_ = color;
set_dirty();
}
void Image::set_background(const Color color) {
background_ = color;
set_dirty();
}
void Image::paint(Painter& painter) {
if( bitmap_ ) {
// Code also handles ImageButton behavior.
const bool selected = (has_focus() || flags.highlighted);
painter.draw_bitmap(
screen_pos(),
*bitmap_,
selected ? background_ : foreground_,
selected ? foreground_ : background_
);
}
}
/* ImageButton ***********************************************************/
// TODO: Virtually all this code is duplicated from Button. Base class?
ImageButton::ImageButton(
const Rect parent_rect,
const Bitmap* bitmap,
const Color foreground,
const Color background
) : Image { parent_rect, bitmap, foreground, background }
{
flags.focusable = true;
}
bool ImageButton::on_key(const KeyEvent key) {
if( key == KeyEvent::Select ) {
if( on_select ) {
on_select(*this);
return true;
}
}
return false;
}
bool ImageButton::on_touch(const TouchEvent event) {
switch(event.type) {
case TouchEvent::Type::Start:
flags.highlighted = true;
set_dirty();
return true;
case TouchEvent::Type::End:
flags.highlighted = false;
set_dirty();
if( on_select ) {
on_select(*this);
}
return true;
default:
return false;
}
}
/* OptionsField **********************************************************/
OptionsField::OptionsField(
@ -480,6 +667,12 @@ void OptionsField::paint(Painter& painter) {
}
}
void OptionsField::on_focus() {
if( on_show_options ) {
on_show_options();
}
}
bool OptionsField::on_encoder(const EncoderEvent delta) {
set_selected_index(selected_index() + delta);
return true;

View File

@ -188,48 +188,11 @@ public:
Text(Rect parent_rect);
void set(const std::string value);
void set_style(const Style* new_style);
void paint(Painter& painter) override;
private:
std::string text;
const Style* style_ { nullptr };
};
class Checkbox : public Widget {
public:
std::function<void(Checkbox&)> on_select;
Checkbox(
Point parent_point,
std::string text
) : Widget { parent_point },
text_ { text }
{
flags.focusable = true;
}
Checkbox(
) : Checkbox { { }, { } }
{
}
void set_text(const std::string value);
void set_style(const Style* new_style);
std::string text() const;
void set_value(const bool value);
bool value() const;
void paint(Painter& painter) override;
bool on_key(const KeyEvent key) override;
bool on_touch(const TouchEvent event) override;
private:
std::string text_;
bool value_ = false;
const Style* style_ { nullptr };
};
class Button : public Widget {
@ -244,8 +207,6 @@ public:
}
void set_text(const std::string value);
void set_text(const int value);
void set_style(const Style* new_style);
std::string text() const;
void paint(Painter& painter) override;
@ -255,7 +216,43 @@ public:
private:
std::string text_;
const Style* style_ { nullptr };
};
class Image : public Widget {
public:
Image();
Image(
const Rect parent_rect,
const Bitmap* bitmap,
const Color foreground,
const Color background
);
void set_bitmap(const Bitmap* bitmap);
void set_foreground(const Color color);
void set_background(const Color color);
void paint(Painter& painter) override;
private:
const Bitmap* bitmap_;
Color foreground_;
Color background_;
};
class ImageButton : public Image {
public:
std::function<void(ImageButton&)> on_select;
ImageButton(
const Rect parent_rect,
const Bitmap* bitmap,
const Color foreground,
const Color background
);
bool on_key(const KeyEvent key) override;
bool on_touch(const TouchEvent event) override;
};
class OptionsField : public Widget {
@ -266,6 +263,7 @@ public:
using options_t = std::vector<option_t>;
std::function<void(size_t, value_t)> on_change;
std::function<void(void)> on_show_options;
OptionsField(Point parent_pos, size_t length, options_t options);
@ -276,6 +274,7 @@ public:
void paint(Painter& painter) override;
void on_focus() override;
bool on_encoder(const EncoderEvent delta) override;
bool on_touch(const TouchEvent event) override;

Binary file not shown.

View File

@ -55,8 +55,9 @@ sys.argv = sys.argv[1:]
# Format for module file:
# Magic (4), Version (2), Length (4), Name (16), MD5 (16), Description (214)
# Module binary...
# MD5 (16)
# 0x00 pad bytes (256)
# Module binary (padded to 32768-16)
# MD5 (16) again, so that module code can read it (dirty...)
for args in sys.argv:
data = read_image(args + '/build/' + args + '.bin')
@ -66,7 +67,7 @@ for args in sys.argv:
info = 'PPM '
# Version
info += struct.pack('H', 1)
info += struct.pack('H', 2)
# Length
info += struct.pack('I', len(data))
@ -94,9 +95,12 @@ for args in sys.argv:
description += (data_default_byte * pad_size)
info += description
# Padding
# Header padding to fit in SD card sector
info += (data_default_byte * 256)
# Binary padding
data = info + data
pad_size = (32768 + 256 - 16) - len(data)
pad_size = (32768 + 512 - 16) - len(data)
data += (data_default_byte * pad_size)
data += digest
write_file(data, args + '.bin')
@ -108,6 +112,6 @@ for args in sys.argv:
h_data += 'const char md5_' + args.replace('-','_') + '[16] = {' + md5sum + '};\n'
# Update original binary with MD5 footprint
write_file(data[256:(32768+256)], args + '/build/' + args + '.bin')
write_file(data[512:(32768+512)], args + '/build/' + args + '.bin')
write_file(h_data, 'common/modules.h')