Xylos (CCIR tones) TX, jammer update, SD card mod load

Xylos TX (CCIR tones) ;)
Jammer update, still buggy and inefficient
SD card module loader update
This commit is contained in:
furrtek 2016-01-03 07:24:30 +01:00
parent 5a5a4c3525
commit 802ac496e9
28 changed files with 2272 additions and 1143 deletions

View File

@ -172,6 +172,9 @@ CPPSRC = main.cpp \
ui_receiver.cpp \
ui_spectrum.cpp \
ui_loadmodule.cpp \
ui_afskrx.cpp \
ui_sigfrx.cpp \
ui_xylos.cpp \
receiver_model.cpp \
transmitter_model.cpp \
spectrum_color_lut.cpp \

View File

@ -19,8 +19,13 @@
* Boston, MA 02110-1301, USA.
*/
//TODO: check jammer bandwidths
//TODO: GSM channel detector
//TODO: wait_for_switch() in baseband-tx !
//TODO: AFSK receiver
//TODO: SIGFOX RX/TX
//TODO: Reset baseband if module not found (instead of lockup in RAM loop)
//TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found
//TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found ui_loadmodule
//TODO: LCD backlight PWM
//TODO: BUG: Crash after TX stop
//TODO: Check bw setting in LCR TX

View File

@ -1,2 +1,2 @@
const char md5_baseband[16] = {0xca,0x05,0xc3,0xbf,0x78,0x10,0xad,0xac,0x2a,0x2b,0x31,0x19,0xf9,0xe8,0x91,0x26,};
const char md5_baseband_tx[16] = {0xe7,0x28,0x33,0x67,0x45,0x37,0x1e,0x13,0x3c,0x85,0xb5,0x91,0x51,0xaa,0xed,0x4f,};
const char md5_baseband[16] = {0xce,0x87,0x2b,0x2c,0x9e,0x74,0xe8,0x1c,0x1c,0xe9,0xfc,0xc2,0x40,0xc3,0x32,0xd5,};
const char md5_baseband_tx[16] = {0x1b,0xef,0x34,0x50,0x45,0xd7,0xae,0x7c,0xb5,0x4f,0x0c,0x5a,0x80,0xa0,0xbc,0x05,};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_afskrx.hpp"
#include "ui_spectrum.hpp"
#include "ui_console.hpp"
#include "ff.h"
#include "portapack.hpp"
using namespace portapack;
#include "ui_receiver.hpp"
namespace ui {
AFSKRXView::AFSKRXView(
NavigationView& nav,
ReceiverModel& receiver_model
) : receiver_model(receiver_model)
{
add_children({ {
&button_done,
&text_rx
} } );
button_done.on_select = [&nav](Button&){
nav.pop();
};
receiver_model.set_baseband_configuration({
.mode = 6,
.sampling_rate = 3072000,
.decimation_factor = 4,
});
receiver_model.set_baseband_bandwidth(1750000);
}
AFSKRXView::~AFSKRXView() {
receiver_model.disable();
}
void AFSKRXView::on_show() {
auto& message_map = context().message_map();
message_map.register_handler(Message::ID::AFSKData,
[this](Message* const p) {
const auto message = static_cast<const AFSKDataMessage*>(p);
this->on_data_afsk(*message);
}
);
receiver_model.enable();
}
void AFSKRXView::on_hide() {
auto& message_map = context().message_map();
message_map.unregister_handler(Message::ID::AFSKData);
}
void AFSKRXView::on_data_afsk(const AFSKDataMessage& message) {
Coord oy,ny;
//text_rx.set(to_string_dec_int(abs(message.data), 8, '0'));
portapack::display.fill_rectangle({0,160-64,240,128},{32,32,32});
oy = 160;
for (int c=0;c<128;c++) {
ny = 160-(message.data[c]>>10);
portapack::display.draw_line({static_cast<Coord>(c),oy},{static_cast<Coord>(c+1),ny},{255,127,0});
oy = ny;
}
/*auto payload = message.packet.payload;
auto payload_length = message.packet.bits_received;
std::string hex_data;
std::string hex_error;
uint8_t byte_data = 0;
uint8_t byte_error = 0;
for(size_t i=0; i<payload_length; i+=2) {
const auto bit_data = payload[i+1];
const auto bit_error = (payload[i+0] == payload[i+1]);
byte_data <<= 1;
byte_data |= bit_data ? 1 : 0;
byte_error <<= 1;
byte_error |= bit_error ? 1 : 0;
if( ((i >> 1) & 7) == 7 ) {
hex_data += to_string_hex(byte_data, 2);
hex_error += to_string_hex(byte_error, 2);
}
}
auto console = reinterpret_cast<Console*>(widget_content.get());
console->writeln(hex_data.substr(0, 240 / 8));
if( !f_error(&fil_tpms) ) {
rtc::RTC datetime;
rtcGetTime(&RTCD1, &datetime);
std::string timestamp =
to_string_dec_uint(datetime.year(), 4) +
to_string_dec_uint(datetime.month(), 2, '0') +
to_string_dec_uint(datetime.day(), 2, '0') +
to_string_dec_uint(datetime.hour(), 2, '0') +
to_string_dec_uint(datetime.minute(), 2, '0') +
to_string_dec_uint(datetime.second(), 2, '0');
const auto tuning_frequency = receiver_model.tuning_frequency();
// TODO: function doesn't take uint64_t, so when >= 1<<32, weirdness will ensue!
const auto tuning_frequency_str = to_string_dec_uint(tuning_frequency, 10);
std::string log = timestamp + " " + tuning_frequency_str + " FSK 38.4 19.2 " + hex_data + "/" + hex_error + "\r\n";
f_puts(log.c_str(), &fil_tpms);
f_sync(&fil_tpms);
}*/
}
void AFSKRXView::focus() {
button_done.focus();
}
} /* namespace ui */

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_AFSKRX_H__
#define __UI_AFSKRX_H__
#include "ui.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "ui_navigation.hpp"
#include "ui_painter.hpp"
#include "ui_widget.hpp"
#include "ui_console.hpp"
#include "utility.hpp"
#include "receiver_model.hpp"
#include <cstddef>
#include <cstdint>
#include <algorithm>
#include <functional>
namespace ui {
class AFSKRXView : public View {
public:
AFSKRXView(NavigationView& nav, ReceiverModel& receiver_model);
~AFSKRXView();
void focus() override;
void on_show() override;
void on_hide() override;
private:
ReceiverModel& receiver_model;
std::unique_ptr<Widget> widget_content;
Button button_done {
{ 4 * 8, 0 * 16, 3 * 8, 16 },
" < "
};
Text text_rx {
{ 1 * 8, 2 * 16, 28 * 8, 16 },
"Ready..."
};
void on_tuning_frequency_changed(rf::Frequency f);
void on_edit_frequency();
void on_data_afsk(const AFSKDataMessage& message);
};
} /* namespace ui */
#endif/*__UI_RECEIVER_H__*/

View File

@ -283,8 +283,8 @@ LCRView::LCRView(
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()*(0x10000*256)/2280;
shared_memory.afsk_phase_inc_space = portapack::persistent_memory::afsk_space_freq()*(0x10000*256)/2280;
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;

View File

@ -36,6 +36,9 @@
#include "ui_whistle.hpp"
#include "ui_jammer.hpp"
#include "ui_loadmodule.hpp"
#include "ui_afskrx.hpp"
#include "ui_xylos.hpp"
#include "ui_sigfrx.hpp"
#include "portapack.hpp"
#include "m4_startup.hpp"
@ -108,16 +111,19 @@ void NavigationView::focus() {
/* SystemMenuView ********************************************************/
SystemMenuView::SystemMenuView(NavigationView& nav) {
add_items<11>({ {
add_items<10>({ {
{ "Play dead", ui::Color::red(), [&nav](){ nav.push(new PlayDeadView { nav, false }); } },
{ "Receiver", ui::Color::cyan(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new ReceiverView { nav, receiver_model } }); } },
{ "Receiver", ui::Color::cyan(), [&nav](){ nav.push(new ReceiverView { nav, receiver_model }); } },
//{ "Nordic/BTLE RX", ui::Color::cyan(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
{ "Jammer", ui::Color::white(), [&nav](){ nav.push(new JammerView { nav, transmitter_model }); } },
{ "Audio file TX", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
//{ "Audio file TX", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
//{ "Encoder TX", ui::Color::green(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
{ "Whistle", ui::Color::purple(), [&nav](){ nav.push(new WhistleView { nav, transmitter_model }); } },
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push(new RDSView { nav, transmitter_model }); } },
{ "TEDI/LCR TX", ui::Color::orange(), [&nav](){ nav.push(new LCRView { nav, transmitter_model }); } },
//{ "SIGFOX RX", ui::Color::orange(), [&nav](){ nav.push(new SIGFRXView { nav, receiver_model }); } },
//{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new RDSView { nav, transmitter_model }}; } },
{ "Xylos TX", ui::Color::orange(), [&nav](){ nav.push(new XylosView { nav, transmitter_model }); } },
//{ "AFSK RX", ui::Color::cyan(), [&nav](){ nav.push(new AFSKRXView { nav, receiver_model }); } },
{ "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push(new LCRView { nav, transmitter_model }); } },
{ "Setup", ui::Color::white(), [&nav](){ nav.push(new SetupMenuView { nav }); } },
{ "About", ui::Color::white(), [&nav](){ nav.push(new AboutView { nav }); } },
{ "Debug", ui::Color::white(), [&nav](){ nav.push(new DebugMenuView { nav }); } },
@ -161,6 +167,8 @@ SystemView::SystemView(
//if (persistent_memory::playing_dead() == 0x59)
// navigation_view.push(new PlayDeadView { navigation_view, true });
//else
// navigation_view.push(new BMPView { navigation_view });
navigation_view.push(new BMPView { navigation_view });
}
@ -187,51 +195,7 @@ BMPView::BMPView(NavigationView& nav) {
}
void BMPView::paint(Painter& painter) {
uint32_t pixel_data;
uint8_t p, by, c, count;
ui::Color linebuffer[185];
ui::Coord px = 0, py = 302;
ui::Color palette[16];
// RLE_4 BMP loader with hardcoded size and no delta :(
pixel_data = splash_bmp[0x0A];
p = 0;
for (c = 0x36; c < (0x36+(16*4)); c+=4) {
palette[p++] = ui::Color(splash_bmp[c+2], splash_bmp[c+1], splash_bmp[c]);
}
do {
by = splash_bmp[pixel_data++];
if (by) {
count = by;
by = splash_bmp[pixel_data++];
for (c = 0; c < count; c+=2) {
linebuffer[px++] = palette[by >> 4];
if (px < 185) linebuffer[px++] = palette[by & 15];
}
if (pixel_data & 1) pixel_data++;
} else {
by = splash_bmp[pixel_data++];
if (by == 0) {
portapack::display.render_line({27, py}, 185, linebuffer);
py--;
px = 0;
} else if (by == 1) {
break;
} else if (by == 2) {
// Delta
} else {
count = by;
for (c = 0; c < count; c+=2) {
by = splash_bmp[pixel_data++];
linebuffer[px++] = palette[by >> 4];
if (px < 185) linebuffer[px++] = palette[by & 15];
}
if (pixel_data & 1) pixel_data++;
}
}
} while (1);
portapack::display.drawBMP({(240-185)/2, 0}, splash_bmp);
}
/* PlayDeadView **********************************************************/

View File

@ -0,0 +1,246 @@
/*
* 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_xylos.hpp"
#include "ch.h"
#include "evtimer.h"
#include "ff.h"
#include "hackrf_gpio.hpp"
#include "portapack.hpp"
#include "radio.hpp"
#include "hackrf_hal.hpp"
#include "portapack_shared_memory.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include <stdio.h>
using namespace hackrf::one;
namespace ui {
void XylosView::focus() {
city_code.focus();
}
XylosView::~XylosView() {
transmitter_model.disable();
}
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[4] = (city_code.value() / 10) + 0x30;
ccirmessage[5] = (city_code.value() % 10) + 0x30;
ccirmessage[6] = family_code.value() + 0x30;
if (checkbox_wcsubfamily.value() == false)
ccirmessage[7] = subfamily_code.value() + 0x30;
else
ccirmessage[7] = 'A';
if (checkbox_wcid.value() == false) {
ccirmessage[8] = (receiver_code.value() / 10) + 0x30;
ccirmessage[9] = (receiver_code.value() % 10) + 0x30;
} else {
ccirmessage[8] = 'A';
ccirmessage[9] = 'A';
}
ccirmessage[10] = 'B';
ccirmessage[11] = options_ra.selected_index() + 0x30;
ccirmessage[12] = options_rb.selected_index() + 0x30;
ccirmessage[13] = options_rc.selected_index() + 0x30;
ccirmessage[14] = '0';
ccirmessage[15] = 'B';
ccirmessage[16] = '0';
ccirmessage[17] = '0';
ccirmessage[18] = '0';
ccirmessage[19] = '0';
// Stuffing
for (c=1; c<20; c++) {
if (ccirmessage[c] == ccirmessage[c-1]) ccirmessage[c] = 'E';
}
ccirmessage[20] = 0;
text_debug.set(ccirmessage);
}
XylosView::XylosView(
NavigationView& nav,
TransmitterModel& transmitter_model
) : transmitter_model(transmitter_model)
{
static constexpr Style style_val {
.font = font::fixed_8x16,
.background = Color::green(),
.foreground = Color::black(),
};
static constexpr Style style_cancel {
.font = font::fixed_8x16,
.background = Color::red(),
.foreground = Color::black(),
};
transmitter_model.set_modulation(19);
add_children({ {
&text_title,
&text_city,
&city_code,
&text_family,
&family_code,
&text_subfamily,
&subfamily_code,
&checkbox_wcsubfamily,
&text_receiver,
&receiver_code,
&checkbox_wcid,
&text_freq,
&options_freq,
&text_ra,
&options_ra,
&text_rb,
&options_rb,
&text_rc,
&options_rc,
&text_progress,
&text_debug,
&button_transmit,
&button_exit
} });
city_code.set_value(18);
family_code.set_value(1);
subfamily_code.set_value(1);
receiver_code.set_value(1);
options_freq.set_selected_index(5);
checkbox_wcsubfamily.set_value(true);
checkbox_wcid.set_value(true);
city_code.on_change = [this](int32_t v) {
(void)v;
XylosView::upd_message();
};
family_code.on_change = [this](int32_t v) {
(void)v;
XylosView::upd_message();
};
subfamily_code.on_change = [this](int32_t v) {
(void)v;
XylosView::upd_message();
};
receiver_code.on_change = [this](int32_t v) {
(void)v;
XylosView::upd_message();
};
checkbox_wcsubfamily.on_select = [this](Checkbox&) {
XylosView::upd_message();
};
checkbox_wcid.on_select = [this](Checkbox&) {
XylosView::upd_message();
};
options_ra.on_change = [this](size_t n, OptionsField::value_t v) {
(void)n;
(void)v;
XylosView::upd_message();
};
options_rb.on_change = [this](size_t n, OptionsField::value_t v) {
(void)n;
(void)v;
XylosView::upd_message();
};
options_rc.on_change = [this](size_t n, OptionsField::value_t v) {
(void)n;
(void)v;
XylosView::upd_message();
};
button_transmit.set_style(&style_val);
button_transmit.on_select = [this,&transmitter_model](Button&) {
if (txing == false) {
upd_message();
auto& message_map = context().message_map();
message_map.unregister_handler(Message::ID::TXDone);
message_map.register_handler(Message::ID::TXDone,
[this,&transmitter_model](Message* const p) {
uint8_t c;
char progress[21];
const auto message = static_cast<const TXDoneMessage*>(p);
if (message->n == 25) {
transmitter_model.disable();
for (c=0;c<20;c++)
progress[c] = ' ';
progress[20] = 0;
text_progress.set(progress);
txing = false;
button_transmit.set_style(&style_val);
button_transmit.set_text("START");
} else {
for (c=0;c<message->n;c++)
progress[c] = ' ';
progress[c] = '.';
progress[++c] = 0;
text_progress.set(progress);
}
}
);
shared_memory.xylos_transmit_done = false;
memcpy(shared_memory.xylosdata, ccirmessage, 21);
transmitter_model.set_tuning_frequency(87700000); //xylos_freqs[options_freq.selected_index()]);
txing = true;
button_transmit.set_style(&style_cancel);
button_transmit.set_text("Wait");
transmitter_model.enable();
}
};
button_exit.on_select = [&nav](Button&){
nav.pop();
};
}
} /* namespace ui */

View File

@ -0,0 +1,191 @@
/*
* 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 "transmitter_model.hpp"
namespace ui {
class XylosView : public View {
public:
XylosView(NavigationView& nav, TransmitterModel& transmitter_model);
~XylosView();
void upd_message();
void focus() override;
void paint(Painter& painter) override;
private:
bool txing = false;
const rf::Frequency xylos_freqs[6] = { 31325000, 31387500, 31437500, 31475000, 31687500, 31975000 };
char ccirmessage[21];
TransmitterModel& transmitter_model;
Text text_title {
{ 1 * 8, 1 * 16, 11, 16 },
"BH Xylos TX"
};
Text text_city {
{ 4 * 8, 3 * 16, 11 * 8, 16 },
"Code ville:"
};
NumberField city_code {
{ 16 * 8, 3 * 16 },
2,
{ 0, 99 },
1,
' '
};
Text text_family {
{ 7 * 8, 4 * 16, 8 * 8, 16 },
"Famille:"
};
NumberField family_code {
{ 16 * 8, 4 * 16 },
2,
{ 0, 9 },
1,
' '
};
Text text_subfamily {
{ 2 * 8, 5 * 16 + 4, 13 * 8, 16 },
"Sous-famille:"
};
NumberField subfamily_code {
{ 16 * 8, 5 * 16 + 4 },
2,
{ 0, 9 },
1,
' '
};
Checkbox checkbox_wcsubfamily {
{ 20 * 8, 5 * 16},
"Toutes"
};
Text text_receiver {
{ 2 * 8, 7 * 16 + 6, 13 * 8, 16 },
"ID recepteur:"
};
NumberField receiver_code {
{ 16 * 8, 7 * 16 + 6 },
2,
{ 0, 99 },
1,
' '
};
Checkbox checkbox_wcid {
{ 20 * 8, 7 * 16 + 4},
"Tous"
};
Text text_freq {
{ 5 * 8, 9 * 16, 10 * 8, 16 },
"Frequence:"
};
OptionsField options_freq {
{ 16 * 8, 9 * 16 },
6,
{
{ "31.3250", 0 },
{ "31.3875", 1 },
{ "31.4375", 2 },
{ "31.4750", 3 },
{ "31.6875", 4 },
{ "31.9750", 5 }
}
};
Text text_ra {
{ 12, 11 * 16, 8 * 8, 16 },
"Relais 1"
};
OptionsField options_ra {
{ 16, 12 * 16 },
3,
{
{ "Ignorer", 0 },
{ " OFF ", 1 },
{ " ON ", 2 }
}
};
Text text_rb {
{ 88, 11 * 16, 8 * 8, 16 },
"Relais 2"
};
OptionsField options_rb {
{ 92, 12 * 16 },
3,
{
{ "Ignorer", 0 },
{ " OFF ", 1 },
{ " ON ", 2 }
}
};
Text text_rc {
{ 164, 11 * 16, 8 * 8, 16 },
"Relais 3"
};
OptionsField options_rc {
{ 168, 12 * 16 },
3,
{
{ "Ignorer", 0 },
{ " OFF ", 1 },
{ " ON ", 2 }
}
};
Text text_progress {
{ 5 * 8, 13 * 16, 20 * 8, 16 },
" "
};
Text text_debug {
{ 5 * 8, 14 * 16, 20 * 8, 16 },
"--------------------"
};
Button button_transmit {
{ 2 * 8, 16 * 16, 64, 32 },
"START"
};
Button button_exit {
{ 21 * 8, 16 * 16, 64, 32 },
"Exit"
};
};
} /* namespace ui */

Binary file not shown.

View File

@ -136,6 +136,7 @@ CPPSRC = main.cpp \
matched_filter.cpp \
proc_jammer.cpp \
proc_fsk_lcr.cpp \
proc_xylos.cpp \
dsp_squelch.cpp \
clock_recovery.cpp \
packet_builder.cpp \

View File

@ -50,6 +50,7 @@
#include "baseband_processor.hpp"
#include "proc_fsk_lcr.hpp"
#include "proc_jammer.hpp"
#include "proc_xylos.hpp"
#include "clock_recovery.hpp"
#include "packet_builder.hpp"
@ -512,6 +513,11 @@ int main(void) {
direction = baseband::Direction::Transmit;
baseband_thread.baseband_processor = new JammerProcessor();
break;
case 19:
direction = baseband::Direction::Transmit;
baseband_thread.baseband_processor = new XylosProcessor();
break;
default:
break;

View File

@ -21,6 +21,7 @@
#include "proc_fsk_lcr.hpp"
#include "portapack_shared_memory.hpp"
#include "sine_table.hpp"
#include <cstdint>
@ -76,7 +77,7 @@ void LCRFSKProcessor::execute(buffer_c8_t buffer) {
s++;
}
//sample = sine_table_f32[(aphase & 0x00FF0000)>>16];
sample = (sine_table_f32[(aphase & 0x03FF0000)>>18]*255);
//FM
frq = sample * shared_memory.afsk_fmmod;
@ -84,8 +85,8 @@ void LCRFSKProcessor::execute(buffer_c8_t buffer) {
phase = (phase + frq);
sphase = phase + (256<<16);
//re = sine_table_f32[(sphase & 0x00FF0000)>>16];
//im = sine_table_f32[(phase & 0x00FF0000)>>16];
re = (sine_table_f32[(sphase & 0x03FF0000)>>18]*127);
im = (sine_table_f32[(phase & 0x03FF0000)>>18]*127);
buffer.p[i] = {(int8_t)re,(int8_t)im};
}

View File

@ -61,7 +61,7 @@ void JammerProcessor::execute(buffer_c8_t buffer) {
if (ir > 15) ir = 0;
if (shared_memory.jammer_ranges[ir].active == true) break;
}
jammer_bw = shared_memory.jammer_ranges[ir].width / 4;
jammer_bw = shared_memory.jammer_ranges[ir].width / 2;
message.freq = shared_memory.jammer_ranges[ir].center;
shared_memory.application_queue.push(message);
@ -89,7 +89,7 @@ void JammerProcessor::execute(buffer_c8_t buffer) {
}
aphase += 8830;
sample = sine_table_f32[(aphase & 0x00FF0000)>>16];
sample = sine_table_f32[(aphase & 0x03FF0000)>>18]*256;
//FM
frq = sample * jammer_bw; // Bandwidth
@ -97,8 +97,8 @@ void JammerProcessor::execute(buffer_c8_t buffer) {
phase = (phase + frq);
sphase = phase + (256<<16);
re = sine_table_f32[(sphase & 0x00FF0000)>>16];
im = sine_table_f32[(phase & 0x00FF0000)>>16];
re = sine_table_f32[(sphase & 0x03FF0000)>>18]*127;
im = sine_table_f32[(phase & 0x03FF0000)>>18]*127;
buffer.p[i] = {(int8_t)re,(int8_t)im};
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_xylos.hpp"
#include "portapack_shared_memory.hpp"
#include "sine_table.hpp"
#include <cstdint>
void XylosProcessor::execute(buffer_c8_t buffer) {
for (size_t i = 0; i<buffer.count; i++) {
//Sample generation 2.28M/10 = 228kHz
if (s >= 9) {
s = 0;
if (sample_count >= CCIR_TONELENGTH) {
if (shared_memory.xylos_transmit_done == false) {
message.n = byte_pos; // Progress
shared_memory.application_queue.push(message);
digit = shared_memory.xylosdata[byte_pos++];
}
if (!digit) {
message.n = 25; // Done code
shared_memory.xylos_transmit_done = true;
shared_memory.application_queue.push(message);
digit = 0;
}
if (digit > '9') digit -= 7;
digit -= 0x30;
sample_count = 0;
} else {
sample_count++;
}
aphase += ccir_phases[digit];
} else {
s++;
}
sample = (sine_table_f32[(aphase & 0x03FF0000)>>18]*255);
//FM
frq = sample * 160; // 20kHz wide (?)
phase = (phase + frq);
sphase = phase + (256<<16);
re = (sine_table_f32[(sphase & 0x03FF0000)>>18]*127);
im = (sine_table_f32[(phase & 0x03FF0000)>>18]*127);
buffer.p[i] = {(int8_t)re,(int8_t)im};
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_XYLOS_H__
#define __PROC_XYLOS_H__
#include "baseband_processor.hpp"
#define CCIR_TONELENGTH 22800
#define PHASEV 294.34
class XylosProcessor : public BasebandProcessor {
public:
void execute(buffer_c8_t buffer) override;
private:
uint32_t ccir_phases[16] = {
1981*PHASEV,
1124*PHASEV,
1197*PHASEV,
1275*PHASEV,
1358*PHASEV,
1446*PHASEV,
1540*PHASEV,
1640*PHASEV,
1747*PHASEV,
1860*PHASEV,
2400*PHASEV,
930*PHASEV,
2247*PHASEV,
991*PHASEV,
2110*PHASEV,
1055*PHASEV
};
int8_t re, im;
uint8_t s;
uint8_t byte_pos = 0;
uint8_t digit = 0;
uint32_t sample_count = CCIR_TONELENGTH;
uint32_t aphase, phase, sphase;
int32_t sample, frq;
TXDoneMessage message;
};
#endif

Binary file not shown.

View File

@ -140,6 +140,8 @@ CPPSRC = main.cpp \
proc_ais.cpp \
proc_wideband_spectrum.cpp \
proc_tpms.cpp \
proc_afskrx.cpp \
proc_sigfrx.cpp \
dsp_squelch.cpp \
clock_recovery.cpp \
packet_builder.cpp \

View File

@ -180,6 +180,79 @@ constexpr fir_taps_real<64> taps_64_lp_130_169_tfilter {
} },
};
// 41kHz/70kHz @ 192kHz
// http://t-filter.appspot.com
constexpr fir_taps_real<64> taps_64_lp_410_700_tfilter {
.pass_frequency_normalized = 0.213f,
.stop_frequency_normalized = 0.364f,
.taps = { {
0,
0,
0,
0,
-1,
0,
3,
-3,
-7,
12,
10,
-35,
-3,
79,
-37,
-138,
146,
180,
-361,
-126,
688,
-149,
-1062,
800,
1308,
-1991,
-1092,
3963,
-286,
-7710,
6211,
32368,
32368,
6211,
-7710,
-286,
3963,
-1092,
-1991,
1308,
800,
-1062,
-149,
688,
-126,
-361,
180,
146,
-138,
-37,
79,
-3,
-35,
10,
12,
-7,
-3,
3,
0,
-1,
0,
0,
0,
0
} },
};
/* Wideband audio filter */
/* 96kHz int16_t input
* -> FIR filter, <15kHz (0.156fs) pass, >19kHz (0.198fs) stop

View File

@ -57,9 +57,11 @@
#include "proc_am_audio.hpp"
#include "proc_nfm_audio.hpp"
#include "proc_wfm_audio.hpp"
#include "proc_ais.hpp"
//#include "proc_ais.hpp"
#include "proc_wideband_spectrum.hpp"
#include "proc_tpms.hpp"
//#include "proc_tpms.hpp"
#include "proc_afskrx.hpp"
#include "proc_sigfrx.hpp"
#include "clock_recovery.hpp"
#include "packet_builder.hpp"
@ -356,7 +358,7 @@ void ram_loop_fn(void) {
void wait_for_switch(void) {
memcpy(&ram_loop[0], reinterpret_cast<char*>(&ram_loop_fn), 32);
loop_ptr = reinterpret_cast<fn_ptr>(&ram_loop[0]);
ReadyForSwitchMessage message { true };
ReadyForSwitchMessage message;
shared_memory.application_queue.push(message);
(*loop_ptr)();
return;
@ -402,19 +404,29 @@ int main(void) {
baseband_thread.baseband_processor = new WidebandFMAudio();
break;
case 3:
/*case 3:
direction = baseband::Direction::Receive;
baseband_thread.baseband_processor = new AISProcessor();
break;
break;*/
case 4:
direction = baseband::Direction::Receive;
baseband_thread.baseband_processor = new WidebandSpectrum();
break;
case 5:
/*case 5:
direction = baseband::Direction::Receive;
baseband_thread.baseband_processor = new TPMSProcessor();
break;*/
case 6:
direction = baseband::Direction::Receive;
baseband_thread.baseband_processor = new AFSKRXProcessor();
break;
case 7:
direction = baseband::Direction::Receive;
baseband_thread.baseband_processor = new SIGFRXProcessor();
break;
case 0xFF:

View File

@ -0,0 +1,122 @@
/*
* 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_afskrx.hpp"
#include "sine_table.hpp"
#include "portapack_shared_memory.hpp"
using namespace lpc43xx;
void AFSKRXProcessor::execute(buffer_c8_t buffer) {
/* Called every 2048/3072000 second -- 1500Hz. */
auto decimator_out = decimator.execute(buffer);
const buffer_c16_t work_baseband_buffer {
(complex16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 96kHz complex<int16_t>[64]
* -> FIR filter, <6kHz (0.063fs) pass, gain 1.0
* -> 48kHz int16_t[32] */
auto channel = channel_filter.execute(decimator_out, work_baseband_buffer);
const buffer_s16_t work_audio_buffer {
(int16_t*)decimator_out.p,
sizeof(*decimator_out.p) * decimator_out.count
};
/* 48kHz complex<int16_t>[32]
* -> FM demodulation
* -> 48kHz int16_t[32] */
auto audio = demod.execute(channel, work_audio_buffer);
/*static uint64_t audio_present_history = 0;
const auto audio_present_now = squelch.execute(audio);
audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0);
const bool audio_present = (audio_present_history != 0);
*/
//if( !audio_present ) {
// Zero audio buffer.
/*for(size_t i=0; i<audio.count; i++) {
if ((i % 3) > 1)
audio.p[i] = 4096;
else
audio.p[i] = -4096;
}*/
//}
audio_hpf.execute_in_place(audio);
for(size_t i=0; i<audio.count; i++) {
if (spur > 10) {
if (audio.p[i] > 2000)
sign = 1;
if (audio.p[i] < -2000)
sign = 0;
spur = 0;
} else {
spur++;
}
if (sign != prev_sign) {
if (freq_timer < 15) // 48
bit = 0;
else
bit++;
freq_timer = 0;
}
prev_sign = sign;
if (freq_timer < 1000) freq_timer++; // TODO: Limit in a more intelligent way
}
if (bit_timer >= 40) {
bit_timer = 0;
// Check bit state here !
} else {
bit_timer++;
}
if (sc >= 600) {
sc = 0;
AFSKDataMessage message;
memcpy(message.data,aud,128*2);
shared_memory.application_queue.push(message);
audc = 0;
} else {
sc++;
}
if (audc < 4) {
memcpy(aud+(audc*32),audio.p,32*2);
audc++;
}
fill_audio_buffer(audio);
}
void AFSKRXProcessor::data_handler(
const double data
) {
/*AFSKDataMessage message;
message.data = 'T';
shared_memory.application_queue.push(message);*/
}

View File

@ -0,0 +1,68 @@
/*
* 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_AFSKRX_H__
#define __PROC_AFSKRX_H__
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "dsp_fir_taps.hpp"
#include "dsp_iir.hpp"
#include "dsp_iir_config.hpp"
#include "dsp_squelch.hpp"
#include "message.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
class AFSKRXProcessor : public BasebandProcessor {
public:
AFSKRXProcessor() {
decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By32);
channel_filter.configure(channel_filter_taps.taps, 2);
}
void execute(buffer_c8_t buffer) override;
private:
ChannelDecimator decimator;
const fir_taps_real<64>& channel_filter_taps = taps_64_lp_042_078_tfilter;
dsp::decimate::FIRAndDecimateComplex channel_filter;
dsp::demodulate::FM demod { 48000, 5000 };
IIRBiquadFilter audio_hpf { audio_hpf_config };
//FMSquelch squelch;
uint16_t bit_timer = 0, freq_timer = 0;
uint16_t sc;
uint8_t audc, spur, sign, prev_sign, bit = 0;
int16_t aud[128];
void data_handler(const double data);
};
#endif/*__PROC_TPMS_H__*/

View File

@ -246,6 +246,70 @@ void ILI9341::render_line(const ui::Point p, const uint8_t count, const ui::Colo
io.lcd_write_pixels(line_buffer, count);
}
void ILI9341::drawBMP(const ui::Point p, const uint8_t * bitmap) {
uint32_t pixel_data, pal_data;
uint8_t pal, by, c, count;
ui::Color linebuffer[240];
ui::Coord px = 0, py;
ui::Color palette[16];
uint32_t bmpwidth, bmpheight;
// RLE_4 BMP loader with hardcoded size and no delta :(
if (bitmap[0x1E] != 2) return; // Bad compression type
bmpwidth = static_cast<int32_t>(
(bitmap[0x12]) |
(bitmap[0x13] << 8) |
(bitmap[0x14] << 16)|
(bitmap[0x15] << 24) );
bmpheight = static_cast<int32_t>(
(bitmap[0x16]) |
(bitmap[0x17] << 8) |
(bitmap[0x18] << 16)|
(bitmap[0x19] << 24) );
pal_data = bitmap[0x0E] + 0x0E;
pixel_data = bitmap[0x0A];
pal = 0;
for (c = 0; c < (16*4); c+=4) {
palette[pal++] = ui::Color(bitmap[c+2+pal_data], bitmap[c+1+pal_data], bitmap[c+pal_data]);
}
py = bmpheight + 16;
do {
by = bitmap[pixel_data++];
if (by) {
count = by;
by = bitmap[pixel_data++];
for (c = 0; c < count; c+=2) {
linebuffer[px++] = palette[by >> 4];
if (px < bmpwidth) linebuffer[px++] = palette[by & 15];
}
if (pixel_data & 1) pixel_data++;
} else {
by = bitmap[pixel_data++];
if (by == 0) {
render_line({p.x, p.y + py}, bmpwidth, linebuffer);
py--;
px = 0;
} else if (by == 1) {
break;
} else if (by == 2) {
// Delta
} else {
count = by;
for (c = 0; c < count; c+=2) {
by = bitmap[pixel_data++];
linebuffer[px++] = palette[by >> 4];
if (px < bmpwidth) linebuffer[px++] = palette[by & 15];
}
if (pixel_data & 1) pixel_data++;
}
}
} while (1);
}
void ILI9341::draw_line(const ui::Point start, const ui::Point end, const ui::Color color) {
int x0 = start.x;
int y0 = start.y;

View File

@ -54,6 +54,7 @@ public:
);
void draw_pixel(const ui::Point p, const ui::Color color);
void drawBMP(const ui::Point p, const uint8_t * bitmap);
void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer);
template<size_t N>

View File

@ -50,6 +50,7 @@ public:
SDCardStatus = 10,
Retune = 11,
ReadyForSwitch = 12,
AFSKData = 13,
MAX
};
@ -236,6 +237,16 @@ public:
TPMSPacket packet;
};
class AFSKDataMessage : public Message {
public:
constexpr AFSKDataMessage(
) : Message { ID::AFSKData }
{
}
int16_t data[128] = {0};
};
class ShutdownMessage : public Message {
public:
constexpr ShutdownMessage(
@ -269,12 +280,9 @@ public:
class ReadyForSwitchMessage : public Message {
public:
ReadyForSwitchMessage(
bool ok
) : Message { ID::ReadyForSwitch }
{
}
const bool ok = false;
};
class RetuneMessage : public Message {

View File

@ -59,6 +59,9 @@ struct SharedMemory {
bool afsk_transmit_done;
JammerRange jammer_ranges[16];
char xylosdata[21];
bool xylos_transmit_done;
};
extern SharedMemory& shared_memory;

View File

@ -433,7 +433,6 @@ bool Checkbox::on_key(const KeyEvent key) {
if( on_select ) {
on_select(*this);
return true;
}
}