Merge remote-tracking branch 'upstream/master'

# Conflicts:
#	firmware/application/bitmap.hpp
#	firmware/application/receiver_model.cpp
#	firmware/application/receiver_model.hpp
#	firmware/application/touch.hpp
#	firmware/application/ui_setup.cpp
#	firmware/baseband/proc_ais.hpp
#	firmware/baseband/proc_ert.hpp
#	firmware/bootstrap/CMakeLists.txt
#	firmware/common/portapack_persistent_memory.cpp
#	firmware/common/portapack_persistent_memory.hpp
This commit is contained in:
furrtek 2016-08-17 02:55:34 +02:00
commit 45a754645e
43 changed files with 1089 additions and 543 deletions

View File

@ -29,7 +29,7 @@ enable_language(C CXX ASM)
project(application)
# Compiler options here.
set(USE_OPT "-Os --specs=nano.specs")
set(USE_OPT "-Os -g --specs=nano.specs")
# C specific options here (added to USE_OPT).
set(USE_COPT "-std=gnu99")
@ -150,6 +150,7 @@ set(CPPSRC
ui_audio.cpp
ui_font_fixed_8x16.cpp
ui_setup.cpp
ui_touch_calibration.cpp
ui_debug.cpp
ui_baseband_stats_view.cpp
ui_sd_card_status_view.cpp

View File

@ -4062,6 +4062,30 @@ ui_textentry.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_textentry.cpp.s
.PHONY : ui_textentry.cpp.s
ui_touch_calibration.obj: ui_touch_calibration.cpp.obj
.PHONY : ui_touch_calibration.obj
# target to build an object file
ui_touch_calibration.cpp.obj:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_touch_calibration.cpp.obj
.PHONY : ui_touch_calibration.cpp.obj
ui_touch_calibration.i: ui_touch_calibration.cpp.i
.PHONY : ui_touch_calibration.i
# target to preprocess a source file
ui_touch_calibration.cpp.i:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_touch_calibration.cpp.i
.PHONY : ui_touch_calibration.cpp.i
ui_touch_calibration.s: ui_touch_calibration.cpp.s
.PHONY : ui_touch_calibration.s
# target to generate assembly for a file
ui_touch_calibration.cpp.s:
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_touch_calibration.cpp.s
.PHONY : ui_touch_calibration.cpp.s
ui_xylos.obj: ui_xylos.cpp.obj
.PHONY : ui_xylos.obj
@ -4588,6 +4612,9 @@ help:
@echo "... ui_textentry.obj"
@echo "... ui_textentry.i"
@echo "... ui_textentry.s"
@echo "... ui_touch_calibration.obj"
@echo "... ui_touch_calibration.i"
@echo "... ui_touch_calibration.s"
@echo "... ui_xylos.obj"
@echo "... ui_xylos.i"
@echo "... ui_xylos.s"

View File

@ -25,6 +25,9 @@
#include "baseband_api.hpp"
#include "portapack.hpp"
using namespace portapack;
#include <algorithm>
namespace ais {
@ -291,6 +294,11 @@ AISAppView::AISAppView(NavigationView&) {
add_children({ {
&label_channel,
&options_channel,
&field_rf_amp,
&field_lna,
&field_vga,
&rssi,
&channel,
&recent_entries_view,
&recent_entry_detail_view,
} });
@ -304,7 +312,9 @@ AISAppView::AISAppView(NavigationView&) {
sampling_rate,
baseband_bandwidth,
rf::Direction::Receive,
false, 32, 32,
receiver_model.rf_amp(),
static_cast<int8_t>(receiver_model.lna()),
static_cast<int8_t>(receiver_model.vga()),
1,
});

View File

@ -24,6 +24,9 @@
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_rssi.hpp"
#include "ui_channel.hpp"
#include "event_m0.hpp"
@ -177,6 +180,26 @@ private:
}
};
RFAmpField field_rf_amp {
{ 13 * 8, 0 * 16 }
};
LNAGainField field_lna {
{ 15 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 18 * 8, 0 * 16 }
};
RSSI rssi {
{ 21 * 8, 0, 6 * 8, 4 },
};
Channel channel {
{ 21 * 8, 5, 6 * 8, 4 },
};
MessageHandlerRegistration message_handler_packet {
Message::ID::AISPacket,
[this](Message* const p) {

View File

@ -119,7 +119,7 @@ AnalogAudioView::AnalogAudioView(
};
const auto modulation = receiver_model.modulation();
options_modulation.set_by_value(modulation);
options_modulation.set_by_value(toUType(modulation));
options_modulation.on_change = [this](size_t, OptionsField::value_t v) {
this->on_modulation_changed(static_cast<ReceiverModel::Mode>(v));
};
@ -286,11 +286,8 @@ void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) {
baseband::run_image(image_tag);
const auto is_wideband_spectrum_mode = (modulation == ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.set_baseband_configuration({
.mode = toUType(modulation),
.sampling_rate = is_wideband_spectrum_mode ? 20000000U : 3072000U,
.decimation_factor = 1,
});
receiver_model.set_modulation(modulation);
receiver_model.set_sampling_rate(is_wideband_spectrum_mode ? 20000000 : 3072000);
receiver_model.set_baseband_bandwidth(is_wideband_spectrum_mode ? 12000000 : 1750000);
receiver_model.enable();

View File

@ -99,6 +99,13 @@ void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phas
send_message(&message);
}
void set_audiotx_data(const uint32_t bw) {
const AudioTXConfigMessage message {
bw
};
send_message(&message);
}
void set_pwmrssi(int32_t avg, bool enabled) {
const PWMRSSIConfigureMessage message {
enabled,

View File

@ -53,6 +53,7 @@ struct WFMConfig {
};
void set_ccir_data( const uint32_t samples_per_tone, const uint16_t tone_count);
void set_audiotx_data(const uint32_t bw);
void set_pwmrssi(int32_t avg, bool enabled);
void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space,
const uint8_t afsk_repeat, const uint32_t afsk_bw, const bool afsk_alt_format);

View File

@ -244,6 +244,98 @@ static constexpr Bitmap bitmap_sd_card_error {
{ 16, 16 }, bitmap_sd_card_error_data
};
static constexpr uint8_t bitmap_target_calibrate_data[] = {
0x02, 0x00, 0x00, 0x40,
0x07, 0x00, 0x00, 0xe0,
0x0e, 0x00, 0x00, 0x70,
0x1c, 0x00, 0x00, 0x38,
0x38, 0x00, 0x00, 0x1c,
0x70, 0x00, 0x00, 0x0e,
0xe0, 0x00, 0x00, 0x07,
0xc0, 0x01, 0x80, 0x03,
0x80, 0x03, 0xc0, 0x01,
0x00, 0x07, 0xe0, 0x00,
0x00, 0x0e, 0x70, 0x00,
0x00, 0x1c, 0x38, 0x00,
0x00, 0x38, 0x1c, 0x00,
0x00, 0x30, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x0c, 0x00,
0x00, 0x38, 0x1c, 0x00,
0x00, 0x1c, 0x38, 0x00,
0x00, 0x0e, 0x70, 0x00,
0x00, 0x07, 0xe0, 0x00,
0x80, 0x03, 0xc0, 0x01,
0xc0, 0x01, 0x80, 0x03,
0xe0, 0x00, 0x00, 0x07,
0x70, 0x00, 0x00, 0x0e,
0x38, 0x00, 0x00, 0x1c,
0x1c, 0x00, 0x00, 0x38,
0x0e, 0x00, 0x00, 0x70,
0x07, 0x00, 0x00, 0xe0,
0x02, 0x00, 0x00, 0x40,
};
static constexpr Bitmap bitmap_target_calibrate {
{ 32, 32 }, bitmap_target_calibrate_data
};
static constexpr uint8_t bitmap_target_verify_data[] = {
0x00, 0xe0, 0x07, 0x00,
0x00, 0xfc, 0x3f, 0x00,
0x00, 0x1f, 0xf8, 0x00,
0xc0, 0x03, 0xc0, 0x03,
0xe0, 0x00, 0x00, 0x07,
0x70, 0x00, 0x00, 0x0e,
0x38, 0x00, 0x00, 0x1c,
0x18, 0x00, 0x00, 0x18,
0x0c, 0x00, 0x00, 0x30,
0x0c, 0x00, 0x00, 0x30,
0x06, 0x00, 0x00, 0x60,
0x06, 0x00, 0x00, 0x60,
0x06, 0x00, 0x00, 0x60,
0x03, 0x80, 0x01, 0xc0,
0x03, 0x80, 0x01, 0xc0,
0x03, 0xe0, 0x07, 0xc0,
0x03, 0xe0, 0x07, 0xc0,
0x03, 0x80, 0x01, 0xc0,
0x03, 0x80, 0x01, 0xc0,
0x06, 0x00, 0x00, 0x60,
0x06, 0x00, 0x00, 0x60,
0x06, 0x00, 0x00, 0x60,
0x0c, 0x00, 0x00, 0x30,
0x0c, 0x00, 0x00, 0x30,
0x18, 0x00, 0x00, 0x18,
0x38, 0x00, 0x00, 0x1c,
0x70, 0x00, 0x00, 0x0e,
0xe0, 0x00, 0x00, 0x07,
0xc0, 0x03, 0xc0, 0x03,
0x00, 0x1f, 0xf8, 0x00,
0x00, 0xfc, 0x3f, 0x00,
0x00, 0xe0, 0x07, 0x00,
};
static constexpr Bitmap bitmap_target_verify {
{ 32, 32 }, bitmap_target_verify_data
};
} /* namespace ui */
#endif/*__BITMAP_HPP__*/

View File

@ -23,6 +23,9 @@
#include "baseband_api.hpp"
#include "portapack.hpp"
using namespace portapack;
#include "manchester.hpp"
#include "crc.hpp"
@ -124,6 +127,10 @@ ERTAppView::ERTAppView(NavigationView&) {
baseband::run_image(portapack::spi_flash::image_tag_ert);
add_children({ {
&field_rf_amp,
&field_lna,
&field_vga,
&rssi,
&recent_entries_view,
} });
@ -132,7 +139,9 @@ ERTAppView::ERTAppView(NavigationView&) {
sampling_rate,
baseband_bandwidth,
rf::Direction::Receive,
false, 32, 32,
receiver_model.rf_amp(),
static_cast<int8_t>(receiver_model.lna()),
static_cast<int8_t>(receiver_model.vga()),
1,
});
@ -149,12 +158,12 @@ ERTAppView::~ERTAppView() {
}
void ERTAppView::focus() {
recent_entries_view.focus();
field_vga.focus();
}
void ERTAppView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect);
recent_entries_view.set_parent_rect({ 0, 0, new_parent_rect.width(), new_parent_rect.height() });
recent_entries_view.set_parent_rect({ 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height });
}
void ERTAppView::on_packet(const ert::Packet& packet) {

View File

@ -23,6 +23,9 @@
#define __ERT_APP_H__
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_rssi.hpp"
#include "ui_channel.hpp"
#include "event_m0.hpp"
@ -128,6 +131,24 @@ private:
ERTRecentEntriesView recent_entries_view { recent };
static constexpr auto header_height = 1 * 16;
RFAmpField field_rf_amp {
{ 13 * 8, 0 * 16 }
};
LNAGainField field_lna {
{ 15 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 18 * 8, 0 * 16 }
};
RSSI rssi {
{ 21 * 8, 0, 6 * 8, 4 },
};
MessageHandlerRegistration message_handler_packet {
Message::ID::ERTPacket,
[this](Message* const p) {

View File

@ -58,27 +58,18 @@ static volatile uint32_t touch_phase { 0 };
* Noise will only occur when the panel is being touched. Not ideal, but
* an acceptable improvement.
*/
static std::array<portapack::IO::TouchPinsConfig, 11> touch_pins_configs {
static std::array<portapack::IO::TouchPinsConfig, 3> touch_pins_configs {
/* State machine will pause here until touch is detected. */
portapack::IO::TouchPinsConfig::WaitTouch,
portapack::IO::TouchPinsConfig::SensePressure,
portapack::IO::TouchPinsConfig::SenseX,
portapack::IO::TouchPinsConfig::SenseY,
portapack::IO::TouchPinsConfig::SenseX,
portapack::IO::TouchPinsConfig::SenseY,
portapack::IO::TouchPinsConfig::SensePressure,
portapack::IO::TouchPinsConfig::SenseX,
portapack::IO::TouchPinsConfig::SenseY,
portapack::IO::TouchPinsConfig::SenseX,
portapack::IO::TouchPinsConfig::SenseY,
};
static touch::Frame temp_frame;
static touch::Frame touch_frame;
static uint32_t touch_debounce = 0;
static uint32_t touch_debounce_mask = (1U << 1) - 1;
static uint32_t touch_debounce_mask = (1U << 4) - 1;
static bool touch_detected = false;
static bool touch_cycle = false;
@ -87,20 +78,20 @@ static bool touch_update() {
const auto current_phase = touch_pins_configs[touch_phase];
switch(current_phase) {
case portapack::IO::TouchPinsConfig::WaitTouch:
case portapack::IO::TouchPinsConfig::SensePressure:
{
/* Debounce touches. */
const bool touch_raw = (samples.yp < touch::touch_threshold) && (samples.yn < touch::touch_threshold);
const auto z1 = samples.xp - samples.xn;
const auto z2 = samples.yp - samples.yn;
const auto touch_raw = (z1 > touch::touch_threshold) || (z2 > touch::touch_threshold);
touch_debounce = (touch_debounce << 1) | (touch_raw ? 1U : 0U);
touch_detected = ((touch_debounce & touch_debounce_mask) == touch_debounce_mask);
if( !touch_detected && !touch_cycle ) {
temp_frame.pressure = { };
return false;
}
}
break;
case portapack::IO::TouchPinsConfig::SensePressure:
} else {
temp_frame.pressure += samples;
}
}
break;
case portapack::IO::TouchPinsConfig::SenseX:

View File

@ -116,11 +116,21 @@ void ReceiverModel::set_vga(int32_t v_db) {
}
uint32_t ReceiverModel::sampling_rate() const {
return baseband_configuration.sampling_rate;
return sampling_rate_;
}
uint32_t ReceiverModel::modulation() const {
return baseband_configuration.mode;
void ReceiverModel::set_sampling_rate(uint32_t v) {
sampling_rate_ = v;
update_sampling_rate();
}
ReceiverModel::Mode ReceiverModel::modulation() const {
return mode_;
}
void ReceiverModel::set_modulation(const Mode v) {
mode_ = v;
update_modulation();
}
volume_t ReceiverModel::headphone_volume() const {
@ -134,7 +144,7 @@ void ReceiverModel::set_headphone_volume(volume_t v) {
uint32_t ReceiverModel::baseband_oversampling() const {
// TODO: Rename decimation_factor.
return baseband_configuration.decimation_factor;
return decimation_factor_;
}
void ReceiverModel::enable() {
@ -146,8 +156,8 @@ void ReceiverModel::enable() {
update_lna();
update_vga();
update_baseband_bandwidth();
update_baseband_configuration();
update_modulation_configuration();
update_sampling_rate();
update_modulation();
update_headphone_volume();
}
@ -161,7 +171,7 @@ void ReceiverModel::disable() {
}
int32_t ReceiverModel::tuning_offset() {
if( (baseband_configuration.mode == 4) || (baseband_configuration.mode == 10) ) {
if( (modulation() == Mode::SpectrumAnalysis) ) {
return 0;
} else {
return -(sampling_rate() / 4);
@ -192,33 +202,28 @@ void ReceiverModel::update_vga() {
radio::set_vga_gain(vga_gain_db_);
}
void ReceiverModel::set_baseband_configuration(const BasebandConfiguration config) {
baseband_configuration = config;
update_baseband_configuration();
}
void ReceiverModel::set_am_configuration(const size_t n) {
if( n < am_configs.size() ) {
am_config_index = n;
update_modulation_configuration();
update_modulation();
}
}
void ReceiverModel::set_nbfm_configuration(const size_t n) {
if( n < nbfm_configs.size() ) {
nbfm_config_index = n;
update_modulation_configuration();
update_modulation();
}
}
void ReceiverModel::set_wfm_configuration(const size_t n) {
if( n < wfm_configs.size() ) {
wfm_config_index = n;
update_modulation_configuration();
update_modulation();
}
}
void ReceiverModel::update_baseband_configuration() {
void ReceiverModel::update_sampling_rate() {
// 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.
@ -236,8 +241,8 @@ void ReceiverModel::update_headphone_volume() {
audio::headphone::set_volume(headphone_volume_);
}
void ReceiverModel::update_modulation_configuration() {
switch(static_cast<Mode>(modulation())) {
void ReceiverModel::update_modulation() {
switch(modulation()) {
default:
case Mode::AMAudio:
update_am_configuration();

View File

@ -53,13 +53,11 @@ struct BasebandConfiguration {
class ReceiverModel {
public:
enum class Mode : int32_t {
enum class Mode {
AMAudio = 0,
NarrowbandFMAudio = 1,
WidebandFMAudio = 2,
SpectrumAnalysis = 4,
Capture = 7,
CloseCall = 10,
SpectrumAnalysis = 3,
};
rf::Frequency tuning_frequency() const;
@ -84,8 +82,10 @@ public:
void set_vga(int32_t v_db);
uint32_t sampling_rate() const;
void set_sampling_rate(uint32_t v);
uint32_t modulation() const;
Mode modulation() const;
void set_modulation(Mode v);
volume_t headphone_volume() const;
void set_headphone_volume(volume_t v);
@ -95,8 +95,6 @@ public:
void enable();
void disable();
void set_baseband_configuration(const BasebandConfiguration config);
size_t am_configuration() const;
void set_am_configuration(const size_t n);
@ -114,11 +112,9 @@ private:
int32_t lna_gain_db_ { 32 };
uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum };
int32_t vga_gain_db_ { 32 };
BasebandConfiguration baseband_configuration {
.mode = 1, /* TODO: Enum! */
.sampling_rate = 3072000,
.decimation_factor = 1,
};
Mode mode_ { Mode::NarrowbandFMAudio };
uint32_t sampling_rate_ { 3072000 };
size_t decimation_factor_ { 1 };
size_t am_config_index = 0;
size_t nbfm_config_index = 0;
size_t wfm_config_index = 0;
@ -132,10 +128,10 @@ private:
void update_lna();
void update_baseband_bandwidth();
void update_vga();
void update_baseband_configuration();
void update_sampling_rate();
void update_headphone_volume();
void update_modulation_configuration();
void update_modulation();
void update_am_configuration();
void update_nbfm_configuration();
void update_wfm_configuration();

View File

@ -21,15 +21,14 @@
#include "touch.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
#include "utility.hpp"
namespace touch {
struct Metrics {
const float x;
const float y;
const float r;
};
static Metrics calculate_metrics(const Frame& frame) {
Metrics calculate_metrics(const Frame& frame) {
/* TODO: Yikes! M0 doesn't have floating point, so this code is
* expensive! On the other hand, it seems to be working well (and
* fast *enough*?), so maybe leave it alone at least for now.
@ -38,14 +37,14 @@ static Metrics calculate_metrics(const Frame& frame) {
const auto x_max = frame.x.xp;
const auto x_min = frame.x.xn;
const auto x_range = x_max - x_min;
const auto x_position = (frame.x.yp + frame.x.yn) / 2;
const float x_norm = float(x_position - x_min) / x_range;
const float x_position = (frame.x.yp + frame.x.yn) * 0.5f;
const float x_norm = (x_position - x_min) / x_range;
const auto y_max = frame.y.yn;
const auto y_min = frame.y.yp;
const auto y_range = y_max - y_min;
const auto y_position = (frame.y.xp + frame.y.xn) / 2;
const float y_norm = float(y_position - y_min) / y_range;
const float y_position = (frame.y.xp + frame.y.xn) * 0.5f;
const float y_norm = (y_position - y_min) / y_range;
const auto z_max = frame.pressure.yp;
const auto z_min = frame.pressure.xn;
@ -66,6 +65,28 @@ static Metrics calculate_metrics(const Frame& frame) {
};
}
ui::Point Calibration::translate(const DigitizerPoint& p) const {
static constexpr range_t<int32_t> x_range { 0, 240 - 1 };
static constexpr range_t<int32_t> y_range { 0, 320 - 1 };
const int32_t x = (a * p.x + b * p.y + c) / k;
const int32_t y = (d * p.x + e * p.y + f) / k;
const auto x_clipped = x_range.clip(x);
const auto y_clipped = y_range.clip(y);
return {
static_cast<ui::Coord>(x_clipped),
static_cast<ui::Coord>(y_clipped)
};
}
const Calibration default_calibration() {
/* Values derived from one PortaPack H1 unit. */
return {
{ { { 256, 731 }, { 880, 432 }, { 568, 146 } } },
{ { { 32, 48 }, { 208, 168 }, { 120, 288 } } }
};
};
void Manager::feed(const Frame& frame) {
// touch_debounce.feed(touch_raw);
const auto touch_raw = frame.touch;
@ -81,10 +102,8 @@ void Manager::feed(const Frame& frame) {
// TODO: Add touch pressure hysteresis?
touch_pressure = (metrics.r < r_touch_threshold);
if( touch_pressure ) {
const float x = width_pixels * (metrics.x - calib_x_low) / calib_x_range;
filter_x.feed(x);
const float y = height_pixels * (calib_y_high - metrics.y) / calib_y_range;
filter_y.feed(y);
filter_x.feed(metrics.x * 1024);
filter_y.feed(metrics.y * 1024);
}
} else {
filter_x.reset();
@ -116,4 +135,8 @@ void Manager::feed(const Frame& frame) {
}
}
ui::Point Manager::filtered_point() const {
return persistent_memory::touch_calibration().translate({ filter_x.value(), filter_y.value() });
}
} /* namespace touch */

View File

@ -38,7 +38,7 @@ using sample_t = uint16_t;
constexpr sample_t sample_max = 1023;
constexpr sample_t touch_threshold = sample_max * 0.5f;
constexpr sample_t touch_threshold = sample_max / 5;
struct Samples {
sample_t xp;
@ -106,6 +106,51 @@ struct Frame {
bool touch { false };
};
struct Metrics {
const float x;
const float y;
const float r;
};
Metrics calculate_metrics(const Frame& frame);
struct DigitizerPoint {
int32_t x;
int32_t y;
};
struct Calibration {
/* Touch screen calibration matrix, based on article by Carlos E. Vidales:
* http://www.embedded.com/design/system-integration/4023968/How-To-Calibrate-Touch-Screens
*/
constexpr Calibration(
const std::array<DigitizerPoint, 3>& s,
const std::array<ui::Point, 3>& d
) : k { (s[0].x - s[2].x) * (s[1].y - s[2].y) - (s[1].x - s[2].x) * (s[0].y - s[2].y) },
a { (d[0].x - d[2].x) * (s[1].y - s[2].y) - (d[1].x - d[2].x) * (s[0].y - s[2].y) },
b { (s[0].x - s[2].x) * (d[1].x - d[2].x) - (d[0].x - d[2].x) * (s[1].x - s[2].x) },
c { s[0].y * (s[2].x * d[1].x - s[1].x * d[2].x) + s[1].y * (s[0].x * d[2].x - s[2].x * d[0].x) + s[2].y * (s[1].x * d[0].x - s[0].x * d[1].x) },
d { (d[0].y - d[2].y) * (s[1].y - s[2].y) - (d[1].y - d[2].y) * (s[0].y - s[2].y) },
e { (s[0].x - s[2].x) * (d[1].y - d[2].y) - (d[0].y - d[2].y) * (s[1].x - s[2].x) },
f { s[0].y * (s[2].x * d[1].y - s[1].x * d[2].y) + s[1].y * (s[0].x * d[2].y - s[2].x * d[0].y) + s[2].y * (s[1].x * d[0].y - s[0].x * d[1].y) }
{
}
ui::Point translate(const DigitizerPoint& p) const;
private:
int32_t k;
int32_t a;
int32_t b;
int32_t c;
int32_t d;
int32_t e;
int32_t f;
};
const Calibration default_calibration();
template<size_t N>
class Filter {
public:
@ -173,20 +218,9 @@ private:
TouchDetected,
};
static constexpr uint32_t width_pixels = 240;
static constexpr uint32_t height_pixels = 320;
static constexpr float r_touch_threshold = 0x1000;
static constexpr size_t touch_count_threshold { 4 };
static constexpr uint32_t touch_stable_bound { 4 };
static constexpr float calib_x_low = 0.15f;
static constexpr float calib_x_high = 0.98f;
static constexpr float calib_x_range = calib_x_high - calib_x_low;
static constexpr float calib_y_low = 0.04f;
static constexpr float calib_y_high = 0.80f; //91
static constexpr float calib_y_range = calib_y_high - calib_y_low;
static constexpr float r_touch_threshold = 640;
static constexpr size_t touch_count_threshold { 3 };
static constexpr uint32_t touch_stable_bound { 8 };
// Ensure filter length is equal or less than touch_count_threshold,
// or coordinates from the last touch will be in the initial averages.
@ -202,12 +236,7 @@ private:
&& filter_y.stable(touch_stable_bound);
}
ui::Point filtered_point() const {
return {
static_cast<ui::Coord>(filter_x.value()),
static_cast<ui::Coord>(filter_y.value())
};
}
ui::Point filtered_point() const;
void touch_started() {
fire_event(ui::TouchEvent::Type::Start);

View File

@ -181,7 +181,7 @@ TPMSAppView::TPMSAppView(NavigationView&) {
sampling_rate,
baseband_bandwidth,
rf::Direction::Receive,
false,
receiver_model.rf_amp(),
static_cast<int8_t>(receiver_model.lna()),
static_cast<int8_t>(receiver_model.vga()),
1,

View File

@ -119,7 +119,7 @@ private:
}
};
static constexpr ui::Dim header_height = 2 * 16;
static constexpr ui::Dim header_height = 1 * 16;
RSSI rssi {
{ 21 * 8, 0, 6 * 8, 4 },

View File

@ -48,8 +48,21 @@ using namespace portapack;
namespace ui {
void AboutView::on_show() {
about_radio_config.tuning_frequency = 92200000; // 92.2MHz, change !
radio::enable(about_radio_config);
transmitter_model.set_tuning_frequency(92200000);
transmitter_model.set_baseband_configuration({
.mode = 0,
.sampling_rate = 1536000,
.decimation_factor = 1,
});
transmitter_model.set_rf_amp(true);
transmitter_model.set_lna(40);
transmitter_model.set_vga(40);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_audiotx_data(
0
);
//audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max);
}
@ -352,6 +365,8 @@ AboutView::AboutView(
{
uint8_t p, c;
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
add_children({ {
&text_title,
&text_firmware,
@ -394,7 +409,8 @@ AboutView::AboutView(
}
AboutView::~AboutView() {
radio::disable();
transmitter_model.disable();
baseband::shutdown();
}
void AboutView::focus() {

View File

@ -48,17 +48,6 @@ private:
void draw_demoglyph(ui::Point p, char ch, ui::Color * pal);
uint16_t debug_cnt = 0;
radio::Configuration about_radio_config = {
0,
1536000, // ?
2500000, // ?
rf::Direction::Transmit,
true,
0,
0,
1,
};
typedef struct ymreg_t {
uint8_t value;
uint8_t cnt;
@ -170,8 +159,6 @@ private:
FIFODataMessage datamessage;
const auto message = static_cast<const FIFOSignalMessage*>(p);
if (message->signaltype == 1) {
//debug_cnt++;
//if (debug_cnt == 250) for(;;) {}
this->render_audio();
datamessage.data = ym_buffer;
EventDispatcher::send_message(datamessage);

View File

@ -247,7 +247,6 @@ void LCRView::start_tx(const bool scan) {
afsk_format = 0;
}
transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
transmitter_model.set_baseband_configuration({
.mode = 0,
@ -281,7 +280,7 @@ LCRView::LCRView(NavigationView& nav) {
baseband::run_image(portapack::spi_flash::image_tag_afsk);
strcpy(rgsb, &scan_list[options_scanlist.selected_index()].addresses[0]);
strcpy(rgsb, &scan_list[0].addresses[0]);
add_children({ {
&text_recap,
@ -298,6 +297,8 @@ LCRView::LCRView(NavigationView& nav) {
&button_clear
} });
options_scanlist.set_selected_index(0);
const auto button_setam_fn = [this, &nav](Button& button) {
this->on_button_setam(nav, button);
};

View File

@ -44,7 +44,7 @@ private:
const char * addresses;
};
scan_list_t scan_list[2] = {
const scan_list_t scan_list[2] = {
{ 36, &RGSB_list_Lille[0][0] },
{ 23, &RGSB_list_Reims[0][0] }
};
@ -80,9 +80,8 @@ private:
tx_modes tx_mode = IDLE;
bool abort_scan = false;
uint8_t scan_count;
uint8_t scan_count, scan_index;
double scan_progress;
unsigned int scan_index;
char litteral[5][8] = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };
char rgsb[5] = { 0 };
char lcr_message[512];
@ -97,20 +96,6 @@ private:
void on_txdone(int n);
void on_button_setam(NavigationView& nav, Button& button);
radio::Configuration lcr_radio_config = {
0,
2280000,
2500000, // ?
rf::Direction::Transmit,
true,
0,
0,
1,
};
// 2: 94 ?
// 9: 85 ?
const Style style_val {
.font = font::fixed_8x16,
.background = Color::green(),

View File

@ -21,6 +21,8 @@
#include "ui_setup.hpp"
#include "ui_touch_calibration.hpp"
#include "portapack_persistent_memory.hpp"
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
@ -32,6 +34,7 @@ using namespace portapack;
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "cpld_update.hpp"
namespace ui {
@ -172,18 +175,6 @@ void AntennaBiasSetupView::focus() {
button_done.focus();
}
void SetTouchCalibView::focus() {
button_ok.focus();
}
bool SetTouchCalibView::on_touch(const TouchEvent event) {
if (event.type == ui::TouchEvent::Type::Start) {
text_debugx.set(to_string_dec_uint(round(event.point.x), 4));
text_debugy.set(to_string_dec_uint(round(event.point.y), 4));
}
return true;
}
SetPlayDeadView::SetPlayDeadView(NavigationView& nav) {
add_children({{
&text_sequence,
@ -445,7 +436,7 @@ SetupMenuView::SetupMenuView(NavigationView& nav) {
{ "Date/Time", ui::Color::white(), [&nav](){ nav.push<SetDateTimeView>(); } },
{ "Frequency correction", ui::Color::white(), [&nav](){ nav.push<SetFrequencyCorrectionView>(); } },
{ "Antenna Bias Voltage", ui::Color::white(), [&nav](){ nav.push<AntennaBiasSetupView>(); } },
{ "Touch screen", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "Touch screen", ui::Color::white(), [&nav](){ nav.push<TouchCalibrationView>(); } },
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<SetPlayDeadView>(); } }
} });
on_left = [&nav](){ nav.pop(); };

View File

@ -0,0 +1,206 @@
/*
* Copyright (C) 2016 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_touch_calibration.hpp"
#include "irq_controls.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
namespace ui {
TouchCalibrationView::TouchCalibrationView(
NavigationView& nav
) : nav { nav },
calibration { touch::default_calibration() }
{
add_children({ {
&image_calibrate_0,
&image_calibrate_1,
&image_calibrate_2,
&image_verify_0,
&image_verify_1,
&image_verify_2,
&label_calibrate,
&label_verify,
&label_success,
&label_failure,
&button_cancel,
&button_ok,
} });
button_cancel.on_select = [this](Button&){ this->on_cancel(); };
button_ok.on_select = [this](Button&){ this->on_ok(); };
set_phase(Phase::Calibrate0);
}
void TouchCalibrationView::focus() {
button_cancel.focus();
}
void TouchCalibrationView::update_target() {
const auto phase_calibrate = (phase == Phase::Calibrate0) || (phase == Phase::Calibrate1) || (phase == Phase::Calibrate2);
const auto phase_verify = (phase == Phase::Verify0) || (phase == Phase::Verify1) || (phase == Phase::Verify2);
image_calibrate_0.hidden(phase != Phase::Calibrate0);
image_calibrate_1.hidden(phase != Phase::Calibrate1);
image_calibrate_2.hidden(phase != Phase::Calibrate2);
image_verify_0.hidden(phase != Phase::Verify0);
image_verify_1.hidden(phase != Phase::Verify1);
image_verify_2.hidden(phase != Phase::Verify2);
label_calibrate.hidden(!phase_calibrate);
label_verify.hidden(!phase_verify);
label_success.hidden(phase != Phase::Success);
label_failure.hidden(phase != Phase::Failure);
button_ok.hidden((phase != Phase::Success) && (phase != Phase::Failure));
/* TODO: Such a hack to get around a poor repaint implementation! This "technique"
* occurs in other places...
*/
set_dirty();
}
void TouchCalibrationView::set_phase(const Phase value) {
if( value != phase ) {
phase = value;
update_target();
}
}
uint32_t TouchCalibrationView::distance_squared(const Point& touch_point, const Image& target) {
const auto target_point = target.screen_rect().center();
const int32_t dx = target_point.x - touch_point.x;
const int32_t dy = target_point.y - touch_point.y;
const uint32_t dx2 = dx * dx;
const uint32_t dy2 = dy * dy;
return dx2 + dy2;
}
void TouchCalibrationView::touch_complete() {
auto next_phase = static_cast<Phase>(toUType(phase) + 1);
switch(phase) {
case Phase::Calibrate0:
case Phase::Verify0:
digitizer_points[0] = average;
break;
case Phase::Calibrate1:
case Phase::Verify1:
digitizer_points[1] = average;
break;
case Phase::Calibrate2:
case Phase::Verify2:
digitizer_points[2] = average;
break;
default:
break;
}
if( phase == Phase::Calibrate2 ) {
const std::array<Point, 3> display_points { {
image_calibrate_0.screen_rect().center(),
image_calibrate_1.screen_rect().center(),
image_calibrate_2.screen_rect().center(),
} };
calibration = { digitizer_points, display_points };
}
if( phase == Phase::Verify2 ) {
const auto calibrated_0 = calibration.translate(digitizer_points[0]);
const auto d_sq_0 = distance_squared(calibrated_0, image_verify_0);
const auto calibrated_1 = calibration.translate(digitizer_points[1]);
const auto d_sq_1 = distance_squared(calibrated_1, image_verify_1);
const auto calibrated_2 = calibration.translate(digitizer_points[2]);
const auto d_sq_2 = distance_squared(calibrated_2, image_verify_2);
if( (d_sq_0 < verify_d_sq_max) && (d_sq_1 < verify_d_sq_max) && (d_sq_2 < verify_d_sq_max) ) {
next_phase = Phase::Success;
} else {
next_phase = Phase::Failure;
}
}
set_phase(next_phase);
}
void TouchCalibrationView::on_ok() {
if( phase == Phase::Success ) {
persistent_memory::set_touch_calibration(calibration);
nav.pop();
}
if( phase == Phase::Failure ) {
set_phase(Phase::Calibrate0);
}
}
void TouchCalibrationView::on_cancel() {
nav.pop();
}
void TouchCalibrationView::on_frame_sync() {
switch(phase) {
case Phase::Calibrate0:
case Phase::Calibrate1:
case Phase::Calibrate2:
case Phase::Verify0:
case Phase::Verify1:
case Phase::Verify2:
break;
default:
return;
}
const auto frame = get_touch_frame();
const auto metrics = touch::calculate_metrics(frame);
const auto x = metrics.x * 1024;
const auto y = metrics.y * 1024;
if( metrics.r < 640.0f ) {
if( samples_count > 0 ) {
average.x = ((average.x * 7) + x) / 8;
average.y = ((average.y * 7) + y) / 8;
} else {
average.x = x;
average.y = y;
}
samples_count += 1;
} else {
if( samples_count >= samples_limit ) {
touch_complete();
}
samples_count = 0;
}
}
} /* namespace ui */

View File

@ -0,0 +1,158 @@
/*
* Copyright (C) 2016 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 __UI_TOUCH_CALIBRATION_HPP__
#define __UI_TOUCH_CALIBRATION_HPP__
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "touch.hpp"
namespace ui {
class TouchCalibrationView : public View {
public:
TouchCalibrationView(NavigationView& nav);
void focus() override;
private:
enum class Phase {
Init,
Calibrate0,
Calibrate1,
Calibrate2,
Verify0,
Verify1,
Verify2,
Success,
Failure,
};
NavigationView& nav;
Phase phase { Phase::Init };
void update_target();
void set_phase(const Phase value);
uint32_t distance_squared(const Point& touch_point, const Image& target);
void touch_complete();
void on_ok();
void on_cancel();
const uint32_t samples_limit { 40 };
const uint32_t verify_d_sq_max = 10 * 10;
uint32_t samples_count { 0 };
touch::DigitizerPoint average;
std::array<touch::DigitizerPoint, 3> digitizer_points;
touch::Calibration calibration;
Image image_calibrate_0 {
{ 32 - 16, 32 - 16, 32, 32 },
&bitmap_target_calibrate,
Color::white(),
Color::black()
};
Image image_calibrate_1 {
{ 240 - 32 - 16, (320 - 16) / 2 - 16, 32, 32 },
&bitmap_target_calibrate,
Color::white(),
Color::black()
};
Image image_calibrate_2 {
{ 240 / 2 - 16, (320 - 16) - 32 - 16, 32, 32 },
&bitmap_target_calibrate,
Color::white(),
Color::black()
};
Image image_verify_0 {
{ 32 - 16, 32 - 16, 32, 32 },
&bitmap_target_verify,
Color::white(),
Color::black()
};
Image image_verify_1 {
{ 240 - 32 - 16, (320 - 16) / 2 - 16, 32, 32 },
&bitmap_target_verify,
Color::white(),
Color::black()
};
Image image_verify_2 {
{ 240 / 2 - 16, (320 - 16) - 32 - 16, 32, 32 },
&bitmap_target_verify,
Color::white(),
Color::black()
};
Text label_calibrate {
{ 16, 5 * 16, 26 * 8, 1 * 16 },
"Touch targets to calibrate"
};
Text label_verify {
{ 28, 5 * 16, 23 * 8, 1 * 16 },
"Touch targets to verify"
};
Text label_success {
{ 32, 5 * 16, 22 * 8, 1 * 16 },
"Apply new calibration?"
};
Text label_failure {
{ 16, 5 * 16, 26 * 8, 1 * 16 },
"Calibration failed. Retry?"
};
Button button_cancel {
{ 40, 200, 64, 24 },
"Cancel"
};
Button button_ok {
{ 136, 200, 64, 24 },
"OK"
};
void on_frame_sync();
MessageHandlerRegistration message_handler_frame_sync {
Message::ID::DisplayFrameSync,
[this](const Message* const) {
this->on_frame_sync();
}
};
};
} /* namespace ui */
#endif/*__UI_TOUCH_CALIBRATION_HPP__*/

View File

@ -29,7 +29,7 @@ enable_language(C CXX ASM)
project(baseband_shared)
# Compiler options here.
set(USE_OPT "-O3 -falign-functions=16 -fno-math-errno --specs=nano.specs")
set(USE_OPT "-O3 -g -falign-functions=16 -fno-math-errno --specs=nano.specs")
# C specific options here (added to USE_OPT).
set(USE_COPT "-std=gnu99")
@ -342,10 +342,10 @@ DeclareTargets(POOK ook)
### Audio transmit
#set(MODE_CPPSRC
# proc_audiotx.cpp
#)
#DeclareTargets(PATX audio_tx)
set(MODE_CPPSRC
proc_audiotx.cpp
)
DeclareTargets(PATX audio_tx)
### AFSK
@ -361,13 +361,6 @@ DeclareTargets(PAFS afsk)
#)
#DeclareTargets(PEPR epar)
### Play audio
#set(MODE_CPPSRC
# proc_playaudio.cpp
#)
#DeclareTargets(PPAU play_audio)
### Xylos
set(MODE_CPPSRC

View File

@ -119,8 +119,8 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) {
}
}
void AFSKProcessor::on_message(const Message* const p) {
const auto message = *reinterpret_cast<const AFSKConfigureMessage*>(p);
void AFSKProcessor::on_message(const Message* const msg) {
const auto message = *reinterpret_cast<const AFSKConfigureMessage*>(msg);
if (message.id == Message::ID::AFSKConfigure) {
afsk_samples_per_bit = message.samples_per_bit;

View File

@ -30,7 +30,7 @@ class AFSKProcessor : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const p) override;
void on_message(const Message* const msg) override;
private:
bool configured = false;

View File

@ -24,6 +24,7 @@
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#include "rssi_thread.hpp"
#include "channel_decimator.hpp"
#include "matched_filter.hpp"
@ -51,6 +52,7 @@ private:
static constexpr size_t baseband_fs = 2457600;
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
RSSIThread rssi_thread { NORMALPRIO + 10 };
std::array<complex16_t, 512> dst;
const buffer_c16_t dst_buffer {

View File

@ -23,33 +23,69 @@
#include "proc_audiotx.hpp"
#include "portapack_shared_memory.hpp"
#include "sine_table.hpp"
//#include "audio_output.hpp"
#include "event_m4.hpp"
#include <cstdint>
void AudioTXProcessor::execute(const buffer_c8_t& buffer){
// This is called at 1536000/2048 = 750Hz
if (!configured) return;
ai = 0;
for (size_t i = 0; i<buffer.count; i++) {
sample = (sine_table_f32[(aphase & 0x03FF0000)>>18]*127); //(int8_t)lfsr(sample + i);
if (bc & 0x40)
aphase += 60000;
else
aphase += 90000;
//audio_fifo.out(&sample, 1);
//FM
frq = sample * 1000;
// Audio preview sample generation: 1536000/48000 = 32
if (as >= 31) {
as = 0;
//audio_fifo.out(&sample, 1);
//preview_audio_buffer.p[ai++] = sample << 8;
//if ((audio_fifo.len() < 1024) && (asked == false)) {
// Ask application to fill up fifo
sigmessage.signaltype = 1;
shared_memory.application_queue.push(sigmessage);
asked = true;
//}
} else {
as++;
}
// FM
frq = (int32_t)(sample) * 4 * 2000;
phase = (phase + frq);
sphase = phase + (256<<16);
sphase = phase + (256 << 16);
re = (sine_table_f32[(sphase & 0x03FF0000)>>18]*127);
im = (sine_table_f32[(phase & 0x03FF0000)>>18]*127);
buffer.p[i] = {(int8_t)re,(int8_t)im};
buffer.p[i] = { (int8_t)re, (int8_t)im };
}
bc++;
//AudioOutput::fill_audio_buffer(preview_audio_buffer, true);
}
void AudioTXProcessor::on_message(const Message* const msg) {
switch(msg->id) {
case Message::ID::AudioTXConfig:
//const auto message = static_cast<const AudioTXConfigMessage*>(msg);
configured = true;
break;
case Message::ID::FIFOData:
//audio_fifo.in(static_cast<const FIFODataMessage*>(msg)->data, 1024);
asked = false;
break;
default:
break;
}
}
int main() {

View File

@ -23,22 +23,39 @@
#ifndef __PROC_AUDIOTX_H__
#define __PROC_AUDIOTX_H__
#include "fifo.hpp"
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#include <cstdint>
class AudioTXProcessor : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const msg) override;
private:
bool configured = false;
//std::unique_ptr<int8_t[]> audio_fifo_data = std::make_unique<int8_t[]>(1UL << 11);
//FIFO<int8_t> audio_fifo = { audio_fifo_data.get(), 11 }; // 43ms @ 48000Hz
uint8_t as = 0, ai;
int8_t re, im;
uint8_t s, as = 0, ai;
uint8_t byte_pos = 0;
uint8_t digit = 0;
int8_t sample;
int16_t st;
bool asked = false;
//int16_t audio_data[64];
/*const buffer_s16_t preview_audio_buffer {
audio_data,
sizeof(int16_t)*64
};*/
FIFOSignalMessage sigmessage;
uint32_t aphase, phase, sphase;
int32_t sample, frq, bc;
int32_t frq;
};
#endif

View File

@ -24,6 +24,7 @@
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#include "rssi_thread.hpp"
#include "channel_decimator.hpp"
@ -63,6 +64,7 @@ private:
const float clock_recovery_rate = symbol_rate * 2;
BasebandThread baseband_thread { baseband_sampling_rate, this, NORMALPRIO + 20, baseband::Direction::Receive };
RSSIThread rssi_thread { NORMALPRIO + 10 };
clock_recovery::ClockRecovery<clock_recovery::FixedErrorFilter> clock_recovery {
clock_recovery_rate, symbol_rate, { 1.0f / 18.0f },

View File

@ -1,83 +0,0 @@
/*
* 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_playaudio.hpp"
#include "portapack_shared_memory.hpp"
#include "sine_table.hpp"
#include "audio_output.hpp"
#include "event_m4.hpp"
#include <cstdint>
void PlayAudioProcessor::on_message(const Message* const msg) {
if (msg->id == Message::ID::FIFOData) {
const auto message = static_cast<const FIFODataMessage*>(msg);
memcpy(&audio_fifo[fifo_put], message->data, 1024);
fifo_put = (fifo_put + 1024) & 0x0FFF;
asked = false;
}
}
void PlayAudioProcessor::execute(const buffer_c8_t& buffer){
// This is called at 1536000/2048 = 750Hz
ai = 0;
for (size_t i = 0; i<buffer.count; i++) {
// Audio preview sample generation: 1536000/48000 = 32
if (as >= 31) {
as = 0;
sample = audio_fifo[fifo_get];
preview_audio_buffer.p[ai++] = sample << 8;
fifo_get = (fifo_get + 1) & 0x0FFF;
if ((((fifo_put - fifo_get) & 0x0FFF) < 3072) && (asked == false)) {
// Ask application to fill up fifo
sigmessage.signaltype = 1;
shared_memory.application_queue.push(sigmessage);
asked = true;
}
} else {
as++;
}
sample = ((int8_t)audio_fifo[fifo_get] * 4);
//FM
frq = sample * 2000;
phase = (phase + frq);
sphase = phase + (256<<16);
re = (sine_table_f32[(sphase & 0x03FF0000)>>18]*127);
im = (sine_table_f32[(phase & 0x03FF0000)>>18]*127);
buffer.p[i] = {(int8_t)re,(int8_t)im};
}
//AudioOutput::fill_audio_buffer(preview_audio_buffer, true);
}
int main() {
EventDispatcher event_dispatcher { std::make_unique<PlayAudioProcessor>() };
event_dispatcher.run();
return 0;
}

View File

@ -1,56 +0,0 @@
/*
* 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_PLAYAUDIO_H__
#define __PROC_PLAYAUDIO_H__
#include "baseband_processor.hpp"
class PlayAudioProcessor : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const msg) override;
private:
int8_t audio_fifo[4096]; // Probably too much (=85ms @ 48000Hz)
uint16_t fifo_put, fifo_get;
uint8_t as = 0, ai;
int8_t re, im;
int16_t st;
int16_t audio_data[64];
bool asked = false;
const buffer_s16_t preview_audio_buffer {
audio_data,
sizeof(int16_t)*64
};
FIFOSignalMessage sigmessage;
uint32_t aphase, phase, sphase;
int32_t sample, frq;
};
#endif

View File

@ -28,10 +28,6 @@
#include <cstdint>
void RDSProcessor::execute(const buffer_c8_t& buffer) {
uint32_t * rdsdata;
// TODO
//rdsdata = (uint32_t *)shared_memory.radio_data;
for (size_t i = 0; i < buffer.count; i++) {
@ -96,6 +92,14 @@ void RDSProcessor::execute(const buffer_c8_t& buffer) {
}
}
void RDSProcessor::on_message(const Message* const msg) {
if (msg->id == Message::ID::RDSConfigure) {
//const auto message = *reinterpret_cast<const RDSConfigureMessage*>(p);
rdsdata = (uint32_t*)shared_memory.tx_data;
configured = true;
}
}
int main() {
EventDispatcher event_dispatcher { std::make_unique<RDSProcessor>() };
event_dispatcher.run();

View File

@ -24,6 +24,7 @@
#define __PROC_RDS_H__
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#define SAMPLES_PER_BIT 192
#define FILTER_SIZE 576
@ -33,7 +34,13 @@ class RDSProcessor : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const msg) override;
private:
uint32_t * rdsdata;
BasebandThread baseband_thread { 2280000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
int8_t re, im;
uint8_t mphase, s;
uint32_t bit_pos;
@ -50,6 +57,8 @@ private:
int32_t sig, frq, frq_im, rdsc;
int32_t k;
bool configured { false };
const int32_t waveform_biphase[576] = {
165,167,168,168,167,166,163,160,
157,152,147,141,134,126,118,109,

View File

@ -98,7 +98,7 @@ private:
};
static constexpr float channel_rate_in = 307200.0f;
static constexpr size_t channel_decimation = 8;
static constexpr size_t channel_decimation = 2;
static constexpr float channel_sample_rate = channel_rate_in / channel_decimation;
OOKSlicerMagSquaredInt ook_slicer_5sps { channel_sample_rate / 8400 + 1};
uint32_t slicer_history { 0 };

View File

@ -29,7 +29,7 @@ enable_language(C CXX ASM)
project(bootstrap)
# Compiler options here.
set(USE_OPT "-Os -falign-functions=16 -fno-math-errno --specs=nano.specs")
set(USE_OPT "-Os -g -falign-functions=16 -fno-math-errno --specs=nano.specs")
# C specific options here (added to USE_OPT).
set(USE_COPT "-std=gnu99")

View File

@ -71,9 +71,11 @@ public:
AFSKConfigure = 23,
PWMRSSIConfigure = 24,
OOKConfigure = 25,
RDSConfigure = 26,
AudioTXConfig = 27,
FIFOSignal = 26,
FIFOData = 27,
FIFOSignal = 28,
FIFOData = 29,
MAX
};
@ -516,6 +518,18 @@ public:
const uint16_t tone_count;
};
class RDSConfigureMessage : public Message {
public:
constexpr RDSConfigureMessage(
const uint32_t length
) : Message { ID::RDSConfigure },
length(length)
{
}
const uint32_t length = 0;
};
class RetuneMessage : public Message {
public:
constexpr RetuneMessage(
@ -528,6 +542,18 @@ public:
const int64_t freq = 0;
};
class AudioTXConfigMessage : public Message {
public:
constexpr AudioTXConfigMessage(
const uint32_t bw
) : Message { ID::AudioTXConfig },
bw(bw)
{
}
const uint32_t bw;
};
class AFSKConfigureMessage : public Message {
public:
constexpr AFSKConfigureMessage(
@ -576,6 +602,7 @@ public:
const uint32_t pause_symbols;
};
// TODO: use streaming buffer instead
class FIFOSignalMessage : public Message {
public:
constexpr FIFOSignalMessage(
@ -583,7 +610,7 @@ public:
{
}
const char signaltype = 0;
char signaltype = 0;
};
class FIFODataMessage : public Message {

View File

@ -36,7 +36,7 @@ using portapack::memory::map::backup_ram;
namespace portapack {
namespace persistent_memory {
constexpr rf::Frequency tuned_frequency_reset_value { 88000000 };
constexpr rf::Frequency tuned_frequency_reset_value { 100000000 };
using ppb_range_t = range_t<ppb_t>;
constexpr ppb_range_t ppb_range { -99000, 99000 };
@ -57,9 +57,11 @@ constexpr int32_t afsk_bw_reset_value { 15 };
/* struct must pack the same way on M4 and M0 cores. */
struct data_t {
// General config
int64_t tuned_frequency;
int32_t correction_ppb;
uint32_t touch_calibration_magic;
touch::Calibration touch_calibration;
// AFSK modem
int32_t afsk_mark_freq;
@ -99,6 +101,20 @@ void set_correction_ppb(const ppb_t new_value) {
portapack::clock_manager.set_reference_ppb(clipped_value);
}
static constexpr uint32_t touch_calibration_magic = 0x074af82f;
void set_touch_calibration(const touch::Calibration& new_value) {
data->touch_calibration = new_value;
data->touch_calibration_magic = touch_calibration_magic;
}
const touch::Calibration& touch_calibration() {
if( data->touch_calibration_magic != touch_calibration_magic ) {
set_touch_calibration(touch::default_calibration());
}
return data->touch_calibration;
}
int32_t afsk_mark_freq() {
afsk_freq_range.reset_if_outside(data->afsk_mark_freq, afsk_mark_reset_value);
return data->afsk_mark_freq;

View File

@ -25,6 +25,7 @@
#include <cstdint>
#include "rf_path.hpp"
#include "touch.hpp"
namespace portapack {
namespace persistent_memory {
@ -37,6 +38,9 @@ void set_tuned_frequency(const rf::Frequency new_value);
ppb_t correction_ppb();
void set_correction_ppb(const ppb_t new_value);
void set_touch_calibration(const touch::Calibration& new_value);
const touch::Calibration& touch_calibration();
int32_t afsk_mark_freq();
void set_afsk_mark(const int32_t new_value);

View File

@ -75,7 +75,6 @@ constexpr image_tag_t image_tag_jammer { 'P', 'J', 'A', 'M' };
constexpr image_tag_t image_tag_audio_tx { 'P', 'A', 'T', 'X' };
constexpr image_tag_t image_tag_afsk { 'P', 'A', 'F', 'S' };
constexpr image_tag_t image_tag_epar { 'P', 'E', 'P', 'R' };
constexpr image_tag_t image_tag_play_audio { 'P', 'P', 'A', 'U' };
constexpr image_tag_t image_tag_xylos { 'P', 'X', 'Y', 'L' };
constexpr image_tag_t image_tag_rds { 'P', 'R', 'D', 'S' };
constexpr image_tag_t image_tag_ook { 'P', 'O', 'O', 'K' };

Binary file not shown.