mirror of
https://github.com/RfidResearchGroup/mayhem-firmware.git
synced 2026-05-12 11:27:21 -07:00
Fixed LCR and Xylos transmitters
This commit is contained in:
+1
-1
@@ -64,7 +64,7 @@ modules: $(TARGET_BASEBAND).bin $(TARGET_BASEBAND_TX).bin
|
||||
cp $(PATH_BASEBAND).bin ../sdcard/$(PATH_BASEBAND).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
|
||||
|
||||
$(TARGET_BOOTSTRAP).bin: $(TARGET_BOOTSTRAP).elf
|
||||
|
||||
@@ -151,6 +151,7 @@ CPPSRC = main.cpp \
|
||||
lcd_ili9341.cpp \
|
||||
ui.cpp \
|
||||
ui_alphanum.cpp \
|
||||
ui_handwrite.cpp \
|
||||
ui_about.cpp \
|
||||
ui_text.cpp \
|
||||
ui_widget.cpp \
|
||||
@@ -162,6 +163,7 @@ CPPSRC = main.cpp \
|
||||
ui_channel.cpp \
|
||||
ui_audio.cpp \
|
||||
ui_audiotx.cpp \
|
||||
ui_soundboard.cpp \
|
||||
ui_lcr.cpp \
|
||||
ui_rds.cpp \
|
||||
ui_jammer.cpp \
|
||||
|
||||
@@ -180,12 +180,12 @@ private:
|
||||
static constexpr size_t touch_count_threshold { 4 };
|
||||
static constexpr uint32_t touch_stable_bound { 4 };
|
||||
|
||||
static constexpr float calib_x_low = 0.07f;
|
||||
static constexpr float calib_x_high = 0.94f;
|
||||
static constexpr float calib_x_low = 0.15f;
|
||||
static constexpr float calib_x_high = 0.98f;
|
||||
static constexpr float calib_x_range = calib_x_high - calib_x_low;
|
||||
|
||||
static constexpr float calib_y_low = 0.04f;
|
||||
static constexpr float calib_y_high = 0.91f;
|
||||
static constexpr float calib_y_high = 0.80f; //91
|
||||
static constexpr float calib_y_range = calib_y_high - calib_y_low;
|
||||
|
||||
// Ensure filter length is equal or less than touch_count_threshold,
|
||||
|
||||
@@ -40,7 +40,6 @@ public:
|
||||
AudioTXView(NavigationView& nav);
|
||||
~AudioTXView();
|
||||
|
||||
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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[6] = 127;
|
||||
lcrframe[7] = 15; // SOM
|
||||
|
||||
strcpy(rgsb, RGSB_list[adr_code.value()]);
|
||||
button_setrgsb.set_text(rgsb);
|
||||
|
||||
strcat(lcrframe, rgsb);
|
||||
strcat(lcrframe, "PA ");
|
||||
if (checkbox_am_a.value() == true) {
|
||||
@@ -191,7 +195,7 @@ LCRView::LCRView(
|
||||
};
|
||||
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 1,
|
||||
.mode = 3,
|
||||
.sampling_rate = 2280000, // Is this right ?
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
@@ -200,11 +204,12 @@ LCRView::LCRView(
|
||||
memset(litteral, 0, 5*8);
|
||||
memset(rgsb, 0, 5);
|
||||
|
||||
strcpy(rgsb, RGSB_list[29]);
|
||||
strcpy(rgsb, RGSB_list[adr_code.value()]);
|
||||
button_setrgsb.set_text(rgsb);
|
||||
|
||||
add_children({ {
|
||||
&text_recap,
|
||||
&adr_code,
|
||||
&button_setrgsb,
|
||||
&button_txsetup,
|
||||
&checkbox_am_a,
|
||||
@@ -290,7 +295,9 @@ LCRView::LCRView(
|
||||
memcpy(shared_memory.lcrdata, lcrframe_f, 256);
|
||||
|
||||
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,
|
||||
[this,&transmitter_model](Message* const p) {
|
||||
@@ -316,7 +323,49 @@ LCRView::LCRView(
|
||||
|
||||
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&){
|
||||
nav.push<AFSKSetupView>();
|
||||
};
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
private:
|
||||
uint8_t adri = 22;
|
||||
const char RGSB_list[37][5] = {
|
||||
"EAA0", "EAB0", "EAC0", "EAD0",
|
||||
"EbA0", "EbB0", "EbC0", "EbD0",
|
||||
@@ -70,9 +71,17 @@ private:
|
||||
};
|
||||
|
||||
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 {
|
||||
{ 16, 24, 96, 32 },
|
||||
|
||||
@@ -35,8 +35,10 @@
|
||||
#include "ui_rds.hpp"
|
||||
#include "ui_xylos.hpp"
|
||||
#include "ui_lcr.hpp"
|
||||
#include "ui_audiotx.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "ui_soundboard.hpp"
|
||||
#include "ui_debug.hpp"
|
||||
#include "ui_audiotx.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
@@ -150,9 +152,12 @@ void LoadModuleView::loadmodule() {
|
||||
LoadModuleView::LoadModuleView(
|
||||
NavigationView& nav,
|
||||
const char * hash,
|
||||
uint8_t ViewID
|
||||
uint8_t ViewID,
|
||||
bool loadplz
|
||||
)
|
||||
{
|
||||
if (loadplz == false) nav.pop(); // Useless, remove !
|
||||
|
||||
add_children({ {
|
||||
&text_info,
|
||||
&text_infob,
|
||||
@@ -163,10 +168,11 @@ LoadModuleView::LoadModuleView(
|
||||
|
||||
button_ok.on_select = [this, &nav, ViewID](Button&){
|
||||
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 == 2) nav.push<LCRView>();
|
||||
if (ViewID == 3) nav.push<AudioTXView>();
|
||||
if (ViewID == 3) nav.push<SoundBoardView>();
|
||||
if (ViewID == 10) nav.push<AnalogAudioView>();
|
||||
} else {
|
||||
nav.pop();
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace ui {
|
||||
|
||||
class LoadModuleView : public View {
|
||||
public:
|
||||
LoadModuleView(NavigationView& nav, const char * hash, uint8_t ViewID);
|
||||
LoadModuleView(NavigationView& nav, const char * hash, uint8_t ViewID, bool loadplz);
|
||||
void loadmodule();
|
||||
|
||||
void on_show() override;
|
||||
|
||||
@@ -53,7 +53,7 @@ void MenuItemView::paint(Painter& painter) {
|
||||
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;
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include "ui_setup.hpp"
|
||||
#include "ui_debug.hpp"
|
||||
|
||||
#include "ui_handwrite.hpp" // DEBUG
|
||||
#include "ui_soundboard.hpp" // DEBUG
|
||||
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "ais_app.hpp"
|
||||
#include "ert_app.hpp"
|
||||
@@ -155,7 +158,7 @@ void NavigationView::focus() {
|
||||
}
|
||||
}
|
||||
|
||||
/* TransceiversMenuView **************************************************/
|
||||
/* TranspondersMenuView **************************************************/
|
||||
|
||||
TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
|
||||
add_items<3>({ {
|
||||
@@ -170,7 +173,9 @@ TranspondersMenuView::TranspondersMenuView(NavigationView& nav) {
|
||||
|
||||
ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
|
||||
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>(); } },
|
||||
} });
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
@@ -180,18 +185,18 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
|
||||
|
||||
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||
add_items<10>({ {
|
||||
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } },
|
||||
{ "Receiver", ui::Color::cyan(), [&nav](){ nav.push<ReceiverMenuView>(); } },
|
||||
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 0); } },
|
||||
{ "Xylos TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 1); } },
|
||||
{ "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 2); } },
|
||||
{ "Audio TX", ui::Color::orange(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 3); } },
|
||||
//{ "Capture", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
//{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
|
||||
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } },
|
||||
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
|
||||
{ "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } },
|
||||
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } },
|
||||
{ "Receiver RX", ui::Color::cyan(), [&nav](){ nav.push<ReceiverMenuView>(); } },
|
||||
{ "Soundboard TX", ui::Color::orange(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 3, true); } },
|
||||
{ "Audio TX TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 0, true); } },
|
||||
{ "Xylos TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 1, true); } },
|
||||
{ "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, 2, true); } },
|
||||
//{ "Capture", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
//{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
|
||||
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } },
|
||||
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
|
||||
{ "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } },
|
||||
} });
|
||||
|
||||
/*
|
||||
@@ -224,7 +229,8 @@ SystemView::SystemView(
|
||||
set_style(&style_default);
|
||||
|
||||
constexpr ui::Dim status_view_height = 16;
|
||||
|
||||
char debugtxt[21] = {0};
|
||||
|
||||
add_child(&status_view);
|
||||
status_view.set_parent_rect({
|
||||
{ 0, 0 },
|
||||
@@ -255,7 +261,9 @@ SystemView::SystemView(
|
||||
if (portapack::persistent_memory::ui_config() & 1)
|
||||
navigation_view.push<BMPView>();
|
||||
else
|
||||
navigation_view.push<SystemMenuView>();
|
||||
//navigation_view.push<SoundBoardView>();
|
||||
//navigation_view.push<SystemMenuView>();
|
||||
navigation_view.push<HandWriteView>(debugtxt, 20);
|
||||
}
|
||||
|
||||
Context& SystemView::context() const {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
uint8_t c;
|
||||
|
||||
ccirmessage[0] = '0';
|
||||
ccirmessage[1] = '0';
|
||||
ccirmessage[2] = '0';
|
||||
ccirmessage[3] = '0';
|
||||
ccirmessage[0] = (header_code_a.value() / 10) + 0x30;
|
||||
ccirmessage[1] = (header_code_a.value() % 10) + 0x30;
|
||||
ccirmessage[2] = (header_code_b.value() / 10) + 0x30;
|
||||
ccirmessage[3] = (header_code_b.value() % 10) + 0x30;
|
||||
|
||||
ccirmessage[4] = (city_code.value() / 10) + 0x30;
|
||||
ccirmessage[5] = (city_code.value() % 10) + 0x30;
|
||||
@@ -228,7 +228,7 @@ XylosView::XylosView(
|
||||
};
|
||||
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 4,
|
||||
.mode = 2,
|
||||
.sampling_rate = 1536000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
@@ -236,6 +236,9 @@ XylosView::XylosView(
|
||||
add_children({ {
|
||||
&text_title,
|
||||
&button_txtest,
|
||||
&text_header,
|
||||
&header_code_a,
|
||||
&header_code_b,
|
||||
&text_city,
|
||||
&city_code,
|
||||
&text_family,
|
||||
@@ -265,11 +268,21 @@ XylosView::XylosView(
|
||||
family_code.set_value(1);
|
||||
subfamily_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);
|
||||
|
||||
checkbox_wcsubfamily.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) {
|
||||
(void)v;
|
||||
XylosView::upd_message();
|
||||
|
||||
@@ -41,8 +41,6 @@ namespace ui {
|
||||
#define XYLOS_VOICE_RELAYS 21
|
||||
#define XYLOS_VOICE_TRAILER 25
|
||||
|
||||
void do_something();
|
||||
|
||||
class XylosRXView : public View {
|
||||
public:
|
||||
XylosRXView(NavigationView& nav);
|
||||
@@ -152,47 +150,38 @@ public:
|
||||
private:
|
||||
bool txing = false;
|
||||
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 ccir_received[21];
|
||||
|
||||
Text text_title {
|
||||
{ 1 * 8, 1 * 16, 11, 16 },
|
||||
{ 8, 8, 11, 16 },
|
||||
"BH Xylos TX"
|
||||
};
|
||||
|
||||
Button button_txtest {
|
||||
{ 170, 1 * 16, 40, 24 },
|
||||
{ 180, 8, 40, 24 },
|
||||
"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 {
|
||||
{ 4 * 8, 3 * 16, 11 * 8, 16 },
|
||||
"Code ville:"
|
||||
@@ -256,7 +245,7 @@ private:
|
||||
"Frequence:"
|
||||
};
|
||||
OptionsField options_freq {
|
||||
{ 16 * 8, 9 * 16 },
|
||||
{ 16 * 8, 9 * 16 + 4},
|
||||
7,
|
||||
{
|
||||
{ "31.3250", 0 },
|
||||
|
||||
Binary file not shown.
@@ -140,6 +140,8 @@ CPPSRC = main.cpp \
|
||||
matched_filter.cpp \
|
||||
proc_audiotx.cpp \
|
||||
proc_playaudio.cpp \
|
||||
proc_xylos.cpp \
|
||||
proc_fsk_lcr.cpp \
|
||||
dsp_squelch.cpp \
|
||||
clock_recovery.cpp \
|
||||
packet_builder.cpp \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user