Fixed LCR and Xylos transmitters

This commit is contained in:
furrtek 2016-05-09 20:42:20 +02:00
parent d55a420dfd
commit d40016ffda
39 changed files with 1614 additions and 151 deletions

View File

@ -64,7 +64,7 @@ modules: $(TARGET_BASEBAND).bin $(TARGET_BASEBAND_TX).bin
cp $(PATH_BASEBAND).bin ../sdcard/$(PATH_BASEBAND).bin cp $(PATH_BASEBAND).bin ../sdcard/$(PATH_BASEBAND).bin
cp $(PATH_BASEBAND_TX).bin ../sdcard/$(PATH_BASEBAND_TX).bin cp $(PATH_BASEBAND_TX).bin ../sdcard/$(PATH_BASEBAND_TX).bin
$(TARGET).bin: modules $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND)_inc.bin $(TARGET_APPLICATION).bin $(TARGET).bin: modules $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND_TX)_inc.bin $(TARGET_APPLICATION).bin
$(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND)_inc.bin $(TARGET_APPLICATION).bin $(TARGET).bin $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND)_inc.bin $(TARGET_APPLICATION).bin $(TARGET).bin
$(TARGET_BOOTSTRAP).bin: $(TARGET_BOOTSTRAP).elf $(TARGET_BOOTSTRAP).bin: $(TARGET_BOOTSTRAP).elf

View File

@ -151,6 +151,7 @@ CPPSRC = main.cpp \
lcd_ili9341.cpp \ lcd_ili9341.cpp \
ui.cpp \ ui.cpp \
ui_alphanum.cpp \ ui_alphanum.cpp \
ui_handwrite.cpp \
ui_about.cpp \ ui_about.cpp \
ui_text.cpp \ ui_text.cpp \
ui_widget.cpp \ ui_widget.cpp \
@ -162,6 +163,7 @@ CPPSRC = main.cpp \
ui_channel.cpp \ ui_channel.cpp \
ui_audio.cpp \ ui_audio.cpp \
ui_audiotx.cpp \ ui_audiotx.cpp \
ui_soundboard.cpp \
ui_lcr.cpp \ ui_lcr.cpp \
ui_rds.cpp \ ui_rds.cpp \
ui_jammer.cpp \ ui_jammer.cpp \

View File

@ -180,12 +180,12 @@ private:
static constexpr size_t touch_count_threshold { 4 }; static constexpr size_t touch_count_threshold { 4 };
static constexpr uint32_t touch_stable_bound { 4 }; static constexpr uint32_t touch_stable_bound { 4 };
static constexpr float calib_x_low = 0.07f; static constexpr float calib_x_low = 0.15f;
static constexpr float calib_x_high = 0.94f; static constexpr float calib_x_high = 0.98f;
static constexpr float calib_x_range = calib_x_high - calib_x_low; 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_low = 0.04f;
static constexpr float calib_y_high = 0.91f; static constexpr float calib_y_high = 0.80f; //91
static constexpr float calib_y_range = calib_y_high - calib_y_low; static constexpr float calib_y_range = calib_y_high - calib_y_low;
// Ensure filter length is equal or less than touch_count_threshold, // Ensure filter length is equal or less than touch_count_threshold,

View File

@ -40,7 +40,6 @@ public:
AudioTXView(NavigationView& nav); AudioTXView(NavigationView& nav);
~AudioTXView(); ~AudioTXView();
void focus() override; void focus() override;
private: private:

View File

@ -0,0 +1,404 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_handwrite.hpp"
#include "ch.h"
#include "ff.h"
#include "portapack.hpp"
#include "event_m0.hpp"
#include "string_format.hpp"
#include "hackrf_hal.hpp"
#include "portapack_shared_memory.hpp"
#include "time.hpp"
#include <cstring>
using namespace portapack;
namespace ui {
HandWriteView::~HandWriteView() {
time::signal_tick_second -= signal_token_tick_second;
}
HandWriteView::HandWriteView(
NavigationView& nav,
char txt[],
uint8_t max_len
) {
_max_len = max_len;
_lowercase = false;
txtidx = 0;
//memcpy(txtinput, txt, max_len+1);
add_child(&text_input);
const auto button_fn = [this](Button& button) {
this->on_button(button);
};
size_t n = 0;
for(auto& button : num_buttons) {
add_child(&button);
button.on_select = button_fn;
button.set_parent_rect({
static_cast<Coord>(n * 24),
static_cast<Coord>(240),
24, 20
});
const std::string label {
n + 0x30
};
button.set_text(label);
button.id = n;
n++;
}
//set_uppercase();
/*add_child(&button_lowercase);
button_lowercase.on_select = [this, &nav, txt, max_len](Button&) {
if (_lowercase == true) {
_lowercase = false;
button_lowercase.set_text("UC");
set_uppercase();
} else {
_lowercase = true;
button_lowercase.set_text("LC");
set_lowercase();
}
};*/
add_child(&text_debug_x);
add_child(&text_debug_y);
add_child(&text_debug_write);
add_child(&button_done);
button_done.on_select = [this, &nav, txt, max_len](Button&) {
//memcpy(txt, txtinput, max_len+1);
//on_changed(this->value());
nav.pop();
};
signal_token_tick_second = time::signal_tick_second += [this]() {
this->on_tick_second();
};
//update_text();
}
bool HandWriteView::MM(uint8_t idx, char cmp) {
if (idx < move_index) {
if ((cmp == 'U') && ((move_list[idx] & 0xF0) == 0x00)) return true;
if ((cmp == 'D') && ((move_list[idx] & 0xF0) == 0x10)) return true;
if ((cmp == 'L') && ((move_list[idx] & 0x0F) == 0x00)) return true;
if ((cmp == 'R') && ((move_list[idx] & 0x0F) == 0x01)) return true;
}
return false;
}
bool HandWriteView::MM(uint8_t idx, char cmpud, char cmplr) {
if (idx < move_index) {
if (cmpud == 'U') cmpud = 0;
if (cmpud == 'D') cmpud = 1;
if (cmpud == '?') cmpud = 2;
if (cmplr == 'L') cmplr = 0;
if (cmplr == 'R') cmplr = 1;
if (cmplr == '?') cmplr = 2;
if (((move_list[idx] >> 4) == cmpud) && ((move_list[idx] & 0x0F) == cmplr)) return true;
}
return false;
}
bool HandWriteView::MI(uint8_t idx) {
if (move_index - 1 < idx)
return true;
else
return false;
}
bool HandWriteView::MLAST(char cmp) {
if ((cmp == 'U') && ((move_list[move_index - 1] & 0xF0) == 0x00)) return true;
if ((cmp == 'D') && ((move_list[move_index - 1] & 0xF0) == 0x10)) return true;
if ((cmp == 'L') && ((move_list[move_index - 1] & 0x0F) == 0x00)) return true;
if ((cmp == 'R') && ((move_list[move_index - 1] & 0x0F) == 0x01)) return true;
return false;
}
bool HandWriteView::on_touch(const TouchEvent event) {
char guess;
if (event.type == ui::TouchEvent::Type::Start) {
move_index = 0;
move_wait = 4;
tracing = true;
}
if (event.type == ui::TouchEvent::Type::End) {
tracing = false;
display.fill_rectangle(
{{0, 16}, {240, 230}},
Color::black()
);
// Letter guessing
guess = '?';
if (MM(0, 'U')) {
if (MM(0, 'U', '?')) {
if (MI(1))
guess = 'A';
else
guess = 'F';
} else if (MM(0, 'U', 'R')) {
if (MI(1)) {
guess = 'K';
} else {
if (MM(1, 'L')) {
if (txt_idx > 0) txtinput[txt_idx--] = 0; // Erase
} else {
guess = 'N';
}
}
} else if (MM(0, 'U', 'L')) {
if (MM(1, 'U', 'R')) guess = 'C';
if (MM(1, 'D', 'L')) guess = 'M';
}
} else if (MM(0, 'D')) {
if (MM(0, 'D', 'R') || MM(1, 'R'))
guess = 'P';
else
guess = 'Q';
if (MM(0, 'D', '?')) {
if (MI(1)) {
guess = 'I';
} else {
if (MM(1, 'R') && MI(2)) {
guess = 'L';
} else if (MM(1, 'L')) {
if (MI(2)) guess = 'J';
} else if (MM(1, 'U', 'R')) {
if (MM(2, 'D')) guess = 'W';
}
}
}
if (MM(0, 'D', 'R')) {
if (MI(1)) guess = 'R';
if (MM(1, 'U', 'R') && MI(2)) guess = 'V';
if (MM(1, 'D', 'L')) guess = 'B';
} else if (MM(0, 'D', 'L')) {
if (MI(1)) guess = 'Y';
if (MM(1, 'U', 'L') && MI(2)) guess = 'U';
if (MM(1, 'D', 'R')) guess = 'D';
}
}
if (MM(0, 'L')) {
if (!MI(2) && (MLAST('U') || MLAST('L'))) guess = 'O';
if (MM(0, '?', 'L')) {
if (MI(1))
guess = 'E';
else
guess = 'S';
}
} else if (MM(0, 'R')) {
if (!MI(2) && (MLAST('U') || MLAST('R'))) guess = 'X';
if (MM(0, '?', 'R')) {
if (MM(1, 'U') && MI(2)) {
guess = 'G';
} else if (MM(1, 'D', '?') && MI(2)) {
guess = 'H';
} else if (MM(1, 'L')) {
guess = 'Z';
} else if (MI(1)) {
guess = 'T';
}
}
}
// if (guess = '?') guess = ' ';
if (guess != '!') txtinput[txt_idx++] = guess;
update_text();
}
if (event.type == ui::TouchEvent::Type::Move) {
if (tracing) {
current_pos = event.point;
}
}
return true;
}
void HandWriteView::sample_pen() {
int16_t diff_x, diff_y;
uint8_t dir, i;
if (!(sample_skip & 1)) {
if (tracing) {
if (move_wait) {
move_wait--; // ~133ms delay
} else {
diff_x = current_pos.x - last_pos.x;
diff_y = current_pos.y - last_pos.y;
text_debug_x.set(to_string_dec_int(diff_x));
text_debug_y.set(to_string_dec_int(diff_y));
display.fill_rectangle(
{{current_pos.x, current_pos.y}, {4, 4}},
Color::grey()
);
dir = 0;
if (abs(diff_x) > 7) {
if (diff_x > 0)
dir |= 0x01; // R
} else {
dir |= 0x02; // ?
}
if (abs(diff_y) > 7) {
if (diff_y > 0)
dir |= 0x10; // D
} else {
dir |= 0x20; // ?
}
if ((dir & 0x11) == (dir_prev & 0x11))
dir_cnt++;
else
dir_cnt = 0;
dir_prev = dir;
// text_debug_d.set(to_string_dec_uint(dir));
if (dir_cnt > 1) {
dir_cnt = 0;
if (move_index) {
if ((move_list[move_index - 1] != dir) && (dir != 0x22)) {
if ((dir & 0xF0) == 0x20) {
if ((move_list[move_index - 1] & 0x0F) != (dir & 0x0F)) {
move_list[move_index] = dir;
move_index++;
}
} else if ((dir & 0x0F) == 0x02) {
if ((move_list[move_index - 1] & 0xF0) != (dir & 0xF0)) {
move_list[move_index] = dir;
move_index++;
}
} else {
// Replacement ?
if (((move_list[move_index - 1] & 0xF0) == 0x20) && ((dir & 0xF0) != 0x20)) {
if ((move_list[move_index - 1] & 0x0F) == (dir & 0x0F)) {
move_list[move_index - 1] = dir;
} else if ((dir & 0x0F) == 0x02) {
// Merge
move_list[move_index - 1] = (dir & 0xF0) | (move_list[move_index - 1] & 0x0F);
} else {
move_list[move_index] = dir;
move_index++;
}
} else if (((move_list[move_index - 1] & 0x0F) == 0x02) && ((dir & 0x0F) != 0x02)) {
if ((move_list[move_index - 1] & 0xF0) == (dir & 0xF0)) {
move_list[move_index - 1] = dir;
} else if ((dir & 0xF0) == 0x20) {
// Merge
move_list[move_index - 1] = (dir & 0x0F) | (move_list[move_index - 1] & 0xF0);
} else {
move_list[move_index] = dir;
move_index++;
}
} else {
move_list[move_index] = dir;
move_index++;
}
}
}
} else {
if (dir != 0x22) {
move_list[move_index] = dir;
move_index++;
}
}
// DEBUG
/*if (move_index) {
memset(txtinput, 0, 20);
txtidx = 0;
for (i = 0; i < move_index; i++) {
if ((move_list[i] & 0x03) == 0) char_add('L');
if ((move_list[i] & 0x03) == 1) char_add('R');
if ((move_list[i] & 0x03) == 2) char_add('?');
if ((move_list[i] >> 4) == 0) char_add('U');
if ((move_list[i] >> 4) == 1) char_add('D');
if ((move_list[i] >> 4) == 2) char_add('?');
char_add(' ');
}
update_text();
}*/
}
}
last_pos = current_pos;
}
}
sample_skip++;
}
void HandWriteView::on_show() {
// Use screen refresh rate as sampling frequency
EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync);
EventDispatcher::message_map().register_handler(Message::ID::DisplayFrameSync,
[this](const Message* const) {
sample_pen();
}
);
}
char * HandWriteView::value() {
return txtinput;
}
void HandWriteView::on_button(Button& button) {
char_add(button.id + 0x30);
update_text();
}
void HandWriteView::char_add(const char c) {
if (txtidx < _max_len) {
txtinput[txtidx] = c;
txtidx++;
}
}
void HandWriteView::char_delete() {
if (txtidx) {
txtidx--;
txtinput[txtidx] = ' ';
}
}
void HandWriteView::update_text() {
text_input.set(txtinput);
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_painter.hpp"
#include "ui_menu.hpp"
#include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "clock_manager.hpp"
#include "message.hpp"
#include "signal.hpp"
namespace ui {
class HandWriteView : public View {
public:
std::function<void(char *)> on_changed;
HandWriteView(NavigationView& nav, char txt[], uint8_t max_len);
~HandWriteView();
void on_show() override;
bool on_touch(const TouchEvent event) override;
char * value();
uint8_t txtidx;
void char_add(const char c);
void char_delete();
private:
SignalToken signal_token_tick_second;
uint8_t _max_len, txt_idx = 0;
uint8_t dir_cnt = 0;
uint8_t dir_prev;
bool tracing = false;
uint8_t move_index;
uint8_t sample_skip, move_wait;
uint8_t move_list[32]; // TODO: Cap !
Point start_pos, current_pos, last_pos;
bool _lowercase = false;
static constexpr size_t button_w = 240 / 5;
static constexpr size_t button_h = 28;
char txtinput[21] = {0}; // DEBUG
bool MM(uint8_t idx, char cmp);
bool MM(uint8_t idx, char cmpud, char cmplr);
bool MI(uint8_t idx);
bool MLAST(char cmp);
void sample_pen();
Text text_input {
{ 0, 0, 240, 16 }
};
Text text_debug_x {
{ 0, 16, 32, 16 }
};
Text text_debug_y {
{ 0, 32, 32, 16 }
};
Text text_debug_write {
{ 80, 24, 150, 16 }
};
std::array<Button, 10> num_buttons;
Button button_lowercase {
{ 88+64+16, 270, 32, 24 },
"UC"
};
Button button_done {
{ 88, 270, 64, 24 },
"Done"
};
void on_button(Button& button);
void update_text();
};
} /* namespace ui */

View File

@ -78,6 +78,10 @@ void LCRView::make_frame() {
lcrframe[5] = 127; lcrframe[5] = 127;
lcrframe[6] = 127; lcrframe[6] = 127;
lcrframe[7] = 15; // SOM lcrframe[7] = 15; // SOM
strcpy(rgsb, RGSB_list[adr_code.value()]);
button_setrgsb.set_text(rgsb);
strcat(lcrframe, rgsb); strcat(lcrframe, rgsb);
strcat(lcrframe, "PA "); strcat(lcrframe, "PA ");
if (checkbox_am_a.value() == true) { if (checkbox_am_a.value() == true) {
@ -191,7 +195,7 @@ LCRView::LCRView(
}; };
transmitter_model.set_baseband_configuration({ transmitter_model.set_baseband_configuration({
.mode = 1, .mode = 3,
.sampling_rate = 2280000, // Is this right ? .sampling_rate = 2280000, // Is this right ?
.decimation_factor = 1, .decimation_factor = 1,
}); });
@ -200,11 +204,12 @@ LCRView::LCRView(
memset(litteral, 0, 5*8); memset(litteral, 0, 5*8);
memset(rgsb, 0, 5); memset(rgsb, 0, 5);
strcpy(rgsb, RGSB_list[29]); strcpy(rgsb, RGSB_list[adr_code.value()]);
button_setrgsb.set_text(rgsb); button_setrgsb.set_text(rgsb);
add_children({ { add_children({ {
&text_recap, &text_recap,
&adr_code,
&button_setrgsb, &button_setrgsb,
&button_txsetup, &button_txsetup,
&checkbox_am_a, &checkbox_am_a,
@ -290,7 +295,9 @@ LCRView::LCRView(
memcpy(shared_memory.lcrdata, lcrframe_f, 256); memcpy(shared_memory.lcrdata, lcrframe_f, 256);
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 = 5; //(portapack::persistent_memory::afsk_config() >> 8) & 0xFF;
EventDispatcher::message_map().unregister_handler(Message::ID::TXDone);
EventDispatcher::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) {
@ -316,7 +323,49 @@ LCRView::LCRView(
transmitter_model.enable(); transmitter_model.enable();
}; };
/*
button_transmit_scan.on_select() = [this,&transmitter_model](Button&){
make_frame();
shared_memory.afsk_samples_per_bit = 228000/portapack::persistent_memory::afsk_bitrate();
shared_memory.afsk_phase_inc_mark = portapack::persistent_memory::afsk_mark_freq()*(0x40000*256)/2280;
shared_memory.afsk_phase_inc_space = portapack::persistent_memory::afsk_space_freq()*(0x40000*256)/2280;
shared_memory.afsk_fmmod = portapack::persistent_memory::afsk_bw() * 8;
memset(shared_memory.lcrdata, 0, 256);
memcpy(shared_memory.lcrdata, lcrframe_f, 256);
shared_memory.afsk_transmit_done = false;
shared_memory.afsk_repeat = 5; //(portapack::persistent_memory::afsk_config() >> 8) & 0xFF;
EventDispatcher::message_map().unregister_handler(Message::ID::TXDone);
EventDispatcher::message_map().register_handler(Message::ID::TXDone,
[this,&transmitter_model](Message* const p) {
char str[8];
const auto message = static_cast<const TXDoneMessage*>(p);
if (message->n > 0) {
text_status.set(" ");
strcpy(str, to_string_dec_int(message->n).c_str());
strcat(str, "/");
strcat(str, to_string_dec_int((portapack::persistent_memory::afsk_config() >> 8) & 0xFF).c_str());
text_status.set(str);
} else {
text_status.set("Done ! ");
transmitter_model.disable();
}
}
);
char str[8];
strcpy(str, "0/");
strcat(str, to_string_dec_int(shared_memory.afsk_repeat).c_str());
text_status.set(str);
transmitter_model.enable();
};
*/
button_txsetup.on_select = [&nav](Button&){ button_txsetup.on_select = [&nav](Button&){
nav.push<AFSKSetupView>(); nav.push<AFSKSetupView>();
}; };

View File

@ -44,6 +44,7 @@ public:
void paint(Painter& painter) override; void paint(Painter& painter) override;
private: private:
uint8_t adri = 22;
const char RGSB_list[37][5] = { const char RGSB_list[37][5] = {
"EAA0", "EAB0", "EAC0", "EAD0", "EAA0", "EAB0", "EAC0", "EAD0",
"EbA0", "EbB0", "EbC0", "EbD0", "EbA0", "EbB0", "EbC0", "EbD0",
@ -70,10 +71,18 @@ private:
}; };
Text text_recap { Text text_recap {
{ 32, 6, 192, 16 }, { 8, 6, 18 * 8, 16 },
"-" "-"
}; };
NumberField adr_code {
{ 220, 6 },
2,
{ 0, 36 },
1,
'0'
};
Button button_setrgsb { Button button_setrgsb {
{ 16, 24, 96, 32 }, { 16, 24, 96, 32 },
"Set RGSB" "Set RGSB"

View File

@ -35,8 +35,10 @@
#include "ui_rds.hpp" #include "ui_rds.hpp"
#include "ui_xylos.hpp" #include "ui_xylos.hpp"
#include "ui_lcr.hpp" #include "ui_lcr.hpp"
#include "ui_audiotx.hpp" #include "analog_audio_app.hpp"
#include "ui_soundboard.hpp"
#include "ui_debug.hpp" #include "ui_debug.hpp"
#include "ui_audiotx.hpp"
#include <cstring> #include <cstring>
#include <stdio.h> #include <stdio.h>
@ -150,9 +152,12 @@ void LoadModuleView::loadmodule() {
LoadModuleView::LoadModuleView( LoadModuleView::LoadModuleView(
NavigationView& nav, NavigationView& nav,
const char * hash, const char * hash,
uint8_t ViewID uint8_t ViewID,
bool loadplz
) )
{ {
if (loadplz == false) nav.pop(); // Useless, remove !
add_children({ { add_children({ {
&text_info, &text_info,
&text_infob, &text_infob,
@ -163,10 +168,11 @@ LoadModuleView::LoadModuleView(
button_ok.on_select = [this, &nav, ViewID](Button&){ button_ok.on_select = [this, &nav, ViewID](Button&){
if (_mod_loaded == true) { if (_mod_loaded == true) {
if (ViewID == 0) nav.push<RDSView>(); if (ViewID == 0) nav.push<AudioTXView>(); //nav.push<RDSView>();
if (ViewID == 1) nav.push<XylosView>(); if (ViewID == 1) nav.push<XylosView>();
if (ViewID == 2) nav.push<LCRView>(); if (ViewID == 2) nav.push<LCRView>();
if (ViewID == 3) nav.push<AudioTXView>(); if (ViewID == 3) nav.push<SoundBoardView>();
if (ViewID == 10) nav.push<AnalogAudioView>();
} else { } else {
nav.pop(); nav.pop();
} }

View File

@ -32,7 +32,7 @@ namespace ui {
class LoadModuleView : public View { class LoadModuleView : public View {
public: public:
LoadModuleView(NavigationView& nav, const char * hash, uint8_t ViewID); LoadModuleView(NavigationView& nav, const char * hash, uint8_t ViewID, bool loadplz);
void loadmodule(); void loadmodule();
void on_show() override; void on_show() override;

View File

@ -53,7 +53,7 @@ void MenuItemView::paint(Painter& painter) {
paint_style.background paint_style.background
); );
ui::Color final_item_color = item.color; ui::Color final_item_color = (highlighted() && parent()->has_focus()) ? ui::Color::black() : item.color;
if (final_item_color.v == paint_style.background.v) final_item_color = paint_style.foreground; if (final_item_color.v == paint_style.background.v) final_item_color = paint_style.foreground;

View File

@ -33,6 +33,9 @@
#include "ui_setup.hpp" #include "ui_setup.hpp"
#include "ui_debug.hpp" #include "ui_debug.hpp"
#include "ui_handwrite.hpp" // DEBUG
#include "ui_soundboard.hpp" // DEBUG
#include "analog_audio_app.hpp" #include "analog_audio_app.hpp"
#include "ais_app.hpp" #include "ais_app.hpp"
#include "ert_app.hpp" #include "ert_app.hpp"
@ -155,7 +158,7 @@ void NavigationView::focus() {
} }
} }
/* TransceiversMenuView **************************************************/ /* TranspondersMenuView **************************************************/
TranspondersMenuView::TranspondersMenuView(NavigationView& nav) { TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
add_items<3>({ { add_items<3>({ {
@ -170,7 +173,9 @@ TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
add_items<2>({ { add_items<2>({ {
{ "Audio", ui::Color::white(), [&nav](){ nav.push<AnalogAudioView>(); } }, { "Audio", ui::Color::white(), [&nav](){ nav.push<LoadModuleView>(md5_baseband, 10, true); } },
//{ "Audio", ui::Color::white(), [&nav](){ nav.push<AnalogAudioView>(); } },
{ "Transponders", ui::Color::white(), [&nav](){ nav.push<TranspondersMenuView>(); } }, { "Transponders", ui::Color::white(), [&nav](){ nav.push<TranspondersMenuView>(); } },
} }); } });
on_left = [&nav](){ nav.pop(); }; on_left = [&nav](){ nav.pop(); };
@ -180,18 +185,18 @@ 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<PlayDeadView>(false); } }, { "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } },
{ "Receiver", ui::Color::cyan(), [&nav](){ nav.push<ReceiverMenuView>(); } }, { "Receiver RX", ui::Color::cyan(), [&nav](){ nav.push<ReceiverMenuView>(); } },
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 0); } }, { "Soundboard TX", ui::Color::orange(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 3, true); } },
{ "Xylos TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 1); } }, { "Audio TX TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 0, true); } },
{ "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 2); } }, { "Xylos TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 1, true); } },
{ "Audio TX", ui::Color::orange(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 3); } }, { "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 2, true); } },
//{ "Capture", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } }, //{ "Capture", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
//{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } }, //{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } }, { "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } }, { "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } },
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } }, { "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
{ "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } }, { "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } },
} }); } });
/* /*
@ -224,6 +229,7 @@ SystemView::SystemView(
set_style(&style_default); set_style(&style_default);
constexpr ui::Dim status_view_height = 16; constexpr ui::Dim status_view_height = 16;
char debugtxt[21] = {0};
add_child(&status_view); add_child(&status_view);
status_view.set_parent_rect({ status_view.set_parent_rect({
@ -255,7 +261,9 @@ SystemView::SystemView(
if (portapack::persistent_memory::ui_config() & 1) if (portapack::persistent_memory::ui_config() & 1)
navigation_view.push<BMPView>(); navigation_view.push<BMPView>();
else else
navigation_view.push<SystemMenuView>(); //navigation_view.push<SoundBoardView>();
//navigation_view.push<SystemMenuView>();
navigation_view.push<HandWriteView>(debugtxt, 20);
} }
Context& SystemView::context() const { Context& SystemView::context() const {

View File

@ -0,0 +1,145 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_soundboard.hpp"
#include "ch.h"
#include "ui_alphanum.hpp"
#include "ff.h"
#include "hackrf_gpio.hpp"
#include "portapack.hpp"
#include "radio.hpp"
#include "event_m0.hpp"
#include "string_format.hpp"
#include "hackrf_hal.hpp"
#include "portapack_shared_memory.hpp"
#include <cstring>
using namespace portapack;
namespace ui {
void SoundBoardView::on_show() {
/*
// Just in case
EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync);
// "Vertical blank interrupt"
EventDispatcher::message_map().register_handler(Message::ID::DisplayFrameSync,
[this](const Message* const) {
pbar_test.set_value(testv/4);
testv++;
}
);*/
}
std::string SoundBoardView::title() const {
return "Sound board";
};
void SoundBoardView::focus() {
buttons[0].focus();
}
void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
}
void SoundBoardView::on_button(Button& button) {
text_test.set(to_string_dec_uint(button.id));
}
SoundBoardView::SoundBoardView(
NavigationView& nav
)
{
size_t n;
for (n = 0; n < 12; n++) {
sounds[n].filename = "";
sounds[n].shortname = "Empty";
sounds[n].min = 0;
sounds[n].sec = 0;
}
add_children({ {
&text_test,
&field_frequency,
&number_bw,
&pbar_test,
&button_load,
&button_exit
} });
const auto button_fn = [this](Button& button) {
this->on_button(button);
};
for(auto& button : buttons) {
add_child(&button);
button.id = n;
button.on_select = button_fn;
button.set_parent_rect({
static_cast<Coord>((n % 3) * 70 + 15),
static_cast<Coord>((n / 3) * 50 + 30),
70, 50
});
button.set_text(sounds[n].shortname);
n++;
}
field_frequency.set_value(transmitter_model.tuning_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_change = [this](rf::Frequency f) {
this->on_tuning_frequency_changed(f);
};
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->on_tuning_frequency_changed(f);
this->field_frequency.set_value(f);
};
};
/*button_transmit.on_select = [](Button&){
transmitter_model.set_baseband_configuration({
.mode = 1,
.sampling_rate = 1536000,
.decimation_factor = 1,
});
transmitter_model.set_rf_amp(true);
transmitter_model.enable();
};*/
button_exit.on_select = [&nav](Button&){
nav.pop();
};
}
SoundBoardView::~SoundBoardView() {
transmitter_model.disable();
}
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_painter.hpp"
#include "ui_menu.hpp"
#include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "clock_manager.hpp"
#include "message.hpp"
#include "rf_path.hpp"
#include "max2837.hpp"
#include "volume.hpp"
#include "ui_receiver.hpp"
#include "transmitter_model.hpp"
namespace ui {
class SoundBoardView : public View {
public:
SoundBoardView(NavigationView& nav);
~SoundBoardView();
std::string title() const;
void on_show() override;
void focus() override;
private:
struct sound {
std::string filename;
std::string shortname;
uint8_t min;
uint8_t sec;
};
sound sounds[12];
std::array<Button, 12> buttons;
void on_button(Button& button);
void on_tuning_frequency_changed(rf::Frequency f);
Text text_test {
{ 120, 4, 64, 16 }
};
FrequencyField field_frequency {
{ 1 * 8, 4 },
};
NumberField number_bw {
{ 16 * 8, 4 },
5,
{1000, 50000},
500,
' '
};
ProgressBar pbar_test {
{ 45, 236, 150, 16 }
};
Button button_load {
{ 8, 270, 64, 32 },
"Load"
};
Button button_exit {
{ 96, 270, 64, 32 },
"Exit"
};
};
} /* namespace ui */

View File

@ -135,10 +135,10 @@ void XylosView::paint(Painter& painter) {
void XylosView::upd_message() { void XylosView::upd_message() {
uint8_t c; uint8_t c;
ccirmessage[0] = '0'; ccirmessage[0] = (header_code_a.value() / 10) + 0x30;
ccirmessage[1] = '0'; ccirmessage[1] = (header_code_a.value() % 10) + 0x30;
ccirmessage[2] = '0'; ccirmessage[2] = (header_code_b.value() / 10) + 0x30;
ccirmessage[3] = '0'; ccirmessage[3] = (header_code_b.value() % 10) + 0x30;
ccirmessage[4] = (city_code.value() / 10) + 0x30; ccirmessage[4] = (city_code.value() / 10) + 0x30;
ccirmessage[5] = (city_code.value() % 10) + 0x30; ccirmessage[5] = (city_code.value() % 10) + 0x30;
@ -228,7 +228,7 @@ XylosView::XylosView(
}; };
transmitter_model.set_baseband_configuration({ transmitter_model.set_baseband_configuration({
.mode = 4, .mode = 2,
.sampling_rate = 1536000, .sampling_rate = 1536000,
.decimation_factor = 1, .decimation_factor = 1,
}); });
@ -236,6 +236,9 @@ XylosView::XylosView(
add_children({ { add_children({ {
&text_title, &text_title,
&button_txtest, &button_txtest,
&text_header,
&header_code_a,
&header_code_b,
&text_city, &text_city,
&city_code, &city_code,
&text_family, &text_family,
@ -265,11 +268,21 @@ XylosView::XylosView(
family_code.set_value(1); family_code.set_value(1);
subfamily_code.set_value(1); subfamily_code.set_value(1);
receiver_code.set_value(1); receiver_code.set_value(1);
header_code_a.set_value(0);
header_code_b.set_value(0);
options_freq.set_selected_index(5); options_freq.set_selected_index(5);
checkbox_wcsubfamily.set_value(true); checkbox_wcsubfamily.set_value(true);
checkbox_wcid.set_value(true); checkbox_wcid.set_value(true);
header_code_a.on_change = [this](int32_t v) {
(void)v;
XylosView::upd_message();
};
header_code_b.on_change = [this](int32_t v) {
(void)v;
XylosView::upd_message();
};
city_code.on_change = [this](int32_t v) { city_code.on_change = [this](int32_t v) {
(void)v; (void)v;
XylosView::upd_message(); XylosView::upd_message();

View File

@ -41,8 +41,6 @@ namespace ui {
#define XYLOS_VOICE_RELAYS 21 #define XYLOS_VOICE_RELAYS 21
#define XYLOS_VOICE_TRAILER 25 #define XYLOS_VOICE_TRAILER 25
void do_something();
class XylosRXView : public View { class XylosRXView : public View {
public: public:
XylosRXView(NavigationView& nav); XylosRXView(NavigationView& nav);
@ -152,47 +150,38 @@ public:
private: private:
bool txing = false; bool txing = false;
const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 }; const rf::Frequency xylos_freqs[7] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000, 88000000 };
uint8_t xylos_voice_phrase[32] = { 0xFF };
const char * xylos_voice_filenames[26] = { "zero.wav",
"one.wav",
"two.wav",
"three.wav",
"four.wav",
"five.wav",
"six.wav",
"seven.wav",
"eight.wav",
"nine.wav",
"a.wav",
"b.wav",
"c.wav",
"d.wav",
"e.wav",
"f.wav",
"header.wav",
"city.wav",
"family.wav",
"subfamily.wav",
"address.wav",
"relays.wav",
"ignored.wav",
"off.wav",
"on.wav",
"trailer.wav"
};
char ccirmessage[21]; char ccirmessage[21];
char ccir_received[21]; char ccir_received[21];
Text text_title { Text text_title {
{ 1 * 8, 1 * 16, 11, 16 }, { 8, 8, 11, 16 },
"BH Xylos TX" "BH Xylos TX"
}; };
Button button_txtest { Button button_txtest {
{ 170, 1 * 16, 40, 24 }, { 180, 8, 40, 24 },
"TEST" "TEST"
}; };
Text text_header {
{ 8 * 8, 2 * 16, 7 * 8, 16 },
"Header:"
};
NumberField header_code_a {
{ 16 * 8, 2 * 16 },
2,
{ 0, 99 },
1,
'0'
};
NumberField header_code_b {
{ 18 * 8, 2 * 16 },
2,
{ 0, 99 },
1,
'0'
};
Text text_city { Text text_city {
{ 4 * 8, 3 * 16, 11 * 8, 16 }, { 4 * 8, 3 * 16, 11 * 8, 16 },
"Code ville:" "Code ville:"
@ -256,7 +245,7 @@ private:
"Frequence:" "Frequence:"
}; };
OptionsField options_freq { OptionsField options_freq {
{ 16 * 8, 9 * 16 }, { 16 * 8, 9 * 16 + 4},
7, 7,
{ {
{ "31.3250", 0 }, { "31.3250", 0 },

Binary file not shown.

View File

@ -140,6 +140,8 @@ CPPSRC = main.cpp \
matched_filter.cpp \ matched_filter.cpp \
proc_audiotx.cpp \ proc_audiotx.cpp \
proc_playaudio.cpp \ proc_playaudio.cpp \
proc_xylos.cpp \
proc_fsk_lcr.cpp \
dsp_squelch.cpp \ dsp_squelch.cpp \
clock_recovery.cpp \ clock_recovery.cpp \
packet_builder.cpp \ packet_builder.cpp \

View File

@ -0,0 +1,52 @@
/*
* 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 "audio_compressor.hpp"
float GainComputer::operator()(const float x) const {
const auto abs_x = std::abs(x);
const auto db = (abs_x < lin_floor) ? db_floor : log2_db_k * fast_log2(abs_x);
const auto overshoot_db = db - threshold_db;
if( knee_width_db > 0.0f ) {
const auto w2 = knee_width_db / 2.0f;
const auto a = w2 / (knee_width_db * knee_width_db);
const auto in_transition = (overshoot_db > -w2) && (overshoot_db < w2);
const auto rectified_overshoot = in_transition ? (a * std::pow(overshoot_db + w2, 2.0f)) : std::max(overshoot_db, 0.0f);
return rectified_overshoot * slope;
} else {
const auto rectified_overshoot = std::max(overshoot_db, 0.0f);
return rectified_overshoot * slope;
}
}
void FeedForwardCompressor::execute_in_place(const buffer_f32_t& buffer) {
constexpr float makeup_gain = std::pow(10.0f, (threshold - (threshold / ratio)) / -20.0f);
for(size_t i=0; i<buffer.count; i++) {
buffer.p[i] = execute_once(buffer.p[i]) * makeup_gain;
}
}
float FeedForwardCompressor::execute_once(const float x) {
const auto gain_db = gain_computer(x);
const auto peak_db = -peak_detector(-gain_db);
const auto gain = fast_pow2(peak_db * (3.321928094887362f / 20.0f));
return x * gain;
}

View File

@ -0,0 +1,102 @@
/*
* 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 __AUDIO_COMPRESSOR_H__
#define __AUDIO_COMPRESSOR_H__
#include "dsp_types.hpp"
#include "utility.hpp"
#include <cmath>
/* Code based on article in Journal of the Audio Engineering Society
* Vol. 60, No. 6, 2012 June, by Dimitrios Giannoulis, Michael Massberg,
* Joshua D. Reiss "Digital Dynamic Range Compressor Design A Tutorial
* and Analysis"
*/
class GainComputer {
public:
constexpr GainComputer(
float ratio,
float threshold
) : ratio { ratio },
slope { 1.0f / ratio - 1.0f },
threshold_db { threshold }
{
}
float operator()(const float x) const;
private:
const float ratio;
const float slope;
const float threshold_db;
static constexpr float knee_width_db = 0.0f;
static constexpr float db_floor = -120.0f;
static constexpr float lin_floor = std::pow(10.0f, db_floor / 20.0f);
static constexpr float log2_db_k = 20.0f * std::log10(2.0f);
};
class PeakDetectorBranchingSmooth {
public:
constexpr PeakDetectorBranchingSmooth(
float att_a,
float rel_a
) : att_a { att_a },
rel_a { rel_a }
{
}
float operator()(const float db) {
const auto a = (db > state) ? att_a : rel_a;
state = db + a * (state - db);
return state;
}
private:
float state { 0.0f };
const float att_a;
const float rel_a;
};
class FeedForwardCompressor {
public:
void execute_in_place(const buffer_f32_t& buffer);
private:
static constexpr float fs = 12000.0f;
static constexpr float ratio = 10.0f;
static constexpr float threshold = -30.0f;
GainComputer gain_computer { ratio, threshold };
PeakDetectorBranchingSmooth peak_detector { tau_alpha(0.010f, fs), tau_alpha(0.300f, fs) };
float execute_once(const float x);
static constexpr float tau_alpha(const float tau, const float fs) {
return std::exp(-1.0f / (tau * fs));
}
};
#endif/*__AUDIO_COMPRESSOR_H__*/

View File

@ -33,6 +33,8 @@
#include "proc_playaudio.hpp" #include "proc_playaudio.hpp"
#include "proc_audiotx.hpp" #include "proc_audiotx.hpp"
#include "proc_xylos.hpp"
#include "proc_fsk_lcr.hpp"
#include "portapack_shared_memory.hpp" #include "portapack_shared_memory.hpp"
@ -120,6 +122,8 @@ BasebandProcessor* BasebandThread::create_processor(const int32_t mode) {
switch(mode) { switch(mode) {
case 0: return new PlayAudioProcessor(); case 0: return new PlayAudioProcessor();
case 1: return new AudioTXProcessor(); case 1: return new AudioTXProcessor();
case 2: return new XylosProcessor();
case 3: return new LCRFSKProcessor();
default: return nullptr; default: return nullptr;
} }
} }

View File

@ -0,0 +1,93 @@
/*
* 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 __OOK_HPP__
#define __OOK_HPP__
#include "phase_detector.hpp"
#include "phase_accumulator.hpp"
#include <cstdint>
#include <complex>
#include <algorithm>
#include <cmath>
class OOKSlicerMagSquaredInt {
public:
using symbol_t = bool;
constexpr OOKSlicerMagSquaredInt(
const float samples_per_symbol
) : mag2_threshold_leak_factor {
static_cast<uint32_t>(
factor_sq(-1.0f / (8.0f * samples_per_symbol)) * float(1ULL << 32)
)
}
{
}
symbol_t operator()(const std::complex<int16_t> in) {
const uint32_t real2 = in.real() * in.real();
const uint32_t imag2 = in.imag() * in.imag();
const uint32_t mag2 = real2 + imag2;
const uint32_t mag2_attenuated = mag2 >> 3; // Approximation of (-4.5dB)^2
mag2_threshold = (uint64_t(mag2_threshold) * uint64_t(mag2_threshold_leak_factor)) >> 32;
mag2_threshold = std::max(mag2_threshold, mag2_attenuated);
const bool symbol = (mag2 > mag2_threshold);
return symbol;
}
private:
const uint32_t mag2_threshold_leak_factor;
uint32_t mag2_threshold = 0;
constexpr float factor_sq(float db) {
return std::pow(10.0f, db / (10.0f / 2));
}
};
class OOKClockRecovery {
public:
constexpr OOKClockRecovery(
const float samples_per_symbol
) : symbol_phase_inc_nominal { static_cast<uint32_t>(std::round((1ULL << 32) / samples_per_symbol)) },
phase_detector { samples_per_symbol },
phase_accumulator { symbol_phase_inc_nominal }
{
}
template<typename SymbolHandler>
void operator()(const uint32_t slicer_history, SymbolHandler symbol_handler) {
if( phase_accumulator() ) {
const auto detector_result = phase_detector(slicer_history);
phase_accumulator.set_inc(symbol_phase_inc_nominal + detector_result.error * (symbol_phase_inc_nominal >> 3));
symbol_handler(detector_result.symbol);
}
}
private:
const uint32_t symbol_phase_inc_nominal;
PhaseDetectorEarlyLateGate phase_detector;
PhaseAccumulator phase_accumulator;
};
#endif/*__OOK_HPP__*/

View File

@ -0,0 +1,50 @@
/*
* 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 __PHASE_ACCUMULATOR_HPP__
#define __PHASE_ACCUMULATOR_HPP__
#include <cstdint>
class PhaseAccumulator {
public:
constexpr PhaseAccumulator(
const uint32_t phase_inc
) : phase_inc { phase_inc }
{
}
bool operator()() {
const auto last_phase = phase;
phase += phase_inc;
return (phase < last_phase);
}
void set_inc(const uint32_t new_phase_inc) {
phase_inc = new_phase_inc;
}
private:
uint32_t phase { 0 };
uint32_t phase_inc;
};
#endif/*__PHASE_ACCUMULATOR_HPP__*/

View File

@ -0,0 +1,68 @@
/*
* 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 __PHASE_DETECTOR_HPP__
#define __PHASE_DETECTOR_HPP__
#include <cstdint>
#include <cstddef>
#include <cmath>
class PhaseDetectorEarlyLateGate {
public:
using history_t = uint32_t;
using symbol_t = bool;
using error_t = int;
struct result_t {
symbol_t symbol;
error_t error;
};
constexpr PhaseDetectorEarlyLateGate(
const float samples_per_symbol
) : late_mask { (1U << static_cast<size_t>(std::ceil(samples_per_symbol / 2))) - 1 },
early_mask { late_mask << static_cast<size_t>(std::floor(samples_per_symbol / 2)) },
sample_bit { static_cast<size_t>(std::floor(samples_per_symbol / 2)) }
{
}
result_t operator()(const history_t symbol_history) const {
// history = ...0111, early
// history = ...1110, late
const symbol_t symbol = (symbol_history >> sample_bit) & 1;
const int late_side = __builtin_popcount(symbol_history & late_mask);
const int early_side = __builtin_popcount(symbol_history & early_mask);
const int lateness = late_side - early_side;
const int direction = lateness; //std::min(std::max(lateness, -1), 1);
const error_t error = direction;
return { symbol, error };
}
private:
const history_t late_mask;
const history_t early_mask;
const size_t sample_bit;
};
#endif/*__PHASE_DETECTOR_HPP__*/

View File

@ -23,63 +23,9 @@
#include "proc_audiotx.hpp" #include "proc_audiotx.hpp"
#include "portapack_shared_memory.hpp" #include "portapack_shared_memory.hpp"
#include "sine_table.hpp" #include "sine_table.hpp"
#include "audio_output.hpp"
#include "lfsr_random.hpp"
#include <cstdint> #include <cstdint>
uint32_t lfsr(uint32_t v) {
enum {
length = 31,
tap_0 = 31,
tap_1 = 18,
shift_amount_0 = 12,
shift_amount_1 = 12,
shift_amount_2 = 8
};
const lfsr_word_t zero = 0;
v = (
(
v << shift_amount_0
) | (
(
(v >> (tap_0 - shift_amount_0)) ^
(v >> (tap_1 - shift_amount_0))
) & (
~(~zero << shift_amount_0)
)
)
);
v = (
(
v << shift_amount_1
) | (
(
(v >> (tap_0 - shift_amount_1)) ^
(v >> (tap_1 - shift_amount_1))
) & (
~(~zero << shift_amount_1)
)
)
);
v = (
(
v << shift_amount_2
) | (
(
(v >> (tap_0 - shift_amount_2)) ^
(v >> (tap_1 - shift_amount_2))
) & (
~(~zero << shift_amount_2)
)
)
);
return v;
}
void AudioTXProcessor::execute(const buffer_c8_t& buffer){ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
for (size_t i = 0; i<buffer.count; i++) { for (size_t i = 0; i<buffer.count; i++) {
@ -91,7 +37,7 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
aphase += 90000; aphase += 90000;
//FM //FM
frq = sample * 2500; frq = sample * 1000;
phase = (phase + frq); phase = (phase + frq);
sphase = phase + (256<<16); sphase = phase + (256<<16);

View File

@ -25,12 +25,6 @@
#include "baseband_processor.hpp" #include "baseband_processor.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "audio_output.hpp"
#include "spectrum_collector.hpp"
#include <cstdint> #include <cstdint>
class AudioTXProcessor : public BasebandProcessor { class AudioTXProcessor : public BasebandProcessor {

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_tpms.hpp"
#include "dsp_fir_taps.hpp"
TPMSProcessor::TPMSProcessor() {
decim_0.configure(taps_200k_decim_0.taps, 33554432);
decim_1.configure(taps_200k_decim_1.taps, 131072);
}
void TPMSProcessor::execute(const buffer_c8_t& buffer) {
/* 2.4576MHz, 2048 samples */
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 decimator_out = decim_1_out;
/* 307.2kHz, 256 samples */
feed_channel_stats(decimator_out);
for(size_t i=0; i<decimator_out.count; i++) {
if( mf.execute_once(decimator_out.p[i]) ) {
clock_recovery(mf.get_output());
}
}
for(size_t i=0; i<decim_1_out.count; i+=channel_decimation) {
const auto sliced = ook_slicer_5sps(decim_1_out.p[i]);
slicer_history = (slicer_history << 1) | sliced;
ook_clock_recovery_subaru(slicer_history, [this](const bool symbol) {
this->packet_builder_ook_subaru.execute(symbol);
});
ook_clock_recovery_gmc(slicer_history, [this](const bool symbol) {
this->packet_builder_ook_gmc.execute(symbol);
});
}
}
void TPMSProcessor::consume_symbol(
const float raw_symbol
) {
const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
packet_builder.execute(sliced_symbol);
}
void TPMSProcessor::payload_handler(
const baseband::Packet& packet
) {
const TPMSPacketMessage message { tpms::SignalType::FLM, packet };
shared_memory.application_queue.push(message);
}

View File

@ -0,0 +1,125 @@
/*
* 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 __PROC_TPMS_H__
#define __PROC_TPMS_H__
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "matched_filter.hpp"
#include "clock_recovery.hpp"
#include "symbol_coding.hpp"
#include "packet_builder.hpp"
#include "baseband_packet.hpp"
#include "ook.hpp"
#include "message.hpp"
#include "portapack_shared_memory.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
// Translate+rectangular filter
// sample=307.2k, deviation=38400, symbol=19200
// Length: 16 taps, 1 symbols, 2 cycles of sinusoid
constexpr std::array<std::complex<float>, 16> rect_taps_307k2_1t_p { {
{ 6.2500000000e-02f, 0.0000000000e+00f }, { 4.4194173824e-02f, 4.4194173824e-02f },
{ 0.0000000000e+00f, 6.2500000000e-02f }, { -4.4194173824e-02f, 4.4194173824e-02f },
{ -6.2500000000e-02f, 0.0000000000e+00f }, { -4.4194173824e-02f, -4.4194173824e-02f },
{ 0.0000000000e+00f, -6.2500000000e-02f }, { 4.4194173824e-02f, -4.4194173824e-02f },
{ 6.2500000000e-02f, 0.0000000000e+00f }, { 4.4194173824e-02f, 4.4194173824e-02f },
{ 0.0000000000e+00f, 6.2500000000e-02f }, { -4.4194173824e-02f, 4.4194173824e-02f },
{ -6.2500000000e-02f, 0.0000000000e+00f }, { -4.4194173824e-02f, -4.4194173824e-02f },
{ 0.0000000000e+00f, -6.2500000000e-02f }, { 4.4194173824e-02f, -4.4194173824e-02f },
} };
class TPMSProcessor : public BasebandProcessor {
public:
TPMSProcessor();
void execute(const buffer_c8_t& buffer) override;
private:
std::array<complex16_t, 512> dst;
const buffer_c16_t dst_buffer {
dst.data(),
dst.size()
};
dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0;
dsp::decimate::FIRC16xR16x16Decim2 decim_1;
dsp::matched_filter::MatchedFilter mf { rect_taps_307k2_1t_p, 8 };
clock_recovery::ClockRecovery<clock_recovery::FixedErrorFilter> clock_recovery {
38400, 19200, { 0.0555f },
[this](const float symbol) { this->consume_symbol(symbol); }
};
PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder {
{ 0b010101010101010101010101010110, 30, 1 },
{ },
{ 256 },
[this](const baseband::Packet& packet) {
this->payload_handler(packet);
}
};
static constexpr float channel_rate_in = 307200.0f;
static constexpr size_t channel_decimation = 8;
static constexpr float channel_sample_rate = channel_rate_in / channel_decimation;
OOKSlicerMagSquaredInt ook_slicer_5sps { 5 };
uint32_t slicer_history { 0 };
OOKClockRecovery ook_clock_recovery_subaru {
channel_sample_rate / 8192.0f
};
PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder_ook_subaru {
{ 0b010101010101010101011110, 24, 0 },
{ },
{ 80 },
[](const baseband::Packet& packet) {
const TPMSPacketMessage message { tpms::SignalType::Subaru, packet };
shared_memory.application_queue.push(message);
}
};
OOKClockRecovery ook_clock_recovery_gmc {
channel_sample_rate / 8400.0f
};
PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder_ook_gmc {
{ 0b01010101010101010101010101100101, 32, 0 },
{ },
{ 192 },
[](const baseband::Packet& packet) {
const TPMSPacketMessage message { tpms::SignalType::GMC, packet };
shared_memory.application_queue.push(message);
}
};
void consume_symbol(const float symbol);
void payload_handler(const baseband::Packet& packet);
};
#endif/*__PROC_TPMS_H__*/

View File

@ -23,7 +23,7 @@
#include "proc_xylos.hpp" #include "proc_xylos.hpp"
#include "dsp_iir_config.hpp" #include "dsp_iir_config.hpp"
//#include "audio_output.hpp" #include "audio_output.hpp"
#include "portapack_shared_memory.hpp" #include "portapack_shared_memory.hpp"
#include "sine_table.hpp" #include "sine_table.hpp"
@ -75,7 +75,7 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) {
// Audio preview sample generation: 1536000/48000 = 32 // Audio preview sample generation: 1536000/48000 = 32
if (as >= 31) { if (as >= 31) {
as = 0; as = 0;
preview_audio_buffer.p[ai++] = sample * 128; audio[ai++] = sample * 128;
} else { } else {
as++; as++;
} }
@ -92,5 +92,5 @@ void XylosProcessor::execute(const buffer_c8_t& buffer) {
buffer.p[i] = {(int8_t)re,(int8_t)im}; buffer.p[i] = {(int8_t)re,(int8_t)im};
} }
//audio_output.write(preview_audio_buffer); //audio_output.write(audio_buffer);
} }

View File

@ -28,7 +28,7 @@
#include "dsp_decimate.hpp" #include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp" #include "dsp_demodulate.hpp"
//#include "audio_output.hpp" #include "audio_output.hpp"
#include "baseband_processor.hpp" #include "baseband_processor.hpp"
#define CCIR_TONELENGTH 15360-1 // 1536000/10/10 #define CCIR_TONELENGTH 15360-1 // 1536000/10/10
@ -41,10 +41,11 @@ public:
private: private:
int16_t audio_data[64]; int16_t audio_data[64];
const buffer_s16_t preview_audio_buffer { std::array<int16_t, 64> audio;
audio_data, /*const buffer_s16_t audio_buffer {
sizeof(int16_t)*64 audio.data(),
}; audio.size()
};*/
uint32_t ccir_phases[16] = { uint32_t ccir_phases[16] = {
(uint32_t)(1981*PHASEV), (uint32_t)(1981*PHASEV),
@ -74,7 +75,7 @@ private:
int32_t sample, frq; int32_t sample, frq;
TXDoneMessage message; TXDoneMessage message;
//AudioOutput audio_output; AudioOutput audio_output;
}; };
#endif #endif

View File

@ -0,0 +1,73 @@
/*
* 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 __STREAM_INPUT_H__
#define __STREAM_INPUT_H__
#include "portapack_shared_memory.hpp"
#include "fifo.hpp"
#include <cstdint>
#include <cstddef>
#include <memory>
class StreamInput {
public:
StreamInput(const size_t K) :
K { K },
data { std::make_unique<uint8_t[]>(1UL << K) },
fifo { data.get(), K }
{
// TODO: Send stream creation message.
shared_memory.FIFO_HACK = &fifo;
}
~StreamInput() {
// TODO: Send stream distruction message.
shared_memory.FIFO_HACK = nullptr;
}
size_t write(const void* const data, const size_t length) {
const auto written = fifo.in(reinterpret_cast<const uint8_t*>(data), length);
const auto last_bytes_written = bytes_written;
bytes_written += written;
if( (bytes_written & event_bytes_mask) < (last_bytes_written & event_bytes_mask) ) {
creg::m4txevent::assert();
}
return written;
}
uint64_t written() const {
return bytes_written;
}
private:
const size_t K;
const uint64_t event_bytes_mask = (1ULL << (K - 2)) - 1;
uint64_t bytes_written = 0;
std::unique_ptr<uint8_t[]> data;
FIFO<uint8_t> fifo;
};
#endif/*__STREAM_INPUT_H__*/

Binary file not shown.

View File

@ -1,2 +1,2 @@
const char md5_baseband[16] = {0x37,0x04,0xf7,0x51,0x68,0x66,0x8a,0x20,0x73,0xa0,0xf7,0x69,0xa2,0xe2,0xb4,0x3a,}; const char md5_baseband[16] = {0xf2,0x01,0x2e,0xbf,0xc2,0xee,0x9f,0x0e,0x36,0x75,0x0e,0xb7,0x87,0x28,0x49,0xbd,};
const char md5_baseband_tx[16] = {0x6c,0x1a,0x90,0x6b,0x68,0x78,0x6e,0xd2,0x08,0x3b,0x05,0xb1,0xbe,0x61,0xf8,0xe7,}; const char md5_baseband_tx[16] = {0xb1,0xe1,0xca,0x79,0x83,0x86,0x2f,0x20,0xba,0x94,0xd3,0x0c,0xc7,0x9d,0x43,0xe2,};

View File

@ -30,13 +30,19 @@ using Coord = int16_t;
using Dim = int16_t; using Dim = int16_t;
struct Color { struct Color {
uint16_t v; uint16_t v; // rrrrrGGGGGGbbbbb
constexpr Color( constexpr Color(
) : v { 0 } ) : v { 0 }
{ {
} }
constexpr Color(
uint16_t v
) : v { v }
{
}
constexpr Color( constexpr Color(
uint8_t r, uint8_t r,
uint8_t g, uint8_t g,
@ -50,6 +56,10 @@ struct Color {
{ {
} }
Color operator-() const {
return (v ^ 0xffff);
}
static constexpr Color black() { static constexpr Color black() {
return { 0, 0, 0 }; return { 0, 0, 0 };
} }
@ -75,7 +85,7 @@ struct Color {
} }
static constexpr Color cyan() { static constexpr Color cyan() {
return { 0, 128, 255 }; return { 0, 255, 255 };
} }
static constexpr Color white() { static constexpr Color white() {

View File

@ -292,6 +292,36 @@ void Text::paint(Painter& painter) {
); );
} }
/* ProgressBar ***********************************************************/
ProgressBar::ProgressBar(
Rect parent_rect
) : Widget { parent_rect }
{
}
void ProgressBar::set_value(const uint16_t value) {
if (value > 100)
_value = 100;
else
_value = value;
set_dirty();
}
void ProgressBar::paint(Painter& painter) {
uint16_t v_sized;
const auto rect = screen_rect();
const auto s = style();
v_sized = (rect.size.w * _value) / 100;
painter.fill_rectangle({rect.pos, {v_sized, rect.size.h}}, ui::Color::green());
painter.fill_rectangle({{rect.pos.x + v_sized, rect.pos.y}, {rect.size.w - v_sized, rect.size.h}}, s.background);
painter.draw_rectangle(rect, s.foreground);
}
/* Checkbox **************************************************************/ /* Checkbox **************************************************************/
Checkbox::Checkbox( Checkbox::Checkbox(
@ -427,12 +457,16 @@ void Button::paint(Painter& painter) {
paint_style.background paint_style.background
); );
const auto label_r = paint_style.font.size_of(text_); //char *token = strtok(text_.c_str(), "\n");
painter.draw_string( //while(token) {
{ r.pos.x + (r.size.w - label_r.w) / 2, r.pos.y + (r.size.h - label_r.h) / 2 }, const auto label_r = paint_style.font.size_of(text_);
paint_style, painter.draw_string(
text_ { r.pos.x + (r.size.w - label_r.w) / 2, r.pos.y + (r.size.h - label_r.h) / 2 },
); paint_style,
text_
);
// token = strtok(NULL, " ");
//}
} }
bool Button::on_key(const KeyEvent key) { bool Button::on_key(const KeyEvent key) {

View File

@ -112,6 +112,8 @@ public:
bool highlighted() const; bool highlighted() const;
void set_highlighted(const bool value); void set_highlighted(const bool value);
uint16_t id = 0;
protected: protected:
void dirty_overlapping_children_in_rect(const Rect& child_rect); void dirty_overlapping_children_in_rect(const Rect& child_rect);
@ -195,6 +197,19 @@ private:
std::string text; std::string text;
}; };
class ProgressBar : public Widget {
public:
ProgressBar(Rect parent_rect);
void set_value(const uint16_t value);
uint16_t value() const;
void paint(Painter& painter) override;
private:
uint16_t _value = 0;
};
class Checkbox : public Widget { class Checkbox : public Widget {
public: public:
std::function<void(Checkbox&)> on_select; std::function<void(Checkbox&)> on_select;

Binary file not shown.

Binary file not shown.

Binary file not shown.