mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-24 06:49:24 -05:00
Merge branch 'master' into gps-sim
This commit is contained in:
commit
d17130092c
136
README.md
136
README.md
@ -1,135 +1 @@
|
||||
![HAVOC banner](doc/banner.png)
|
||||
|
||||
HAVOC is an **unofficial** fork of the PortaPack H1 firmware, a portability add-on for the [HackRF One software-defined radio](http://greatscottgadgets.com/hackrf/).
|
||||
|
||||
Hardware is available at [ShareBrained Technology](http://sharebrained.com/portapack).
|
||||
|
||||
It is build on top of [ShareBrained's firmware](https://github.com/sharebrained/portapack-hackrf/), meaning most of the original functionality remains the same.
|
||||
|
||||
# Documentation & finding help
|
||||
|
||||
![Helpful note](doc/helpful.png)
|
||||
|
||||
Please RTFM before asking for help:
|
||||
* [Havoc wiki](https://github.com/furrtek/portapack-havoc/wiki)
|
||||
* [PortaPack wiki](https://github.com/sharebrained/portapack-hackrf/wiki)
|
||||
* [Some questions and answers](https://github.com/furrtek/portapack-havoc/issues)
|
||||
* [Facebook group](https://www.facebook.com/groups/177623356165819/) if that's your thing
|
||||
* And probably a bunch of posts on a variety of forums...
|
||||
|
||||
If you want to submit a bug report, use this page: https://github.com/furrtek/portapack-havoc/issues. Check if it hasn't been already posted, there's a search function. Also check the progress list below. Tickets which aren't related to the firmware itself, or the original HackRF and Portapack H1 will be closed.
|
||||
|
||||
# Summary
|
||||
|
||||
As its name implies, HAVOC's functions can be fun, mean or even useful sometimes. You probably shouldn't use them. No ! Bad ! Put it down.
|
||||
|
||||
**In most countries, radio transmissions are tightly regulated. Transmitting outside of free/public bands without a licence or authorization, even at very low power, is certainly forbidden where you live. Always bear that in mind. You're the ONLY ONE responsible for what you do with this software.**
|
||||
|
||||
# Fork features
|
||||
|
||||
* IQ file replay
|
||||
* Microphone FM transmit with CTCSS
|
||||
* CTCSS decoder
|
||||
* Frequency manager (save & load from SD card, with categories and notes)
|
||||
* File manager
|
||||
* "Soundboard" wave file player (put 8-bit mono files in SD card /wav directory)
|
||||
* ADS-B receiver with map view
|
||||
* ADS-B transmitter (aircraft spoof)
|
||||
* SSTV transmitter
|
||||
* Fully configurable jammer
|
||||
* POCSAG transmitter
|
||||
* POCSAG receiver/decoder
|
||||
* Morse transmitter (FM tone and CW)
|
||||
* OOK transmitter for common remote encoders (PT2262, doorbells, remote outlets, some garage doors, ...)
|
||||
* RDS (Radio Data System) PSN, RadioText and Time groups transmitter
|
||||
* Meteorological radiosonde receiver (M10, M2K2, ...)
|
||||
* AFSK receiver
|
||||
* AFSK transmitter (Bell202, ...)
|
||||
* Nuoptix DTMF sync transmitter (quite specific but can be useful in some theme parks :) )
|
||||
* TouchTunes jukebox universal remote (by Notpike)
|
||||
* LCR (Language de Commande Routier) message generator
|
||||
* Street lighting control transmitter (CCIR tones)
|
||||
* "Play Dead" in case of emergency
|
||||
* Fully configurable RF signal generator
|
||||
* RSSI audio output as pitch (for direction finding)
|
||||
|
||||
# Progress
|
||||
|
||||
Feature | Progress | Notes
|
||||
------- | -------- | -----
|
||||
POCSAG RX | 95% | Needs support for numeric messages
|
||||
Morse TX | 95% | Needs fox hunt scheduler and live keying mode
|
||||
Mic. TX | 95% | Carrier leak bug, need to find guard tones for various brands of wireless mics
|
||||
ADS-B RX | 90% | Needs angle and speed decoding
|
||||
Close-Call™ | 85% | Needs adjustments and optimization for wider frequency range
|
||||
ADS-B TX | 85% | Works but baseband module needs cleaning
|
||||
SSTV TX | 80% | Needs better bitmap file handling, support for other modes (ROBOT ?) and callsign FSK ID
|
||||
Radiosondes | 75% | Needs support for other models
|
||||
Wave visualizer | 70% | Needs cleaning and handling of other sample formats, high priority
|
||||
AFSK RX | 70% | Needs work regarding flexibility
|
||||
Sigfox RX | 40% | Tuning basics done, needs decoding code and testing
|
||||
Generic TXs | 30% | Raw AX.25, AFSK, FSK, CCIR, DTMF... Tonesets are ready
|
||||
CC1101 TRX | 10% | And other sub-GHz transceiver chips like SI4032...
|
||||
SSTV RX | 0% |
|
||||
Scanner | 0% | Easy, could be used with POCSAG RX to catch jumping channels
|
||||
SSB TX | 0% | Requested but math is hard :(
|
||||
OOK RX | 0% | See if rtl_433's author is fine with using protocol defs
|
||||
Analog TV TX| 0% | Enough CPU ? B&W and no sound ?
|
||||
LoJack RX | 0% | Basically AFSK RX
|
||||
DMR info RX | 0% | Retrieve DMR channel info. **No voice** because of vocoder complexity and possible legal issue
|
||||
Tetra info? | 0% | Same
|
||||
|
||||
# Screenshots
|
||||
|
||||
![HAVOC screenshots](doc/screenshots.png)
|
||||
|
||||
# Thanks
|
||||
|
||||
* Sig and cLx for research on AFSK LCR, Xylos, and for lending remote-controlled outlets
|
||||
* Pyr3x, Rainer Matla and DC1RDB for the donations :)
|
||||
* Keld Norman and Giorgio Campiotti for ideas and suggestions
|
||||
* In general, people who help making it better instead of asking already answered questions
|
||||
|
||||
# License
|
||||
|
||||
Except where specified in subdirectories of this project, all work is offered under the following license:
|
||||
|
||||
Copyright (C) 2013-2019 Jared Boone, ShareBrained Technology, Inc.
|
||||
|
||||
Copyright (C) 2015-2016 Furrtek
|
||||
|
||||
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
|
||||
of the License, 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; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA.
|
||||
|
||||
# Contact
|
||||
|
||||
## Original firmware and hardware
|
||||
|
||||
Jared Boone <jared@sharebrained.com>
|
||||
|
||||
ShareBrained Technology, Inc.
|
||||
|
||||
<http://www.sharebrained.com/>
|
||||
|
||||
The latest version of this repository can be found at
|
||||
https://github.com/sharebrained/portapack-hackrf/
|
||||
|
||||
## HAVOC specific things
|
||||
|
||||
Warning: won't reply to questions about flashing and compiling. See links above.
|
||||
|
||||
Furrtek <furrtek@gmail.com>
|
||||
|
||||
<http://www.furrtek.org>
|
||||
Unofficial fork of the unofficial HAVOC. Just keeping the latest release files and all features I found around here.
|
||||
|
27
dockerfile-nogit
Normal file
27
dockerfile-nogit
Normal file
@ -0,0 +1,27 @@
|
||||
FROM ubuntu:latest
|
||||
|
||||
# Set location to download ARM toolkit from.
|
||||
# This will need to be changed over time or replaced with a static link to the latest release.
|
||||
ENV ARMBINURL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2?revision=108bd959-44bd-4619-9c19-26187abf5225&la=en&hash=E788CE92E5DFD64B2A8C246BBA91A249CB8E2D2D \
|
||||
PATH=$PATH:/opt/build/armbin/bin
|
||||
|
||||
#Create volume /havoc/bin for compiled firmware binaries
|
||||
VOLUME /havoc
|
||||
WORKDIR /havoc/firmware
|
||||
|
||||
# Fetch dependencies from APT
|
||||
RUN apt-get update && \
|
||||
apt-get install -y git tar wget dfu-util cmake python3 python-pip && \
|
||||
apt-get -qy autoremove
|
||||
|
||||
RUN pip install pyyaml
|
||||
|
||||
# Grab the GNU ARM toolchain from arm.com
|
||||
# Then extract contents to /opt/build/armbin/
|
||||
RUN mkdir /opt/build && cd /opt/build && \
|
||||
wget -O gcc-arm-none-eabi $ARMBINURL && \
|
||||
mkdir armbin && \
|
||||
tar --strip=1 -xjvf gcc-arm-none-eabi -C armbin
|
||||
|
||||
CMD cd .. && cd build && \
|
||||
cmake .. && make firmware
|
@ -209,6 +209,7 @@ set(CPPSRC
|
||||
ui/ui_btngrid.cpp
|
||||
ui/ui_receiver.cpp
|
||||
ui/ui_rssi.cpp
|
||||
ui/ui_tv.cpp
|
||||
ui/ui_spectrum.cpp
|
||||
ui/ui_tabview.cpp
|
||||
ui/ui_textentry.cpp
|
||||
@ -217,6 +218,8 @@ set(CPPSRC
|
||||
apps/ui_adsb_rx.cpp
|
||||
apps/ui_adsb_tx.cpp
|
||||
apps/ui_afsk_rx.cpp
|
||||
apps/ui_btle_rx.cpp
|
||||
apps/ui_nrf_rx.cpp
|
||||
apps/ui_aprs_tx.cpp
|
||||
apps/ui_bht_tx.cpp
|
||||
apps/ui_coasterp.cpp
|
||||
@ -251,6 +254,7 @@ set(CPPSRC
|
||||
apps/acars_app.cpp
|
||||
apps/ais_app.cpp
|
||||
apps/analog_audio_app.cpp
|
||||
apps/analog_tv_app.cpp
|
||||
apps/capture_app.cpp
|
||||
apps/ert_app.cpp
|
||||
apps/lge_app.cpp
|
||||
|
238
firmware/application/apps/analog_tv_app.cpp
Normal file
238
firmware/application/apps/analog_tv_app.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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 "analog_tv_app.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
using namespace portapack;
|
||||
using namespace tonekey;
|
||||
|
||||
#include "audio.hpp"
|
||||
#include "file.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
#include "string_format.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
/* AnalogTvView *******************************************************/
|
||||
|
||||
AnalogTvView::AnalogTvView(
|
||||
NavigationView& nav
|
||||
) : nav_ (nav)
|
||||
{
|
||||
add_children({
|
||||
&rssi,
|
||||
&channel,
|
||||
&audio,
|
||||
&field_frequency,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&options_modulation,
|
||||
&field_volume,
|
||||
&tv
|
||||
});
|
||||
|
||||
field_frequency.set_value(receiver_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);
|
||||
};
|
||||
};
|
||||
|
||||
field_frequency.on_show_options = [this]() {
|
||||
this->on_show_options_frequency();
|
||||
};
|
||||
|
||||
field_lna.on_show_options = [this]() {
|
||||
this->on_show_options_rf_gain();
|
||||
};
|
||||
|
||||
field_vga.on_show_options = [this]() {
|
||||
this->on_show_options_rf_gain();
|
||||
};
|
||||
|
||||
const auto modulation = receiver_model.modulation();
|
||||
options_modulation.set_by_value(toUType(ReceiverModel::Mode::WidebandFMAudio));
|
||||
options_modulation.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
this->on_modulation_changed(static_cast<ReceiverModel::Mode>(v));
|
||||
};
|
||||
options_modulation.on_show_options = [this]() {
|
||||
this->on_show_options_modulation();
|
||||
};
|
||||
|
||||
field_volume.set_value(0);
|
||||
field_volume.on_change = [this](int32_t v) {
|
||||
this->on_headphone_volume_changed(v);
|
||||
};
|
||||
|
||||
tv.on_select = [this](int32_t offset) {
|
||||
field_frequency.set_value(receiver_model.tuning_frequency() + offset);
|
||||
};
|
||||
|
||||
update_modulation(static_cast<ReceiverModel::Mode>(modulation));
|
||||
on_modulation_changed(ReceiverModel::Mode::WidebandFMAudio);
|
||||
}
|
||||
|
||||
AnalogTvView::~AnalogTvView() {
|
||||
// TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do
|
||||
// both?
|
||||
audio::output::stop();
|
||||
|
||||
receiver_model.disable();
|
||||
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void AnalogTvView::on_hide() {
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
tv.on_hide();
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
void AnalogTvView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
const ui::Rect tv_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
|
||||
tv.set_parent_rect(tv_rect);
|
||||
}
|
||||
|
||||
void AnalogTvView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
void AnalogTvView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
receiver_model.set_tuning_frequency(f);
|
||||
}
|
||||
|
||||
void AnalogTvView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) {
|
||||
receiver_model.set_baseband_bandwidth(bandwidth_hz);
|
||||
}
|
||||
|
||||
void AnalogTvView::on_modulation_changed(const ReceiverModel::Mode modulation) {
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
tv.on_hide();
|
||||
update_modulation(modulation);
|
||||
on_show_options_modulation();
|
||||
tv.on_show();
|
||||
}
|
||||
|
||||
void AnalogTvView::remove_options_widget() {
|
||||
if( options_widget ) {
|
||||
remove_child(options_widget.get());
|
||||
options_widget.reset();
|
||||
}
|
||||
|
||||
field_lna.set_style(nullptr);
|
||||
options_modulation.set_style(nullptr);
|
||||
field_frequency.set_style(nullptr);
|
||||
}
|
||||
|
||||
void AnalogTvView::set_options_widget(std::unique_ptr<Widget> new_widget) {
|
||||
remove_options_widget();
|
||||
|
||||
if( new_widget ) {
|
||||
options_widget = std::move(new_widget);
|
||||
} else {
|
||||
// TODO: Lame hack to hide options view due to my bad paint/damage algorithm.
|
||||
options_widget = std::make_unique<Rectangle>(options_view_rect, style_options_group_new.background);
|
||||
}
|
||||
add_child(options_widget.get());
|
||||
}
|
||||
|
||||
void AnalogTvView::on_show_options_frequency() {
|
||||
auto widget = std::make_unique<FrequencyOptionsView>(options_view_rect, &style_options_group_new);
|
||||
|
||||
widget->set_step(receiver_model.frequency_step());
|
||||
widget->on_change_step = [this](rf::Frequency f) {
|
||||
this->on_frequency_step_changed(f);
|
||||
};
|
||||
widget->set_reference_ppm_correction(persistent_memory::correction_ppb() / 1000);
|
||||
widget->on_change_reference_ppm_correction = [this](int32_t v) {
|
||||
this->on_reference_ppm_correction_changed(v);
|
||||
};
|
||||
|
||||
set_options_widget(std::move(widget));
|
||||
field_frequency.set_style(&style_options_group_new);
|
||||
}
|
||||
|
||||
void AnalogTvView::on_show_options_rf_gain() {
|
||||
auto widget = std::make_unique<RadioGainOptionsView>(options_view_rect, &style_options_group_new);
|
||||
|
||||
set_options_widget(std::move(widget));
|
||||
field_lna.set_style(&style_options_group_new);
|
||||
}
|
||||
|
||||
void AnalogTvView::on_show_options_modulation() {
|
||||
std::unique_ptr<Widget> widget;
|
||||
|
||||
const auto modulation = static_cast<ReceiverModel::Mode>(receiver_model.modulation());
|
||||
tv.show_audio_spectrum_view(true);
|
||||
|
||||
set_options_widget(std::move(widget));
|
||||
options_modulation.set_style(&style_options_group_new);
|
||||
}
|
||||
|
||||
void AnalogTvView::on_frequency_step_changed(rf::Frequency f) {
|
||||
receiver_model.set_frequency_step(f);
|
||||
field_frequency.set_step(f);
|
||||
}
|
||||
|
||||
void AnalogTvView::on_reference_ppm_correction_changed(int32_t v) {
|
||||
persistent_memory::set_correction_ppb(v * 1000);
|
||||
}
|
||||
|
||||
void AnalogTvView::on_headphone_volume_changed(int32_t v) {
|
||||
//tv::TVView::set_headphone_volume(this,v);
|
||||
}
|
||||
|
||||
void AnalogTvView::update_modulation(const ReceiverModel::Mode modulation) {
|
||||
audio::output::mute();
|
||||
|
||||
baseband::shutdown();
|
||||
|
||||
portapack::spi_flash::image_tag_t image_tag;
|
||||
image_tag = portapack::spi_flash::image_tag_am_tv;
|
||||
|
||||
baseband::run_image(image_tag);
|
||||
|
||||
receiver_model.set_modulation(modulation);
|
||||
receiver_model.set_sampling_rate(2000000);
|
||||
receiver_model.set_baseband_bandwidth(2000000);
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
133
firmware/application/apps/analog_tv_app.hpp
Normal file
133
firmware/application/apps/analog_tv_app.hpp
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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 __ANALOG_TV_APP_H__
|
||||
#define __ANALOG_TV_APP_H__
|
||||
|
||||
#include "receiver_model.hpp"
|
||||
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_tv.hpp"
|
||||
#include "ui_record_view.hpp"
|
||||
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
#include "tone_key.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
constexpr Style style_options_group_new {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::blue(),
|
||||
.foreground = Color::white(),
|
||||
};
|
||||
|
||||
class AnalogTvView : public View {
|
||||
public:
|
||||
AnalogTvView(NavigationView& nav);
|
||||
~AnalogTvView();
|
||||
|
||||
void on_hide() override;
|
||||
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Analog TV"; };
|
||||
|
||||
private:
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
const Rect options_view_rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 };
|
||||
const Rect nbfm_view_rect { 0 * 8, 1 * 16, 18 * 8, 1 * 16 };
|
||||
|
||||
NavigationView& nav_;
|
||||
|
||||
RSSI rssi {
|
||||
{ 21 * 8, 0, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
Channel channel {
|
||||
{ 21 * 8, 5, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
Audio audio {
|
||||
{ 21 * 8, 10, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 5 * 8, 0 * 16 },
|
||||
};
|
||||
|
||||
LNAGainField field_lna {
|
||||
{ 15 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
VGAGainField field_vga {
|
||||
{ 18 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
OptionsField options_modulation {
|
||||
{ 0 * 8, 0 * 16 },
|
||||
4,
|
||||
{
|
||||
{ "TV ", toUType(ReceiverModel::Mode::WidebandFMAudio) },
|
||||
{ "TV ", toUType(ReceiverModel::Mode::WidebandFMAudio) },
|
||||
{ "TV ", toUType(ReceiverModel::Mode::WidebandFMAudio) },
|
||||
}
|
||||
};
|
||||
|
||||
NumberField field_volume {
|
||||
{ 27 * 8, 0 * 16 },
|
||||
3,
|
||||
{ 0, 255 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
std::unique_ptr<Widget> options_widget { };
|
||||
|
||||
tv::TVWidget tv { true };
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
|
||||
void on_modulation_changed(const ReceiverModel::Mode modulation);
|
||||
void on_show_options_frequency();
|
||||
void on_show_options_rf_gain();
|
||||
void on_show_options_modulation();
|
||||
void on_frequency_step_changed(rf::Frequency f);
|
||||
void on_reference_ppm_correction_changed(int32_t v);
|
||||
void on_headphone_volume_changed(int32_t v);
|
||||
void on_edit_frequency();
|
||||
|
||||
void remove_options_widget();
|
||||
void set_options_widget(std::unique_ptr<Widget> new_widget);
|
||||
|
||||
void update_modulation(const ReceiverModel::Mode modulation);
|
||||
|
||||
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__ANALOG_TV_APP_H__*/
|
@ -72,7 +72,7 @@ private:
|
||||
int32_t delay;
|
||||
} credits_t;
|
||||
|
||||
const credits_t credits[25] = {
|
||||
const credits_t credits[26] = {
|
||||
// 012345678901234567890123456789
|
||||
{ 60, "PortaPack|HAVOC", 0 },
|
||||
{ 4 * 8, "Version " VERSION_STRING, 16 },
|
||||
@ -89,7 +89,8 @@ private:
|
||||
{ 7 * 8, "World map NASA", 16 },
|
||||
{ 0 * 8, "TouchTunes infos Notpike", 16 },
|
||||
{ 4 * 8, "Subaru infos Tom", 0 },
|
||||
{ 18 * 8, "Wimmenhove", 24 },
|
||||
{ 18 * 8, "Wimmenhove", 16 },
|
||||
{ 1 * 8, "GPS,TV,BTLE,NRF Shao", 24 },
|
||||
{ 6 * 8, "Thanks & donators", 16 },
|
||||
{ 1 * 8, "Rainer Matla Keld Norman", 0 },
|
||||
{ 1 * 8, " Giorgio C. DC1RDB", 0 },
|
||||
|
160
firmware/application/apps/ui_btle_rx.cpp
Normal file
160
firmware/application/apps/ui_btle_rx.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_btle_rx.hpp"
|
||||
#include "ui_modemsetup.hpp"
|
||||
|
||||
#include "modems.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace modems;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void BTLERxView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
void BTLERxView::update_freq(rf::Frequency f) {
|
||||
receiver_model.set_tuning_frequency(f);
|
||||
}
|
||||
|
||||
BTLERxView::BTLERxView(NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_btle_rx);
|
||||
|
||||
add_children({
|
||||
&rssi,
|
||||
&channel,
|
||||
&field_rf_amp,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_frequency,
|
||||
&text_debug,
|
||||
&button_modem_setup,
|
||||
&record_view,
|
||||
&console
|
||||
});
|
||||
|
||||
// DEBUG
|
||||
record_view.on_error = [&nav](std::string message) {
|
||||
nav.display_modal("Error", message);
|
||||
};
|
||||
record_view.set_sampling_rate(24000);
|
||||
|
||||
// Auto-configure modem for LCR RX (will be removed later)
|
||||
update_freq(2426000000);
|
||||
auto def_bell202 = &modem_defs[0];
|
||||
persistent_memory::set_modem_baudrate(def_bell202->baudrate);
|
||||
serial_format_t serial_format;
|
||||
serial_format.data_bits = 7;
|
||||
serial_format.parity = EVEN;
|
||||
serial_format.stop_bits = 1;
|
||||
serial_format.bit_order = LSB_FIRST;
|
||||
persistent_memory::set_serial_format(serial_format);
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_step(100);
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
update_freq(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
update_freq(f);
|
||||
field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
|
||||
button_modem_setup.on_select = [&nav](Button&) {
|
||||
nav.push<ModemSetupView>();
|
||||
};
|
||||
|
||||
|
||||
// Auto-configure modem for LCR RX (will be removed later)
|
||||
baseband::set_btle(persistent_memory::modem_baudrate(), 8, 0, false);
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
|
||||
receiver_model.set_sampling_rate(4000000);
|
||||
receiver_model.set_baseband_bandwidth(4000000);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
void BTLERxView::on_data(uint32_t value, bool is_data) {
|
||||
//std::string str_console = "\x1B";
|
||||
std::string str_console = "";
|
||||
if (is_data) {
|
||||
// Colorize differently after message splits
|
||||
//str_console += (char)((console_color & 3) + 9);
|
||||
|
||||
//value &= 0xFF; // ABCDEFGH
|
||||
//value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4); // EFGHABCD
|
||||
//value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2); // GHEFCDAB
|
||||
//value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1); // HGFEDCBA
|
||||
//value &= 0x7F; // Ignore parity, which is the MSB now
|
||||
|
||||
//if ((value >= 32) && (value < 127)) {
|
||||
// str_console += (char)value; // Printable
|
||||
//}
|
||||
|
||||
//str_console += (char)'A';
|
||||
//str_console += (char)value;
|
||||
//str_console += "[" + to_string_hex(value, 2) + "]";
|
||||
str_console += ":" + to_string_hex(value, 2) ;
|
||||
console.write(str_console);
|
||||
|
||||
|
||||
|
||||
/*if ((value != 0x7F) && (prev_value == 0x7F)) {
|
||||
// Message split
|
||||
console.writeln("");
|
||||
console_color++;
|
||||
|
||||
|
||||
}*/
|
||||
//prev_value = value;
|
||||
} else {
|
||||
// Baudrate estimation
|
||||
//text_debug.set("~" + to_string_dec_uint(value));
|
||||
if (value == 'A')
|
||||
{console.write("mac");}
|
||||
else if (value == 'B')
|
||||
{console.writeln("");}
|
||||
//console.writeln("");
|
||||
}
|
||||
}
|
||||
|
||||
BTLERxView::~BTLERxView() {
|
||||
audio::output::stop();
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
107
firmware/application/apps/ui_btle_rx.hpp
Normal file
107
firmware/application/apps/ui_btle_rx.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_BTLE_RX_H__
|
||||
#define __UI_BTLE_RX_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_record_view.hpp" // DEBUG
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class BTLERxView : public View {
|
||||
public:
|
||||
BTLERxView(NavigationView& nav);
|
||||
~BTLERxView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "BTLE RX"; };
|
||||
|
||||
private:
|
||||
void on_data(uint32_t value, bool is_data);
|
||||
|
||||
uint8_t console_color { 0 };
|
||||
uint32_t prev_value { 0 };
|
||||
std::string str_log { "" };
|
||||
|
||||
RFAmpField field_rf_amp {
|
||||
{ 13 * 8, 0 * 16 }
|
||||
};
|
||||
LNAGainField field_lna {
|
||||
{ 15 * 8, 0 * 16 }
|
||||
};
|
||||
VGAGainField field_vga {
|
||||
{ 18 * 8, 0 * 16 }
|
||||
};
|
||||
RSSI rssi {
|
||||
{ 21 * 8, 0, 6 * 8, 4 },
|
||||
};
|
||||
Channel channel {
|
||||
{ 21 * 8, 5, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 0 * 8, 0 * 16 },
|
||||
};
|
||||
|
||||
Text text_debug {
|
||||
{ 0 * 8, 1 * 16, 10 * 8, 16 },
|
||||
"DEBUG"
|
||||
};
|
||||
|
||||
|
||||
Button button_modem_setup {
|
||||
{ 12 * 8, 1 * 16, 96, 24 },
|
||||
"Modem setup"
|
||||
};
|
||||
|
||||
// DEBUG
|
||||
RecordView record_view {
|
||||
{ 0 * 8, 3 * 16, 30 * 8, 1 * 16 },
|
||||
u"AFS_????", RecordView::FileType::WAV, 4096, 4
|
||||
};
|
||||
|
||||
Console console {
|
||||
{ 0, 4 * 16, 240, 240 }
|
||||
};
|
||||
|
||||
void update_freq(rf::Frequency f);
|
||||
//void on_data_afsk(const AFSKDataMessage& message);
|
||||
|
||||
MessageHandlerRegistration message_handler_packet {
|
||||
Message::ID::AFSKData,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const AFSKDataMessage*>(p);
|
||||
this->on_data(message->value, message->is_data);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__UI_BTLE_RX_H__*/
|
165
firmware/application/apps/ui_nrf_rx.cpp
Normal file
165
firmware/application/apps/ui_nrf_rx.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_nrf_rx.hpp"
|
||||
#include "ui_modemsetup.hpp"
|
||||
|
||||
#include "modems.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace modems;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void NRFRxView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
void NRFRxView::update_freq(rf::Frequency f) {
|
||||
receiver_model.set_tuning_frequency(f);
|
||||
}
|
||||
|
||||
NRFRxView::NRFRxView(NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_nrf_rx);
|
||||
|
||||
add_children({
|
||||
&rssi,
|
||||
&channel,
|
||||
&field_rf_amp,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_frequency,
|
||||
&text_debug,
|
||||
&button_modem_setup,
|
||||
&record_view,
|
||||
&console
|
||||
});
|
||||
|
||||
// DEBUG
|
||||
record_view.on_error = [&nav](std::string message) {
|
||||
nav.display_modal("Error", message);
|
||||
};
|
||||
record_view.set_sampling_rate(24000);
|
||||
|
||||
// Auto-configure modem for LCR RX (will be removed later)
|
||||
update_freq(2480000000);
|
||||
auto def_bell202 = &modem_defs[0];
|
||||
persistent_memory::set_modem_baudrate(def_bell202->baudrate);
|
||||
serial_format_t serial_format;
|
||||
serial_format.data_bits = 7;
|
||||
serial_format.parity = EVEN;
|
||||
serial_format.stop_bits = 1;
|
||||
serial_format.bit_order = LSB_FIRST;
|
||||
persistent_memory::set_serial_format(serial_format);
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_step(100);
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
update_freq(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
update_freq(f);
|
||||
field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
|
||||
button_modem_setup.on_select = [&nav](Button&) {
|
||||
nav.push<ModemSetupView>();
|
||||
};
|
||||
|
||||
|
||||
// Auto-configure modem for LCR RX (will be removed later)
|
||||
baseband::set_nrf(persistent_memory::modem_baudrate(), 8, 0, false);
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
|
||||
receiver_model.set_sampling_rate(4000000);
|
||||
receiver_model.set_baseband_bandwidth(4000000);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
void NRFRxView::on_data(uint32_t value, bool is_data) {
|
||||
//std::string str_console = "\x1B";
|
||||
std::string str_console = "";
|
||||
if (is_data) {
|
||||
// Colorize differently after message splits
|
||||
//str_console += (char)((console_color & 3) + 9);
|
||||
|
||||
//value &= 0xFF; // ABCDEFGH
|
||||
//value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4); // EFGHABCD
|
||||
//value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2); // GHEFCDAB
|
||||
//value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1); // HGFEDCBA
|
||||
//value &= 0x7F; // Ignore parity, which is the MSB now
|
||||
|
||||
//if ((value >= 32) && (value < 127)) {
|
||||
// str_console += (char)value; // Printable
|
||||
//}
|
||||
|
||||
//str_console += (char)'A';
|
||||
//str_console += (char)value;
|
||||
//str_console += "[" + to_string_hex(value, 2) + "]";
|
||||
str_console += " " + to_string_hex(value, 2) ;
|
||||
console.write(str_console);
|
||||
|
||||
|
||||
|
||||
/*if ((value != 0x7F) && (prev_value == 0x7F)) {
|
||||
// Message split
|
||||
console.writeln("");
|
||||
console_color++;
|
||||
|
||||
|
||||
}*/
|
||||
//prev_value = value;
|
||||
} else {
|
||||
// Baudrate estimation
|
||||
//text_debug.set("~" + to_string_dec_uint(value));
|
||||
if (value == 'A')
|
||||
{console.write("addr:");}
|
||||
else if (value == 'B')
|
||||
{console.write(" data:");}
|
||||
else if (value == 'C')
|
||||
{
|
||||
console.writeln("");
|
||||
console.writeln("");
|
||||
}
|
||||
//console.writeln("");
|
||||
}
|
||||
}
|
||||
|
||||
NRFRxView::~NRFRxView() {
|
||||
audio::output::stop();
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
107
firmware/application/apps/ui_nrf_rx.hpp
Normal file
107
firmware/application/apps/ui_nrf_rx.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_NRF_RX_H__
|
||||
#define __UI_NRF_RX_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_record_view.hpp" // DEBUG
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class NRFRxView : public View {
|
||||
public:
|
||||
NRFRxView(NavigationView& nav);
|
||||
~NRFRxView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "NRF RX"; };
|
||||
|
||||
private:
|
||||
void on_data(uint32_t value, bool is_data);
|
||||
|
||||
uint8_t console_color { 0 };
|
||||
uint32_t prev_value { 0 };
|
||||
std::string str_log { "" };
|
||||
|
||||
RFAmpField field_rf_amp {
|
||||
{ 13 * 8, 0 * 16 }
|
||||
};
|
||||
LNAGainField field_lna {
|
||||
{ 15 * 8, 0 * 16 }
|
||||
};
|
||||
VGAGainField field_vga {
|
||||
{ 18 * 8, 0 * 16 }
|
||||
};
|
||||
RSSI rssi {
|
||||
{ 21 * 8, 0, 6 * 8, 4 },
|
||||
};
|
||||
Channel channel {
|
||||
{ 21 * 8, 5, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 0 * 8, 0 * 16 },
|
||||
};
|
||||
|
||||
Text text_debug {
|
||||
{ 0 * 8, 1 * 16, 10 * 8, 16 },
|
||||
"DEBUG"
|
||||
};
|
||||
|
||||
|
||||
Button button_modem_setup {
|
||||
{ 12 * 8, 1 * 16, 96, 24 },
|
||||
"Modem setup"
|
||||
};
|
||||
|
||||
// DEBUG
|
||||
RecordView record_view {
|
||||
{ 0 * 8, 3 * 16, 30 * 8, 1 * 16 },
|
||||
u"AFS_????", RecordView::FileType::WAV, 4096, 4
|
||||
};
|
||||
|
||||
Console console {
|
||||
{ 0, 4 * 16, 240, 240 }
|
||||
};
|
||||
|
||||
void update_freq(rf::Frequency f);
|
||||
//void on_data_afsk(const AFSKDataMessage& message);
|
||||
|
||||
MessageHandlerRegistration message_handler_packet {
|
||||
Message::ID::AFSKData,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const AFSKDataMessage*>(p);
|
||||
this->on_data(message->value, message->is_data);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__UI_NRF_RX_H__*/
|
@ -130,6 +130,26 @@ void set_afsk(const uint32_t baudrate, const uint32_t word_length, const uint32_
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void set_btle(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word) {
|
||||
const BTLERxConfigureMessage message {
|
||||
baudrate,
|
||||
word_length,
|
||||
trigger_value,
|
||||
trigger_word
|
||||
};
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void set_nrf(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word) {
|
||||
const NRFRxConfigureMessage message {
|
||||
baudrate,
|
||||
word_length,
|
||||
trigger_value,
|
||||
trigger_word
|
||||
};
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space,
|
||||
const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count) {
|
||||
const AFSKTxConfigureMessage message {
|
||||
|
@ -68,6 +68,11 @@ void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phas
|
||||
const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count);
|
||||
void kill_afsk();
|
||||
void set_afsk(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word);
|
||||
|
||||
void set_btle(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word);
|
||||
|
||||
void set_nrf(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word);
|
||||
|
||||
void set_ook_data(const uint32_t stream_length, const uint32_t samples_per_bit, const uint8_t repeat,
|
||||
const uint32_t pause_symbols);
|
||||
void set_fsk_data(const uint32_t stream_length, const uint32_t samples_per_bit, const uint32_t shift,
|
||||
|
@ -1524,6 +1524,51 @@ static constexpr uint8_t bitmap_gps_sim_data[] = {
|
||||
static constexpr Bitmap bitmap_gps_sim {
|
||||
{ 16, 16 }, bitmap_gps_sim_data
|
||||
};
|
||||
|
||||
static constexpr uint8_t bitmap_icon_btle_data[] = {
|
||||
0x00, 0x00,
|
||||
0x80, 0x00,
|
||||
0x80, 0x01,
|
||||
0x80, 0x07,
|
||||
0x80, 0x0C,
|
||||
0x98, 0x06,
|
||||
0xF0, 0x03,
|
||||
0xE0, 0x01,
|
||||
0xE0, 0x01,
|
||||
0xF0, 0x03,
|
||||
0x98, 0x06,
|
||||
0x80, 0x0C,
|
||||
0x80, 0x07,
|
||||
0x80, 0x01,
|
||||
0x80, 0x00,
|
||||
0x00, 0x00,
|
||||
};
|
||||
static constexpr Bitmap bitmap_icon_btle {
|
||||
{ 16, 16 }, bitmap_icon_btle_data
|
||||
};
|
||||
|
||||
static constexpr uint8_t bitmap_icon_nrf_data[] = {
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x07, 0xE0,
|
||||
0x05, 0x20,
|
||||
0xCC, 0x33,
|
||||
0xF4, 0x2F,
|
||||
0xE6, 0x67,
|
||||
0xE2, 0x47,
|
||||
0x36, 0x5C,
|
||||
0x0E, 0xE0,
|
||||
0x06, 0x60,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
};
|
||||
static constexpr Bitmap bitmap_icon_nrf {
|
||||
{ 16, 16 }, bitmap_icon_nrf_data
|
||||
};
|
||||
|
||||
static constexpr uint8_t bitmap_sig_sine_data[] = {
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -538,3 +538,262 @@ const std::array<ui::Color, 256> spectrum_rgb3_lut { {
|
||||
{ 252, 3, 0 },
|
||||
{ 255, 0, 0 },
|
||||
} };
|
||||
|
||||
const std::array<ui::Color, 256> spectrum_rgb4_lut { {
|
||||
{ 0, 0, 0 },
|
||||
{ 1, 1, 1 },
|
||||
{ 2, 2, 2 },
|
||||
{ 3, 3, 3 },
|
||||
{ 4, 4, 4 },
|
||||
{ 5, 5, 5 },
|
||||
{ 6, 6, 6 },
|
||||
{ 7, 7, 7 },
|
||||
{ 8, 8, 8 },
|
||||
{ 9, 9, 9 },
|
||||
{ 10, 10, 10 },
|
||||
{ 11, 11, 11 },
|
||||
{ 12, 12, 12 },
|
||||
{ 13, 13, 13 },
|
||||
{ 14, 14, 14 },
|
||||
{ 15, 15, 15 },
|
||||
{ 16, 16, 16 },
|
||||
{ 17, 17, 17 },
|
||||
{ 18, 18, 18 },
|
||||
{ 19, 19, 19 },
|
||||
{ 20, 20, 20 },
|
||||
{ 21, 21, 21 },
|
||||
{ 22, 22, 22 },
|
||||
{ 23, 23, 23 },
|
||||
{ 24, 24, 24 },
|
||||
{ 25, 25, 25 },
|
||||
{ 26, 26, 26 },
|
||||
{ 27, 27, 27 },
|
||||
{ 28, 28, 28 },
|
||||
{ 29, 29, 29 },
|
||||
{ 30, 30, 30 },
|
||||
{ 31, 31, 31 },
|
||||
{ 32, 32, 32 },
|
||||
{ 33, 33, 33 },
|
||||
{ 34, 34, 34 },
|
||||
{ 35, 35, 35 },
|
||||
{ 36, 36, 36 },
|
||||
{ 37, 37, 37 },
|
||||
{ 38, 38, 38 },
|
||||
{ 39, 39, 39 },
|
||||
{ 40, 40, 40 },
|
||||
{ 41, 41, 41 },
|
||||
{ 42, 42, 42 },
|
||||
{ 43, 43, 43 },
|
||||
{ 44, 44, 44 },
|
||||
{ 45, 45, 45 },
|
||||
{ 46, 46, 46 },
|
||||
{ 47, 47, 47 },
|
||||
{ 48, 48, 48 },
|
||||
{ 49, 49, 49 },
|
||||
{ 50, 50, 50 },
|
||||
{ 51, 51, 51 },
|
||||
{ 52, 52, 52 },
|
||||
{ 53, 53, 53 },
|
||||
{ 54, 54, 54 },
|
||||
{ 55, 55, 55 },
|
||||
{ 56, 56, 56 },
|
||||
{ 57, 57, 57 },
|
||||
{ 58, 58, 58 },
|
||||
{ 59, 59, 59 },
|
||||
{ 60, 60, 60 },
|
||||
{ 61, 61, 61 },
|
||||
{ 62, 62, 62 },
|
||||
{ 63, 63, 63 },
|
||||
{ 64, 64, 64 },
|
||||
{ 65, 65, 65 },
|
||||
{ 66, 66, 66 },
|
||||
{ 67, 67, 67 },
|
||||
{ 68, 68, 68 },
|
||||
{ 69, 69, 69 },
|
||||
{ 70, 70, 70 },
|
||||
{ 71, 71, 71 },
|
||||
{ 72, 72, 72 },
|
||||
{ 73, 73, 73 },
|
||||
{ 74, 74, 74 },
|
||||
{ 75, 75, 75 },
|
||||
{ 76, 76, 76 },
|
||||
{ 77, 77, 77 },
|
||||
{ 78, 78, 78 },
|
||||
{ 79, 79, 79 },
|
||||
{ 80, 80, 80 },
|
||||
{ 81, 81, 81 },
|
||||
{ 82, 82, 82 },
|
||||
{ 83, 83, 83 },
|
||||
{ 84, 84, 84 },
|
||||
{ 85, 85, 85 },
|
||||
{ 86, 86, 86 },
|
||||
{ 87, 87, 87 },
|
||||
{ 88, 88, 88 },
|
||||
{ 89, 89, 89 },
|
||||
{ 90, 90, 90 },
|
||||
{ 91, 91, 91 },
|
||||
{ 92, 92, 92 },
|
||||
{ 93, 93, 93 },
|
||||
{ 94, 94, 94 },
|
||||
{ 95, 95, 95 },
|
||||
{ 96, 96, 96 },
|
||||
{ 97, 97, 97 },
|
||||
{ 98, 98, 98 },
|
||||
{ 99, 99, 99 },
|
||||
{ 100, 100, 100 },
|
||||
{ 101, 101, 101 },
|
||||
{ 102, 102, 102 },
|
||||
{ 103, 103, 103 },
|
||||
{ 104, 104, 104 },
|
||||
{ 105, 105, 105 },
|
||||
{ 106, 106, 106 },
|
||||
{ 107, 107, 107 },
|
||||
{ 108, 108, 108 },
|
||||
{ 109, 109, 109 },
|
||||
{ 110, 110, 110 },
|
||||
{ 111, 111, 111 },
|
||||
{ 112, 112, 112 },
|
||||
{ 113, 113, 113 },
|
||||
{ 114, 114, 114 },
|
||||
{ 115, 115, 115 },
|
||||
{ 116, 116, 116 },
|
||||
{ 117, 117, 117 },
|
||||
{ 118, 118, 118 },
|
||||
{ 119, 119, 119 },
|
||||
{ 120, 120, 120 },
|
||||
{ 121, 121, 121 },
|
||||
{ 122, 122, 122 },
|
||||
{ 123, 123, 123 },
|
||||
{ 124, 124, 124 },
|
||||
{ 125, 125, 125 },
|
||||
{ 126, 126, 126 },
|
||||
{ 127, 127, 127 },
|
||||
{ 128, 128, 128 },
|
||||
{ 129, 129, 129 },
|
||||
{ 130, 130, 130 },
|
||||
{ 131, 131, 131 },
|
||||
{ 132, 132, 132 },
|
||||
{ 133, 133, 133 },
|
||||
{ 134, 134, 134 },
|
||||
{ 135, 135, 135 },
|
||||
{ 136, 136, 136 },
|
||||
{ 137, 137, 137 },
|
||||
{ 138, 138, 138 },
|
||||
{ 139, 139, 139 },
|
||||
{ 140, 140, 140 },
|
||||
{ 141, 141, 141 },
|
||||
{ 142, 142, 142 },
|
||||
{ 143, 143, 143 },
|
||||
{ 144, 144, 144 },
|
||||
{ 145, 145, 145 },
|
||||
{ 146, 146, 146 },
|
||||
{ 147, 147, 147 },
|
||||
{ 148, 148, 148 },
|
||||
{ 149, 149, 149 },
|
||||
{ 150, 150, 150 },
|
||||
{ 151, 151, 151 },
|
||||
{ 152, 152, 152 },
|
||||
{ 153, 153, 153 },
|
||||
{ 154, 154, 154 },
|
||||
{ 155, 155, 155 },
|
||||
{ 156, 156, 156 },
|
||||
{ 157, 157, 157 },
|
||||
{ 158, 158, 158 },
|
||||
{ 159, 159, 159 },
|
||||
{ 160, 160, 160 },
|
||||
{ 161, 161, 161 },
|
||||
{ 162, 162, 162 },
|
||||
{ 163, 163, 163 },
|
||||
{ 164, 164, 164 },
|
||||
{ 165, 165, 165 },
|
||||
{ 166, 166, 166 },
|
||||
{ 167, 167, 167 },
|
||||
{ 168, 168, 168 },
|
||||
{ 169, 169, 169 },
|
||||
{ 170, 170, 170 },
|
||||
{ 171, 171, 171 },
|
||||
{ 172, 172, 172 },
|
||||
{ 173, 173, 173 },
|
||||
{ 174, 174, 174 },
|
||||
{ 175, 175, 175 },
|
||||
{ 176, 176, 176 },
|
||||
{ 177, 177, 177 },
|
||||
{ 178, 178, 178 },
|
||||
{ 179, 179, 179 },
|
||||
{ 180, 180, 180 },
|
||||
{ 181, 181, 181 },
|
||||
{ 182, 182, 182 },
|
||||
{ 183, 183, 183 },
|
||||
{ 184, 184, 184 },
|
||||
{ 185, 185, 185 },
|
||||
{ 186, 186, 186 },
|
||||
{ 187, 187, 187 },
|
||||
{ 188, 188, 188 },
|
||||
{ 189, 189, 189 },
|
||||
{ 190, 190, 190 },
|
||||
{ 191, 191, 191 },
|
||||
{ 192, 192, 192 },
|
||||
{ 193, 193, 193 },
|
||||
{ 194, 194, 194 },
|
||||
{ 195, 195, 195 },
|
||||
{ 196, 196, 196 },
|
||||
{ 197, 197, 197 },
|
||||
{ 198, 198, 198 },
|
||||
{ 199, 199, 199 },
|
||||
{ 200, 200, 200 },
|
||||
{ 201, 201, 201 },
|
||||
{ 202, 202, 202 },
|
||||
{ 203, 203, 203 },
|
||||
{ 204, 204, 204 },
|
||||
{ 205, 205, 205 },
|
||||
{ 206, 206, 206 },
|
||||
{ 207, 207, 207 },
|
||||
{ 208, 208, 208 },
|
||||
{ 209, 209, 209 },
|
||||
{ 210, 210, 210 },
|
||||
{ 211, 211, 211 },
|
||||
{ 212, 212, 212 },
|
||||
{ 213, 213, 213 },
|
||||
{ 214, 214, 214 },
|
||||
{ 215, 215, 215 },
|
||||
{ 216, 216, 216 },
|
||||
{ 217, 217, 217 },
|
||||
{ 218, 218, 218 },
|
||||
{ 219, 219, 219 },
|
||||
{ 220, 220, 220 },
|
||||
{ 221, 221, 221 },
|
||||
{ 222, 222, 222 },
|
||||
{ 223, 223, 223 },
|
||||
{ 224, 224, 224 },
|
||||
{ 225, 225, 225 },
|
||||
{ 226, 226, 226 },
|
||||
{ 227, 227, 227 },
|
||||
{ 228, 228, 228 },
|
||||
{ 229, 229, 229 },
|
||||
{ 230, 230, 230 },
|
||||
{ 231, 231, 231 },
|
||||
{ 232, 232, 232 },
|
||||
{ 233, 233, 233 },
|
||||
{ 234, 234, 234 },
|
||||
{ 235, 235, 235 },
|
||||
{ 236, 236, 236 },
|
||||
{ 237, 237, 237 },
|
||||
{ 238, 238, 238 },
|
||||
{ 239, 239, 239 },
|
||||
{ 240, 240, 240 },
|
||||
{ 241, 241, 241 },
|
||||
{ 242, 242, 242 },
|
||||
{ 243, 243, 243 },
|
||||
{ 244, 244, 244 },
|
||||
{ 245, 245, 245 },
|
||||
{ 246, 246, 246 },
|
||||
{ 247, 247, 247 },
|
||||
{ 248, 248, 248 },
|
||||
{ 249, 249, 249 },
|
||||
{ 250, 250, 250 },
|
||||
{ 251, 251, 251 },
|
||||
{ 252, 252, 252 },
|
||||
{ 253, 253, 253 },
|
||||
{ 254, 254, 254 },
|
||||
{ 255, 255, 255 },
|
||||
} };
|
||||
|
@ -28,5 +28,6 @@
|
||||
|
||||
extern const std::array<ui::Color, 256> spectrum_rgb2_lut;
|
||||
extern const std::array<ui::Color, 256> spectrum_rgb3_lut;
|
||||
extern const std::array<ui::Color, 256> spectrum_rgb4_lut;
|
||||
|
||||
#endif/*__SPECTRUM_COLOR_LUT_H__*/
|
||||
|
251
firmware/application/ui/ui_tv.cpp
Normal file
251
firmware/application/ui/ui_tv.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_tv.hpp"
|
||||
|
||||
#include "spectrum_color_lut.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
|
||||
namespace ui {
|
||||
namespace tv {
|
||||
|
||||
/* TimeScopeView******************************************************/
|
||||
|
||||
TimeScopeView::TimeScopeView(
|
||||
const Rect parent_rect
|
||||
) : View { parent_rect }
|
||||
{
|
||||
set_focusable(true);
|
||||
|
||||
add_children({
|
||||
//&labels,
|
||||
//&field_frequency,
|
||||
&waveform
|
||||
});
|
||||
|
||||
/*field_frequency.on_change = [this](int32_t) {
|
||||
set_dirty();
|
||||
};
|
||||
field_frequency.set_value(10);*/
|
||||
}
|
||||
|
||||
void TimeScopeView::paint(Painter& painter) {
|
||||
const auto r = screen_rect();
|
||||
|
||||
painter.fill_rectangle(r, Color::black());
|
||||
|
||||
// Cursor
|
||||
/*
|
||||
const Rect r_cursor {
|
||||
field_frequency.value() / (48000 / 240), r.bottom() - 32 - cursor_band_height,
|
||||
1, cursor_band_height
|
||||
};
|
||||
painter.fill_rectangle(
|
||||
r_cursor,
|
||||
Color::red()
|
||||
);*/
|
||||
}
|
||||
|
||||
void TimeScopeView::on_audio_spectrum(const AudioSpectrum* spectrum) {
|
||||
for (size_t i = 0; i < spectrum->db.size(); i++)
|
||||
audio_spectrum[i] = ((int16_t)spectrum->db[i] - 127) * 256;
|
||||
waveform.set_dirty();
|
||||
}
|
||||
|
||||
/* TVView *********************************************************/
|
||||
|
||||
void TVView::on_show() {
|
||||
clear();
|
||||
|
||||
const auto screen_r = screen_rect();
|
||||
display.scroll_set_area(screen_r.top(), screen_r.bottom());
|
||||
}
|
||||
|
||||
void TVView::on_hide() {
|
||||
/* TODO: Clear region to eliminate brief flash of content at un-shifted
|
||||
* position?
|
||||
*/
|
||||
display.scroll_disable();
|
||||
}
|
||||
|
||||
void TVView::paint(Painter& painter) {
|
||||
// Do nothing.
|
||||
(void)painter;
|
||||
}
|
||||
|
||||
void TVView::on_adjust_xcorr(uint8_t xcorr){
|
||||
x_correction = xcorr;
|
||||
}
|
||||
|
||||
void TVView::on_channel_spectrum(
|
||||
const ChannelSpectrum& spectrum
|
||||
) {
|
||||
//portapack has limitations
|
||||
// 1.screen resolution (less than 240x320) 2.samples each call back (128 or 256)
|
||||
// 3.memory size (for ui::Color, the buffer size
|
||||
//spectrum.db[i] is 256 long
|
||||
//768x625 ->128x625 ->128x312 -> 128x104
|
||||
//originally @6MHz sample rate, the PAL should be 768x625
|
||||
//I reduced sample rate to 2MHz(3 times less samples), then calculate mag (effectively decimate by 2)
|
||||
//the resolution is now changed to 128x625. The total decimation factor is 6, which changes how many samples in a line
|
||||
//However 625 is too large for the screen, also interlaced scanning is harder to realize in portapack than normal computer.
|
||||
//So I decided to simply drop half of the lines, once y is larger than 625/2=312.5 or 312, I recognize it as a new frame.
|
||||
//then the resolution is changed to 128x312
|
||||
//128x312 is now able to put into a 240x320 screen, but the buffer for a whole frame is 128x312=39936, which is too large
|
||||
//according to my test, I can only make a buffer with a length of 13312 of type ui::Color. which is 1/3 of what I wanted.
|
||||
//So now the resolution is changed to 128x104, the height is shrinked to 1/3 of the original height.
|
||||
//I was expecting to see 1/3 height of original video.
|
||||
|
||||
//Look how nice is that! I am now able to meet the requirements of 1 and 3 for portapack. Also the length of a line is 128
|
||||
//Each call back gives me 256 samples which is exactly 2 lines. What a coincidence!
|
||||
|
||||
//After some experiment, I did some improvements.
|
||||
//1.I found that instead of 1/3 of the frame is shown, I got 3 whole frames shrinked into one window.
|
||||
//So I made the height twice simply by painting 2 identical lines in the place of original lines
|
||||
//2.I found sometimes there is an horizontal offset, so I added x_correction to move the frame back to center manually
|
||||
//3.I changed video_buffer's type, from ui::Color to uint_8, since I don't need 3 digit to represent a grey scale value.
|
||||
//I was hoping that by doing this, I can have a longer buffer like 39936, then the frame will looks better vertically
|
||||
//however this is useless until now.
|
||||
|
||||
for(size_t i=0; i<256; i++)
|
||||
{
|
||||
//video_buffer[i+count*256] = spectrum_rgb4_lut[spectrum.db[i]];
|
||||
video_buffer_int[i+count*256] = 255 - spectrum.db[i];
|
||||
}
|
||||
count = count + 1;
|
||||
if (count == 52 -1)
|
||||
{
|
||||
ui::Color line_buffer[128];
|
||||
Coord line;
|
||||
uint32_t bmp_px;
|
||||
|
||||
/*for (line = 0; line < 104; line++)
|
||||
{
|
||||
for (bmp_px = 0; bmp_px < 128; bmp_px++)
|
||||
{
|
||||
//line_buffer[bmp_px] = video_buffer[bmp_px+line*128];
|
||||
line_buffer[bmp_px] = spectrum_rgb4_lut[video_buffer_int[bmp_px+line*128 + x_correction]];
|
||||
}
|
||||
|
||||
display.render_line({ 0, line + 100 }, 128, line_buffer);
|
||||
}*/
|
||||
for (line = 0; line < 208; line=line+2)
|
||||
{
|
||||
for (bmp_px = 0; bmp_px < 128; bmp_px++)
|
||||
{
|
||||
//line_buffer[bmp_px] = video_buffer[bmp_px+line*128];
|
||||
line_buffer[bmp_px] = spectrum_rgb4_lut[video_buffer_int[bmp_px+line/2*128 + x_correction]];
|
||||
}
|
||||
|
||||
display.render_line({ 0, line + 100 }, 128, line_buffer);
|
||||
display.render_line({ 0, line + 101 }, 128, line_buffer);
|
||||
}
|
||||
count = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TVView::clear() {
|
||||
display.fill_rectangle(
|
||||
screen_rect(),
|
||||
Color::black()
|
||||
);
|
||||
}
|
||||
|
||||
/* TVWidget *******************************************************/
|
||||
|
||||
TVWidget::TVWidget(const bool cursor) {
|
||||
add_children({
|
||||
&tv_view,
|
||||
&field_xcorr
|
||||
});
|
||||
field_xcorr.set_value(10);
|
||||
}
|
||||
|
||||
void TVWidget::on_show() {
|
||||
baseband::spectrum_streaming_start();
|
||||
}
|
||||
|
||||
void TVWidget::on_hide() {
|
||||
baseband::spectrum_streaming_stop();
|
||||
}
|
||||
|
||||
void TVWidget::show_audio_spectrum_view(const bool show) {
|
||||
if ((audio_spectrum_view && show) || (!audio_spectrum_view && !show)) return;
|
||||
|
||||
if (show) {
|
||||
audio_spectrum_view = std::make_unique<TimeScopeView>(audio_spectrum_view_rect);
|
||||
add_child(audio_spectrum_view.get());
|
||||
update_widgets_rect();
|
||||
} else {
|
||||
audio_spectrum_update = false;
|
||||
remove_child(audio_spectrum_view.get());
|
||||
audio_spectrum_view.reset();
|
||||
update_widgets_rect();
|
||||
}
|
||||
}
|
||||
|
||||
void TVWidget::update_widgets_rect() {
|
||||
if (audio_spectrum_view) {
|
||||
tv_view.set_parent_rect(tv_reduced_rect);
|
||||
} else {
|
||||
tv_view.set_parent_rect(tv_normal_rect);
|
||||
}
|
||||
tv_view.on_show();
|
||||
}
|
||||
|
||||
void TVWidget::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
tv_normal_rect = { 0, scale_height, new_parent_rect.width(), new_parent_rect.height() - scale_height};
|
||||
tv_reduced_rect = { 0, audio_spectrum_height + scale_height, new_parent_rect.width(), new_parent_rect.height() - scale_height - audio_spectrum_height };
|
||||
|
||||
update_widgets_rect();
|
||||
}
|
||||
|
||||
void TVWidget::paint(Painter& painter) {
|
||||
// TODO:
|
||||
(void)painter;
|
||||
}
|
||||
|
||||
void TVWidget::on_channel_spectrum(const ChannelSpectrum& spectrum) {
|
||||
tv_view.on_channel_spectrum(spectrum);
|
||||
tv_view.on_adjust_xcorr(field_xcorr.value());
|
||||
sampling_rate = spectrum.sampling_rate;
|
||||
|
||||
}
|
||||
|
||||
void TVWidget::on_audio_spectrum() {
|
||||
audio_spectrum_view->on_audio_spectrum(audio_spectrum_data);
|
||||
}
|
||||
|
||||
} /* namespace tv */
|
||||
} /* namespace ui */
|
176
firmware/application/ui/ui_tv.hpp
Normal file
176
firmware/application/ui/ui_tv.hpp
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_TV_H__
|
||||
#define __UI_TV_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "message.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace ui {
|
||||
namespace tv {
|
||||
|
||||
class TimeScopeView : public View {
|
||||
public:
|
||||
TimeScopeView(const Rect parent_rect);
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
void on_audio_spectrum(const AudioSpectrum* spectrum);
|
||||
|
||||
private:
|
||||
static constexpr int cursor_band_height = 4;
|
||||
|
||||
int16_t audio_spectrum[128] { 0 };
|
||||
|
||||
/*Labels labels {
|
||||
{ { 6 * 8, 0 * 16 }, "Hz", Color::light_grey() }
|
||||
};*/
|
||||
/*
|
||||
NumberField field_frequency {
|
||||
{ 0 * 8, 0 * 16 },
|
||||
5,
|
||||
{ 0, 48000 },
|
||||
48000 / 240,
|
||||
' '
|
||||
};*/
|
||||
|
||||
Waveform waveform {
|
||||
{ 0, 1 * 16 + cursor_band_height, 30 * 8, 2 * 16 },
|
||||
audio_spectrum,
|
||||
128,
|
||||
0,
|
||||
false,
|
||||
Color::white()
|
||||
};
|
||||
};
|
||||
|
||||
class TVView : public Widget {
|
||||
public:
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
||||
void on_adjust_xcorr(uint8_t xcorr);
|
||||
//ui::Color video_buffer[13312];
|
||||
uint8_t video_buffer_int[13312+128] { 0 }; //128 is for the over length caused by x_correction
|
||||
uint32_t count=0;
|
||||
uint8_t x_correction=0;
|
||||
private:
|
||||
void clear();
|
||||
|
||||
};
|
||||
|
||||
class TVWidget : public View {
|
||||
public:
|
||||
std::function<void(int32_t offset)> on_select { };
|
||||
|
||||
TVWidget(const bool cursor = false);
|
||||
|
||||
TVWidget(const TVWidget&) = delete;
|
||||
TVWidget(TVWidget&&) = delete;
|
||||
TVWidget& operator=(const TVWidget&) = delete;
|
||||
TVWidget& operator=(TVWidget&&) = delete;
|
||||
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
|
||||
void show_audio_spectrum_view(const bool show);
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
NumberField field_xcorr {
|
||||
{ 0 * 8, 0 * 16 },
|
||||
5,
|
||||
{ 0, 128 },
|
||||
1,
|
||||
' '
|
||||
};
|
||||
|
||||
private:
|
||||
void update_widgets_rect();
|
||||
|
||||
const Rect audio_spectrum_view_rect { 0 * 8, 0 * 16, 30 * 8, 2 * 16 + 20 };
|
||||
static constexpr Dim audio_spectrum_height = 16 * 2 + 20;
|
||||
static constexpr Dim scale_height = 20;
|
||||
|
||||
TVView tv_view { };
|
||||
|
||||
ChannelSpectrumFIFO* channel_fifo { nullptr };
|
||||
AudioSpectrum* audio_spectrum_data { nullptr };
|
||||
bool audio_spectrum_update { false };
|
||||
|
||||
std::unique_ptr<TimeScopeView> audio_spectrum_view { };
|
||||
|
||||
int sampling_rate { 0 };
|
||||
int32_t cursor_position { 0 };
|
||||
ui::Rect tv_normal_rect { };
|
||||
ui::Rect tv_reduced_rect { };
|
||||
|
||||
MessageHandlerRegistration message_handler_channel_spectrum_config {
|
||||
Message::ID::ChannelSpectrumConfig,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const ChannelSpectrumConfigMessage*>(p);
|
||||
this->channel_fifo = message.fifo;
|
||||
}
|
||||
};
|
||||
MessageHandlerRegistration message_handler_audio_spectrum {
|
||||
Message::ID::AudioSpectrum,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const AudioSpectrumMessage*>(p);
|
||||
this->audio_spectrum_data = message.data;
|
||||
this->audio_spectrum_update = true;
|
||||
}
|
||||
};
|
||||
MessageHandlerRegistration message_handler_frame_sync {
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
if( this->channel_fifo ) {
|
||||
ChannelSpectrum channel_spectrum;
|
||||
while( channel_fifo->out(channel_spectrum) ) {
|
||||
this->on_channel_spectrum(channel_spectrum);
|
||||
}
|
||||
}
|
||||
if (this->audio_spectrum_update) {
|
||||
this->audio_spectrum_update = false;
|
||||
this->on_audio_spectrum();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
||||
void on_audio_spectrum();
|
||||
};
|
||||
|
||||
} /* namespace tv */
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__UI_TV_H__*/
|
@ -34,6 +34,8 @@
|
||||
#include "ui_adsb_rx.hpp"
|
||||
#include "ui_adsb_tx.hpp"
|
||||
#include "ui_afsk_rx.hpp"
|
||||
#include "ui_btle_rx.hpp"
|
||||
#include "ui_nrf_rx.hpp"
|
||||
#include "ui_aprs_tx.hpp"
|
||||
#include "ui_bht_tx.hpp"
|
||||
#include "ui_coasterp.hpp"
|
||||
@ -68,6 +70,7 @@
|
||||
#include "acars_app.hpp"
|
||||
#include "ais_app.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "analog_tv_app.hpp"
|
||||
#include "capture_app.hpp"
|
||||
#include "ert_app.hpp"
|
||||
#include "lge_app.hpp"
|
||||
@ -348,7 +351,10 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
||||
{ "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ACARSAppView>(); }, },
|
||||
{ "AIS Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
|
||||
{ "AFSK", ui::Color::yellow(), &bitmap_icon_receivers, [&nav](){ nav.push<AFSKRxView>(); } },
|
||||
{ "BTLE", ui::Color::yellow(), &bitmap_icon_btle, [&nav](){ nav.push<BTLERxView>(); } },
|
||||
{ "NRF", ui::Color::yellow(), &bitmap_icon_nrf, [&nav](){ nav.push<NRFRxView>(); } },
|
||||
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push<AnalogAudioView>(); } },
|
||||
{ "Analog TV", ui::Color::yellow(), &bitmap_icon_sstv, [&nav](){ nav.push<AnalogTvView>(); } },
|
||||
{ "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
|
||||
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
|
||||
{ "Radiosnde", ui::Color::yellow(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
|
||||
|
@ -116,6 +116,7 @@ set(CPPSRC
|
||||
dsp_goertzel.cpp
|
||||
matched_filter.cpp
|
||||
spectrum_collector.cpp
|
||||
tv_collector.cpp
|
||||
stream_input.cpp
|
||||
stream_output.cpp
|
||||
dsp_squelch.cpp
|
||||
@ -311,7 +312,19 @@ set(MODE_CPPSRC
|
||||
proc_afskrx.cpp
|
||||
)
|
||||
DeclareTargets(PAFR afskrx)
|
||||
### NRF RX
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_nrfrx.cpp
|
||||
)
|
||||
DeclareTargets(PNRR nrfrx)
|
||||
|
||||
### BTLE RX
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_btlerx.cpp
|
||||
)
|
||||
DeclareTargets(PBTR btlerx)
|
||||
### AIS
|
||||
|
||||
set(MODE_CPPSRC
|
||||
@ -326,6 +339,13 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(PAMA am_audio)
|
||||
|
||||
### AM TV
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_am_tv.cpp
|
||||
)
|
||||
DeclareTargets(PAMT am_tv)
|
||||
|
||||
### Audio transmit
|
||||
|
||||
set(MODE_CPPSRC
|
||||
|
86
firmware/baseband/proc_am_tv.cpp
Normal file
86
firmware/baseband/proc_am_tv.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_am_tv.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "dsp_fft.hpp"
|
||||
#include "event_m4.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
void WidebandFMAudio::execute(const buffer_c8_t& buffer) {
|
||||
if( !configured ) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::fill(spectrum.begin(), spectrum.end(), 0);
|
||||
|
||||
for(size_t i=0; i<spectrum.size(); i++) {
|
||||
spectrum[i] += buffer.p[i];
|
||||
}
|
||||
|
||||
const buffer_c16_t buffer_c16 {spectrum.data(),spectrum.size(),buffer.sampling_rate};
|
||||
channel_spectrum.feed(buffer_c16);
|
||||
|
||||
int8_t re, im;
|
||||
int8_t mag;
|
||||
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
re = buffer.p[i].real();
|
||||
im = buffer.p[i].imag();
|
||||
mag = __builtin_sqrtf((re * re) + (im * im)) ;
|
||||
const unsigned int v = re + 127.0f; //timescope
|
||||
audio_spectrum.db[i] = std::max(0U, std::min(255U, v));
|
||||
}
|
||||
AudioSpectrumMessage message { &audio_spectrum };
|
||||
shared_memory.application_queue.push(message);
|
||||
}
|
||||
|
||||
void WidebandFMAudio::on_message(const Message* const message) {
|
||||
switch(message->id) {
|
||||
case Message::ID::UpdateSpectrum:
|
||||
case Message::ID::SpectrumStreamingConfig:
|
||||
channel_spectrum.on_message(message);
|
||||
break;
|
||||
|
||||
case Message::ID::WFMConfigure:
|
||||
configure(*reinterpret_cast<const WFMConfigureMessage*>(message));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WidebandFMAudio::configure(const WFMConfigureMessage& message) {
|
||||
configured = true;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
EventDispatcher event_dispatcher { std::make_unique<WidebandFMAudio>() };
|
||||
event_dispatcher.run();
|
||||
return 0;
|
||||
}
|
65
firmware/baseband/proc_am_tv.hpp
Normal file
65
firmware/baseband/proc_am_tv.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_AM_TV_H__
|
||||
#define __PROC_AM_TV_H__
|
||||
|
||||
#include "baseband_processor.hpp"
|
||||
#include "baseband_thread.hpp"
|
||||
#include "rssi_thread.hpp"
|
||||
|
||||
#include "dsp_types.hpp"
|
||||
#include "dsp_decimate.hpp"
|
||||
#include "dsp_demodulate.hpp"
|
||||
#include "block_decimator.hpp"
|
||||
|
||||
#include "tv_collector.hpp"
|
||||
|
||||
class WidebandFMAudio : public BasebandProcessor {
|
||||
public:
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
|
||||
void on_message(const Message* const message) override;
|
||||
|
||||
private:
|
||||
static constexpr size_t baseband_fs = 2000000;
|
||||
|
||||
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
|
||||
RSSIThread rssi_thread { NORMALPRIO + 10 };
|
||||
|
||||
std::array<complex16_t, 512> dst { };
|
||||
const buffer_c16_t dst_buffer {
|
||||
dst.data(),
|
||||
dst.size()
|
||||
};
|
||||
|
||||
AudioSpectrum audio_spectrum { };
|
||||
TvCollector channel_spectrum { };
|
||||
std::array<complex16_t, 256> spectrum { };
|
||||
|
||||
bool configured { false };
|
||||
void configure(const WFMConfigureMessage& message);
|
||||
|
||||
};
|
||||
|
||||
#endif/*__PROC_AM_TV_H__*/
|
339
firmware/baseband/proc_btlerx.cpp
Normal file
339
firmware/baseband/proc_btlerx.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_btlerx.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "event_m4.hpp"
|
||||
|
||||
void BTLERxProcessor::execute(const buffer_c8_t& buffer) {
|
||||
if (!configured) return;
|
||||
|
||||
// FM demodulation
|
||||
|
||||
/*const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
|
||||
const auto channel = decim_1.execute(decim_0_out, dst_buffer);
|
||||
|
||||
feed_channel_stats(channel);
|
||||
|
||||
auto audio_oversampled = demod.execute(channel, work_audio_buffer);*/
|
||||
|
||||
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
|
||||
feed_channel_stats(decim_0_out);
|
||||
|
||||
auto audio_oversampled = demod.execute(decim_0_out, work_audio_buffer);
|
||||
|
||||
/*std::fill(spectrum.begin(), spectrum.end(), 0);
|
||||
for(size_t i=0; i<spectrum.size(); i++) {
|
||||
spectrum[i] += buffer.p[i];
|
||||
}
|
||||
const buffer_c16_t buffer_c16 {spectrum.data(),spectrum.size(),buffer.sampling_rate};
|
||||
feed_channel_stats(buffer_c16);
|
||||
|
||||
auto audio_oversampled = demod.execute(buffer_c16, work_audio_buffer);*/
|
||||
// Audio signal processing
|
||||
for (size_t c = 0; c < audio_oversampled.count; c++) {
|
||||
int result;
|
||||
|
||||
/*const int32_t sample_int = audio_oversampled.p[c] * 32768.0f;
|
||||
int32_t current_sample = __SSAT(sample_int, 16);
|
||||
current_sample /= 128;*/
|
||||
|
||||
int32_t current_sample = audio_oversampled.p[c]; //if I directly use this, some results can pass crc but not correct.
|
||||
rb_head++;
|
||||
rb_head=(rb_head)%RB_SIZE;
|
||||
|
||||
rb_buf[rb_head] = current_sample;
|
||||
|
||||
skipSamples = skipSamples - 1;
|
||||
|
||||
|
||||
if (skipSamples<1)
|
||||
{
|
||||
|
||||
|
||||
int32_t threshold_tmp=0;
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
threshold_tmp = threshold_tmp + (int32_t)rb_buf[(rb_head+c)%RB_SIZE];
|
||||
}
|
||||
g_threshold = (int32_t)threshold_tmp/8;
|
||||
|
||||
|
||||
int transitions=0;
|
||||
if (rb_buf[(rb_head+9)%RB_SIZE] > g_threshold)
|
||||
{
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head + c)%RB_SIZE] > rb_buf[(rb_head + c + 1)%RB_SIZE])
|
||||
transitions = transitions + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head + c)%RB_SIZE] < rb_buf[(rb_head + c + 1)%RB_SIZE])
|
||||
transitions = transitions + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool packet_detected=false;
|
||||
//if ( transitions==4 && abs(g_threshold)<15500)
|
||||
if ( transitions==4)
|
||||
{
|
||||
|
||||
|
||||
uint8_t packet_data[500];
|
||||
int packet_length;
|
||||
uint32_t packet_crc;
|
||||
uint32_t calced_crc;
|
||||
uint64_t packet_addr_l;
|
||||
uint32_t result;
|
||||
uint8_t crc[3];
|
||||
uint8_t packet_header_arr[2];
|
||||
|
||||
packet_addr_l=0;
|
||||
for (int i=0;i<4;i++)
|
||||
{
|
||||
bool current_bit;
|
||||
uint8_t byte=0;
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head + (i+1)*8 + c)%RB_SIZE] > g_threshold)
|
||||
current_bit = true;
|
||||
else
|
||||
current_bit = false;
|
||||
byte |= current_bit << (7-c);
|
||||
}
|
||||
uint8_t byte_temp = (uint8_t) (((byte * 0x0802LU & 0x22110LU) | (byte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
packet_addr_l|=((uint64_t)byte_temp)<<(8*i);
|
||||
}
|
||||
|
||||
channel_number = 38;
|
||||
|
||||
|
||||
for (int t=0;t<2;t++)
|
||||
{
|
||||
bool current_bit;
|
||||
uint8_t byte=0;
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head + 5*8+t*8 + c)%RB_SIZE] > g_threshold)
|
||||
current_bit = true;
|
||||
else
|
||||
current_bit = false;
|
||||
byte |= current_bit << (7-c);
|
||||
}
|
||||
|
||||
packet_header_arr[t] = byte;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t byte_temp2 = (uint8_t) (((channel_number * 0x0802LU & 0x22110LU) | (channel_number * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
uint8_t lfsr_1 = byte_temp2 | 2;
|
||||
int header_length = 2;
|
||||
int header_counter = 0;
|
||||
while(header_length--)
|
||||
{
|
||||
for(uint8_t i = 0x80; i; i >>= 1)
|
||||
{
|
||||
if(lfsr_1 & 0x80)
|
||||
{
|
||||
lfsr_1 ^= 0x11;
|
||||
(packet_header_arr[header_counter]) ^= i;
|
||||
}
|
||||
lfsr_1 <<= 1;
|
||||
}
|
||||
header_counter = header_counter + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (packet_addr_l==0x8E89BED6)
|
||||
{
|
||||
|
||||
uint8_t byte_temp3 = (uint8_t) (((packet_header_arr[1] * 0x0802LU & 0x22110LU) | (packet_header_arr[1] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
packet_length=byte_temp3&0x3F;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_length=0;
|
||||
}
|
||||
|
||||
for (int t=0;t<packet_length+2+3;t++)
|
||||
{
|
||||
bool current_bit;
|
||||
uint8_t byte=0;
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head + 5*8+t*8 + c)%RB_SIZE] > g_threshold)
|
||||
current_bit = true;
|
||||
else
|
||||
current_bit = false;
|
||||
byte |= current_bit << (7-c);
|
||||
}
|
||||
|
||||
packet_data[t] = byte;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t byte_temp4 = (uint8_t) (((channel_number * 0x0802LU & 0x22110LU) | (channel_number * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
uint8_t lfsr_2 = byte_temp4 | 2;
|
||||
int pdu_crc_length = packet_length+2+3;
|
||||
int pdu_crc_counter = 0;
|
||||
while(pdu_crc_length--)
|
||||
{
|
||||
for(uint8_t i = 0x80; i; i >>= 1)
|
||||
{
|
||||
if(lfsr_2 & 0x80)
|
||||
{
|
||||
lfsr_2 ^= 0x11;
|
||||
(packet_data[pdu_crc_counter]) ^= i;
|
||||
}
|
||||
lfsr_2 <<= 1;
|
||||
}
|
||||
pdu_crc_counter = pdu_crc_counter + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (packet_addr_l==0x8E89BED6)
|
||||
{
|
||||
crc[0]=crc[1]=crc[2]=0x55;
|
||||
}
|
||||
else
|
||||
{
|
||||
crc[0]=crc[1]=crc[2]=0;
|
||||
}
|
||||
|
||||
uint8_t v, t, d, crc_length;
|
||||
uint32_t crc_result=0;
|
||||
crc_length = packet_length + 2;
|
||||
int counter = 0;
|
||||
while(crc_length--)
|
||||
{
|
||||
uint8_t byte_temp5 = (uint8_t) (((packet_data[counter] * 0x0802LU & 0x22110LU) | (packet_data[counter] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
d = byte_temp5;
|
||||
for(v = 0; v < 8; v++, d >>= 1)
|
||||
{
|
||||
t = crc[0] >> 7;
|
||||
crc[0] <<= 1;
|
||||
if(crc[1] & 0x80) crc[0] |= 1;
|
||||
crc[1] <<= 1;
|
||||
if(crc[2] & 0x80) crc[1] |= 1;
|
||||
crc[2] <<= 1;
|
||||
if(t != (d & 1))
|
||||
{
|
||||
crc[2] ^= 0x5B;
|
||||
crc[1] ^= 0x06;
|
||||
}
|
||||
}
|
||||
counter = counter + 1;
|
||||
}
|
||||
for (v=0;v<3;v++) crc_result=(crc_result<<8)|crc[v];
|
||||
calced_crc = crc_result;
|
||||
|
||||
packet_crc=0;
|
||||
for (int c=0;c<3;c++) packet_crc=(packet_crc<<8)|packet_data[packet_length+2+c];
|
||||
|
||||
if (packet_addr_l==0x8E89BED6)
|
||||
//if (packet_crc==calced_crc)
|
||||
{
|
||||
uint8_t mac_data[6];
|
||||
int counter = 0;
|
||||
for (int i = 7; i >= 2; i--)
|
||||
{
|
||||
uint8_t byte_temp6 = (uint8_t) (((packet_data[i] * 0x0802LU & 0x22110LU) | (packet_data[i] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
//result = byte_temp6;
|
||||
mac_data[counter] = byte_temp6;
|
||||
counter = counter + 1;
|
||||
}
|
||||
|
||||
data_message.is_data = false;
|
||||
data_message.value = 'A';
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = true;
|
||||
data_message.value = mac_data[0];
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = true;
|
||||
data_message.value = mac_data[1];
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = true;
|
||||
data_message.value = mac_data[2];
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = true;
|
||||
data_message.value = mac_data[3];
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = true;
|
||||
data_message.value = mac_data[4];
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = true;
|
||||
data_message.value = mac_data[5];
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = false;
|
||||
data_message.value = 'B';
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
packet_detected = true;
|
||||
}
|
||||
else
|
||||
packet_detected = false;
|
||||
}
|
||||
|
||||
if (packet_detected)
|
||||
{
|
||||
skipSamples=20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BTLERxProcessor::on_message(const Message* const message) {
|
||||
if (message->id == Message::ID::BTLERxConfigure)
|
||||
configure(*reinterpret_cast<const BTLERxConfigureMessage*>(message));
|
||||
}
|
||||
|
||||
void BTLERxProcessor::configure(const BTLERxConfigureMessage& message) {
|
||||
decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432);
|
||||
decim_1.configure(taps_200k_wfm_decim_1.taps, 131072);
|
||||
demod.configure(audio_fs, 5000);
|
||||
|
||||
configured = true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
EventDispatcher event_dispatcher { std::make_unique<BTLERxProcessor>() };
|
||||
event_dispatcher.run();
|
||||
return 0;
|
||||
}
|
95
firmware/baseband/proc_btlerx.hpp
Normal file
95
firmware/baseband/proc_btlerx.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_BTLERX_H__
|
||||
#define __PROC_BTLERX_H__
|
||||
|
||||
#include "baseband_processor.hpp"
|
||||
#include "baseband_thread.hpp"
|
||||
#include "rssi_thread.hpp"
|
||||
|
||||
#include "dsp_decimate.hpp"
|
||||
#include "dsp_demodulate.hpp"
|
||||
|
||||
#include "audio_output.hpp"
|
||||
|
||||
#include "fifo.hpp"
|
||||
#include "message.hpp"
|
||||
|
||||
class BTLERxProcessor : public BasebandProcessor {
|
||||
public:
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
|
||||
void on_message(const Message* const message) override;
|
||||
|
||||
private:
|
||||
static constexpr size_t baseband_fs = 4000000;
|
||||
static constexpr size_t audio_fs = baseband_fs / 8 / 8 / 2;
|
||||
|
||||
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
|
||||
RSSIThread rssi_thread { NORMALPRIO + 10 };
|
||||
|
||||
std::array<complex16_t, 512> dst { };
|
||||
const buffer_c16_t dst_buffer {
|
||||
dst.data(),
|
||||
dst.size()
|
||||
};
|
||||
|
||||
std::array<complex16_t, 512> spectrum { };
|
||||
const buffer_c16_t spectrum_buffer {
|
||||
spectrum.data(),
|
||||
spectrum.size()
|
||||
};
|
||||
|
||||
const buffer_s16_t work_audio_buffer {
|
||||
(int16_t*)dst.data(),
|
||||
sizeof(dst) / sizeof(int16_t)
|
||||
};
|
||||
|
||||
|
||||
// Array size ok down to 375 bauds (24000 / 375)
|
||||
std::array<int32_t, 64> delay_line { 0 };
|
||||
std::array<int16_t, 1000> rb_buf { 0 };
|
||||
|
||||
/*dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
|
||||
dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
|
||||
dsp::decimate::FIRAndDecimateComplex channel_filter { };*/
|
||||
dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { };
|
||||
dsp::decimate::FIRC16xR16x16Decim2 decim_1 { };
|
||||
|
||||
dsp::demodulate::FM demod { };
|
||||
int rb_head {-1};
|
||||
int32_t g_threshold {0};
|
||||
uint8_t channel_number {38};
|
||||
int skipSamples {1000};
|
||||
int RB_SIZE {1000};
|
||||
|
||||
bool configured { false };
|
||||
|
||||
|
||||
void configure(const BTLERxConfigureMessage& message);
|
||||
|
||||
AFSKDataMessage data_message { false, 0 };
|
||||
};
|
||||
|
||||
#endif/*__PROC_BTLERX_H__*/
|
286
firmware/baseband/proc_nrfrx.cpp
Normal file
286
firmware/baseband/proc_nrfrx.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_nrfrx.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "event_m4.hpp"
|
||||
|
||||
void NRFRxProcessor::execute(const buffer_c8_t& buffer) {
|
||||
if (!configured) return;
|
||||
|
||||
// FM demodulation
|
||||
|
||||
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
|
||||
feed_channel_stats(decim_0_out);
|
||||
|
||||
auto audio_oversampled = demod.execute(decim_0_out, work_audio_buffer);
|
||||
// Audio signal processing
|
||||
for (size_t c = 0; c < audio_oversampled.count; c++) {
|
||||
int result;
|
||||
int g_srate = 4; //4 for 250KPS
|
||||
//int g_srate = 1; //1 for 1MPS, not working yet
|
||||
int32_t current_sample = audio_oversampled.p[c]; //if I directly use this, some results can pass crc but not correct.
|
||||
rb_head++;
|
||||
rb_head=(rb_head)%RB_SIZE;
|
||||
|
||||
rb_buf[rb_head] = current_sample;
|
||||
|
||||
skipSamples = skipSamples - 1;
|
||||
|
||||
|
||||
if (skipSamples<1)
|
||||
{
|
||||
|
||||
|
||||
int32_t threshold_tmp=0;
|
||||
for (int c=0;c<8*g_srate;c++)
|
||||
{
|
||||
threshold_tmp = threshold_tmp + (int32_t)rb_buf[(rb_head+c)%RB_SIZE];
|
||||
}
|
||||
|
||||
g_threshold = (int32_t)threshold_tmp/(8*g_srate);
|
||||
|
||||
int transitions=0;
|
||||
if (rb_buf[(rb_head + 9*g_srate)%RB_SIZE] > g_threshold)
|
||||
{
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head + c*g_srate)%RB_SIZE] > rb_buf[(rb_head + (c+1)*g_srate)%RB_SIZE])
|
||||
transitions = transitions + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head + c*g_srate)%RB_SIZE] < rb_buf[(rb_head + (c+1)*g_srate)%RB_SIZE])
|
||||
transitions = transitions + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool packet_detected=false;
|
||||
//if ( transitions==4 && abs(g_threshold)<15500)
|
||||
if ( transitions==4 && abs(g_threshold)<15500)
|
||||
{
|
||||
int packet_length = 0;
|
||||
uint8_t tmp_buf[10];
|
||||
uint8_t packet_data[500];
|
||||
uint8_t packet_packed[50];
|
||||
uint16_t pcf;
|
||||
uint32_t packet_crc;
|
||||
uint32_t calced_crc;
|
||||
uint64_t packet_addr_l;
|
||||
|
||||
/* extract address */
|
||||
packet_addr_l=0;
|
||||
|
||||
for (int t=0;t<5;t++)
|
||||
{
|
||||
bool current_bit;
|
||||
uint8_t byte=0;
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head+(1*8+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
|
||||
current_bit = true;
|
||||
else
|
||||
current_bit = false;
|
||||
byte |= current_bit << (7-c);
|
||||
}
|
||||
tmp_buf[t]=byte;
|
||||
}
|
||||
|
||||
for (int t=0;t<5;t++) packet_addr_l|=((uint64_t)tmp_buf[t])<<(4-t)*8;
|
||||
|
||||
//channel_number = 26;
|
||||
|
||||
|
||||
/* extract pcf */
|
||||
for (int t=0;t<2;t++)
|
||||
{
|
||||
bool current_bit;
|
||||
uint8_t byte=0;
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head+(6*8+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
|
||||
current_bit = true;
|
||||
else
|
||||
current_bit = false;
|
||||
byte |= current_bit << (7-c);
|
||||
}
|
||||
tmp_buf[t]=byte;
|
||||
}
|
||||
|
||||
pcf = tmp_buf[0]<<8 | tmp_buf[1];
|
||||
pcf >>=7;
|
||||
|
||||
/* extract packet length, avoid excessive length packets */
|
||||
if(packet_length == 0)
|
||||
packet_length=(int)pcf>>3;
|
||||
if (packet_length>32)
|
||||
packet_detected = false;
|
||||
|
||||
/* extract data */
|
||||
for (int t=0;t<packet_length;t++)
|
||||
{
|
||||
bool current_bit;
|
||||
uint8_t byte=0;
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head+(6*8+9+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
|
||||
current_bit = true;
|
||||
else
|
||||
current_bit = false;
|
||||
byte |= current_bit << (7-c);
|
||||
}
|
||||
packet_data[t]=byte;
|
||||
}
|
||||
|
||||
/* Prepare packed bit stream for CRC calculation */
|
||||
uint64_t packet_header=packet_addr_l;
|
||||
packet_header<<=9;
|
||||
packet_header|=pcf;
|
||||
for (int c=0;c<7;c++){
|
||||
packet_packed[c]=(packet_header>>((6-c)*8))&0xFF;
|
||||
}
|
||||
|
||||
for (int c=0;c<packet_length;c++){
|
||||
packet_packed[c+7]=packet_data[c];
|
||||
}
|
||||
|
||||
/* calculate packet crc */
|
||||
const uint8_t* data = packet_packed;
|
||||
size_t data_len = 7+packet_length;
|
||||
bool bit;
|
||||
uint8_t cc;
|
||||
uint_fast16_t crc=0x3C18;
|
||||
while (data_len--) {
|
||||
cc = *data++;
|
||||
for (uint8_t i = 0x80; i > 0; i >>= 1)
|
||||
{
|
||||
bit = crc & 0x8000;
|
||||
if (cc & i)
|
||||
{
|
||||
bit = !bit;
|
||||
}
|
||||
crc <<= 1;
|
||||
if (bit)
|
||||
{
|
||||
crc ^= 0x1021;
|
||||
}
|
||||
}
|
||||
crc &= 0xffff;
|
||||
}
|
||||
calced_crc = (uint16_t)(crc & 0xffff);
|
||||
|
||||
/* extract crc */
|
||||
for (int t=0;t<2;t++)
|
||||
{
|
||||
bool current_bit;
|
||||
uint8_t byte=0;
|
||||
for (int c=0;c<8;c++)
|
||||
{
|
||||
if (rb_buf[(rb_head+((6+packet_length)*8+9+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
|
||||
current_bit = true;
|
||||
else
|
||||
current_bit = false;
|
||||
byte |= current_bit << (7-c);
|
||||
}
|
||||
tmp_buf[t]=byte;
|
||||
}
|
||||
packet_crc = tmp_buf[0]<<8 | tmp_buf[1];
|
||||
|
||||
/* NRF24L01+ packet found, dump information */
|
||||
//if (packet_addr_l==0xE7E7E7E7)
|
||||
if (packet_crc==calced_crc)
|
||||
{
|
||||
data_message.is_data = false;
|
||||
data_message.value = 'A';
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = true;
|
||||
data_message.value = packet_addr_l;
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
for (int c=0;c<7;c++)
|
||||
{
|
||||
data_message.is_data = true;
|
||||
data_message.value = packet_addr_l >> 8;
|
||||
shared_memory.application_queue.push(data_message);
|
||||
}
|
||||
/*data_message.is_data = true;
|
||||
data_message.value = packet_addr_l;
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
data_message.is_data = true;
|
||||
data_message.value = packet_addr_l >> 8;
|
||||
shared_memory.application_queue.push(data_message);*/
|
||||
|
||||
data_message.is_data = false;
|
||||
data_message.value = 'B';
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
for (int c=0;c<packet_length;c++)
|
||||
{
|
||||
data_message.is_data = true;
|
||||
data_message.value = packet_data[c];
|
||||
shared_memory.application_queue.push(data_message);
|
||||
}
|
||||
|
||||
data_message.is_data = false;
|
||||
data_message.value = 'C';
|
||||
shared_memory.application_queue.push(data_message);
|
||||
|
||||
|
||||
packet_detected = true;
|
||||
}
|
||||
else
|
||||
packet_detected = false;
|
||||
}
|
||||
|
||||
if (packet_detected)
|
||||
{
|
||||
skipSamples=20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NRFRxProcessor::on_message(const Message* const message) {
|
||||
if (message->id == Message::ID::NRFRxConfigure)
|
||||
configure(*reinterpret_cast<const NRFRxConfigureMessage*>(message));
|
||||
}
|
||||
|
||||
void NRFRxProcessor::configure(const NRFRxConfigureMessage& message) {
|
||||
decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432);
|
||||
decim_1.configure(taps_200k_wfm_decim_1.taps, 131072);
|
||||
demod.configure(audio_fs, 5000);
|
||||
|
||||
configured = true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
EventDispatcher event_dispatcher { std::make_unique<NRFRxProcessor>() };
|
||||
event_dispatcher.run();
|
||||
return 0;
|
||||
}
|
96
firmware/baseband/proc_nrfrx.hpp
Normal file
96
firmware/baseband/proc_nrfrx.hpp
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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_NRFRX_H__
|
||||
#define __PROC_NRFRX_H__
|
||||
|
||||
#include "baseband_processor.hpp"
|
||||
#include "baseband_thread.hpp"
|
||||
#include "rssi_thread.hpp"
|
||||
|
||||
#include "dsp_decimate.hpp"
|
||||
#include "dsp_demodulate.hpp"
|
||||
|
||||
#include "audio_output.hpp"
|
||||
|
||||
#include "fifo.hpp"
|
||||
#include "message.hpp"
|
||||
|
||||
class NRFRxProcessor : public BasebandProcessor {
|
||||
public:
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
|
||||
void on_message(const Message* const message) override;
|
||||
|
||||
private:
|
||||
static constexpr size_t baseband_fs = 4000000;
|
||||
static constexpr size_t audio_fs = baseband_fs / 8 / 8 / 2;
|
||||
|
||||
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
|
||||
RSSIThread rssi_thread { NORMALPRIO + 10 };
|
||||
|
||||
std::array<complex16_t, 512> dst { };
|
||||
const buffer_c16_t dst_buffer {
|
||||
dst.data(),
|
||||
dst.size()
|
||||
};
|
||||
|
||||
std::array<complex16_t, 512> spectrum { };
|
||||
const buffer_c16_t spectrum_buffer {
|
||||
spectrum.data(),
|
||||
spectrum.size()
|
||||
};
|
||||
|
||||
const buffer_s16_t work_audio_buffer {
|
||||
(int16_t*)dst.data(),
|
||||
sizeof(dst) / sizeof(int16_t)
|
||||
};
|
||||
|
||||
|
||||
// Array size ok down to 375 bauds (24000 / 375)
|
||||
std::array<int32_t, 64> delay_line { 0 };
|
||||
std::array<int16_t, 1000> rb_buf { 0 };
|
||||
|
||||
/*dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
|
||||
dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
|
||||
dsp::decimate::FIRAndDecimateComplex channel_filter { };*/
|
||||
dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { };
|
||||
dsp::decimate::FIRC16xR16x16Decim2 decim_1 { };
|
||||
|
||||
dsp::demodulate::FM demod { };
|
||||
int rb_head {-1};
|
||||
int32_t g_threshold {0};
|
||||
//uint8_t g_srate {8};
|
||||
uint8_t channel_number {38};
|
||||
int skipSamples {1000};
|
||||
int RB_SIZE {1000};
|
||||
|
||||
bool configured { false };
|
||||
|
||||
|
||||
void configure(const NRFRxConfigureMessage& message);
|
||||
|
||||
AFSKDataMessage data_message { false, 0 };
|
||||
};
|
||||
|
||||
#endif/*__PROC_NRFRX_H__*/
|
122
firmware/baseband/tv_collector.cpp
Normal file
122
firmware/baseband/tv_collector.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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 "tv_collector.hpp"
|
||||
|
||||
#include "dsp_fft.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
#include "event_m4.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "event_m4.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void TvCollector::on_message(const Message* const message) {
|
||||
switch(message->id) {
|
||||
case Message::ID::UpdateSpectrum:
|
||||
update();
|
||||
break;
|
||||
|
||||
case Message::ID::SpectrumStreamingConfig:
|
||||
set_state(*reinterpret_cast<const SpectrumStreamingConfigMessage*>(message));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TvCollector::set_state(const SpectrumStreamingConfigMessage& message) {
|
||||
if( message.mode == SpectrumStreamingConfigMessage::Mode::Running ) {
|
||||
start();
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void TvCollector::start() {
|
||||
streaming = true;
|
||||
ChannelSpectrumConfigMessage message { &fifo };
|
||||
shared_memory.application_queue.push(message);
|
||||
}
|
||||
|
||||
void TvCollector::stop() {
|
||||
streaming = false;
|
||||
fifo.reset_in();
|
||||
}
|
||||
|
||||
void TvCollector::set_decimation_factor(
|
||||
const size_t decimation_factor
|
||||
) {
|
||||
channel_spectrum_decimator.set_factor(decimation_factor);
|
||||
}
|
||||
|
||||
/* TODO: Refactor to register task with idle thread?
|
||||
* It's sad that the idle thread has to call all the way back here just to
|
||||
* perform the deferred task on the buffer of data we prepared.
|
||||
*/
|
||||
|
||||
void TvCollector::feed(
|
||||
const buffer_c16_t& channel
|
||||
) {
|
||||
// Called from baseband processing thread.
|
||||
channel_spectrum_decimator.feed(channel,[this](const buffer_c16_t& data) {this->post_message(data);});
|
||||
}
|
||||
|
||||
void TvCollector::post_message(const buffer_c16_t& data) {
|
||||
// Called from baseband processing thread.
|
||||
float re, im;
|
||||
float mag;
|
||||
float max;
|
||||
if( streaming && !channel_spectrum_request_update ) {
|
||||
for(size_t i=0; i<256; i++)
|
||||
{
|
||||
const auto s = data.p[i];
|
||||
re = (float)(data.p[i].real());
|
||||
im = (float)(data.p[i].imag());
|
||||
mag = __builtin_sqrtf((re * re) + (im * im)) ;
|
||||
channel_spectrum[i] = {mag, mag};
|
||||
}
|
||||
channel_spectrum_sampling_rate = data.sampling_rate;
|
||||
channel_spectrum_request_update = true;
|
||||
EventDispatcher::events_flag(EVT_MASK_SPECTRUM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TvCollector::update() {
|
||||
// Called from idle thread (after EVT_MASK_SPECTRUM is flagged)
|
||||
if( streaming && channel_spectrum_request_update ) {
|
||||
ChannelSpectrum spectrum;
|
||||
spectrum.sampling_rate = channel_spectrum_sampling_rate;
|
||||
for(size_t i=0; i<spectrum.db.size(); i++) {
|
||||
const auto corrected_sample = channel_spectrum[i].real();
|
||||
const unsigned int v = corrected_sample + 127.0f;
|
||||
spectrum.db[i] = std::max(0U, std::min(255U, v));
|
||||
}
|
||||
fifo.in(spectrum);
|
||||
}
|
||||
|
||||
channel_spectrum_request_update = false;
|
||||
}
|
66
firmware/baseband/tv_collector.hpp
Normal file
66
firmware/baseband/tv_collector.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2020 Shao
|
||||
*
|
||||
* 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 __TV_COLLECTOR_H__
|
||||
#define __TV_COLLECTOR_H__
|
||||
|
||||
#include "dsp_types.hpp"
|
||||
#include "complex.hpp"
|
||||
|
||||
#include "block_decimator.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
#include "message.hpp"
|
||||
|
||||
class TvCollector {
|
||||
public:
|
||||
void on_message(const Message* const message);
|
||||
|
||||
void set_decimation_factor(const size_t decimation_factor);
|
||||
|
||||
void feed(
|
||||
const buffer_c16_t& channel
|
||||
);
|
||||
|
||||
private:
|
||||
BlockDecimator<complex16_t, 256> channel_spectrum_decimator { 1 };
|
||||
ChannelSpectrum fifo_data[1 << ChannelSpectrumConfigMessage::fifo_k] { };
|
||||
ChannelSpectrumFIFO fifo { fifo_data, ChannelSpectrumConfigMessage::fifo_k };
|
||||
|
||||
volatile bool channel_spectrum_request_update { false };
|
||||
bool streaming { false };
|
||||
std::array<std::complex<float>, 256> channel_spectrum { };
|
||||
uint32_t channel_spectrum_sampling_rate { 0 };
|
||||
|
||||
void post_message(const buffer_c16_t& data);
|
||||
|
||||
void set_state(const SpectrumStreamingConfigMessage& message);
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void update();
|
||||
|
||||
};
|
||||
|
||||
#endif/*__TV_COLLECTOR_H__*/
|
@ -78,6 +78,8 @@ public:
|
||||
AFSKRxConfigure = 22,
|
||||
StatusRefresh = 23,
|
||||
SamplerateConfig = 24,
|
||||
BTLERxConfigure = 25,
|
||||
NRFRxConfigure = 26,
|
||||
|
||||
TXProgress = 30,
|
||||
Retune = 31,
|
||||
@ -722,6 +724,46 @@ public:
|
||||
const bool trigger_word;
|
||||
};
|
||||
|
||||
class BTLERxConfigureMessage : public Message {
|
||||
public:
|
||||
constexpr BTLERxConfigureMessage(
|
||||
const uint32_t baudrate,
|
||||
const uint32_t word_length,
|
||||
const uint32_t trigger_value,
|
||||
const bool trigger_word
|
||||
) : Message { ID::BTLERxConfigure },
|
||||
baudrate(baudrate),
|
||||
word_length(word_length),
|
||||
trigger_value(trigger_value),
|
||||
trigger_word(trigger_word)
|
||||
{
|
||||
}
|
||||
const uint32_t baudrate;
|
||||
const uint32_t word_length;
|
||||
const uint32_t trigger_value;
|
||||
const bool trigger_word;
|
||||
};
|
||||
|
||||
class NRFRxConfigureMessage : public Message {
|
||||
public:
|
||||
constexpr NRFRxConfigureMessage(
|
||||
const uint32_t baudrate,
|
||||
const uint32_t word_length,
|
||||
const uint32_t trigger_value,
|
||||
const bool trigger_word
|
||||
) : Message { ID::NRFRxConfigure },
|
||||
baudrate(baudrate),
|
||||
word_length(word_length),
|
||||
trigger_value(trigger_value),
|
||||
trigger_word(trigger_word)
|
||||
{
|
||||
}
|
||||
const uint32_t baudrate;
|
||||
const uint32_t word_length;
|
||||
const uint32_t trigger_value;
|
||||
const bool trigger_word;
|
||||
};
|
||||
|
||||
class PitchRSSIConfigureMessage : public Message {
|
||||
public:
|
||||
constexpr PitchRSSIConfigureMessage(
|
||||
|
@ -68,8 +68,11 @@ private:
|
||||
constexpr image_tag_t image_tag_acars { 'P', 'A', 'C', 'A' };
|
||||
constexpr image_tag_t image_tag_adsb_rx { 'P', 'A', 'D', 'R' };
|
||||
constexpr image_tag_t image_tag_afsk_rx { 'P', 'A', 'F', 'R' };
|
||||
constexpr image_tag_t image_tag_btle_rx { 'P', 'B', 'T', 'R' };
|
||||
constexpr image_tag_t image_tag_nrf_rx { 'P', 'N', 'R', 'R' };
|
||||
constexpr image_tag_t image_tag_ais { 'P', 'A', 'I', 'S' };
|
||||
constexpr image_tag_t image_tag_am_audio { 'P', 'A', 'M', 'A' };
|
||||
constexpr image_tag_t image_tag_am_tv { 'P', 'A', 'M', 'T' };
|
||||
constexpr image_tag_t image_tag_capture { 'P', 'C', 'A', 'P' };
|
||||
constexpr image_tag_t image_tag_ert { 'P', 'E', 'R', 'T' };
|
||||
constexpr image_tag_t image_tag_nfm_audio { 'P', 'N', 'F', 'M' };
|
||||
|
Loading…
Reference in New Issue
Block a user