mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-07-21 22:19:12 -04:00
Merge fixing, commit to catch up on recent files
This commit is contained in:
parent
44638e504b
commit
6e496e2b26
90 changed files with 2257 additions and 1428 deletions
|
@ -148,6 +148,8 @@ CPPSRC = main.cpp \
|
||||||
encoder.cpp \
|
encoder.cpp \
|
||||||
lcd_ili9341.cpp \
|
lcd_ili9341.cpp \
|
||||||
ui.cpp \
|
ui.cpp \
|
||||||
|
ui_alphanum.cpp \
|
||||||
|
ui_about.cpp \
|
||||||
ui_text.cpp \
|
ui_text.cpp \
|
||||||
ui_widget.cpp \
|
ui_widget.cpp \
|
||||||
ui_painter.cpp \
|
ui_painter.cpp \
|
||||||
|
@ -157,6 +159,9 @@ CPPSRC = main.cpp \
|
||||||
ui_rssi.cpp \
|
ui_rssi.cpp \
|
||||||
ui_channel.cpp \
|
ui_channel.cpp \
|
||||||
ui_audio.cpp \
|
ui_audio.cpp \
|
||||||
|
ui_lcr.cpp \
|
||||||
|
ui_rds.cpp \
|
||||||
|
ui_jammer.cpp \
|
||||||
ui_font_fixed_8x16.cpp \
|
ui_font_fixed_8x16.cpp \
|
||||||
ui_setup.cpp \
|
ui_setup.cpp \
|
||||||
ui_debug.cpp \
|
ui_debug.cpp \
|
||||||
|
|
|
@ -19,36 +19,34 @@
|
||||||
* Boston, MA 02110-1301, USA.
|
* 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 <cstddef>
|
||||||
#include "hal.h"
|
#include <string>
|
||||||
|
|
||||||
#include "lpc43xx_cpp.hpp"
|
class File {
|
||||||
using namespace lpc43xx;
|
public:
|
||||||
|
~File();
|
||||||
|
|
||||||
void m4txevent_interrupt_enable() {
|
bool open_for_append(const std::string file_path);
|
||||||
nvicEnableVector(M4CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M4TXEVENT_IRQ_PRIORITY));
|
bool close();
|
||||||
}
|
|
||||||
|
|
||||||
void m4txevent_interrupt_disable() {
|
bool is_ready();
|
||||||
nvicDisableVector(M4CORE_IRQn);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
bool puts(const std::string string);
|
||||||
CH_IRQ_PROLOGUE();
|
|
||||||
|
|
||||||
chSysLockFromIsr();
|
bool sync();
|
||||||
events_flag_isr(EVT_MASK_APPLICATION);
|
|
||||||
chSysUnlockFromIsr();
|
|
||||||
|
|
||||||
creg::m4txevent::clear();
|
private:
|
||||||
|
const std::string file_path;
|
||||||
|
|
||||||
CH_IRQ_EPILOGUE();
|
FIL f;
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
#endif/*__FILE_H__*/
|
||||||
|
|
|
@ -106,7 +106,7 @@ void m4_switch(const char * hash) {
|
||||||
|
|
||||||
// Ask M4 to enter wait loop in RAM
|
// Ask M4 to enter wait loop in RAM
|
||||||
BasebandConfiguration baseband_switch {
|
BasebandConfiguration baseband_switch {
|
||||||
.mode = SWITCH,
|
.mode = 255, // DEBUG
|
||||||
.sampling_rate = 0,
|
.sampling_rate = 0,
|
||||||
.decimation_factor = 1,
|
.decimation_factor = 1,
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,6 @@
|
||||||
#include "ui_painter.hpp"
|
#include "ui_painter.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
|
|
||||||
#include "irq_ipc.hpp"
|
|
||||||
#include "irq_lcd_frame.hpp"
|
#include "irq_lcd_frame.hpp"
|
||||||
#include "irq_controls.hpp"
|
#include "irq_controls.hpp"
|
||||||
#include "irq_rtc.hpp"
|
#include "irq_rtc.hpp"
|
||||||
|
|
|
@ -75,31 +75,8 @@ uint32_t TransmitterModel::sampling_rate() const {
|
||||||
return baseband_configuration.sampling_rate;
|
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() {
|
void TransmitterModel::enable() {
|
||||||
|
enabled_ = true;
|
||||||
radio::set_direction(rf::Direction::Transmit);
|
radio::set_direction(rf::Direction::Transmit);
|
||||||
update_tuning_frequency();
|
update_tuning_frequency();
|
||||||
update_rf_amp();
|
update_rf_amp();
|
||||||
|
@ -107,23 +84,30 @@ void TransmitterModel::enable() {
|
||||||
update_vga();
|
update_vga();
|
||||||
update_baseband_bandwidth();
|
update_baseband_bandwidth();
|
||||||
update_baseband_configuration();
|
update_baseband_configuration();
|
||||||
radio::streaming_enable();
|
}
|
||||||
|
|
||||||
|
void TransmitterModel::baseband_disable() {
|
||||||
|
shared_memory.baseband_queue.push_and_wait(
|
||||||
|
BasebandConfigurationMessage {
|
||||||
|
.configuration = { },
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransmitterModel::disable() {
|
void TransmitterModel::disable() {
|
||||||
/* TODO: This is a dumb hack to stop baseband from working so hard. */
|
enabled_ = false;
|
||||||
BasebandConfigurationMessage message {
|
baseband_disable();
|
||||||
.configuration = {
|
|
||||||
.mode = NONE,
|
|
||||||
.sampling_rate = 0,
|
|
||||||
.decimation_factor = 1,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
shared_memory.baseband_queue.push(message);
|
|
||||||
|
|
||||||
|
// TODO: Responsibility for enabling/disabling the radio is muddy.
|
||||||
|
// Some happens in ReceiverModel, some inside radio namespace.
|
||||||
radio::disable();
|
radio::disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t TransmitterModel::baseband_oversampling() const {
|
||||||
|
// TODO: Rename decimation_factor.
|
||||||
|
return baseband_configuration.decimation_factor;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t TransmitterModel::tuning_offset() {
|
int32_t TransmitterModel::tuning_offset() {
|
||||||
return -(sampling_rate() / 4);
|
return -(sampling_rate() / 4);
|
||||||
}
|
}
|
||||||
|
@ -148,8 +132,8 @@ void TransmitterModel::update_vga() {
|
||||||
radio::set_vga_gain(vga_gain_db_);
|
radio::set_vga_gain(vga_gain_db_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransmitterModel::update_modulation() {
|
uint32_t TransmitterModel::modulation() const {
|
||||||
update_baseband_configuration();
|
return baseband_configuration.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransmitterModel::set_baseband_configuration(const BasebandConfiguration config) {
|
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() {
|
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());
|
clock_manager.set_sampling_frequency(sampling_rate() * baseband_oversampling());
|
||||||
update_tuning_frequency();
|
update_tuning_frequency();
|
||||||
|
@ -166,7 +155,5 @@ void TransmitterModel::update_baseband_configuration() {
|
||||||
|
|
||||||
BasebandConfigurationMessage message { baseband_configuration };
|
BasebandConfigurationMessage message { baseband_configuration };
|
||||||
shared_memory.baseband_queue.push(message);
|
shared_memory.baseband_queue.push(message);
|
||||||
|
|
||||||
radio::streaming_enable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,13 +55,10 @@ public:
|
||||||
void set_vga(int32_t v_db);
|
void set_vga(int32_t v_db);
|
||||||
|
|
||||||
uint32_t sampling_rate() const;
|
uint32_t sampling_rate() const;
|
||||||
void set_sampling_rate(uint32_t hz);
|
|
||||||
|
|
||||||
mode_type modulation() const;
|
uint32_t modulation() const;
|
||||||
void set_modulation(mode_type v);
|
|
||||||
|
|
||||||
uint32_t baseband_oversampling() const;
|
uint32_t baseband_oversampling() const;
|
||||||
void set_baseband_oversampling(uint32_t v);
|
|
||||||
|
|
||||||
void enable();
|
void enable();
|
||||||
void disable();
|
void disable();
|
||||||
|
@ -69,12 +66,14 @@ public:
|
||||||
void set_baseband_configuration(const BasebandConfiguration config);
|
void set_baseband_configuration(const BasebandConfiguration config);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
rf::Frequency frequency_step_ { 25000 };
|
||||||
|
bool enabled_ { false };
|
||||||
bool rf_amp_ { true };
|
bool rf_amp_ { true };
|
||||||
int32_t lna_gain_db_ { 0 };
|
int32_t lna_gain_db_ { 0 };
|
||||||
uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum };
|
uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum };
|
||||||
int32_t vga_gain_db_ { 8 };
|
int32_t vga_gain_db_ { 8 };
|
||||||
BasebandConfiguration baseband_configuration {
|
BasebandConfiguration baseband_configuration {
|
||||||
.mode = NONE,
|
.mode = 1,
|
||||||
.sampling_rate = 2280000,
|
.sampling_rate = 2280000,
|
||||||
.decimation_factor = 1,
|
.decimation_factor = 1,
|
||||||
};
|
};
|
||||||
|
@ -89,6 +88,8 @@ private:
|
||||||
void update_vga();
|
void update_vga();
|
||||||
void update_modulation();
|
void update_modulation();
|
||||||
void update_baseband_configuration();
|
void update_baseband_configuration();
|
||||||
|
|
||||||
|
void baseband_disable();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif/*__TRANSMITTER_MODEL_H__*/
|
#endif/*__TRANSMITTER_MODEL_H__*/
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "ymdata.hpp"
|
#include "ymdata.hpp"
|
||||||
|
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
|
#include "event_m0.hpp"
|
||||||
|
|
||||||
#include "ui_about.hpp"
|
#include "ui_about.hpp"
|
||||||
#include "touch.hpp"
|
#include "touch.hpp"
|
||||||
|
@ -44,23 +45,21 @@ using namespace portapack;
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
void AboutView::on_show() {
|
void AboutView::on_show() {
|
||||||
auto& message_map = context().message_map();
|
|
||||||
|
|
||||||
// Just in case
|
// Just in case
|
||||||
message_map.unregister_handler(Message::ID::DisplayFrameSync);
|
EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync);
|
||||||
|
|
||||||
// "Vertical blank interrupt"
|
// "Vertical blank interrupt"
|
||||||
message_map.register_handler(Message::ID::DisplayFrameSync,
|
EventDispatcher::message_map().register_handler(Message::ID::DisplayFrameSync,
|
||||||
[this](const Message* const) {
|
[this](const Message* const) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Just in case
|
// 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
|
// 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) {
|
[this](Message* const p) {
|
||||||
FIFODataMessage datamessage;
|
FIFODataMessage datamessage;
|
||||||
const auto message = static_cast<const FIFOSignalMessage*>(p);
|
const auto message = static_cast<const FIFOSignalMessage*>(p);
|
||||||
|
@ -349,6 +348,7 @@ void AboutView::update() {
|
||||||
refresh_cnt++;
|
refresh_cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Slowly increase volume to avoid jumpscare
|
||||||
if (headphone_vol < (70<<2)) {
|
if (headphone_vol < (70<<2)) {
|
||||||
portapack::audio_codec.set_headphone_volume(volume_t::decibel((headphone_vol/4) - 99) + wolfson::wm8731::headphone_gain_range.max);
|
portapack::audio_codec.set_headphone_volume(volume_t::decibel((headphone_vol/4) - 99) + wolfson::wm8731::headphone_gain_range.max);
|
||||||
headphone_vol++;
|
headphone_vol++;
|
||||||
|
@ -370,14 +370,13 @@ void AboutView::ym_init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
AboutView::AboutView(
|
AboutView::AboutView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
TransmitterModel& transmitter_model
|
)
|
||||||
) : transmitter_model(transmitter_model)
|
|
||||||
{
|
{
|
||||||
uint8_t p, c;
|
uint8_t p, c;
|
||||||
|
|
||||||
transmitter_model.set_baseband_configuration({
|
transmitter_model.set_baseband_configuration({
|
||||||
.mode = PLAY_AUDIO,
|
.mode = 5,
|
||||||
.sampling_rate = 1536000,
|
.sampling_rate = 1536000,
|
||||||
.decimation_factor = 1,
|
.decimation_factor = 1,
|
||||||
});
|
});
|
||||||
|
@ -412,8 +411,7 @@ AboutView::AboutView(
|
||||||
ym_init();
|
ym_init();
|
||||||
|
|
||||||
button_ok.on_select = [this,&nav](Button&){
|
button_ok.on_select = [this,&nav](Button&){
|
||||||
auto& message_map = context().message_map();
|
EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync);
|
||||||
message_map.unregister_handler(Message::ID::DisplayFrameSync);
|
|
||||||
if (framebuffer) chHeapFree(framebuffer); // Do NOT forget this
|
if (framebuffer) chHeapFree(framebuffer); // Do NOT forget this
|
||||||
nav.pop();
|
nav.pop();
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace ui {
|
||||||
|
|
||||||
class AboutView : public View {
|
class AboutView : public View {
|
||||||
public:
|
public:
|
||||||
AboutView(NavigationView& nav, TransmitterModel& transmitter_model);
|
AboutView(NavigationView& nav);
|
||||||
~AboutView();
|
~AboutView();
|
||||||
|
|
||||||
void on_show() override;
|
void on_show() override;
|
||||||
|
@ -54,8 +54,6 @@ private:
|
||||||
bool same;
|
bool same;
|
||||||
} ymreg_t;
|
} ymreg_t;
|
||||||
|
|
||||||
TransmitterModel& transmitter_model;
|
|
||||||
|
|
||||||
uint16_t headphone_vol = 5<<2;
|
uint16_t headphone_vol = 5<<2;
|
||||||
|
|
||||||
ymreg_t ym_regs[14];
|
ymreg_t ym_regs[14];
|
||||||
|
|
|
@ -24,19 +24,17 @@
|
||||||
#include "ui_spectrum.hpp"
|
#include "ui_spectrum.hpp"
|
||||||
#include "ui_console.hpp"
|
#include "ui_console.hpp"
|
||||||
|
|
||||||
|
#include "event_m0.hpp"
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
|
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
#include "ui_receiver.hpp"
|
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
AFSKRXView::AFSKRXView(
|
AFSKRXView::AFSKRXView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
ReceiverModel& receiver_model
|
)
|
||||||
) : receiver_model(receiver_model)
|
|
||||||
{
|
{
|
||||||
add_children({ {
|
add_children({ {
|
||||||
&button_done,
|
&button_done,
|
||||||
|
@ -48,7 +46,7 @@ AFSKRXView::AFSKRXView(
|
||||||
};
|
};
|
||||||
|
|
||||||
receiver_model.set_baseband_configuration({
|
receiver_model.set_baseband_configuration({
|
||||||
.mode = RX_AFSK,
|
.mode = 6,
|
||||||
.sampling_rate = 3072000,
|
.sampling_rate = 3072000,
|
||||||
.decimation_factor = 4,
|
.decimation_factor = 4,
|
||||||
});
|
});
|
||||||
|
@ -60,8 +58,7 @@ AFSKRXView::~AFSKRXView() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AFSKRXView::on_show() {
|
void AFSKRXView::on_show() {
|
||||||
auto& message_map = context().message_map();
|
EventDispatcher::message_map().register_handler(Message::ID::AFSKData,
|
||||||
message_map.register_handler(Message::ID::AFSKData,
|
|
||||||
[this](Message* const p) {
|
[this](Message* const p) {
|
||||||
const auto message = static_cast<const AFSKDataMessage*>(p);
|
const auto message = static_cast<const AFSKDataMessage*>(p);
|
||||||
this->on_data_afsk(*message);
|
this->on_data_afsk(*message);
|
||||||
|
@ -72,8 +69,7 @@ void AFSKRXView::on_show() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AFSKRXView::on_hide() {
|
void AFSKRXView::on_hide() {
|
||||||
auto& message_map = context().message_map();
|
EventDispatcher::message_map().unregister_handler(Message::ID::AFSKData);
|
||||||
message_map.unregister_handler(Message::ID::AFSKData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AFSKRXView::on_data_afsk(const AFSKDataMessage& message) {
|
void AFSKRXView::on_data_afsk(const AFSKDataMessage& message) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace ui {
|
||||||
|
|
||||||
class AFSKRXView : public View {
|
class AFSKRXView : public View {
|
||||||
public:
|
public:
|
||||||
AFSKRXView(NavigationView& nav, ReceiverModel& receiver_model);
|
AFSKRXView(NavigationView& nav);
|
||||||
~AFSKRXView();
|
~AFSKRXView();
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
|
@ -51,8 +51,6 @@ public:
|
||||||
void on_hide() override;
|
void on_hide() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReceiverModel& receiver_model;
|
|
||||||
|
|
||||||
std::unique_ptr<Widget> widget_content;
|
std::unique_ptr<Widget> widget_content;
|
||||||
|
|
||||||
Button button_done {
|
Button button_done {
|
||||||
|
|
|
@ -66,9 +66,8 @@ void AFSKSetupView::updfreq(rf::Frequency f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AFSKSetupView::AFSKSetupView(
|
AFSKSetupView::AFSKSetupView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
TransmitterModel& transmitter_model
|
)
|
||||||
) : transmitter_model(transmitter_model)
|
|
||||||
{
|
{
|
||||||
uint8_t rpt;
|
uint8_t rpt;
|
||||||
|
|
||||||
|
|
|
@ -36,15 +36,13 @@ namespace ui {
|
||||||
|
|
||||||
class AFSKSetupView : public View {
|
class AFSKSetupView : public View {
|
||||||
public:
|
public:
|
||||||
AFSKSetupView(NavigationView& nav, TransmitterModel& transmitter_model);
|
AFSKSetupView(NavigationView& nav);
|
||||||
|
|
||||||
void updfreq(rf::Frequency f);
|
void updfreq(rf::Frequency f);
|
||||||
void focus() override;
|
void focus() override;
|
||||||
void paint(Painter& painter) override;
|
void paint(Painter& painter) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TransmitterModel& transmitter_model;
|
|
||||||
|
|
||||||
Text text_title {
|
Text text_title {
|
||||||
{ 40, 32, 160, 16 },
|
{ 40, 32, 160, 16 },
|
||||||
"AFSK modulator setup"
|
"AFSK modulator setup"
|
||||||
|
|
|
@ -110,7 +110,7 @@ void AlphanumView::set_uppercase() {
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
for(auto& button : buttons) {
|
for(auto& button : buttons) {
|
||||||
add_child(&button);
|
//add_child(&button);
|
||||||
const std::string label {
|
const std::string label {
|
||||||
key_caps[n]
|
key_caps[n]
|
||||||
};
|
};
|
||||||
|
@ -125,7 +125,7 @@ void AlphanumView::set_lowercase() {
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
for(auto& button : buttons) {
|
for(auto& button : buttons) {
|
||||||
add_child(&button);
|
//add_child(&button);
|
||||||
const std::string label {
|
const std::string label {
|
||||||
key_caps[n]
|
key_caps[n]
|
||||||
};
|
};
|
||||||
|
|
|
@ -245,20 +245,6 @@ void RegistersView::focus() {
|
||||||
button_done.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) {
|
char hexify(char in) {
|
||||||
if (in > 9) in += 7;
|
if (in > 9) in += 7;
|
||||||
return in + 0x30;
|
return in + 0x30;
|
||||||
|
@ -301,26 +287,26 @@ void DebugLCRView::focus() {
|
||||||
|
|
||||||
DebugMenuView::DebugMenuView(NavigationView& nav) {
|
DebugMenuView::DebugMenuView(NavigationView& nav) {
|
||||||
add_items<8>({ {
|
add_items<8>({ {
|
||||||
{ "Memory", [&nav](){ nav.push<DebugMemoryView>(); } },
|
{ "Memory", ui::Color::white(), [&nav](){ nav.push<DebugMemoryView>(); } },
|
||||||
{ "Radio State", [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "Radio State", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
|
||||||
{ "SD Card", [&nav](){ nav.push<NotImplementedView>(); } },
|
{ "SD Card", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
|
||||||
{ "RFFC5072", [&nav](){ nav.push<RegistersView>(
|
{ "RFFC5072", ui::Color::white(), [&nav](){ nav.push<RegistersView>(
|
||||||
"RFFC5072", RegistersWidgetConfig { 31, 2, 4, 4 },
|
"RFFC5072", RegistersWidgetConfig { 31, 2, 4, 4 },
|
||||||
[](const size_t register_number) { return radio::first_if.read(register_number); }
|
[](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 },
|
"MAX2837", RegistersWidgetConfig { 32, 2, 3, 4 },
|
||||||
[](const size_t register_number) { return radio::second_if.read(register_number); }
|
[](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 },
|
"Si5351C", RegistersWidgetConfig { 96, 2, 2, 8 },
|
||||||
[](const size_t register_number) { return portapack::clock_generator.read_register(register_number); }
|
[](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 },
|
"WM8731", RegistersWidgetConfig { wolfson::wm8731::reg_count, 1, 3, 4 },
|
||||||
[](const size_t register_number) { return portapack::audio_codec.read(register_number); }
|
[](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(); };
|
on_left = [&nav](){ nav.pop(); };
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,8 +246,6 @@ public:
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
|
|
||||||
void paint(Painter& painter) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Text text_lcr1 {
|
Text text_lcr1 {
|
||||||
{ 16, 32, 208, 8 },
|
{ 16, 32, 208, 8 },
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include "hackrf_gpio.hpp"
|
#include "hackrf_gpio.hpp"
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "radio.hpp"
|
#include "radio.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
#include "event_m0.hpp"
|
||||||
|
|
||||||
#include "hackrf_hal.hpp"
|
#include "hackrf_hal.hpp"
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
|
@ -37,7 +39,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
using namespace hackrf::one;
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -146,9 +148,8 @@ void JammerView::updfreq(uint8_t id, rf::Frequency f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
JammerView::JammerView(
|
JammerView::JammerView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
TransmitterModel& transmitter_model
|
)
|
||||||
) : transmitter_model(transmitter_model)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
static constexpr Style style_val {
|
static constexpr Style style_val {
|
||||||
|
@ -169,7 +170,11 @@ JammerView::JammerView(
|
||||||
.foreground = Color::grey(),
|
.foreground = Color::grey(),
|
||||||
};
|
};
|
||||||
|
|
||||||
transmitter_model.set_modulation(TX_JAMMER);
|
transmitter_model.set_baseband_configuration({
|
||||||
|
.mode = 3,
|
||||||
|
.sampling_rate = 1536000, // ?
|
||||||
|
.decimation_factor = 1,
|
||||||
|
});
|
||||||
|
|
||||||
add_children({ {
|
add_children({ {
|
||||||
&text_type,
|
&text_type,
|
||||||
|
@ -232,11 +237,9 @@ JammerView::JammerView(
|
||||||
button_transmit.on_select = [this,&transmitter_model](Button&) {
|
button_transmit.on_select = [this,&transmitter_model](Button&) {
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
rf::Frequency t, range_lower;
|
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);
|
EventDispatcher::message_map().register_handler(Message::ID::Retune,
|
||||||
|
|
||||||
message_map.register_handler(Message::ID::Retune,
|
|
||||||
[this,&transmitter_model](Message* const p) {
|
[this,&transmitter_model](Message* const p) {
|
||||||
const auto message = static_cast<const RetuneMessage*>(p);
|
const auto message = static_cast<const RetuneMessage*>(p);
|
||||||
if (message->freq > 0) {
|
if (message->freq > 0) {
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace ui {
|
||||||
|
|
||||||
class JammerView : public View {
|
class JammerView : public View {
|
||||||
public:
|
public:
|
||||||
JammerView(NavigationView& nav, TransmitterModel& transmitter_model);
|
JammerView(NavigationView& nav);
|
||||||
~JammerView();
|
~JammerView();
|
||||||
|
|
||||||
void updfreq(uint8_t id, rf::Frequency f);
|
void updfreq(uint8_t id, rf::Frequency f);
|
||||||
|
@ -117,7 +117,6 @@ private:
|
||||||
|
|
||||||
bool jamming = false;
|
bool jamming = false;
|
||||||
rf::Frequency f;
|
rf::Frequency f;
|
||||||
TransmitterModel& transmitter_model;
|
|
||||||
|
|
||||||
Text text_type {
|
Text text_type {
|
||||||
{ 1 * 8, 1 * 16, 40, 16 },
|
{ 1 * 8, 1 * 16, 40, 16 },
|
||||||
|
|
|
@ -31,8 +31,11 @@
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
#include "hackrf_gpio.hpp"
|
#include "hackrf_gpio.hpp"
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
|
#include "event_m0.hpp"
|
||||||
#include "radio.hpp"
|
#include "radio.hpp"
|
||||||
|
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
#include "hackrf_hal.hpp"
|
#include "hackrf_hal.hpp"
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
@ -40,7 +43,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
using namespace hackrf::one;
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -176,9 +179,8 @@ void LCRView::paint(Painter& painter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LCRView::LCRView(
|
LCRView::LCRView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
TransmitterModel& transmitter_model
|
)
|
||||||
) : transmitter_model(transmitter_model)
|
|
||||||
{
|
{
|
||||||
char finalstr[24] = {0};
|
char finalstr[24] = {0};
|
||||||
|
|
||||||
|
@ -188,7 +190,12 @@ LCRView::LCRView(
|
||||||
.foreground = Color::black(),
|
.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());
|
transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
|
||||||
memset(litteral, 0, 5*8);
|
memset(litteral, 0, 5*8);
|
||||||
memset(rgsb, 0, 5);
|
memset(rgsb, 0, 5);
|
||||||
|
@ -277,8 +284,6 @@ LCRView::LCRView(
|
||||||
};
|
};
|
||||||
|
|
||||||
button_transmit.on_select = [this,&transmitter_model](Button&){
|
button_transmit.on_select = [this,&transmitter_model](Button&){
|
||||||
auto& message_map = context().message_map();
|
|
||||||
|
|
||||||
make_frame();
|
make_frame();
|
||||||
|
|
||||||
shared_memory.afsk_samples_per_bit = 228000/portapack::persistent_memory::afsk_bitrate();
|
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_transmit_done = false;
|
||||||
shared_memory.afsk_repeat = (portapack::persistent_memory::afsk_config() >> 8) & 0xFF;
|
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) {
|
[this,&transmitter_model](Message* const p) {
|
||||||
char str[8];
|
char str[8];
|
||||||
const auto message = static_cast<const TXDoneMessage*>(p);
|
const auto message = static_cast<const TXDoneMessage*>(p);
|
||||||
|
@ -319,7 +324,7 @@ LCRView::LCRView(
|
||||||
};
|
};
|
||||||
|
|
||||||
button_txsetup.on_select = [&nav, &transmitter_model](Button&){
|
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&){
|
button_exit.on_select = [&nav](Button&){
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace ui {
|
||||||
|
|
||||||
class LCRView : public View {
|
class LCRView : public View {
|
||||||
public:
|
public:
|
||||||
LCRView(NavigationView& nav, TransmitterModel& transmitter_model);
|
LCRView(NavigationView& nav);
|
||||||
~LCRView();
|
~LCRView();
|
||||||
|
|
||||||
void make_frame();
|
void make_frame();
|
||||||
|
@ -63,7 +63,6 @@ private:
|
||||||
char lcrframe[256];
|
char lcrframe[256];
|
||||||
char lcrframe_f[256];
|
char lcrframe_f[256];
|
||||||
rf::Frequency f;
|
rf::Frequency f;
|
||||||
TransmitterModel& transmitter_model;
|
|
||||||
|
|
||||||
Text text_status {
|
Text text_status {
|
||||||
{ 168, 196, 64, 16 },
|
{ 168, 196, 64, 16 },
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
*
|
*
|
||||||
* This file is part of PortaPack.
|
* This file is part of PortaPack.
|
||||||
*
|
*
|
||||||
|
@ -24,10 +25,12 @@
|
||||||
#include "ch.h"
|
#include "ch.h"
|
||||||
|
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
|
#include "event_m0.hpp"
|
||||||
#include "hackrf_gpio.hpp"
|
#include "hackrf_gpio.hpp"
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
#include "hackrf_hal.hpp"
|
#include "hackrf_hal.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -45,18 +48,17 @@ void LoadModuleView::paint(Painter& painter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadModuleView::on_hide() {
|
void LoadModuleView::on_hide() {
|
||||||
auto& message_map = context().message_map();
|
EventDispatcher::message_map().unregister_handler(Message::ID::ReadyForSwitch);
|
||||||
message_map.unregister_handler(Message::ID::ReadyForSwitch);
|
EventDispatcher::message_map().unregister_handler(Message::ID::ModuleID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadModuleView::on_show() {
|
void LoadModuleView::on_show() {
|
||||||
// Ask for MD5 signature and compare
|
// Ask for MD5 signature and compare
|
||||||
ModuleIDMessage message;
|
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) {
|
[this](Message* const p) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
const auto message = static_cast<const ModuleIDMessage*>(p);
|
const auto message = static_cast<const ModuleIDMessage*>(p);
|
||||||
|
@ -78,13 +80,66 @@ void LoadModuleView::on_show() {
|
||||||
shared_memory.baseband_queue.push(message);
|
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() {
|
void LoadModuleView::loadmodule() {
|
||||||
auto& message_map = context().message_map();
|
//message_map.unregister_handler(Message::ID::ReadyForSwitch);
|
||||||
message_map.register_handler(Message::ID::ReadyForSwitch,
|
|
||||||
|
EventDispatcher::message_map().register_handler(Message::ID::ReadyForSwitch,
|
||||||
[this](Message* const p) {
|
[this](Message* const p) {
|
||||||
(void)p;
|
(void)p;
|
||||||
if (m4_load_image()) {
|
if (load_image()) {
|
||||||
text_info.set("Module loaded :)");
|
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;
|
_mod_loaded = true;
|
||||||
} else {
|
} else {
|
||||||
text_info.set("Module not found :(");
|
text_info.set("Module not found :(");
|
||||||
|
@ -104,6 +159,7 @@ LoadModuleView::LoadModuleView(
|
||||||
{
|
{
|
||||||
add_children({ {
|
add_children({ {
|
||||||
&text_info,
|
&text_info,
|
||||||
|
&text_infob,
|
||||||
&button_ok
|
&button_ok
|
||||||
} });
|
} });
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
*
|
*
|
||||||
* This file is part of PortaPack.
|
* This file is part of PortaPack.
|
||||||
*
|
*
|
||||||
|
@ -40,12 +41,17 @@ public:
|
||||||
void paint(Painter& painter) override;
|
void paint(Painter& painter) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int load_image(void);
|
||||||
const char * _hash;
|
const char * _hash;
|
||||||
bool _mod_loaded = false;
|
bool _mod_loaded = false;
|
||||||
|
|
||||||
Text text_info {
|
Text text_info {
|
||||||
{ 8, 64, 224, 16 },
|
{ 8, 64, 224, 16 },
|
||||||
"Searching module..."
|
"-"
|
||||||
|
};
|
||||||
|
Text text_infob {
|
||||||
|
{ 8, 64+16, 224, 16 },
|
||||||
|
"-"
|
||||||
};
|
};
|
||||||
|
|
||||||
Button button_ok {
|
Button button_ok {
|
||||||
|
|
|
@ -108,6 +108,10 @@ View* NavigationView::push_view(std::unique_ptr<View> new_view) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NavigationView::push(View* v) {
|
||||||
|
push_view(std::unique_ptr<View>(v));
|
||||||
|
}
|
||||||
|
|
||||||
void NavigationView::pop() {
|
void NavigationView::pop() {
|
||||||
// Can't pop last item from stack.
|
// Can't pop last item from stack.
|
||||||
if( view_stack.size() > 1 ) {
|
if( view_stack.size() > 1 ) {
|
||||||
|
@ -149,9 +153,9 @@ void NavigationView::focus() {
|
||||||
|
|
||||||
TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
|
TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
|
||||||
add_items<3>({ {
|
add_items<3>({ {
|
||||||
{ "AIS: Boats", [&nav](){ nav.push<AISAppView>(); } },
|
{ "AIS: Boats", ui::Color::white(), [&nav](){ nav.push<AISAppView>(); } },
|
||||||
{ "ERT: Utility Meters", [&nav](){ nav.push<ERTAppView>(); } },
|
{ "ERT: Utility Meters", ui::Color::white(), [&nav](){ nav.push<ERTAppView>(); } },
|
||||||
{ "TPMS: Cars", [&nav](){ nav.push<TPMSAppView>(); } },
|
{ "TPMS: Cars", ui::Color::white(), [&nav](){ nav.push<TPMSAppView>(); } },
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +163,8 @@ TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
|
||||||
|
|
||||||
ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
|
ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
|
||||||
add_items<2>({ {
|
add_items<2>({ {
|
||||||
{ "Audio", [&nav](){ nav.push<ReceiverView>(); } },
|
{ "Audio", ui::Color::white(), [&nav](){ nav.push<ReceiverView>(); } },
|
||||||
{ "Transponders", [&nav](){ nav.push<TranspondersMenuView>(); } },
|
{ "Transponders", ui::Color::white(), [&nav](){ nav.push<TranspondersMenuView>(); } },
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,24 +172,24 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
|
||||||
|
|
||||||
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||||
add_items<10>({ {
|
add_items<10>({ {
|
||||||
{ "Play dead", ui::Color::red(), [&nav](){ nav.push(new PlayDeadView { nav, false }); } },
|
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } },
|
||||||
{ "Receiver", ui::Color::cyan(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new ReceiverMenuView { nav, receiver_model }}); } },
|
{ "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 }); } },
|
//{ "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 }); } },
|
//{ "Audio file TX", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
|
||||||
//{ "Encoder TX", ui::Color::green(), [&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 }}); } },
|
//{ "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 }}); } },
|
//{ "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 }}); } },
|
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, new RDSView(nav)); } },
|
||||||
{ "Xylos TX", ui::Color::orange(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new XylosView { nav, transmitter_model }}); } },
|
{ "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 }}); } },
|
//{ "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 }}); } },
|
//{ "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 }}); } },
|
//{ "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 }); } },
|
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
|
||||||
{ "About", ui::Color::white(), [&nav](){ nav.push(new AboutView { nav, transmitter_model }); } },
|
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } },
|
||||||
{ "Debug", ui::Color::white(), [&nav](){ nav.push(new DebugMenuView { nav }); } },
|
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
|
||||||
{ "HackRF", ui::Color::white(), [&nav](){ nav.push(new HackRFFirmwareView { nav }); } },
|
{ "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() {
|
void HackRFFirmwareView::focus() {
|
||||||
button_no.focus();
|
button_no.focus();
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,8 @@ public:
|
||||||
return reinterpret_cast<T*>(push_view(std::unique_ptr<View>(new T(*this, std::forward<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();
|
void pop();
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
|
@ -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 {
|
class ReceiverMenuView : public MenuView {
|
||||||
public:
|
public:
|
||||||
ReceiverMenuView(NavigationView& nav);
|
ReceiverMenuView(NavigationView& nav);
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
using namespace hackrf::one;
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -134,9 +134,8 @@ void RDSView::paint(Painter& painter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RDSView::RDSView(
|
RDSView::RDSView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
TransmitterModel& transmitter_model
|
)
|
||||||
) : transmitter_model(transmitter_model)
|
|
||||||
{
|
{
|
||||||
transmitter_model.set_tuning_frequency(93000000);
|
transmitter_model.set_tuning_frequency(93000000);
|
||||||
strcpy(psname, "TEST1234");
|
strcpy(psname, "TEST1234");
|
||||||
|
|
|
@ -86,7 +86,7 @@ private:
|
||||||
*/
|
*/
|
||||||
class RDSView : public View {
|
class RDSView : public View {
|
||||||
public:
|
public:
|
||||||
RDSView(NavigationView& nav, TransmitterModel& transmitter_model);
|
RDSView(NavigationView& nav);
|
||||||
~RDSView();
|
~RDSView();
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
|
@ -94,7 +94,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char psname[9];
|
char psname[9];
|
||||||
TransmitterModel& transmitter_model;
|
|
||||||
|
|
||||||
Text text_title {
|
Text text_title {
|
||||||
{ 76, 16, 88, 16 },
|
{ 76, 16, 88, 16 },
|
||||||
|
|
|
@ -20,13 +20,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui_setup.hpp"
|
#include "ui_setup.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
|
|
||||||
#include "lpc43xx_cpp.hpp"
|
#include "lpc43xx_cpp.hpp"
|
||||||
using namespace lpc43xx;
|
using namespace lpc43xx;
|
||||||
|
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
using portapack::receiver_model;
|
using portapack::receiver_model;
|
||||||
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -167,12 +170,6 @@ void AntennaBiasSetupView::focus() {
|
||||||
button_done.focus();
|
button_done.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AboutView::focus() {
|
|
||||||
button_ok.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTouchCalibView::focus() {
|
void SetTouchCalibView::focus() {
|
||||||
button_ok.focus();
|
button_ok.focus();
|
||||||
}
|
}
|
||||||
|
@ -433,13 +430,13 @@ void ModInfoView::focus() {
|
||||||
|
|
||||||
SetupMenuView::SetupMenuView(NavigationView& nav) {
|
SetupMenuView::SetupMenuView(NavigationView& nav) {
|
||||||
add_items<7>({ {
|
add_items<7>({ {
|
||||||
{ "SD card modules", ui::Color::white(), [&nav](){ nav.push(new ModInfoView { nav }); } },
|
{ "SD card modules", ui::Color::white(), [&nav](){ nav.push<ModInfoView>(); } },
|
||||||
{ "Date/Time", ui::Color::white(), [&nav](){ nav.push(new SetDateTimeView { nav }); } },
|
{ "Date/Time", ui::Color::white(), [&nav](){ nav.push<SetDateTimeView>(); } },
|
||||||
{ "Frequency correction", ui::Color::white(), [&nav](){ nav.push<SetFrequencyCorrectionView>(); } },
|
{ "Frequency correction", ui::Color::white(), [&nav](){ nav.push<SetFrequencyCorrectionView>(); } },
|
||||||
{ "Antenna Bias Voltage", [&nav](){ nav.push<AntennaBiasSetupView>(); } },
|
{ "Antenna Bias Voltage", ui::Color::white(), [&nav](){ nav.push<AntennaBiasSetupView>(); } },
|
||||||
{ "Touch screen", ui::Color::white(), [&nav](){ nav.push(new SetTouchCalibView { nav }); } },
|
{ "Touch screen", ui::Color::white(), [&nav](){ nav.push<SetTouchCalibView>(); } },
|
||||||
{ "Play dead", ui::Color::red(), [&nav](){ nav.push(new SetPlayDeadView { nav }); } },
|
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<SetPlayDeadView>(); } },
|
||||||
{ "UI", ui::Color::white(), [&nav](){ nav.push(new SetUIView { nav }); } },
|
{ "UI", ui::Color::white(), [&nav](){ nav.push<SetUIView>(); } },
|
||||||
} });
|
} });
|
||||||
on_left = [&nav](){ nav.pop(); };
|
on_left = [&nav](){ nav.pop(); };
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "ui_widget.hpp"
|
#include "ui_widget.hpp"
|
||||||
#include "ui_menu.hpp"
|
#include "ui_menu.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
|
#include "ff.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#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 {
|
class SetupMenuView : public MenuView {
|
||||||
public:
|
public:
|
||||||
SetupMenuView(NavigationView& nav);
|
SetupMenuView(NavigationView& nav);
|
||||||
|
|
|
@ -25,11 +25,13 @@
|
||||||
#include "ch.h"
|
#include "ch.h"
|
||||||
#include "evtimer.h"
|
#include "evtimer.h"
|
||||||
|
|
||||||
|
#include "event_m0.hpp"
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
#include "hackrf_gpio.hpp"
|
#include "hackrf_gpio.hpp"
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "radio.hpp"
|
#include "radio.hpp"
|
||||||
//#include "fox_bmp.hpp"
|
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
#include "hackrf_hal.hpp"
|
#include "hackrf_hal.hpp"
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
|
@ -38,7 +40,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
using namespace hackrf::one;
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -98,20 +100,23 @@ void SIGFRXView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SIGFRXView::on_show() {
|
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](const Message* const p) {
|
||||||
this->on_channel_spectrum(reinterpret_cast<const ChannelSpectrumMessage*>(p)->spectrum);
|
this->on_channel_spectrum(reinterpret_cast<const ChannelSpectrumMessage*>(p)->spectrum);
|
||||||
}
|
}
|
||||||
);
|
);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void SIGFRXView::on_hide() {
|
||||||
|
//EventDispatcher::message_map().unregister_handler(Message::ID::ChannelSpectrum);
|
||||||
}
|
}
|
||||||
|
|
||||||
SIGFRXView::SIGFRXView(
|
SIGFRXView::SIGFRXView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
ReceiverModel& receiver_model
|
)
|
||||||
) : receiver_model(receiver_model)
|
|
||||||
{
|
{
|
||||||
receiver_model.set_baseband_configuration({
|
receiver_model.set_baseband_configuration({
|
||||||
.mode = RX_SIGFOX,
|
.mode = 255, // DEBUG
|
||||||
.sampling_rate = 3072000,
|
.sampling_rate = 3072000,
|
||||||
.decimation_factor = 4,
|
.decimation_factor = 4,
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,17 +36,16 @@ namespace ui {
|
||||||
|
|
||||||
class SIGFRXView : public View {
|
class SIGFRXView : public View {
|
||||||
public:
|
public:
|
||||||
SIGFRXView(NavigationView& nav, ReceiverModel& receiver_model);
|
SIGFRXView(NavigationView& nav);
|
||||||
~SIGFRXView();
|
~SIGFRXView();
|
||||||
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
||||||
|
|
||||||
void on_show() override;
|
void on_show() override;
|
||||||
|
void on_hide() override;
|
||||||
void focus() override;
|
void focus() override;
|
||||||
void paint(Painter& painter) override;
|
void paint(Painter& painter) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReceiverModel& receiver_model;
|
|
||||||
|
|
||||||
uint8_t last_channel;
|
uint8_t last_channel;
|
||||||
uint8_t detect_counter = 0;
|
uint8_t detect_counter = 0;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "ch.h"
|
#include "ch.h"
|
||||||
#include "hackrf_hal.hpp"
|
#include "hackrf_hal.hpp"
|
||||||
|
|
||||||
|
#include "event_m0.hpp"
|
||||||
#include "ui_alphanum.hpp"
|
#include "ui_alphanum.hpp"
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
#include "hackrf_gpio.hpp"
|
#include "hackrf_gpio.hpp"
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
using namespace hackrf::one;
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -91,9 +92,8 @@ void XylosRXView::on_show() {
|
||||||
}
|
}
|
||||||
|
|
||||||
XylosRXView::XylosRXView(
|
XylosRXView::XylosRXView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
ReceiverModel& receiver_model
|
)
|
||||||
) : receiver_model(receiver_model)
|
|
||||||
{
|
{
|
||||||
char ccirdebug[21] = { 0,0,0,0,1,8,1,10,10,10,11,1,1,2,0,11,0,0,0,0,0xFF };
|
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(
|
XylosView::XylosView(
|
||||||
NavigationView& nav,
|
NavigationView& nav
|
||||||
TransmitterModel& transmitter_model
|
)
|
||||||
) : transmitter_model(transmitter_model)
|
|
||||||
{
|
{
|
||||||
static constexpr Style style_val {
|
static constexpr Style style_val {
|
||||||
.font = font::fixed_8x16,
|
.font = font::fixed_8x16,
|
||||||
|
@ -228,13 +227,11 @@ XylosView::XylosView(
|
||||||
};
|
};
|
||||||
|
|
||||||
transmitter_model.set_baseband_configuration({
|
transmitter_model.set_baseband_configuration({
|
||||||
.mode = TX_XYLOS,
|
.mode = 4,
|
||||||
.sampling_rate = 1536000,
|
.sampling_rate = 1536000,
|
||||||
.decimation_factor = 1,
|
.decimation_factor = 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
transmitter_model.set_modulation(TX_XYLOS); // Useless ?
|
|
||||||
|
|
||||||
add_children({ {
|
add_children({ {
|
||||||
&text_title,
|
&text_title,
|
||||||
&button_txtest,
|
&button_txtest,
|
||||||
|
@ -323,11 +320,9 @@ XylosView::XylosView(
|
||||||
button_txtest.on_select = [this,&transmitter_model](Button&) {
|
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 };
|
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) {
|
if (txing == false) {
|
||||||
auto& message_map = context().message_map();
|
EventDispatcher::message_map().unregister_handler(Message::ID::TXDone);
|
||||||
|
|
||||||
message_map.unregister_handler(Message::ID::TXDone);
|
EventDispatcher::message_map().register_handler(Message::ID::TXDone,
|
||||||
|
|
||||||
message_map.register_handler(Message::ID::TXDone,
|
|
||||||
[this,&transmitter_model](Message* const p) {
|
[this,&transmitter_model](Message* const p) {
|
||||||
const auto message = static_cast<const TXDoneMessage*>(p);
|
const auto message = static_cast<const TXDoneMessage*>(p);
|
||||||
if (message->n == 25) {
|
if (message->n == 25) {
|
||||||
|
@ -359,11 +354,9 @@ XylosView::XylosView(
|
||||||
if (txing == false) {
|
if (txing == false) {
|
||||||
upd_message();
|
upd_message();
|
||||||
|
|
||||||
auto& message_map = context().message_map();
|
EventDispatcher::message_map().unregister_handler(Message::ID::TXDone);
|
||||||
|
|
||||||
message_map.unregister_handler(Message::ID::TXDone);
|
EventDispatcher::message_map().register_handler(Message::ID::TXDone,
|
||||||
|
|
||||||
message_map.register_handler(Message::ID::TXDone,
|
|
||||||
[this,&transmitter_model](Message* const p) {
|
[this,&transmitter_model](Message* const p) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
char progress[21];
|
char progress[21];
|
||||||
|
|
|
@ -45,7 +45,7 @@ void do_something();
|
||||||
|
|
||||||
class XylosRXView : public View {
|
class XylosRXView : public View {
|
||||||
public:
|
public:
|
||||||
XylosRXView(NavigationView& nav, ReceiverModel& receiver_model);
|
XylosRXView(NavigationView& nav);
|
||||||
~XylosRXView();
|
~XylosRXView();
|
||||||
|
|
||||||
void talk();
|
void talk();
|
||||||
|
@ -92,8 +92,6 @@ private:
|
||||||
};
|
};
|
||||||
char ccir_received[21];
|
char ccir_received[21];
|
||||||
|
|
||||||
ReceiverModel& receiver_model;
|
|
||||||
|
|
||||||
Text text_title {
|
Text text_title {
|
||||||
{ 1 * 8, 1 * 16, 11, 16 },
|
{ 1 * 8, 1 * 16, 11, 16 },
|
||||||
"BH Xylos RX"
|
"BH Xylos RX"
|
||||||
|
@ -142,7 +140,7 @@ private:
|
||||||
|
|
||||||
class XylosView : public View {
|
class XylosView : public View {
|
||||||
public:
|
public:
|
||||||
XylosView(NavigationView& nav, TransmitterModel& transmitter_model);
|
XylosView(NavigationView& nav);
|
||||||
~XylosView();
|
~XylosView();
|
||||||
void journuit();
|
void journuit();
|
||||||
|
|
||||||
|
@ -185,8 +183,6 @@ private:
|
||||||
char ccirmessage[21];
|
char ccirmessage[21];
|
||||||
char ccir_received[21];
|
char ccir_received[21];
|
||||||
|
|
||||||
TransmitterModel& transmitter_model;
|
|
||||||
|
|
||||||
Text text_title {
|
Text text_title {
|
||||||
{ 1 * 8, 1 * 16, 11, 16 },
|
{ 1 * 8, 1 * 16, 11, 16 },
|
||||||
"BH Xylos TX"
|
"BH Xylos TX"
|
||||||
|
|
Binary file not shown.
|
@ -124,16 +124,20 @@ CSRC = $(PORTSRC) \
|
||||||
# setting.
|
# setting.
|
||||||
CPPSRC = main.cpp \
|
CPPSRC = main.cpp \
|
||||||
message_queue.cpp \
|
message_queue.cpp \
|
||||||
|
event.cpp \
|
||||||
event_m4.cpp \
|
event_m4.cpp \
|
||||||
irq_ipc_m4.cpp \
|
|
||||||
gpdma.cpp \
|
gpdma.cpp \
|
||||||
baseband_dma.cpp \
|
baseband_dma.cpp \
|
||||||
|
baseband_sgpio.cpp \
|
||||||
portapack_shared_memory.cpp \
|
portapack_shared_memory.cpp \
|
||||||
|
baseband_thread.cpp \
|
||||||
baseband_processor.cpp \
|
baseband_processor.cpp \
|
||||||
channel_decimator.cpp \
|
baseband_stats_collector.cpp \
|
||||||
dsp_decimate.cpp \
|
dsp_decimate.cpp \
|
||||||
dsp_demodulate.cpp \
|
dsp_demodulate.cpp \
|
||||||
matched_filter.cpp \
|
matched_filter.cpp \
|
||||||
|
spectrum_collector.cpp \
|
||||||
|
proc_rds.cpp \
|
||||||
proc_jammer.cpp \
|
proc_jammer.cpp \
|
||||||
proc_fsk_lcr.cpp \
|
proc_fsk_lcr.cpp \
|
||||||
proc_xylos.cpp \
|
proc_xylos.cpp \
|
||||||
|
@ -144,11 +148,15 @@ CPPSRC = main.cpp \
|
||||||
packet_builder.cpp \
|
packet_builder.cpp \
|
||||||
dsp_fft.cpp \
|
dsp_fft.cpp \
|
||||||
dsp_fir_taps.cpp \
|
dsp_fir_taps.cpp \
|
||||||
|
dsp_iir.cpp \
|
||||||
fxpt_atan2.cpp \
|
fxpt_atan2.cpp \
|
||||||
rssi.cpp \
|
rssi.cpp \
|
||||||
rssi_dma.cpp \
|
rssi_dma.cpp \
|
||||||
|
rssi_thread.cpp \
|
||||||
audio.cpp \
|
audio.cpp \
|
||||||
|
audio_output.cpp \
|
||||||
audio_dma.cpp \
|
audio_dma.cpp \
|
||||||
|
audio_stats_collector.cpp \
|
||||||
touch_dma.cpp \
|
touch_dma.cpp \
|
||||||
../common/utility.cpp \
|
../common/utility.cpp \
|
||||||
../common/chibios_cpp.cpp \
|
../common/chibios_cpp.cpp \
|
||||||
|
|
|
@ -121,7 +121,7 @@ constexpr gpdma::channel::Config config_rx() {
|
||||||
|
|
||||||
/* TODO: Clean up terminology around "buffer", "transfer", "samples" */
|
/* 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 buffer_samples = (1 << buffer_samples_log2n);
|
||||||
constexpr size_t transfers_per_buffer_log2n = 2;
|
constexpr size_t transfers_per_buffer_log2n = 2;
|
||||||
constexpr size_t transfers_per_buffer = (1 << transfers_per_buffer_log2n);
|
constexpr size_t transfers_per_buffer = (1 << transfers_per_buffer_log2n);
|
||||||
|
@ -208,8 +208,8 @@ void enable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable() {
|
void disable() {
|
||||||
gpdma_channel_i2s0_tx.disable_force();
|
gpdma_channel_i2s0_tx.disable();
|
||||||
gpdma_channel_i2s0_rx.disable_force();
|
gpdma_channel_i2s0_rx.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_t tx_empty_buffer() {
|
buffer_t tx_empty_buffer() {
|
||||||
|
|
100
firmware/baseband-tx/audio_output.cpp
Normal file
100
firmware/baseband-tx/audio_output.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
58
firmware/baseband-tx/audio_output.hpp
Normal file
58
firmware/baseband-tx/audio_output.hpp
Normal 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__*/
|
67
firmware/baseband-tx/audio_stats_collector.cpp
Normal file
67
firmware/baseband-tx/audio_stats_collector.cpp
Normal 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);
|
||||||
|
}
|
|
@ -22,9 +22,8 @@
|
||||||
#ifndef __AUDIO_STATS_COLLECTOR_H__
|
#ifndef __AUDIO_STATS_COLLECTOR_H__
|
||||||
#define __AUDIO_STATS_COLLECTOR_H__
|
#define __AUDIO_STATS_COLLECTOR_H__
|
||||||
|
|
||||||
#include "buffer.hpp"
|
#include "dsp_types.hpp"
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
@ -32,64 +31,33 @@
|
||||||
class AudioStatsCollector {
|
class AudioStatsCollector {
|
||||||
public:
|
public:
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void feed(buffer_s16_t src, Callback callback) {
|
void feed(const buffer_f32_t& src, Callback callback) {
|
||||||
consume_audio_buffer(src);
|
if( feed(src) ) {
|
||||||
|
|
||||||
if( update_stats(src.count, src.sampling_rate) ) {
|
|
||||||
callback(statistics);
|
callback(statistics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void mute(const size_t sample_count, const size_t sampling_rate, Callback 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);
|
callback(statistics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr float update_interval { 0.1f };
|
static constexpr float update_interval { 0.1f };
|
||||||
uint64_t squared_sum { 0 };
|
float squared_sum { 0 };
|
||||||
uint32_t max_squared { 0 };
|
float max_squared { 0 };
|
||||||
size_t count { 0 };
|
size_t count { 0 };
|
||||||
|
|
||||||
AudioStatistics statistics;
|
AudioStatistics statistics;
|
||||||
|
|
||||||
void consume_audio_buffer(buffer_s16_t src) {
|
void 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 uint64_t sample_squared = sample * sample;
|
|
||||||
squared_sum += sample_squared;
|
|
||||||
if( sample_squared > max_squared ) {
|
|
||||||
max_squared = sample_squared;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool update_stats(const size_t sample_count, const size_t sampling_rate) {
|
bool 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;
|
bool feed(const buffer_f32_t& src);
|
||||||
|
bool mute(const size_t sample_count, const size_t sampling_rate);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif/*__AUDIO_STATS_COLLECTOR_H__*/
|
#endif/*__AUDIO_STATS_COLLECTOR_H__*/
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "baseband_dma.hpp"
|
#include "baseband_dma.hpp"
|
||||||
#include "portapack_shared_memory.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
@ -36,8 +35,6 @@ using namespace lpc43xx;
|
||||||
namespace baseband {
|
namespace baseband {
|
||||||
namespace dma {
|
namespace dma {
|
||||||
|
|
||||||
int quitt = 0;
|
|
||||||
|
|
||||||
constexpr uint32_t gpdma_ahb_master_sgpio = 0;
|
constexpr uint32_t gpdma_ahb_master_sgpio = 0;
|
||||||
constexpr uint32_t gpdma_ahb_master_memory = 1;
|
constexpr uint32_t gpdma_ahb_master_memory = 1;
|
||||||
constexpr uint32_t gpdma_ahb_master_lli_fetch = 0;
|
constexpr uint32_t gpdma_ahb_master_lli_fetch = 0;
|
||||||
|
@ -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 std::array<gpdma::channel::LLI, transfers_per_buffer> lli_loop;
|
||||||
static constexpr auto& gpdma_channel_sgpio = gpdma::channels[portapack::sgpio_gpdma_channel_number];
|
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 Semaphore semaphore;
|
||||||
|
|
||||||
static volatile const gpdma::channel::LLI* next_lli = nullptr;
|
static volatile const gpdma::channel::LLI* next_lli = nullptr;
|
||||||
|
|
||||||
void transfer_complete() {
|
static void transfer_complete() {
|
||||||
next_lli = gpdma_channel_sgpio.next_lli();
|
next_lli = gpdma_channel_sgpio.next_lli();
|
||||||
quitt = 0;
|
|
||||||
/* TODO: Is Mailbox the proper synchronization mechanism for this? */
|
|
||||||
//chMBPostI(&mailbox, 0);
|
|
||||||
chSemSignalI(&semaphore);
|
chSemSignalI(&semaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +113,6 @@ static void dma_error() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
//chMBInit(&mailbox, messages.data(), messages.size());
|
|
||||||
chSemInit(&semaphore, 0);
|
chSemInit(&semaphore, 0);
|
||||||
gpdma_channel_sgpio.set_handlers(transfer_complete, dma_error);
|
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);
|
const auto gpdma_config = config(direction);
|
||||||
gpdma_channel_sgpio.configure(lli_loop[0], gpdma_config);
|
gpdma_channel_sgpio.configure(lli_loop[0], gpdma_config);
|
||||||
|
|
||||||
//chMBReset(&mailbox);
|
|
||||||
chSemReset(&semaphore, 0);
|
chSemReset(&semaphore, 0);
|
||||||
|
|
||||||
gpdma_channel_sgpio.enable();
|
gpdma_channel_sgpio.enable();
|
||||||
|
@ -159,14 +149,11 @@ bool is_enabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable() {
|
void disable() {
|
||||||
gpdma_channel_sgpio.disable_force();
|
gpdma_channel_sgpio.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
baseband::buffer_t wait_for_rx_buffer() {
|
baseband::buffer_t wait_for_rx_buffer() {
|
||||||
//msg_t msg;
|
|
||||||
//const auto status = chMBFetch(&mailbox, &msg, TIME_INFINITE);
|
|
||||||
const auto status = chSemWait(&semaphore);
|
const auto status = chSemWait(&semaphore);
|
||||||
if (quitt) return { nullptr, 0 };
|
|
||||||
if( status == RDY_OK ) {
|
if( status == RDY_OK ) {
|
||||||
const auto next = next_lli;
|
const auto next = next_lli;
|
||||||
if( next ) {
|
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;
|
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 };
|
return { reinterpret_cast<sample_t*>(lli_loop[free_index].destaddr), transfer_samples };
|
||||||
} else {
|
} else {
|
||||||
return { nullptr, 0 };
|
return { };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { nullptr, 0 };
|
return { };
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,104 +23,14 @@
|
||||||
|
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
|
|
||||||
#include "dsp_fft.hpp"
|
|
||||||
|
|
||||||
#include "audio_dma.hpp"
|
|
||||||
|
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
#include "event_m4.hpp"
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <cstddef>
|
void BasebandProcessor::feed_channel_stats(const buffer_c16_t& channel) {
|
||||||
#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) {
|
|
||||||
channel_stats.feed(
|
channel_stats.feed(
|
||||||
channel,
|
channel,
|
||||||
[this](const ChannelStatistics statistics) {
|
[](const ChannelStatistics& statistics) {
|
||||||
this->post_channel_stats_message(statistics);
|
const ChannelStatisticsMessage channel_stats_message { statistics };
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,55 +23,24 @@
|
||||||
#define __BASEBAND_PROCESSOR_H__
|
#define __BASEBAND_PROCESSOR_H__
|
||||||
|
|
||||||
#include "dsp_types.hpp"
|
#include "dsp_types.hpp"
|
||||||
#include "complex.hpp"
|
|
||||||
|
|
||||||
#include "block_decimator.hpp"
|
|
||||||
#include "channel_stats_collector.hpp"
|
#include "channel_stats_collector.hpp"
|
||||||
#include "audio_stats_collector.hpp"
|
|
||||||
|
|
||||||
#include <array>
|
#include "message.hpp"
|
||||||
#include <cstdint>
|
|
||||||
#include <complex>
|
|
||||||
|
|
||||||
class BasebandProcessor {
|
class BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
virtual ~BasebandProcessor() = default;
|
virtual ~BasebandProcessor() = default;
|
||||||
|
|
||||||
virtual void execute(buffer_c8_t buffer) = 0;
|
virtual void execute(const buffer_c8_t& buffer) = 0;
|
||||||
virtual void fill_buffer(int8_t * inptr);
|
|
||||||
|
|
||||||
void update_spectrum();
|
virtual void on_message(const Message* const) { };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void feed_channel_stats(const buffer_c16_t channel);
|
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 };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BlockDecimator<256> channel_spectrum_decimator { 4 };
|
|
||||||
|
|
||||||
ChannelStatsCollector channel_stats;
|
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__*/
|
#endif/*__BASEBAND_PROCESSOR_H__*/
|
||||||
|
|
59
firmware/baseband-tx/baseband_stats_collector.cpp
Normal file
59
firmware/baseband-tx/baseband_stats_collector.cpp
Normal 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;
|
||||||
|
}
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
#include "dsp_types.hpp"
|
#include "dsp_types.hpp"
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
#include "utility_m4.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
@ -46,36 +45,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void process(buffer_c8_t buffer, Callback callback) {
|
void process(const buffer_c8_t& buffer, Callback callback) {
|
||||||
samples += buffer.count;
|
if( process(buffer) ) {
|
||||||
|
callback(capture_statistics());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +63,9 @@ private:
|
||||||
uint32_t last_rssi_ticks { 0 };
|
uint32_t last_rssi_ticks { 0 };
|
||||||
const Thread* const thread_baseband;
|
const Thread* const thread_baseband;
|
||||||
uint32_t last_baseband_ticks { 0 };
|
uint32_t last_baseband_ticks { 0 };
|
||||||
|
|
||||||
|
bool process(const buffer_c8_t& buffer);
|
||||||
|
BasebandStatistics capture_statistics();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif/*__BASEBAND_STATS_COLLECTOR_H__*/
|
#endif/*__BASEBAND_STATS_COLLECTOR_H__*/
|
||||||
|
|
155
firmware/baseband-tx/baseband_thread.cpp
Normal file
155
firmware/baseband-tx/baseband_thread.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
65
firmware/baseband-tx/baseband_thread.hpp
Normal file
65
firmware/baseband-tx/baseband_thread.hpp
Normal 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__*/
|
|
@ -1 +1 @@
|
||||||
More specific stuff for testing :o
|
More or less experimental stuff, mainly TX.
|
||||||
|
|
57
firmware/baseband-tx/dsp_iir.cpp
Normal file
57
firmware/baseband-tx/dsp_iir.cpp
Normal 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);
|
||||||
|
}
|
|
@ -27,13 +27,27 @@
|
||||||
#include "dsp_types.hpp"
|
#include "dsp_types.hpp"
|
||||||
|
|
||||||
struct iir_biquad_config_t {
|
struct iir_biquad_config_t {
|
||||||
const std::array<float, 3> b;
|
std::array<float, 3> b;
|
||||||
const std::array<float, 3> a;
|
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 {
|
class IIRBiquadFilter {
|
||||||
public:
|
public:
|
||||||
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
|
// 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
|
// Assume all coefficients are normalized so that a0=1.0
|
||||||
constexpr IIRBiquadFilter(
|
constexpr IIRBiquadFilter(
|
||||||
|
@ -42,34 +56,15 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(buffer_s16_t buffer_in, buffer_s16_t buffer_out) {
|
void configure(const iir_biquad_config_t& new_config);
|
||||||
// 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 execute_in_place(buffer_s16_t buffer) {
|
void execute(const buffer_f32_t& buffer_in, const buffer_f32_t& buffer_out);
|
||||||
execute(buffer, buffer);
|
void execute_in_place(const buffer_f32_t& buffer);
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
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> x { { 0.0f, 0.0f, 0.0f } };
|
||||||
std::array<float, 3> y { { 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__*/
|
#endif/*__DSP_IIR_H__*/
|
||||||
|
|
|
@ -24,22 +24,30 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#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.
|
// TODO: No hard-coded array size.
|
||||||
std::array<int16_t, N> squelch_energy_buffer;
|
std::array<float, N> squelch_energy_buffer;
|
||||||
const buffer_s16_t squelch_energy {
|
const buffer_f32_t squelch_energy {
|
||||||
squelch_energy_buffer.data(),
|
squelch_energy_buffer.data(),
|
||||||
squelch_energy_buffer.size()
|
squelch_energy_buffer.size()
|
||||||
};
|
};
|
||||||
non_audio_hpf.execute(audio, squelch_energy);
|
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) {
|
for(const auto sample : squelch_energy_buffer) {
|
||||||
const uint64_t sample_squared = sample * sample;
|
const float sample_squared = sample * sample;
|
||||||
if( sample_squared > max_squared ) {
|
if( sample_squared > non_audio_max_squared ) {
|
||||||
max_squared = sample_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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,14 +31,14 @@
|
||||||
|
|
||||||
class FMSquelch {
|
class FMSquelch {
|
||||||
public:
|
public:
|
||||||
bool execute(buffer_s16_t audio);
|
bool execute(const buffer_f32_t& audio);
|
||||||
|
|
||||||
|
void set_threshold(const float new_value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t N = 32;
|
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 };
|
IIRBiquadFilter non_audio_hpf { non_audio_hpf_config };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,99 @@
|
||||||
|
|
||||||
#include "event_m4.hpp"
|
#include "event_m4.hpp"
|
||||||
|
|
||||||
|
#include "portapack_shared_memory.hpp"
|
||||||
|
|
||||||
|
#include "message_queue.hpp"
|
||||||
|
|
||||||
#include "ch.h"
|
#include "ch.h"
|
||||||
|
|
||||||
Thread* thread_event_loop = nullptr;
|
#include "lpc43xx_cpp.hpp"
|
||||||
|
using namespace lpc43xx;
|
||||||
|
|
||||||
void events_initialize(Thread* const event_loop_thread) {
|
#include <cstdint>
|
||||||
thread_event_loop = event_loop_thread;
|
#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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,25 +22,54 @@
|
||||||
#ifndef __EVENT_M4_H__
|
#ifndef __EVENT_M4_H__
|
||||||
#define __EVENT_M4_H__
|
#define __EVENT_M4_H__
|
||||||
|
|
||||||
|
#include "event.hpp"
|
||||||
|
|
||||||
|
#include "baseband_thread.hpp"
|
||||||
|
#include "rssi_thread.hpp"
|
||||||
|
|
||||||
|
#include "message.hpp"
|
||||||
|
|
||||||
#include "ch.h"
|
#include "ch.h"
|
||||||
|
|
||||||
constexpr auto EVT_MASK_BASEBAND = EVENT_MASK(0);
|
constexpr auto EVT_MASK_BASEBAND = EVENT_MASK(0);
|
||||||
constexpr auto EVT_MASK_SPECTRUM = EVENT_MASK(1);
|
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;
|
static inline void events_flag(const eventmask_t events) {
|
||||||
|
|
||||||
inline void events_flag(const eventmask_t events) {
|
|
||||||
if( thread_event_loop ) {
|
if( thread_event_loop ) {
|
||||||
chEvtSignal(thread_event_loop, events);
|
chEvtSignal(thread_event_loop, events);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void events_flag_isr(const eventmask_t events) {
|
static inline void events_flag_isr(const eventmask_t events) {
|
||||||
if( thread_event_loop ) {
|
if( thread_event_loop ) {
|
||||||
chEvtSignalI(thread_event_loop, events);
|
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__*/
|
#endif/*__EVENT_M4_H__*/
|
||||||
|
|
|
@ -15,13 +15,11 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* 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
|
||||||
* along with this program; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ch.h"
|
#include "ch.h"
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
#include "lpc43xx_cpp.hpp"
|
#include "lpc43xx_cpp.hpp"
|
||||||
|
|
||||||
|
@ -30,34 +28,13 @@
|
||||||
|
|
||||||
#include "gpdma.hpp"
|
#include "gpdma.hpp"
|
||||||
|
|
||||||
#include "baseband.hpp"
|
|
||||||
#include "baseband_dma.hpp"
|
|
||||||
|
|
||||||
#include "event_m4.hpp"
|
#include "event_m4.hpp"
|
||||||
|
|
||||||
#include "irq_ipc_m4.hpp"
|
|
||||||
|
|
||||||
#include "touch_dma.hpp"
|
#include "touch_dma.hpp"
|
||||||
|
|
||||||
#include "modules.h"
|
#include "baseband_thread.hpp"
|
||||||
|
#include "rssi_thread.hpp"
|
||||||
#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_processor.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"
|
#include "message_queue.hpp"
|
||||||
|
|
||||||
|
@ -73,55 +50,87 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
|
||||||
#include <bitset>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
static baseband::Direction direction = baseband::Direction::Receive;
|
extern "C" {
|
||||||
|
|
||||||
class ThreadBase {
|
void __late_init(void) {
|
||||||
public:
|
/*
|
||||||
constexpr ThreadBase(
|
* System initializations.
|
||||||
const char* const name
|
* - HAL initialization, this also initializes the configured device drivers
|
||||||
) : name { name }
|
* 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 msg_t fn(void* arg) {
|
}
|
||||||
auto obj = static_cast<ThreadBase*>(arg);
|
|
||||||
chRegSetThreadName(obj->name);
|
static void init() {
|
||||||
obj->run();
|
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 void shutdown() {
|
||||||
|
// TODO: Is this complete?
|
||||||
|
|
||||||
|
nvicDisableVector(DMA_IRQn);
|
||||||
|
|
||||||
|
chSysDisable();
|
||||||
|
|
||||||
|
systick_stop();
|
||||||
|
|
||||||
|
ShutdownMessage shutdown_message;
|
||||||
|
shared_memory.application_queue.push(shutdown_message);
|
||||||
|
|
||||||
|
halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
init();
|
||||||
|
|
||||||
|
/* TODO: Ensure DMAs are configured to point at first LLI in chain. */
|
||||||
|
|
||||||
|
EventDispatcher event_dispatcher;
|
||||||
|
event_dispatcher.run();
|
||||||
|
|
||||||
|
shutdown();
|
||||||
|
|
||||||
return 0;
|
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 };
|
|
||||||
BasebandProcessor* baseband_processor { nullptr };
|
|
||||||
BasebandConfiguration baseband_configuration;
|
|
||||||
|
|
||||||
private:
|
|
||||||
WORKING_AREA(wa, 2048);
|
|
||||||
|
|
||||||
void run() override {
|
void run() override {
|
||||||
while(true) {
|
while(true) {
|
||||||
if (direction == baseband::Direction::Transmit) {
|
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 {
|
class ToneProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
void execute(buffer_c8_t buffer) override {
|
void execute(buffer_c8_t buffer) override {
|
||||||
|
@ -348,130 +196,6 @@ private:
|
||||||
int32_t sample, sig, frq;
|
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];
|
char ram_loop[32];
|
||||||
typedef int (*fn_ptr)(void);
|
typedef int (*fn_ptr)(void);
|
||||||
fn_ptr loop_ptr;
|
fn_ptr loop_ptr;
|
||||||
|
@ -586,27 +310,4 @@ int main(void) {
|
||||||
event_dispatcher.request_stop();
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Second module
|
Experimental
|
||||||
|
|
|
@ -26,6 +26,6 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
void AudioTXProcessor::execute(buffer_c8_t buffer) {
|
void AudioTXProcessor::execute(const buffer_c8_t& buffer) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
|
|
||||||
class AudioTXProcessor : public BasebandProcessor {
|
class AudioTXProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
void execute(buffer_c8_t buffer) override;
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int8_t audio_fifo[SAMPLERATE];
|
int8_t audio_fifo[SAMPLERATE];
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#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++) {
|
for (size_t i = 0; i<buffer.count; i++) {
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
class LCRFSKProcessor : public BasebandProcessor {
|
class LCRFSKProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
void execute(buffer_c8_t buffer) override;
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int8_t re, im;
|
int8_t re, im;
|
||||||
|
|
|
@ -27,33 +27,9 @@
|
||||||
|
|
||||||
#define POLY_MASK_32 0xB4BCD35C
|
#define POLY_MASK_32 0xB4BCD35C
|
||||||
|
|
||||||
|
void JammerProcessor::execute(const buffer_c8_t& buffer) {
|
||||||
void JammerProcessor::execute(buffer_c8_t buffer) {
|
|
||||||
for (size_t i = 0; i<buffer.count; i++) {
|
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
|
if (s >= 10000) { //shared_memory.jammer_ranges[ir].duration
|
||||||
s = 0;
|
s = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
class JammerProcessor : public BasebandProcessor {
|
class JammerProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
void execute(buffer_c8_t buffer) override;
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32_t lfsr32 = 0xABCDE;
|
int32_t lfsr32 = 0xABCDE;
|
||||||
|
|
|
@ -33,7 +33,7 @@ void PlayAudioProcessor::fill_buffer(int8_t * inptr) {
|
||||||
asked = false;
|
asked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayAudioProcessor::execute(buffer_c8_t buffer) {
|
void PlayAudioProcessor::execute(const buffer_c8_t& buffer){
|
||||||
|
|
||||||
// This is called at 1536000/2048 = 750Hz
|
// 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};
|
buffer.p[i] = {(int8_t)re,(int8_t)im};
|
||||||
}
|
}
|
||||||
|
|
||||||
fill_audio_buffer(preview_audio_buffer);
|
//fill_audio_buffer(preview_audio_buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
class PlayAudioProcessor : public BasebandProcessor {
|
class PlayAudioProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
void execute(buffer_c8_t buffer) override;
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
void fill_buffer(int8_t * inptr);
|
void fill_buffer(int8_t * inptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
90
firmware/baseband-tx/proc_rds.cpp
Normal file
90
firmware/baseband-tx/proc_rds.cpp
Normal 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};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
130
firmware/baseband-tx/proc_rds.hpp
Normal file
130
firmware/baseband-tx/proc_rds.hpp
Normal 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
|
|
@ -21,6 +21,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "proc_xylos.hpp"
|
#include "proc_xylos.hpp"
|
||||||
|
|
||||||
|
#include "dsp_iir_config.hpp"
|
||||||
|
//#include "audio_output.hpp"
|
||||||
|
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
#include "sine_table.hpp"
|
#include "sine_table.hpp"
|
||||||
|
|
||||||
|
@ -31,7 +35,7 @@
|
||||||
// 14 13 12 11:
|
// 14 13 12 11:
|
||||||
// 2108 989 2259 931
|
// 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
|
// 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};
|
buffer.p[i] = {(int8_t)re,(int8_t)im};
|
||||||
}
|
}
|
||||||
|
|
||||||
fill_audio_buffer(preview_audio_buffer);
|
//audio_output.write(preview_audio_buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,18 @@
|
||||||
|
|
||||||
#include "baseband_processor.hpp"
|
#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 CCIR_TONELENGTH 15360-1 // 1536000/10/10
|
||||||
#define PHASEV 436.91 // (65536*1024)/1536000*10
|
#define PHASEV 436.91 // (65536*1024)/1536000*10
|
||||||
|
|
||||||
class XylosProcessor : public BasebandProcessor {
|
class XylosProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
void execute(buffer_c8_t buffer) override;
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int16_t audio_data[64];
|
int16_t audio_data[64];
|
||||||
|
@ -67,6 +73,8 @@ private:
|
||||||
uint32_t aphase, phase, sphase;
|
uint32_t aphase, phase, sphase;
|
||||||
int32_t sample, frq;
|
int32_t sample, frq;
|
||||||
TXDoneMessage message;
|
TXDoneMessage message;
|
||||||
|
|
||||||
|
//AudioOutput audio_output;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -157,7 +157,7 @@ bool is_enabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable() {
|
void disable() {
|
||||||
gpdma_channel.disable_force();
|
gpdma_channel.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
rf::rssi::buffer_t wait_for_buffer() {
|
rf::rssi::buffer_t wait_for_buffer() {
|
||||||
|
|
63
firmware/baseband-tx/rssi_thread.cpp
Normal file
63
firmware/baseband-tx/rssi_thread.cpp
Normal 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();
|
||||||
|
}
|
46
firmware/baseband-tx/rssi_thread.hpp
Normal file
46
firmware/baseband-tx/rssi_thread.hpp
Normal 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__*/
|
130
firmware/baseband-tx/spectrum_collector.cpp
Normal file
130
firmware/baseband-tx/spectrum_collector.cpp
Normal 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;
|
||||||
|
}
|
72
firmware/baseband-tx/spectrum_collector.hpp
Normal file
72
firmware/baseband-tx/spectrum_collector.hpp
Normal 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__*/
|
50
firmware/baseband-tx/thread_base.hpp
Normal file
50
firmware/baseband-tx/thread_base.hpp
Normal 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__*/
|
|
@ -122,7 +122,7 @@ bool is_enabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable() {
|
void disable() {
|
||||||
gpdma_channel.disable_force();
|
gpdma_channel.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace dma */
|
} /* namespace dma */
|
||||||
|
|
Binary file not shown.
|
@ -1 +1 @@
|
||||||
Basic RX/TX stuff for testing :)
|
Original firmware's functionalities: Receiver.
|
||||||
|
|
|
@ -50,121 +50,6 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <array>
|
#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" {
|
extern "C" {
|
||||||
|
|
||||||
|
@ -187,9 +72,6 @@ void __late_init(void) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BasebandThread baseband_thread;
|
|
||||||
static RSSIThread rssi_thread;
|
|
||||||
|
|
||||||
static void init() {
|
static void init() {
|
||||||
i2s::i2s0::configure(
|
i2s::i2s0::configure(
|
||||||
audio::i2s0_config_tx,
|
audio::i2s0_config_tx,
|
||||||
|
@ -208,31 +90,9 @@ static void init() {
|
||||||
gpdma::controller.enable();
|
gpdma::controller.enable();
|
||||||
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
|
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
|
||||||
|
|
||||||
baseband::dma::init();
|
|
||||||
|
|
||||||
rf::rssi::init();
|
|
||||||
touch::dma::init();
|
touch::dma::init();
|
||||||
|
touch::dma::allocate();
|
||||||
const auto thread_main = chThdSelf();
|
touch::dma::enable();
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void halt() {
|
static void halt() {
|
||||||
|
@ -242,146 +102,27 @@ static void halt() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EventDispatcher {
|
static void shutdown() {
|
||||||
public:
|
// TODO: Is this complete?
|
||||||
MessageHandlerMap& message_handlers() {
|
|
||||||
return message_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() {
|
nvicDisableVector(DMA_IRQn);
|
||||||
while(is_running) {
|
|
||||||
const auto events = wait();
|
|
||||||
dispatch(events);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void request_stop() {
|
chSysDisable();
|
||||||
is_running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
systick_stop();
|
||||||
MessageHandlerMap message_map;
|
|
||||||
|
|
||||||
bool is_running = true;
|
ShutdownMessage shutdown_message;
|
||||||
|
shared_memory.application_queue.push(shutdown_message);
|
||||||
|
|
||||||
eventmask_t wait() {
|
halt();
|
||||||
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;
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
init();
|
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. */
|
/* TODO: Ensure DMAs are configured to point at first LLI in chain. */
|
||||||
|
|
||||||
if( direction == baseband::Direction::Receive ) {
|
EventDispatcher event_dispatcher;
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
event_dispatcher.run();
|
event_dispatcher.run();
|
||||||
|
|
||||||
shutdown();
|
shutdown();
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
First module
|
Receiver
|
||||||
|
|
|
@ -25,30 +25,17 @@
|
||||||
|
|
||||||
using namespace lpc43xx;
|
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. */
|
/* Called every 2048/3072000 second -- 1500Hz. */
|
||||||
|
|
||||||
auto decimator_out = decimator.execute(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);
|
||||||
|
|
||||||
const buffer_c16_t work_baseband_buffer {
|
auto audio = demod.execute(channel_out, work_audio_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);
|
|
||||||
|
|
||||||
/*static uint64_t audio_present_history = 0;
|
/*static uint64_t audio_present_history = 0;
|
||||||
const auto audio_present_now = squelch.execute(audio);
|
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++) {
|
for(size_t i=0; i<audio.count; i++) {
|
||||||
if (spur > 10) {
|
if (spur > 10) {
|
||||||
|
@ -97,9 +84,9 @@ void AFSKRXProcessor::execute(buffer_c8_t buffer) {
|
||||||
|
|
||||||
if (sc >= 600) {
|
if (sc >= 600) {
|
||||||
sc = 0;
|
sc = 0;
|
||||||
AFSKDataMessage message;
|
//AFSKDataMessage message;
|
||||||
memcpy(message.data,aud,128*2);
|
//memcpy(message.data,aud,128*2);
|
||||||
shared_memory.application_queue.push(message);
|
//shared_memory.application_queue.push(message);
|
||||||
audc = 0;
|
audc = 0;
|
||||||
} else {
|
} else {
|
||||||
sc++;
|
sc++;
|
||||||
|
@ -110,7 +97,7 @@ void AFSKRXProcessor::execute(buffer_c8_t buffer) {
|
||||||
audc++;
|
audc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
fill_audio_buffer(audio);
|
audio_output.write(audio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AFSKRXProcessor::data_handler(
|
void AFSKRXProcessor::data_handler(
|
||||||
|
|
|
@ -24,37 +24,34 @@
|
||||||
|
|
||||||
#include "baseband_processor.hpp"
|
#include "baseband_processor.hpp"
|
||||||
|
|
||||||
#include "channel_decimator.hpp"
|
|
||||||
#include "dsp_decimate.hpp"
|
#include "dsp_decimate.hpp"
|
||||||
#include "dsp_demodulate.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 "message.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <bitset>
|
|
||||||
|
|
||||||
class AFSKRXProcessor : public BasebandProcessor {
|
class AFSKRXProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
AFSKRXProcessor() {
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By32);
|
|
||||||
channel_filter.configure(channel_filter_taps.taps, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void execute(buffer_c8_t buffer) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ChannelDecimator decimator;
|
std::array<complex16_t, 512> dst;
|
||||||
const fir_taps_real<64>& channel_filter_taps = taps_64_lp_042_078_tfilter;
|
const buffer_c16_t dst_buffer {
|
||||||
dsp::decimate::FIRAndDecimateComplex channel_filter;
|
dst.data(),
|
||||||
dsp::demodulate::FM demod { 48000, 5000 };
|
dst.size()
|
||||||
|
};
|
||||||
|
const buffer_f32_t work_audio_buffer {
|
||||||
|
(float*)dst.data(),
|
||||||
|
sizeof(dst) / sizeof(float)
|
||||||
|
};
|
||||||
|
|
||||||
IIRBiquadFilter audio_hpf { audio_hpf_config };
|
dsp::decimate::FIRAndDecimateComplex channel_filter;
|
||||||
//FMSquelch squelch;
|
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 bit_timer = 0, freq_timer = 0;
|
||||||
uint16_t sc;
|
uint16_t sc;
|
||||||
|
@ -63,6 +60,9 @@ private:
|
||||||
int16_t aud[128];
|
int16_t aud[128];
|
||||||
|
|
||||||
void data_handler(const double data);
|
void data_handler(const double data);
|
||||||
|
|
||||||
|
bool configured { false };
|
||||||
|
void configure(const NBFMConfigureMessage& message);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif/*__PROC_TPMS_H__*/
|
#endif/*__PROC_TPMS_H__*/
|
||||||
|
|
|
@ -24,46 +24,6 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
void SIGFRXProcessor::execute(buffer_c8_t buffer) {
|
void SIGFRXProcessor::execute(const buffer_c8_t& buffer) {
|
||||||
/* Called every 2048/3072000 second -- 1500Hz. */
|
/* 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);*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,31 +24,15 @@
|
||||||
|
|
||||||
#include "baseband_processor.hpp"
|
#include "baseband_processor.hpp"
|
||||||
|
|
||||||
#include "channel_decimator.hpp"
|
|
||||||
#include "dsp_decimate.hpp"
|
#include "dsp_decimate.hpp"
|
||||||
#include "dsp_demodulate.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 {
|
class SIGFRXProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
SIGFRXProcessor() {
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By16);
|
|
||||||
//channel_filter.configure(channel_filter_taps.taps, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void execute(buffer_c8_t buffer) override;
|
|
||||||
|
|
||||||
private:
|
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
|
#endif
|
||||||
|
|
BIN
firmware/bootstrap/bootstrap.bin
Executable file
BIN
firmware/bootstrap/bootstrap.bin
Executable file
Binary file not shown.
|
@ -2579,7 +2579,6 @@ FRESULT f_read (
|
||||||
UINT rcnt, cc;
|
UINT rcnt, cc;
|
||||||
BYTE csect, *rbuff = (BYTE*)buff;
|
BYTE csect, *rbuff = (BYTE*)buff;
|
||||||
|
|
||||||
|
|
||||||
*br = 0; /* Clear read byte counter */
|
*br = 0; /* Clear read byte counter */
|
||||||
|
|
||||||
res = validate(fp); /* Check validity */
|
res = validate(fp); /* Check validity */
|
||||||
|
|
|
@ -619,7 +619,7 @@ void sdc_lld_start_clk(SDCDriver *sdcp) {
|
||||||
(void)sdcp;
|
(void)sdcp;
|
||||||
sdio_cclk_set_400khz();
|
sdio_cclk_set_400khz();
|
||||||
/* TODO: Reset card using CMD0 + init flag? */
|
/* 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(;;);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -419,12 +419,14 @@ public:
|
||||||
int64_t freq = 0;
|
int64_t freq = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DisplayFrameSyncMessage : public Message {
|
class AFSKDataMessage : public Message {
|
||||||
public:
|
public:
|
||||||
constexpr DisplayFrameSyncMessage(
|
constexpr AFSKDataMessage(
|
||||||
) : Message { ID::DisplayFrameSync }
|
) : Message { ID::AFSKData }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16_t data[128] = {0};
|
||||||
};
|
};
|
||||||
|
|
||||||
class FIFOSignalMessage : public Message {
|
class FIFOSignalMessage : public Message {
|
||||||
|
|
|
@ -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[16] = {0xf8,0xf3,0x7b,0x36,0x68,0xd3,0xa1,0x85,0x26,0xb1,0x76,0x99,0x46,0x95,0xfd,0xec,};
|
||||||
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_tx[16] = {0xfc,0xe9,0x57,0x6b,0xfb,0xac,0x72,0x61,0x65,0x4e,0x3d,0x7f,0xb4,0x78,0xbd,0xd2,};
|
||||||
|
|
|
@ -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_widget.hpp"
|
||||||
#include "ui_painter.hpp"
|
#include "ui_painter.hpp"
|
||||||
|
|
||||||
|
@ -305,77 +284,91 @@ void Text::set(const std::string value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Text::paint(Painter& painter) {
|
void Text::paint(Painter& painter) {
|
||||||
if (style_ == nullptr) style_ = &style();
|
|
||||||
const auto rect = screen_rect();
|
const auto rect = screen_rect();
|
||||||
|
const auto s = style();
|
||||||
|
|
||||||
painter.fill_rectangle(rect, s.background);
|
painter.fill_rectangle(rect, s.background);
|
||||||
|
|
||||||
painter.draw_string(
|
painter.draw_string(
|
||||||
rect.pos,
|
rect.pos,
|
||||||
(*style_),
|
s,
|
||||||
text
|
text
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Button ****************************************************************/
|
/* Checkbox **************************************************************/
|
||||||
|
|
||||||
Button::Button(
|
void Checkbox::set_text(const std::string value) {
|
||||||
Rect parent_rect,
|
|
||||||
std::string text
|
|
||||||
) : Widget { parent_rect },
|
|
||||||
text_ { text }
|
|
||||||
{
|
|
||||||
flags.focusable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Button::set_text(const std::string value) {
|
|
||||||
text_ = value;
|
text_ = value;
|
||||||
set_dirty();
|
set_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Button::text() const {
|
std::string Checkbox::text() const {
|
||||||
return text_;
|
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();
|
const auto r = screen_rect();
|
||||||
|
|
||||||
if (style_ == nullptr) style_ = &style();
|
const auto paint_style = (has_focus() || flags.highlighted) ? style().invert() : style();
|
||||||
|
|
||||||
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.draw_rectangle(r, style().foreground);
|
|
||||||
|
|
||||||
painter.fill_rectangle(
|
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_);
|
const auto label_r = paint_style.font.size_of(text_);
|
||||||
painter.draw_string(
|
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,
|
paint_style,
|
||||||
text_
|
text_
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Button::on_key(const KeyEvent key) {
|
bool Checkbox::on_key(const KeyEvent key) {
|
||||||
if( key == KeyEvent::Select ) {
|
if( key == KeyEvent::Select ) {
|
||||||
|
value_ = not value_;
|
||||||
|
set_dirty();
|
||||||
|
|
||||||
if( on_select ) {
|
if( on_select ) {
|
||||||
on_select(*this);
|
on_select(*this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if( on_dir ) {
|
|
||||||
on_dir(*this, key);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Button::on_touch(const TouchEvent event) {
|
bool Checkbox::on_touch(const TouchEvent event) {
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
case TouchEvent::Type::Start:
|
case TouchEvent::Type::Start:
|
||||||
flags.highlighted = true;
|
flags.highlighted = true;
|
||||||
|
@ -385,6 +378,7 @@ bool Button::on_touch(const TouchEvent event) {
|
||||||
|
|
||||||
case TouchEvent::Type::End:
|
case TouchEvent::Type::End:
|
||||||
flags.highlighted = false;
|
flags.highlighted = false;
|
||||||
|
value_ = not value_;
|
||||||
set_dirty();
|
set_dirty();
|
||||||
if( on_select ) {
|
if( on_select ) {
|
||||||
on_select(*this);
|
on_select(*this);
|
||||||
|
@ -427,6 +421,199 @@ bool Button::on_touch(const TouchEvent event) {
|
||||||
#endif
|
#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::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) {
|
bool OptionsField::on_encoder(const EncoderEvent delta) {
|
||||||
set_selected_index(selected_index() + delta);
|
set_selected_index(selected_index() + delta);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -188,48 +188,11 @@ public:
|
||||||
Text(Rect parent_rect);
|
Text(Rect parent_rect);
|
||||||
|
|
||||||
void set(const std::string value);
|
void set(const std::string value);
|
||||||
void set_style(const Style* new_style);
|
|
||||||
|
|
||||||
void paint(Painter& painter) override;
|
void paint(Painter& painter) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string text;
|
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 {
|
class Button : public Widget {
|
||||||
|
@ -244,8 +207,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_text(const std::string value);
|
void set_text(const std::string value);
|
||||||
void set_text(const int value);
|
|
||||||
void set_style(const Style* new_style);
|
|
||||||
std::string text() const;
|
std::string text() const;
|
||||||
|
|
||||||
void paint(Painter& painter) override;
|
void paint(Painter& painter) override;
|
||||||
|
@ -255,7 +216,43 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string text_;
|
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 {
|
class OptionsField : public Widget {
|
||||||
|
@ -266,6 +263,7 @@ public:
|
||||||
using options_t = std::vector<option_t>;
|
using options_t = std::vector<option_t>;
|
||||||
|
|
||||||
std::function<void(size_t, value_t)> on_change;
|
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);
|
OptionsField(Point parent_pos, size_t length, options_t options);
|
||||||
|
|
||||||
|
@ -276,6 +274,7 @@ public:
|
||||||
|
|
||||||
void paint(Painter& painter) override;
|
void paint(Painter& painter) override;
|
||||||
|
|
||||||
|
void on_focus() override;
|
||||||
bool on_encoder(const EncoderEvent delta) override;
|
bool on_encoder(const EncoderEvent delta) override;
|
||||||
bool on_touch(const TouchEvent event) override;
|
bool on_touch(const TouchEvent event) override;
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -55,8 +55,9 @@ sys.argv = sys.argv[1:]
|
||||||
|
|
||||||
# Format for module file:
|
# Format for module file:
|
||||||
# Magic (4), Version (2), Length (4), Name (16), MD5 (16), Description (214)
|
# Magic (4), Version (2), Length (4), Name (16), MD5 (16), Description (214)
|
||||||
# Module binary...
|
# 0x00 pad bytes (256)
|
||||||
# MD5 (16)
|
# Module binary (padded to 32768-16)
|
||||||
|
# MD5 (16) again, so that module code can read it (dirty...)
|
||||||
|
|
||||||
for args in sys.argv:
|
for args in sys.argv:
|
||||||
data = read_image(args + '/build/' + args + '.bin')
|
data = read_image(args + '/build/' + args + '.bin')
|
||||||
|
@ -66,7 +67,7 @@ for args in sys.argv:
|
||||||
info = 'PPM '
|
info = 'PPM '
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
info += struct.pack('H', 1)
|
info += struct.pack('H', 2)
|
||||||
|
|
||||||
# Length
|
# Length
|
||||||
info += struct.pack('I', len(data))
|
info += struct.pack('I', len(data))
|
||||||
|
@ -94,9 +95,12 @@ for args in sys.argv:
|
||||||
description += (data_default_byte * pad_size)
|
description += (data_default_byte * pad_size)
|
||||||
info += description
|
info += description
|
||||||
|
|
||||||
# Padding
|
# Header padding to fit in SD card sector
|
||||||
|
info += (data_default_byte * 256)
|
||||||
|
|
||||||
|
# Binary padding
|
||||||
data = info + data
|
data = info + data
|
||||||
pad_size = (32768 + 256 - 16) - len(data)
|
pad_size = (32768 + 512 - 16) - len(data)
|
||||||
data += (data_default_byte * pad_size)
|
data += (data_default_byte * pad_size)
|
||||||
data += digest
|
data += digest
|
||||||
write_file(data, args + '.bin')
|
write_file(data, args + '.bin')
|
||||||
|
@ -108,6 +112,6 @@ for args in sys.argv:
|
||||||
h_data += 'const char md5_' + args.replace('-','_') + '[16] = {' + md5sum + '};\n'
|
h_data += 'const char md5_' + args.replace('-','_') + '[16] = {' + md5sum + '};\n'
|
||||||
|
|
||||||
# Update original binary with MD5 footprint
|
# 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')
|
write_file(h_data, 'common/modules.h')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue