mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-24 23:09:26 -05:00
Fixed LCR and Xylos transmitters
This commit is contained in:
parent
d55a420dfd
commit
d40016ffda
@ -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
|
||||||
|
@ -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 \
|
||||||
|
@ -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,
|
||||||
|
@ -40,7 +40,6 @@ public:
|
|||||||
AudioTXView(NavigationView& nav);
|
AudioTXView(NavigationView& nav);
|
||||||
~AudioTXView();
|
~AudioTXView();
|
||||||
|
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
404
firmware/application/ui_handwrite.cpp
Normal file
404
firmware/application/ui_handwrite.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
firmware/application/ui_handwrite.hpp
Normal file
105
firmware/application/ui_handwrite.hpp
Normal 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 */
|
@ -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>();
|
||||||
};
|
};
|
||||||
|
@ -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"
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
145
firmware/application/ui_soundboard.cpp
Normal file
145
firmware/application/ui_soundboard.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
93
firmware/application/ui_soundboard.hpp
Normal file
93
firmware/application/ui_soundboard.hpp
Normal 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 */
|
@ -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();
|
||||||
|
@ -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.
@ -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 \
|
||||||
|
52
firmware/baseband-tx/audio_compressor.cpp
Normal file
52
firmware/baseband-tx/audio_compressor.cpp
Normal 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;
|
||||||
|
}
|
102
firmware/baseband-tx/audio_compressor.hpp
Normal file
102
firmware/baseband-tx/audio_compressor.hpp
Normal 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__*/
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
93
firmware/baseband-tx/ook.hpp
Normal file
93
firmware/baseband-tx/ook.hpp
Normal 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__*/
|
50
firmware/baseband-tx/phase_accumulator.hpp
Normal file
50
firmware/baseband-tx/phase_accumulator.hpp
Normal 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__*/
|
68
firmware/baseband-tx/phase_detector.hpp
Normal file
68
firmware/baseband-tx/phase_detector.hpp
Normal 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__*/
|
@ -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);
|
||||||
|
@ -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 {
|
||||||
|
72
firmware/baseband-tx/proc_tpms.cpp
Normal file
72
firmware/baseband-tx/proc_tpms.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
125
firmware/baseband-tx/proc_tpms.hpp
Normal file
125
firmware/baseband-tx/proc_tpms.hpp
Normal 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__*/
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
73
firmware/baseband-tx/stream_input.hpp
Normal file
73
firmware/baseband-tx/stream_input.hpp
Normal 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.
@ -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,};
|
||||||
|
@ -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() {
|
||||||
|
@ -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) {
|
||||||
|
@ -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.
Loading…
Reference in New Issue
Block a user