mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-04 05:49:01 +00:00
Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d521819ff | |||
| 83f7c9ae63 | |||
| 310fbd53ec | |||
| c80595db7e | |||
| 040dded2a6 | |||
| 958c9a1bfa | |||
| 76a137924c | |||
| 861db600e8 | |||
| 4993a6abcb | |||
| 9086f32a63 | |||
| 9d59c07855 | |||
| 0d18aa47f3 | |||
| cf40f5eb14 | |||
| fe4bc7902f | |||
| 5d5865eefb | |||
| a7370ee95d | |||
| 223cd7c20d | |||
| 1be3167748 | |||
| 1bbd889005 | |||
| d87e9853a1 | |||
| 36109964a7 | |||
| 6087c658e9 | |||
| 08a108d3e4 | |||
| c78659db38 | |||
| 5021a03572 | |||
| 961a4c4588 | |||
| a89d418202 | |||
| 1dcc80ba59 | |||
| 1e14ca4df1 | |||
| 5096f91986 | |||
| 65be02c5b1 | |||
| f5a604a0a5 | |||
| 823c69eb42 | |||
| 15f3d81798 | |||
| fa2791004f | |||
| 50bd08d9ff | |||
| a26ee84ff8 | |||
| 39134b62c3 | |||
| e5a30b4309 | |||
| 840da4c685 | |||
| 2031a79b34 | |||
| deff646e36 | |||
| 4aa3314906 | |||
| e3da9d4cb2 | |||
| c389ce7c0e | |||
| dda543f7f3 | |||
| 92844a7528 | |||
| ef52339b1d | |||
| 5e0780839c | |||
| 85602d145a | |||
| 2efab19bf6 | |||
| 4562228b55 | |||
| b56acb0c9d | |||
| 6af0d4e751 | |||
| 0fed174a80 | |||
| d71c759480 | |||
| c1e568f62c | |||
| db1b7ffddf | |||
| f48980e381 | |||
| cdaa6683ae | |||
| d2dbad73c7 | |||
| 9412dd8bec | |||
| d624b92e85 | |||
| 584c46af64 | |||
| 1976c3648b | |||
| c4eb02422b | |||
| 95ac4a2d1e | |||
| a7c7495428 | |||
| 8f311ea1f2 | |||
| d0643421a8 | |||
| adb0cdf8fb | |||
| 1b93a042a3 | |||
| 52c6d0e4ed | |||
| 22a5ca7df7 | |||
| d0b356a7ef | |||
| 28ee69baae | |||
| bfd614b51f | |||
| 4a6fc35384 | |||
| 35cece1cb0 |
@@ -1,12 +1,18 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
about: Create a report to help us improve the software
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
----
|
||||
|
||||
(Please try the latest nightly release before submitting this. You can find the latest nightly verison here: https://github.com/eried/portapack-mayhem/releases)
|
||||
|
||||
----
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
@@ -21,9 +27,9 @@ A clear and concise description of what you expected to happen.
|
||||
|
||||
**Affected versions**
|
||||
Please write any difference related with the Expected behavior, on the following versions:
|
||||
* Latest Stable Release
|
||||
* Previous one (if any) that did not presented the issue
|
||||
* Old versions available here: https://github.com/eried/Research/tree/master/HackRF/PortaPack/old_legacy_firmware
|
||||
* Latest Stable release:
|
||||
* Latest Nightly release:
|
||||
* Previous working release:
|
||||
|
||||
**Additional**
|
||||
If the bug is difficult to explain, additionally to the text please include images and videos.
|
||||
|
||||
@@ -1,18 +1,39 @@
|
||||
---
|
||||
name: Problem upgrading the firmware
|
||||
about: Deal with the firmware upgrade problems
|
||||
title: Problem upgrading the firmware
|
||||
labels: ''
|
||||
name: Problem upgrading the firmware or booting
|
||||
about: If you are having firmware upgrade or booting problems
|
||||
title: ''
|
||||
labels: 'firmware'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**What is happening?**
|
||||
Describe here why you are unable to upgrade the firmware. Before describing your problems, **do the following**:
|
||||
----
|
||||
Before creating this issue, **do the following**:
|
||||
* Read the Wiki on booting: https://github.com/eried/portapack-mayhem/wiki/Won't-boot
|
||||
* Read: https://github.com/eried/portapack-havoc/wiki/Update-firmware
|
||||
* Watch carefully: https://www.youtube.com/watch?v=_zx4ZvurgOs
|
||||
* (if you are not in Windows) also check: https://www.youtube.com/watch?v=kjFB58Y1TAo
|
||||
|
||||
----
|
||||
|
||||
**Describe the issue**
|
||||
A clear and concise description of what the issue you are facing is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Tap on '....'
|
||||
|
||||
|
||||
**My Hardware**
|
||||
Please specify what PortaPack hardware version you are using.
|
||||
You can find the list of versions here: https://github.com/eried/portapack-mayhem/wiki/PortaPack-Versions
|
||||
|
||||
**Affected versions**
|
||||
Please tell us what version you are running.
|
||||
Also please try the latest nightly release before submitting this.
|
||||
You can find the latest nightly version here https://github.com/eried/portapack-mayhem/releases
|
||||
|
||||
**Were you able to update the firmware before?**
|
||||
Things might be confusing the first time, please check the video available on the link above.
|
||||
|
||||
@@ -20,4 +41,4 @@ Things might be confusing the first time, please check the video available on th
|
||||
If is possible, swap hardware and try again. Also, try different USB cables, even if the one you are using works fine for other purposes.
|
||||
|
||||
**Additional**
|
||||
Add photos and videos of your procedure.
|
||||
If the issue is difficult to explain, additionally to the text please include images and videos.
|
||||
|
||||
@@ -1 +1 @@
|
||||
v1.5.1
|
||||
v1.5.3
|
||||
|
||||
@@ -1 +1 @@
|
||||
v1.5.3
|
||||
v1.5.4
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# PortaPack Mayhem
|
||||
|
||||
[](https://travis-ci.com/eried/portapack-mayhem) [](https://codescene.io/projects/8381) [](https://github.com/eried/portapack-mayhem/releases) [](https://github.com/eried/portapack-mayhem/releases/latest) [](https://hub.docker.com/r/eried/portapack) [](https://discord.gg/tuwVMv3) [](https://www.bountysource.com/teams/portapack-mayhem/issues)
|
||||
[](https://travis-ci.com/eried/portapack-mayhem) [](https://github.com/eried/portapack-mayhem/actions/workflows/create_nightly_release.yml) [](https://codescene.io/projects/8381) [](https://github.com/eried/portapack-mayhem/releases) [](https://github.com/eried/portapack-mayhem/releases/latest) [](https://hub.docker.com/r/eried/portapack) [](https://discord.gg/tuwVMv3) [](https://www.bountysource.com/teams/portapack-mayhem/issues)
|
||||
|
||||
This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmware, which itself was a fork of the [PortaPack](https://github.com/sharebrained/portapack-hackrf) firmware, an add-on for the [HackRF](http://greatscottgadgets.com/hackrf/). A fork is a derivate, in this case one that has extra features and fixes when compared to the older versions.
|
||||
|
||||
|
||||
+12
-9
@@ -1,6 +1,6 @@
|
||||
#Download base image.
|
||||
#The ubuntu:latest tag points to the "latest LTS"
|
||||
FROM ubuntu:latest
|
||||
#The ubuntu:20.04 tag points to the "20.04 LTS"
|
||||
FROM ubuntu:20.04
|
||||
|
||||
#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.
|
||||
@@ -14,16 +14,18 @@ COPY ./ /havocsrc
|
||||
|
||||
#Fetch dependencies from APT
|
||||
RUN apt-get update && \
|
||||
apt-get install -y tar wget dfu-util cmake python bzip2 curl && \
|
||||
apt-get -qy autoremove
|
||||
apt-get install -y tar wget dfu-util cmake python bzip2 curl python3 python3-yaml && \
|
||||
apt-get -qy autoremove
|
||||
|
||||
#Install current pip from PyPa
|
||||
RUN curl https://bootstrap.pypa.io/pip/3.4/get-pip.py -o get-pip.py && \
|
||||
python get-pip.py
|
||||
python get-pip.py
|
||||
|
||||
#Fetch additional dependencies from Python 2.x pip
|
||||
RUN pip install pyyaml
|
||||
RUN ln -s /usr/bin/python3 /usr/bin/python && \
|
||||
RUN rm -rf /usr/bin/python && \
|
||||
rm -rf /usr/bin/pip && \
|
||||
ln -s /usr/bin/python3 /usr/bin/python && \
|
||||
ln -s /usr/bin/pip3 /usr/bin/pip
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
@@ -32,9 +34,9 @@ ENV LC_ALL C.UTF-8
|
||||
#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
|
||||
wget -O gcc-arm-none-eabi $ARMBINURL && \
|
||||
mkdir armbin && \
|
||||
tar --strip=1 -xjvf gcc-arm-none-eabi -C armbin
|
||||
|
||||
#Set environment variable so compiler knows where the toolchain lives
|
||||
ENV PATH=$PATH:/opt/build/armbin/bin
|
||||
@@ -43,3 +45,4 @@ CMD cd /havocsrc && \
|
||||
mkdir build && cd build && \
|
||||
cmake .. && make firmware && \
|
||||
cp /portapack-havoc/firmware/portapack-h1-havoc.bin /havocbin
|
||||
|
||||
|
||||
@@ -267,8 +267,12 @@ set(CPPSRC
|
||||
apps/lge_app.cpp
|
||||
apps/pocsag_app.cpp
|
||||
apps/replay_app.cpp
|
||||
apps/ui_playlist.cpp
|
||||
apps/gps_sim_app.cpp
|
||||
apps/soundboard_app.cpp
|
||||
apps/ui_recon.cpp
|
||||
apps/ui_recon_settings.cpp
|
||||
apps/tpms_app.cpp
|
||||
apps/tpms_app.cpp
|
||||
protocols/aprs.cpp
|
||||
protocols/ax25.cpp
|
||||
|
||||
@@ -76,12 +76,18 @@ static std::string mid(
|
||||
mid_code = to_string_dec_uint(mmsi, 9, ' ').substr(0, 3);
|
||||
return_code = db.retrieve_mid_record(&mid_record, mid_code);
|
||||
switch(return_code) {
|
||||
case DATABASE_RECORD_FOUND: return mid_record.country;
|
||||
case DATABASE_RECORD_FOUND: return mid_record.country;
|
||||
case DATABASE_NOT_FOUND: return "No mids.db file";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string text(const std::string &text) {
|
||||
size_t end = text.find_last_not_of("@");
|
||||
return (end == std::string::npos) ? "" : text.substr(0, end + 1);
|
||||
|
||||
}
|
||||
|
||||
static std::string navigational_status(const unsigned int value) {
|
||||
switch(value) {
|
||||
case 0: return "under way w/engine";
|
||||
@@ -164,7 +170,7 @@ void AISLogger::on_packet(const ais::Packet& packet) {
|
||||
}
|
||||
|
||||
log_file.write_entry(packet.received_at(), entry);
|
||||
}
|
||||
}
|
||||
|
||||
void AISRecentEntry::update(const ais::Packet& packet) {
|
||||
received_count++;
|
||||
@@ -195,6 +201,15 @@ void AISRecentEntry::update(const ais::Packet& packet) {
|
||||
destination = packet.text(302, 20);
|
||||
break;
|
||||
|
||||
case 18:
|
||||
last_position.timestamp = packet.received_at();
|
||||
last_position.speed_over_ground = packet.read(46, 10);
|
||||
last_position.latitude = packet.latitude(85);
|
||||
last_position.longitude = packet.longitude(57);
|
||||
last_position.course_over_ground = packet.read(112, 12);
|
||||
last_position.true_heading = packet.read(124, 9);
|
||||
break;
|
||||
|
||||
case 21:
|
||||
name = packet.text(43, 20);
|
||||
last_position.timestamp = packet.received_at();
|
||||
@@ -202,6 +217,23 @@ void AISRecentEntry::update(const ais::Packet& packet) {
|
||||
last_position.longitude = packet.longitude(164);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
switch (packet.read(38, 2))
|
||||
{
|
||||
case 0:
|
||||
name = packet.text(40, 20);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
call_sign = packet.text(90, 7);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -218,9 +250,9 @@ void RecentEntriesTable<AISRecentEntries>::draw(
|
||||
) {
|
||||
std::string line = ais::format::mmsi(entry.mmsi) + " ";
|
||||
if( !entry.name.empty() ) {
|
||||
line += entry.name;
|
||||
line += ais::format::text(entry.name);
|
||||
} else {
|
||||
line += entry.call_sign;
|
||||
line += ais::format::text(entry.call_sign);
|
||||
}
|
||||
|
||||
line.resize(target_rect.width() / 8, ' ');
|
||||
@@ -241,7 +273,7 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) {
|
||||
|
||||
button_see_map.on_select = [this, &nav](Button&) {
|
||||
geomap_view = nav.push<GeoMapView>(
|
||||
entry_.name,
|
||||
ais::format::text(entry_.name),
|
||||
0,
|
||||
GeoPos::alt_unit::METERS,
|
||||
ais::format::latlon_float(entry_.last_position.latitude.normalized()),
|
||||
@@ -252,7 +284,7 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) {
|
||||
});
|
||||
send_updates = true;
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -262,7 +294,7 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(const AISRecentEntryDetailVie
|
||||
(void)Entry;
|
||||
}
|
||||
|
||||
AISRecentEntryDetailView & AISRecentEntryDetailView::operator=(const AISRecentEntryDetailView&Entry)
|
||||
AISRecentEntryDetailView & AISRecentEntryDetailView::operator=(const AISRecentEntryDetailView&Entry)
|
||||
{
|
||||
(void)Entry;
|
||||
return *this;
|
||||
@@ -302,9 +334,9 @@ void AISRecentEntryDetailView::paint(Painter& painter) {
|
||||
|
||||
field_rect = draw_field(painter, field_rect, s, "MMSI", ais::format::mmsi(entry_.mmsi));
|
||||
field_rect = draw_field(painter, field_rect, s, "Ctry", ais::format::mid(entry_.mmsi));
|
||||
field_rect = draw_field(painter, field_rect, s, "Name", entry_.name);
|
||||
field_rect = draw_field(painter, field_rect, s, "Call", entry_.call_sign);
|
||||
field_rect = draw_field(painter, field_rect, s, "Dest", entry_.destination);
|
||||
field_rect = draw_field(painter, field_rect, s, "Name", ais::format::text(entry_.name));
|
||||
field_rect = draw_field(painter, field_rect, s, "Call", ais::format::text(entry_.call_sign));
|
||||
field_rect = draw_field(painter, field_rect, s, "Dest", ais::format::text(entry_.destination));
|
||||
field_rect = draw_field(painter, field_rect, s, "Last", to_string_datetime(entry_.last_position.timestamp));
|
||||
field_rect = draw_field(painter, field_rect, s, "Pos ", ais::format::latlon(entry_.last_position.latitude, entry_.last_position.longitude));
|
||||
field_rect = draw_field(painter, field_rect, s, "Stat", ais::format::navigational_status(entry_.navigational_status));
|
||||
@@ -352,7 +384,7 @@ AISAppView::AISAppView(NavigationView& nav) : nav_ { nav } {
|
||||
receiver_model.set_sampling_rate(sampling_rate);
|
||||
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
|
||||
receiver_model.enable(); // Before using radio::enable(), but not updating Ant.DC-Bias.
|
||||
|
||||
|
||||
options_channel.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
this->on_frequency_changed(v);
|
||||
};
|
||||
|
||||
@@ -113,8 +113,12 @@ ERTAppView::ERTAppView(NavigationView&) {
|
||||
field_rf_amp.set_value(app_settings.rx_amp);
|
||||
}
|
||||
|
||||
receiver_model.set_tuning_frequency(initial_target_frequency);
|
||||
receiver_model.set_sampling_rate(sampling_rate);
|
||||
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
|
||||
receiver_model.enable(); // Before using radio::enable(), but not updating Ant.DC-Bias.
|
||||
|
||||
radio::enable({
|
||||
/* radio::enable({
|
||||
initial_target_frequency,
|
||||
sampling_rate,
|
||||
baseband_bandwidth,
|
||||
@@ -122,7 +126,7 @@ ERTAppView::ERTAppView(NavigationView&) {
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
});
|
||||
}); */
|
||||
|
||||
logger = std::make_unique<ERTLogger>();
|
||||
if( logger ) {
|
||||
@@ -135,7 +139,7 @@ ERTAppView::~ERTAppView() {
|
||||
// save app settings
|
||||
settings.save("rx_ert", &app_settings);
|
||||
|
||||
radio::disable();
|
||||
receiver_model.disable(); // to switch off all, including DC bias and change flag enabled_
|
||||
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
@@ -242,7 +243,8 @@ GpsSimAppView::GpsSimAppView(
|
||||
|
||||
GpsSimAppView::~GpsSimAppView() {
|
||||
radio::disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void GpsSimAppView::on_hide() {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "lge_app.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
|
||||
#include "string_format.hpp"
|
||||
@@ -48,7 +49,8 @@ LGEView::~LGEView() {
|
||||
settings.save("tx_lge", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
|
||||
baseband::shutdown();// better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void LGEView::generate_lge_frame(const uint8_t command, const uint16_t address_a, const uint16_t address_b, std::vector<uint8_t>& data) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "soundboard_app.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "tonesets.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
|
||||
using namespace tonekey;
|
||||
using namespace portapack;
|
||||
@@ -295,7 +296,8 @@ SoundBoardView::~SoundBoardView() {
|
||||
|
||||
stop();
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -161,7 +161,12 @@ TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
}
|
||||
else options_band.set_by_value(receiver_model.tuning_frequency());
|
||||
|
||||
radio::enable({
|
||||
receiver_model.set_tuning_frequency(tuning_frequency());
|
||||
receiver_model.set_sampling_rate(sampling_rate);
|
||||
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
|
||||
receiver_model.enable(); // Before using radio::enable(), but not updating Ant.DC-Bias.
|
||||
|
||||
/* radio::enable({
|
||||
tuning_frequency(),
|
||||
sampling_rate,
|
||||
baseband_bandwidth,
|
||||
@@ -169,7 +174,7 @@ TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
});
|
||||
}); */
|
||||
|
||||
options_band.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
this->on_band_changed(v);
|
||||
@@ -200,7 +205,7 @@ TPMSAppView::~TPMSAppView() {
|
||||
app_settings.rx_frequency = target_frequency_;
|
||||
settings.save("rx_tpms", &app_settings);
|
||||
|
||||
radio::disable();
|
||||
receiver_model.disable(); // to switch off all, including DC bias and change flag enabled_
|
||||
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "manchester.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include <cstring>
|
||||
@@ -290,8 +291,9 @@ ADSBTxView::~ADSBTxView() {
|
||||
settings.save("tx_adsb", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, withouth ghost signal problem at the exit .
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void ADSBTxView::generate_frames() {
|
||||
const uint32_t ICAO_address = sym_icao.value_hex_u64();
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "aprs.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
@@ -48,7 +49,8 @@ APRSTXView::~APRSTXView() {
|
||||
settings.save("tx_aprs", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void APRSTXView::start_tx() {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
@@ -145,6 +146,8 @@ BHTView::~BHTView() {
|
||||
settings.save("tx_bht", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
BHTView::BHTView(NavigationView& nav) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ui_coasterp.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
@@ -42,7 +43,8 @@ CoasterPagerView::~CoasterPagerView() {
|
||||
settings.save("tx_coaster", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void CoasterPagerView::generate_frame() {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
@@ -208,7 +209,8 @@ EncodersView::~EncodersView() {
|
||||
settings.save("tx_ook", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // ghost signal c/m to the problem at the exit .
|
||||
baseband::shutdown(); // better this function after load_sram()
|
||||
}
|
||||
|
||||
void EncodersView::update_progress() {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "ui_freqman.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
@@ -183,7 +184,8 @@ void JammerView::focus() {
|
||||
|
||||
JammerView::~JammerView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void JammerView::on_retune(const rf::Frequency freq, const uint32_t range) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ui_keyfob.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
@@ -140,7 +141,8 @@ KeyfobView::~KeyfobView() {
|
||||
settings.save("tx_keyfob", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void KeyfobView::update_progress(const uint32_t progress) {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "modems.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
|
||||
#include "serializer.hpp"
|
||||
|
||||
@@ -44,7 +45,8 @@ LCRView::~LCRView() {
|
||||
settings.save("tx_lcr", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,6 +30,7 @@ using wolfson::wm8731::WM8731;
|
||||
|
||||
#include "tonesets.hpp"
|
||||
#include "portapack_hal.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "irq_controls.hpp"
|
||||
|
||||
@@ -178,6 +179,7 @@ void MicTXView::rxaudio(bool is_on) {
|
||||
receiver_model.set_vga(rx_vga);
|
||||
receiver_model.set_rf_amp(rx_amp);
|
||||
receiver_model.enable();
|
||||
hackrf::cpld::load_sram_no_verify(); // to have a good RX without any ghost inside Mic App
|
||||
audio::output::start();
|
||||
} else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX.
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); //This fixes something with AM RX...
|
||||
@@ -548,7 +550,8 @@ MicTXView::~MicTXView() {
|
||||
transmitter_model.disable();
|
||||
if (rx_enabled) //Also turn off audio rx if enabled
|
||||
rxaudio(false);
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "baseband_api.hpp"
|
||||
#include "hackrf_gpio.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
@@ -102,7 +103,8 @@ MorseView::~MorseView() {
|
||||
settings.save("tx_morse", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void MorseView::paint(Painter&) {
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyleft (ↄ) 2022 NotPike
|
||||
*
|
||||
* 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_playlist.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "ui_fileman.hpp"
|
||||
#include "io_file.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void PlaylistView::set_ready() {
|
||||
ready_signal = true;
|
||||
}
|
||||
|
||||
|
||||
void PlaylistView::load_file(std::filesystem::path playlist_path) {
|
||||
File playlist_file;
|
||||
|
||||
auto error = playlist_file.open(playlist_path.string());
|
||||
if (!error.is_valid()) {
|
||||
std::string line;
|
||||
char one_char[1];
|
||||
for (size_t pointer =0 ; pointer < playlist_file.size(); pointer++) {
|
||||
playlist_file.seek(pointer);
|
||||
playlist_file.read(one_char, 1);
|
||||
if ((int) one_char[0] >= ' ') {
|
||||
line += one_char[0];
|
||||
} else if (one_char[0] == '\n') {
|
||||
txtline_process(line);
|
||||
line.clear();
|
||||
}
|
||||
}
|
||||
if (line.length() > 0) {
|
||||
txtline_process(line);
|
||||
}
|
||||
}
|
||||
playlist_masterdb = playlist_db;
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
void PlaylistView::txtline_process(std::string &line) {
|
||||
playlist_entry new_item;
|
||||
rf::Frequency f;
|
||||
size_t previous = 0;
|
||||
size_t current = line.find(',');
|
||||
std::string freqs = line.substr(0, current);
|
||||
previous = current +1;
|
||||
current = line.find(',', previous);
|
||||
std::string file = line.substr(previous, current - previous);
|
||||
previous = current +1;
|
||||
current = line.find(',', previous);
|
||||
uint32_t sample_rate = strtoll(line.substr(previous).c_str(), nullptr, 10);
|
||||
|
||||
f = strtoll(freqs.c_str(), nullptr, 0);
|
||||
new_item.replay_frequency = f;
|
||||
new_item.replay_file = "/" + file;
|
||||
new_item.sample_rate = sample_rate;
|
||||
new_item.next_delay = 0;
|
||||
|
||||
playlist_db.push_back(std::move(new_item));
|
||||
}
|
||||
|
||||
void PlaylistView::on_file_changed(std::filesystem::path new_file_path, rf::Frequency replay_frequency, uint32_t replay_sample_rate) {
|
||||
File data_file;
|
||||
// Get file size
|
||||
auto data_open_error = data_file.open("/" + new_file_path.string());
|
||||
if (data_open_error.is_valid()) {
|
||||
file_error();
|
||||
return;
|
||||
}
|
||||
|
||||
file_path = new_file_path;
|
||||
field_frequency.set_value(replay_frequency);
|
||||
|
||||
sample_rate = replay_sample_rate;
|
||||
|
||||
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 0) + "Hz");
|
||||
|
||||
auto file_size = data_file.size();
|
||||
auto duration = (file_size * 1000) / (2 * 2 * sample_rate);
|
||||
|
||||
progressbar.set_max(file_size);
|
||||
text_filename.set(file_path.filename().string().substr(0, 12));
|
||||
text_duration.set(to_string_time_ms(duration));
|
||||
|
||||
button_play.focus();
|
||||
}
|
||||
|
||||
void PlaylistView::on_tx_progress(const uint32_t progress) {
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void PlaylistView::focus() {
|
||||
button_open.focus();
|
||||
}
|
||||
|
||||
void PlaylistView::file_error() {
|
||||
nav_.display_modal("Error", "File "+file_path.string() +" read error. " +file_path.string());
|
||||
}
|
||||
|
||||
bool PlaylistView::is_active() const {
|
||||
return (bool)replay_thread;
|
||||
}
|
||||
|
||||
bool PlaylistView::loop() const {
|
||||
return (bool) playlist_db.size();
|
||||
}
|
||||
|
||||
void PlaylistView::toggle() {
|
||||
if( is_active() ) {
|
||||
stop(false);
|
||||
} else {
|
||||
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
void PlaylistView::start() {
|
||||
stop(false);
|
||||
|
||||
playlist_entry item = playlist_db.front();
|
||||
playlist_db.pop_front();
|
||||
// playlist_entry item = playlist_db[0];
|
||||
// for (playlist_entry item : playlist_db) {
|
||||
// file_path = item.replay_file;
|
||||
// rf::Frequency replay_frequency = strtoll(item.replay_frequency.c_str(),nullptr,10);
|
||||
on_file_changed(item.replay_file, item.replay_frequency, item.sample_rate);
|
||||
on_target_frequency_changed(item.replay_frequency);
|
||||
|
||||
std::unique_ptr<stream::Reader> reader;
|
||||
|
||||
auto p = std::make_unique<FileReader>();
|
||||
auto open_error = p->open(file_path);
|
||||
if( open_error.is_valid() ) {
|
||||
file_error();
|
||||
return; // Fixes TX bug if there's a file error
|
||||
} else {
|
||||
reader = std::move(p);
|
||||
}
|
||||
|
||||
if( reader ) {
|
||||
button_play.set_bitmap(&bitmap_stop);
|
||||
baseband::set_sample_rate(sample_rate * 8);
|
||||
|
||||
replay_thread = std::make_unique<ReplayThread>(
|
||||
std::move(reader),
|
||||
read_size, buffer_count,
|
||||
&ready_signal,
|
||||
[](uint32_t return_code) {
|
||||
ReplayThreadDoneMessage message { return_code };
|
||||
EventDispatcher::send_message(message);
|
||||
}
|
||||
);
|
||||
}
|
||||
field_rfgain.on_change = [this](int32_t v) {
|
||||
tx_gain = v;
|
||||
};
|
||||
field_rfgain.set_value(tx_gain);
|
||||
receiver_model.set_tx_gain(tx_gain);
|
||||
|
||||
|
||||
field_rfamp.on_change = [this](int32_t v) {
|
||||
rf_amp = (bool)v;
|
||||
};
|
||||
field_rfamp.set_value(rf_amp ? 14 : 0);
|
||||
|
||||
//Enable Bias Tee if selected
|
||||
radio::set_antenna_bias(portapack::get_antenna_bias());
|
||||
|
||||
radio::enable({
|
||||
receiver_model.tuning_frequency(),
|
||||
sample_rate * 8,
|
||||
baseband_bandwidth,
|
||||
rf::Direction::Transmit,
|
||||
rf_amp, // previous code line : "receiver_model.rf_amp()," was passing the same rf_amp of all Receiver Apps
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga())
|
||||
});
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
void PlaylistView::stop(const bool do_loop) {
|
||||
if( is_active() ) {
|
||||
replay_thread.reset();
|
||||
}
|
||||
if (do_loop) {
|
||||
if (playlist_db.size() > 0 ) {
|
||||
start();
|
||||
} else {
|
||||
playlist_db = playlist_masterdb;
|
||||
start();
|
||||
}
|
||||
} else {
|
||||
radio::set_antenna_bias(false); //Turn off Bias Tee
|
||||
radio::disable();
|
||||
button_play.set_bitmap(&bitmap_play);
|
||||
}
|
||||
|
||||
ready_signal = false;
|
||||
}
|
||||
|
||||
void PlaylistView::handle_replay_thread_done(const uint32_t return_code) {
|
||||
if (return_code == ReplayThread::END_OF_FILE) {
|
||||
stop(true);
|
||||
} else if (return_code == ReplayThread::READ_ERROR) {
|
||||
stop(false);
|
||||
file_error();
|
||||
}
|
||||
|
||||
progressbar.set_value(0);
|
||||
}
|
||||
|
||||
PlaylistView::PlaylistView(
|
||||
NavigationView& nav
|
||||
) : nav_ (nav)
|
||||
{
|
||||
|
||||
tx_gain = 35;field_rfgain.set_value(tx_gain); // Initial default value (-12 dB's max ).
|
||||
field_rfamp.set_value(rf_amp ? 14 : 0); // Initial default value True. (TX RF amp on , +14dB's)
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_replay);
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&button_open,
|
||||
&text_filename,
|
||||
&text_sample_rate,
|
||||
&text_duration,
|
||||
&progressbar,
|
||||
&field_frequency,
|
||||
&field_rfgain,
|
||||
&field_rfamp, // let's not use common rf_amp
|
||||
&check_loop,
|
||||
&button_play,
|
||||
&waterfall,
|
||||
});
|
||||
|
||||
field_frequency.set_value(target_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
this->on_target_frequency_changed(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
this->on_target_frequency_changed(f);
|
||||
this->field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
|
||||
field_frequency.set_step(5000);
|
||||
|
||||
button_play.on_select = [this](ImageButton&) {
|
||||
this->toggle();
|
||||
};
|
||||
|
||||
button_open.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->on_changed = [this](std::filesystem::path new_file_path) {
|
||||
load_file(new_file_path);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
PlaylistView::~PlaylistView() {
|
||||
radio::disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void PlaylistView::on_hide() {
|
||||
stop(false);
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
waterfall.on_hide();
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
void PlaylistView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
|
||||
waterfall.set_parent_rect(waterfall_rect);
|
||||
}
|
||||
|
||||
void PlaylistView::on_target_frequency_changed(rf::Frequency f) {
|
||||
set_target_frequency(f);
|
||||
}
|
||||
|
||||
void PlaylistView::set_target_frequency(const rf::Frequency new_value) {
|
||||
persistent_memory::set_tuned_frequency(new_value);;
|
||||
}
|
||||
|
||||
rf::Frequency PlaylistView::target_frequency() const {
|
||||
return persistent_memory::tuned_frequency();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* 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_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "replay_thread.hpp"
|
||||
#include "ui_spectrum.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class PlaylistView : public View {
|
||||
public:
|
||||
PlaylistView(NavigationView& nav);
|
||||
~PlaylistView();
|
||||
|
||||
void on_hide() override;
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Playlist"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
struct playlist_entry {
|
||||
rf::Frequency replay_frequency { 0 };
|
||||
std::string replay_file{};
|
||||
uint32_t sample_rate{};
|
||||
uint32_t next_delay{};
|
||||
};
|
||||
std::deque<playlist_entry> playlist_db{};
|
||||
std::deque<playlist_entry> playlist_masterdb{};
|
||||
uint32_t sample_rate = 0;
|
||||
int32_t tx_gain { 47 };
|
||||
bool rf_amp { true }; // aux private var to store temporal, Replay App rf_amp user selection.
|
||||
static constexpr uint32_t baseband_bandwidth = 2500000;
|
||||
const size_t read_size { 16384 };
|
||||
const size_t buffer_count { 3 };
|
||||
void load_file(std::filesystem::path playlist_path);
|
||||
void txtline_process(std::string &);
|
||||
void on_file_changed(std::filesystem::path new_file_path, rf::Frequency replay_frequency, uint32_t replay_sample_rate);
|
||||
void on_target_frequency_changed(rf::Frequency f);
|
||||
void on_tx_progress(const uint32_t progress);
|
||||
|
||||
void set_target_frequency(const rf::Frequency new_value);
|
||||
rf::Frequency target_frequency() const;
|
||||
|
||||
void toggle();
|
||||
void start();
|
||||
void stop(const bool do_loop);
|
||||
bool is_active() const;
|
||||
bool loop() const;
|
||||
void set_ready();
|
||||
void handle_replay_thread_done(const uint32_t return_code);
|
||||
void file_error();
|
||||
|
||||
std::filesystem::path file_path { };
|
||||
std::unique_ptr<ReplayThread> replay_thread { };
|
||||
bool ready_signal { false };
|
||||
|
||||
Labels labels {
|
||||
{ { 10 * 8, 2 * 16 }, "GAIN A:", Color::light_grey() }
|
||||
};
|
||||
|
||||
Button button_open {
|
||||
{ 0 * 8, 0 * 16, 10 * 8, 2 * 16 },
|
||||
"Open file"
|
||||
};
|
||||
|
||||
|
||||
Text text_filename {
|
||||
{ 11 * 8, 0 * 16, 12 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
Text text_sample_rate {
|
||||
{ 24 * 8, 0 * 16, 6 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_duration {
|
||||
{ 11 * 8, 1 * 16, 6 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
ProgressBar progressbar {
|
||||
{ 18 * 8, 1 * 16, 12 * 8, 16 }
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 0 * 8, 2 * 16 },
|
||||
};
|
||||
|
||||
NumberField field_rfgain {
|
||||
{ 14 * 8, 2 * 16 },
|
||||
2,
|
||||
{ 0, 47 },
|
||||
1,
|
||||
' '
|
||||
};
|
||||
NumberField field_rfamp { // previously I was using "RFAmpField field_rf_amp" but that is general Receiver amp setting.
|
||||
{ 19 * 8, 2 * 16 },
|
||||
2,
|
||||
{ 0, 14 }, // this time we will display GUI , 0 or 14 dBs same as Mic App
|
||||
14,
|
||||
' '
|
||||
};
|
||||
Checkbox check_loop {
|
||||
{ 21 * 8, 2 * 16 },
|
||||
4,
|
||||
"Loop",
|
||||
true
|
||||
};
|
||||
ImageButton button_play {
|
||||
{ 28 * 8, 2 * 16, 2 * 8, 1 * 16 },
|
||||
&bitmap_play,
|
||||
Color::green(),
|
||||
Color::black()
|
||||
};
|
||||
|
||||
spectrum::WaterfallWidget waterfall { };
|
||||
|
||||
MessageHandlerRegistration message_handler_replay_thread_error {
|
||||
Message::ID::ReplayThreadDone,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
|
||||
this->handle_replay_thread_done(message.return_code);
|
||||
}
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal {
|
||||
Message::ID::RequestSignal,
|
||||
[this](const Message* const p) {
|
||||
const auto message = static_cast<const RequestSignalMessage*>(p);
|
||||
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
|
||||
this->set_ready();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_tx_progress {
|
||||
Message::ID::TXProgress,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||
this->on_tx_progress(message.progress);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ui_pocsag_tx.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
|
||||
@@ -43,7 +44,8 @@ POCSAGTXView::~POCSAGTXView() {
|
||||
settings.save("tx_pocsag", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void POCSAGTXView::on_tx_progress(const uint32_t progress, const bool done) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
@@ -180,7 +181,8 @@ RDSView::~RDSView() {
|
||||
settings.save("tx_rds", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void RDSView::start_tx() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
*
|
||||
* 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_RECON
|
||||
#define _UI_RECON
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "receiver_model.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "freqman.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "ui_mictx.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "file.hpp"
|
||||
#include "app_settings.hpp"
|
||||
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ReconThread {
|
||||
public:
|
||||
ReconThread(freqman_db *database );
|
||||
~ReconThread();
|
||||
|
||||
void set_recon(const bool v);
|
||||
void set_freq_delete(const bool v);
|
||||
bool is_recon();
|
||||
|
||||
void set_lock_duration( const uint32_t v );
|
||||
uint32_t get_lock_duration();
|
||||
void set_lock_nb_match( const uint32_t v );
|
||||
void set_match_mode( const uint32_t v );
|
||||
uint32_t get_lock_nb_match();
|
||||
|
||||
void set_freq_lock(const uint32_t v);
|
||||
uint32_t is_freq_lock();
|
||||
int64_t get_current_freq();
|
||||
|
||||
void set_stepper(const int64_t v);
|
||||
|
||||
void change_recon_direction();
|
||||
bool get_recon_direction();
|
||||
void set_recon_direction( const bool v);
|
||||
|
||||
void set_continuous(const bool v);
|
||||
|
||||
void set_default_modulation( freqman_index_t index );
|
||||
freqman_index_t get_current_modulation();
|
||||
void set_default_bandwidth( freqman_index_t index );
|
||||
freqman_index_t get_current_bandwidth();
|
||||
void set_default_step( freqman_index_t index );
|
||||
void set_freq_index( int16_t index );
|
||||
int16_t get_freq_index();
|
||||
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
ReconThread(const ReconThread&) = delete;
|
||||
ReconThread(ReconThread&&) = delete;
|
||||
ReconThread& operator=(const ReconThread&) = delete;
|
||||
ReconThread& operator=(ReconThread&&) = delete;
|
||||
|
||||
private:
|
||||
freqman_db &frequency_list_ ;
|
||||
Thread* thread { nullptr };
|
||||
int64_t freq = 0 ;
|
||||
uint32_t step = 0 ;
|
||||
freqman_index_t def_modulation = 0 ;
|
||||
freqman_index_t def_bandwidth = 0 ;
|
||||
freqman_index_t def_step = 0 ;
|
||||
tone_index tone = 0 ;
|
||||
freqman_entry last_entry = { } ;
|
||||
int16_t frequency_index = 0 ;
|
||||
|
||||
bool _recon { true };
|
||||
bool _freq_delete { false };
|
||||
bool _fwd { true };
|
||||
bool _continuous { true };
|
||||
int64_t _stepper { 0 };
|
||||
int32_t _freq_lock { 0 };
|
||||
uint32_t _lock_duration { 50 };
|
||||
uint32_t _lock_nb_match { 10 };
|
||||
static msg_t static_fn(void* arg);
|
||||
};
|
||||
|
||||
class ReconView : public View {
|
||||
public:
|
||||
ReconView(NavigationView& nav);
|
||||
~ReconView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
void big_display_freq( int64_t f );
|
||||
|
||||
const Style style_grey { // recon
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::grey(),
|
||||
};
|
||||
|
||||
const Style style_white { // recon
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::white(),
|
||||
};
|
||||
|
||||
const Style style_yellow { //Found signal
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::yellow(),
|
||||
};
|
||||
|
||||
const Style style_green { //Found signal
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::green(),
|
||||
};
|
||||
|
||||
const Style style_red { //erasing freq
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::red(),
|
||||
};
|
||||
|
||||
const Style style_blue { // quick recon, wait == 0
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::blue(),
|
||||
};
|
||||
|
||||
std::string title() const override { return "Recon"; };
|
||||
|
||||
//void set_parent_rect(const Rect new_parent_rect) override;
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
void start_recon_thread();
|
||||
size_t change_mode( freqman_index_t mod_type);
|
||||
void show_max( bool refresh_display = false );
|
||||
void recon_pause();
|
||||
void recon_resume();
|
||||
void user_pause();
|
||||
void user_resume();
|
||||
void frequency_file_load( bool stop_all_before = false);
|
||||
void on_statistics_update(const ChannelStatistics& statistics);
|
||||
void on_headphone_volume_changed(int32_t v);
|
||||
void set_display_freq( int64_t freq );
|
||||
void handle_retune( int64_t freq , uint32_t index );
|
||||
bool check_sd_card();
|
||||
|
||||
jammer::jammer_range_t frequency_range { false, 0, 0 }; //perfect for manual recon task too...
|
||||
int32_t squelch { 0 };
|
||||
int32_t db { 0 };
|
||||
int32_t timer { 0 };
|
||||
int32_t wait { 5000 }; // in msec. if > 0 wait duration after a lock, if < 0 duration is set to 'wait' unless there is no more activity
|
||||
uint32_t lock_wait { 500 }; // in msec. Represent the maximum amount of time we will wait for a lock to complete before switching to next
|
||||
int32_t def_step { 0 };
|
||||
freqman_db frequency_list = { };
|
||||
uint32_t current_index { 0 };
|
||||
bool userpause { false };
|
||||
bool continuous_lock { false };
|
||||
std::string input_file = { "RECON" };
|
||||
std::string output_file = { "RECON_RESULTS" };
|
||||
bool autosave = { true };
|
||||
bool autostart = { true };
|
||||
bool continuous = { true };
|
||||
bool filedelete = { true };
|
||||
bool load_freqs = { true };
|
||||
bool load_ranges = { true };
|
||||
bool load_hamradios = { true };
|
||||
bool update_ranges = { true };
|
||||
bool fwd = { true };
|
||||
// maximum usable freq
|
||||
long long int MAX_UFREQ = { 7200000000 };
|
||||
uint32_t recon_lock_nb_match = { 10 };
|
||||
uint32_t recon_lock_duration = { 50 };
|
||||
uint32_t recon_match_mode = { 0 };
|
||||
bool scanner_mode { false };
|
||||
bool manual_mode { false };
|
||||
bool sd_card_mounted = false ;
|
||||
int32_t volume = 40 ;
|
||||
|
||||
Labels labels
|
||||
{
|
||||
{ { 0 * 8 , 0 * 16 }, "LNA: VGA: AMP: VOL: ", Color::light_grey() },
|
||||
{ { 0 * 8 , 1 * 16 }, "BW : SQ: W,L: , ", Color::light_grey() },
|
||||
{ { 3 * 8 , 10 * 16 }, "START END MANUAL", Color::light_grey() },
|
||||
{ { 0 * 8 , (26 * 8) + 4 }, "MODE:", Color::light_grey() },
|
||||
{ { 11 * 8 , (26 * 8) + 4 }, "STEP:", Color::light_grey() },
|
||||
};
|
||||
|
||||
LNAGainField field_lna {
|
||||
{ 4 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
VGAGainField field_vga {
|
||||
{ 11 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
RFAmpField field_rf_amp {
|
||||
{ 18 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
NumberField field_volume {
|
||||
{ 24 * 8, 0 * 16 },
|
||||
2,
|
||||
{ 0, 99 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
OptionsField field_bw {
|
||||
{ 3 * 8, 1 * 16 },
|
||||
4,
|
||||
{ }
|
||||
};
|
||||
|
||||
NumberField field_squelch {
|
||||
{ 10 * 8, 1 * 16 },
|
||||
3,
|
||||
{ -90, 20 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_wait {
|
||||
{ 18 * 8, 1 * 16 },
|
||||
5,
|
||||
{ -9000, 9000 },
|
||||
100,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_lock_wait {
|
||||
{ 24 * 8, 1 * 16 },
|
||||
4,
|
||||
{ 100 , 9000 },
|
||||
100,
|
||||
' ',
|
||||
};
|
||||
|
||||
RSSI rssi {
|
||||
{ 0 * 16, 2 * 16, 15 * 16, 8 },
|
||||
};
|
||||
|
||||
Text text_cycle {
|
||||
{ 0, 3 * 16, 3 * 8, 16 },
|
||||
};
|
||||
|
||||
Text text_max {
|
||||
{ 3 * 8, 3 * 16, 20 * 8 , 16 },
|
||||
};
|
||||
|
||||
Text desc_cycle {
|
||||
{0, 4 * 16, 240, 16 },
|
||||
};
|
||||
|
||||
/* BigFrequency big_display { //Show frequency in glamour
|
||||
{ 4, 7 * 16 - 8 , 28 * 8, 52 },
|
||||
0
|
||||
}; */
|
||||
|
||||
Text big_display { //Show frequency in text mode
|
||||
{ 0, 5 * 16 , 28 * 8, 16 },
|
||||
};
|
||||
|
||||
Text freq_stats { //Show frequency stats in text mode
|
||||
{ 0, 6 * 16 , 28 * 8, 16 },
|
||||
};
|
||||
|
||||
Text text_timer { //Show frequency stats in text mode
|
||||
{ 0, 7 * 16 , 28 * 8, 16 },
|
||||
};
|
||||
|
||||
Button button_recon_setup {
|
||||
{ 25 * 8 , 2 * 16 + 8 , 4 * 8, 28 },
|
||||
"OPT"
|
||||
};
|
||||
|
||||
Button button_scanner_mode {
|
||||
{ 21 * 8 , 8 * 16 , 9 * 8, 28 },
|
||||
"RECON"
|
||||
};
|
||||
|
||||
Text file_name { //Show file used
|
||||
{ 0 , 8 * 16 + 4 , 20 * 8, 16 },
|
||||
};
|
||||
|
||||
|
||||
ButtonWithEncoder button_manual_start {
|
||||
{ 0 * 8, 11 * 16, 11 * 8, 28 },
|
||||
""
|
||||
};
|
||||
|
||||
ButtonWithEncoder button_manual_end {
|
||||
{ 12 * 8 - 6, 11 * 16, 11 * 8, 28 },
|
||||
""
|
||||
};
|
||||
|
||||
Button button_manual_recon {
|
||||
{ 23 * 8 - 3, 11 * 16, 7 * 8 , 28 },
|
||||
"SEARCH"
|
||||
};
|
||||
|
||||
OptionsField field_mode {
|
||||
{ 5 * 8, (26 * 8) + 4 },
|
||||
6,
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
OptionsField step_mode {
|
||||
{ 17 * 8, (26 * 8) + 4 },
|
||||
12,
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
ButtonWithEncoder button_pause {
|
||||
{ 0, (15 * 16) - 4, 72, 28 },
|
||||
"PAUSE"
|
||||
};
|
||||
|
||||
|
||||
Button button_audio_app {
|
||||
{ 84, (15 * 16) - 4, 72, 28 },
|
||||
"AUDIO"
|
||||
};
|
||||
|
||||
ButtonWithEncoder button_add {
|
||||
{ 168, (15 * 16) - 4, 72, 28 },
|
||||
"<STORE>"
|
||||
};
|
||||
|
||||
Button button_dir {
|
||||
{ 0, (35 * 8) - 4, 34, 28 },
|
||||
"FW>"
|
||||
};
|
||||
|
||||
Button button_restart {
|
||||
{ 38, (35 * 8) - 4, 34, 28 },
|
||||
"RST"
|
||||
};
|
||||
|
||||
|
||||
Button button_mic_app {
|
||||
{ 84, (35 * 8) - 4, 72, 28 },
|
||||
"MIC TX"
|
||||
};
|
||||
|
||||
ButtonWithEncoder button_remove {
|
||||
{ 168, (35 * 8) - 4, 72, 28 },
|
||||
"<REMOVE>"
|
||||
};
|
||||
|
||||
std::unique_ptr<ReconThread> recon_thread { };
|
||||
|
||||
MessageHandlerRegistration message_handler_retune {
|
||||
Message::ID::Retune,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const RetuneMessage*>(p);
|
||||
this->handle_retune(message.freq,message.range);
|
||||
}
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_stats {
|
||||
Message::ID::ChannelStatistics,
|
||||
[this](const Message* const p) {
|
||||
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
|
||||
}
|
||||
};
|
||||
// app save settings
|
||||
std::app_settings settings { };
|
||||
std::app_settings::AppSettings app_settings { };
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* 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_recon_settings.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
bool ReconSetupLoadStrings( std::string source, std::string &input_file , std::string &output_file , uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , int32_t &recon_squelch_level , uint32_t &recon_match_mode , int32_t &wait , uint32_t &lock_wait , int32_t &volume )
|
||||
{
|
||||
File settings_file;
|
||||
size_t length, file_position = 0;
|
||||
char * pos;
|
||||
char * line_start;
|
||||
char * line_end;
|
||||
char file_data[257];
|
||||
|
||||
uint32_t it = 0 ;
|
||||
uint32_t nb_params = 9 ;
|
||||
std::string params[ 9 ];
|
||||
|
||||
bool check_sd_card = (sd_card::status() == sd_card::Status::Mounted) ? true : false ;
|
||||
|
||||
if( check_sd_card )
|
||||
{
|
||||
auto result = settings_file.open( source );
|
||||
if( !result.is_valid() )
|
||||
{
|
||||
while( it < nb_params )
|
||||
{
|
||||
// Read a 256 bytes block from file
|
||||
settings_file.seek(file_position);
|
||||
memset(file_data, 0, 257);
|
||||
auto read_size = settings_file.read(file_data, 256);
|
||||
if (read_size.is_error())
|
||||
break ;
|
||||
file_position += 256;
|
||||
// Reset line_start to beginning of buffer
|
||||
line_start = file_data;
|
||||
pos=line_start;
|
||||
while ((line_end = strstr(line_start, "\x0A"))) {
|
||||
length = line_end - line_start - 1 ;
|
||||
params[ it ] = string( pos , length );
|
||||
it ++ ;
|
||||
line_start = line_end + 1;
|
||||
pos=line_start ;
|
||||
if (line_start - file_data >= 256)
|
||||
break;
|
||||
if( it >= nb_params )
|
||||
break ;
|
||||
}
|
||||
if (read_size.value() != 256)
|
||||
break; // End of file
|
||||
|
||||
// Restart at beginning of last incomplete line
|
||||
file_position -= (file_data + 256 - line_start);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( it > 0 )
|
||||
input_file = params[ 0 ];
|
||||
else
|
||||
input_file = "RECON" ;
|
||||
|
||||
if( it > 1 )
|
||||
output_file= params[ 1 ];
|
||||
else
|
||||
output_file = "RECON_RESULTS" ;
|
||||
|
||||
if( it > 2 )
|
||||
recon_lock_duration = strtoll( params[ 2 ].c_str() , nullptr , 10 );
|
||||
else
|
||||
recon_lock_duration = 50 ;
|
||||
|
||||
if( it > 3 )
|
||||
recon_lock_nb_match = strtoll( params[ 3 ].c_str() , nullptr , 10 );
|
||||
else
|
||||
recon_lock_nb_match = 10 ;
|
||||
|
||||
if( it > 4 )
|
||||
recon_squelch_level = strtoll( params[ 4 ].c_str() , nullptr , 10 );
|
||||
else
|
||||
recon_squelch_level = -14 ;
|
||||
|
||||
if( it > 5 )
|
||||
recon_match_mode = strtoll( params[ 5 ].c_str() , nullptr , 10 );
|
||||
else
|
||||
recon_match_mode = 0 ;
|
||||
|
||||
if( it > 6 )
|
||||
wait = strtoll( params[ 6 ].c_str() , nullptr , 10 );
|
||||
else
|
||||
wait = 5000 ;
|
||||
|
||||
if( it > 7 )
|
||||
lock_wait = strtoll( params[ 7 ].c_str() , nullptr , 10 );
|
||||
else
|
||||
lock_wait = 1000 ;
|
||||
|
||||
if( it > 8 )
|
||||
volume = strtoll( params[ 8 ].c_str() , nullptr , 10 );
|
||||
else
|
||||
volume = 40 ;
|
||||
|
||||
if( it < nb_params )
|
||||
{
|
||||
/* bad number of params, signal defaults */
|
||||
return false ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool ReconSetupSaveStrings( std::string dest, std::string input_file , std::string output_file , uint32_t recon_lock_duration , uint32_t recon_lock_nb_match , int32_t recon_squelch_level , uint32_t recon_match_mode , int32_t wait , uint32_t lock_wait , int32_t volume )
|
||||
{
|
||||
File settings_file;
|
||||
|
||||
auto result = settings_file.create( dest );
|
||||
if( result.is_valid() )
|
||||
return false ;
|
||||
settings_file.write_line( input_file );
|
||||
settings_file.write_line( output_file );
|
||||
settings_file.write_line( to_string_dec_uint( recon_lock_duration ) );
|
||||
settings_file.write_line( to_string_dec_uint( recon_lock_nb_match ) );
|
||||
settings_file.write_line( to_string_dec_int( recon_squelch_level ) );
|
||||
settings_file.write_line( to_string_dec_uint( recon_match_mode ) );
|
||||
settings_file.write_line( to_string_dec_int( wait ) );
|
||||
settings_file.write_line( to_string_dec_uint( lock_wait ) );
|
||||
settings_file.write_line( to_string_dec_int( volume ) );
|
||||
return true ;
|
||||
}
|
||||
|
||||
ReconSetupViewMain::ReconSetupViewMain( NavigationView &nav , Rect parent_rect , std::string input_file , std::string output_file ) : View( parent_rect ) , _input_file { input_file } , _output_file { output_file }
|
||||
{
|
||||
hidden(true);
|
||||
add_children({
|
||||
&button_load_freqs,
|
||||
&text_input_file,
|
||||
&button_save_freqs,
|
||||
&button_output_file,
|
||||
&checkbox_autosave_freqs,
|
||||
&checkbox_autostart_recon,
|
||||
&checkbox_continuous,
|
||||
&checkbox_clear_output
|
||||
});
|
||||
|
||||
checkbox_autosave_freqs.set_value( persistent_memory::recon_autosave_freqs() );
|
||||
checkbox_autostart_recon.set_value( persistent_memory::recon_autostart_recon() );
|
||||
checkbox_continuous.set_value( persistent_memory::recon_continuous() );
|
||||
checkbox_clear_output.set_value( persistent_memory::recon_clear_output() );
|
||||
|
||||
text_input_file.set( _input_file );
|
||||
button_output_file.set_text( _output_file );
|
||||
|
||||
button_load_freqs.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->on_changed = [this,&nav](std::filesystem::path new_file_path) {
|
||||
std::string dir_filter = "FREQMAN/";
|
||||
std::string str_file_path = new_file_path.string();
|
||||
if (str_file_path.find(dir_filter) != string::npos) { // assert file from the FREQMAN folder
|
||||
// get the filename without txt extension so we can use load_freqman_file fcn
|
||||
_input_file = new_file_path.stem().string();
|
||||
text_input_file.set( _input_file );
|
||||
} else {
|
||||
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
button_save_freqs.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->on_changed = [this,&nav](std::filesystem::path new_file_path) {
|
||||
std::string dir_filter = "FREQMAN/";
|
||||
std::string str_file_path = new_file_path.string();
|
||||
if (str_file_path.find(dir_filter) != string::npos) { // assert file from the FREQMAN folder
|
||||
_output_file = new_file_path.stem().string();
|
||||
button_output_file.set_text( _output_file );
|
||||
} else {
|
||||
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
button_output_file.on_select =[this, &nav](Button&) {
|
||||
text_prompt( nav, _output_file , 28 ,
|
||||
[this](std::string& buffer) {
|
||||
_output_file = buffer ;
|
||||
button_output_file.set_text( _output_file );
|
||||
} );
|
||||
};
|
||||
};
|
||||
|
||||
void ReconSetupViewMain::Save( std::string &input_file , std::string &output_file ) {
|
||||
persistent_memory::set_recon_autosave_freqs(checkbox_autosave_freqs.value());
|
||||
persistent_memory::set_recon_autostart_recon(checkbox_autostart_recon.value());
|
||||
persistent_memory::set_recon_continuous(checkbox_continuous.value());
|
||||
persistent_memory::set_recon_clear_output(checkbox_clear_output.value());
|
||||
input_file=_input_file ;
|
||||
output_file=_output_file ;
|
||||
};
|
||||
void ReconSetupViewMore::Save( uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , uint32_t &recon_match_mode ) {
|
||||
persistent_memory::set_recon_load_freqs(checkbox_load_freqs.value());
|
||||
persistent_memory::set_recon_load_ranges(checkbox_load_ranges.value());
|
||||
persistent_memory::set_recon_load_hamradios(checkbox_load_hamradios.value());
|
||||
persistent_memory::set_recon_update_ranges_when_recon(checkbox_update_ranges_when_recon.value());
|
||||
recon_lock_duration = field_recon_lock_duration.value();
|
||||
recon_lock_nb_match = field_recon_lock_nb_match.value();
|
||||
recon_match_mode = field_recon_match_mode . selected_index_value() ;
|
||||
};
|
||||
|
||||
void ReconSetupViewMain::focus() {
|
||||
button_load_freqs.focus();
|
||||
}
|
||||
|
||||
ReconSetupViewMore::ReconSetupViewMore( NavigationView &nav , Rect parent_rect , uint32_t recon_lock_duration , uint32_t recon_lock_nb_match , uint32_t recon_match_mode ) : View( parent_rect ), _recon_lock_duration { recon_lock_duration } , _recon_lock_nb_match { recon_lock_nb_match } , _recon_match_mode { recon_match_mode }
|
||||
{
|
||||
(void)nav;
|
||||
hidden(true);
|
||||
|
||||
add_children({
|
||||
&checkbox_load_freqs,
|
||||
&checkbox_load_ranges,
|
||||
&checkbox_load_hamradios,
|
||||
&checkbox_update_ranges_when_recon,
|
||||
&text_recon_lock_duration,
|
||||
&field_recon_lock_duration,
|
||||
&text_recon_lock_nb,
|
||||
&field_recon_lock_nb_match,
|
||||
&field_recon_match_mode,
|
||||
});
|
||||
|
||||
checkbox_load_freqs.set_value( persistent_memory::recon_load_freqs() );
|
||||
checkbox_load_ranges.set_value( persistent_memory::recon_load_ranges() );
|
||||
checkbox_load_hamradios.set_value( persistent_memory::recon_load_hamradios() );
|
||||
checkbox_update_ranges_when_recon.set_value( persistent_memory::recon_update_ranges_when_recon() );
|
||||
field_recon_lock_duration.set_value( _recon_lock_duration );
|
||||
field_recon_lock_nb_match.set_value( _recon_lock_nb_match );
|
||||
field_recon_match_mode.set_by_value( _recon_match_mode );
|
||||
};
|
||||
|
||||
void ReconSetupViewMore::focus() {
|
||||
checkbox_load_freqs.focus();
|
||||
}
|
||||
|
||||
void ReconSetupView::focus() {
|
||||
viewMain.focus();
|
||||
}
|
||||
|
||||
ReconSetupView::ReconSetupView(
|
||||
NavigationView& nav , std::string _input_file , std::string _output_file , uint32_t _recon_lock_duration , uint32_t _recon_lock_nb_match , uint32_t _recon_match_mode ) : nav_ { nav } , input_file { _input_file } , output_file { _output_file } , recon_lock_duration { _recon_lock_duration } , recon_lock_nb_match { _recon_lock_nb_match } , recon_match_mode { _recon_match_mode }
|
||||
{
|
||||
add_children({
|
||||
&tab_view,
|
||||
&viewMain,
|
||||
&viewMore,
|
||||
&button_save
|
||||
});
|
||||
|
||||
button_save.on_select = [this,&nav](Button&) {
|
||||
viewMain.Save( input_file , output_file );
|
||||
viewMore.Save( recon_lock_duration , recon_lock_nb_match , recon_match_mode );
|
||||
std::vector<std::string> messages ;
|
||||
messages.push_back( input_file );
|
||||
messages.push_back( output_file );
|
||||
messages.push_back( to_string_dec_uint( recon_lock_duration ) );
|
||||
messages.push_back( to_string_dec_uint( recon_lock_nb_match ) );
|
||||
messages.push_back( to_string_dec_uint( recon_match_mode ) );
|
||||
on_changed( messages );
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
} /* namespace ui */
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* 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 "serializer.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_tabview.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
bool ReconSetupLoadStrings( std::string source, std::string &input_file , std::string &output_file , uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , int32_t &recon_squelch_level , uint32_t &recon_match_mode , int32_t &wait , uint32_t &lock_wait , int32_t &volume );
|
||||
bool ReconSetupSaveStrings( std::string dest, const std::string input_file , const std::string output_file , const uint32_t recon_lock_duration , const uint32_t recon_lock_nb_match , int32_t recon_squelch_level , uint32_t recon_match_mode , int32_t wait , uint32_t lock_wait , int32_t volume );
|
||||
|
||||
class ReconSetupViewMain : public View {
|
||||
public:
|
||||
ReconSetupViewMain( NavigationView& nav, Rect parent_rect , std::string input_file , std::string output_file );
|
||||
void Save( std::string &input_file , std::string &output_file );
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
std::string _input_file = { "RECON" };
|
||||
std::string _output_file = { "RECON_RESULTS" };
|
||||
|
||||
Button button_load_freqs {
|
||||
{ 1 * 8 , 12 , 18 * 8 , 22 },
|
||||
"select input file"
|
||||
};
|
||||
Text text_input_file {
|
||||
{ 1 * 8 , 4 + 2 * 16, 18 * 8, 22 },
|
||||
"RECON"
|
||||
};
|
||||
|
||||
Button button_save_freqs {
|
||||
{ 1 * 8 , 4 * 16 - 8 , 18 * 8 , 22 },
|
||||
"select output file"
|
||||
};
|
||||
Button button_output_file {
|
||||
{ 1 * 8 , 5 * 16 - 2, 18 * 8, 22 },
|
||||
"RECON_RESULTS"
|
||||
};
|
||||
|
||||
Checkbox checkbox_autosave_freqs {
|
||||
{ 1 * 8, 7 * 16 - 4 },
|
||||
3,
|
||||
"autosave freqs"
|
||||
};
|
||||
|
||||
Checkbox checkbox_autostart_recon {
|
||||
{ 1 * 8, 9 * 16 - 4 },
|
||||
3,
|
||||
"autostart recon"
|
||||
};
|
||||
|
||||
Checkbox checkbox_continuous {
|
||||
{ 1 * 8, 11 * 16 - 4 },
|
||||
3,
|
||||
"continuous"
|
||||
};
|
||||
Checkbox checkbox_clear_output {
|
||||
{ 1 * 8, 13 * 16 - 4 },
|
||||
3,
|
||||
"clear output at start"
|
||||
};
|
||||
};
|
||||
|
||||
class ReconSetupViewMore : public View {
|
||||
public:
|
||||
ReconSetupViewMore( NavigationView& nav, Rect parent_rect , const uint32_t _recon_lock_duration , const uint32_t _recon_lock_nb_match , const uint32_t _recon_match_mode );
|
||||
|
||||
void Save( uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , uint32_t &recon_match_mode );
|
||||
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
|
||||
const uint32_t _recon_lock_duration = 50 ;
|
||||
const uint32_t _recon_lock_nb_match = 10 ;
|
||||
const uint32_t _recon_match_mode = 0 ;
|
||||
|
||||
Checkbox checkbox_load_freqs {
|
||||
{ 1 * 8, 12 },
|
||||
3,
|
||||
"input: load freqs"
|
||||
};
|
||||
|
||||
Checkbox checkbox_load_ranges {
|
||||
{ 1 * 8, 42 },
|
||||
3,
|
||||
"input: load ranges"
|
||||
};
|
||||
|
||||
Checkbox checkbox_load_hamradios {
|
||||
{ 1 * 8, 72 },
|
||||
3,
|
||||
"input: load hamradios"
|
||||
};
|
||||
|
||||
Checkbox checkbox_update_ranges_when_recon {
|
||||
{ 1 * 8, 102 },
|
||||
3,
|
||||
"auto update m-ranges"
|
||||
};
|
||||
Text text_recon_lock_duration {
|
||||
{ 1 * 8 , 132 , 22 * 8 , 22 },
|
||||
" ms (lock duration)"
|
||||
};
|
||||
NumberField field_recon_lock_duration {
|
||||
{ 1 * 8, 132 }, // position X , Y
|
||||
4, // number of displayed digits (even empty)
|
||||
{ 50 , 990 }, // range of number
|
||||
10, // rotary encoder increment
|
||||
' ', // filling character
|
||||
false // can loop
|
||||
};
|
||||
Text text_recon_lock_nb {
|
||||
{ 1 * 8 , 162 , 25 * 8 , 22 },
|
||||
" x (nb lock to match freq)"
|
||||
};
|
||||
NumberField field_recon_lock_nb_match {
|
||||
{ 1 * 8, 162 },
|
||||
4,
|
||||
{ 1, 99 },
|
||||
1,
|
||||
' ',
|
||||
false
|
||||
};
|
||||
OptionsField field_recon_match_mode {
|
||||
{ 1 * 8, 192 },
|
||||
20, // CONTINUOUS MATCH MODE / SPARSE TIMED MATCH MODE
|
||||
{
|
||||
{ "SQL MATCH: CONTINOUS" , 0 },
|
||||
{ "SQL MATCH: SPARSE" , 1 }
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class ReconSetupView : public View {
|
||||
public:
|
||||
ReconSetupView( NavigationView& nav , std::string _input_file , std::string _output_file , const uint32_t _recon_lock_duration , const uint32_t _recon_lock_nb_match , const uint32_t _recon_match_mode );
|
||||
|
||||
std::function<void( std::vector<std::string> messages )> on_changed { };
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Recon setup"; };
|
||||
|
||||
private:
|
||||
|
||||
NavigationView& nav_ ;
|
||||
|
||||
std::string input_file = { "RECON" };
|
||||
std::string output_file = { "RECON_RESULTS" };
|
||||
uint32_t recon_lock_duration = 50 ;
|
||||
uint32_t recon_lock_nb_match = 10 ;
|
||||
uint32_t recon_match_mode = 0 ;
|
||||
|
||||
Rect view_rect = { 0, 3 * 8, 240, 230 };
|
||||
|
||||
ReconSetupViewMain viewMain{ nav_ , view_rect , input_file , output_file };
|
||||
ReconSetupViewMore viewMore{ nav_ , view_rect , recon_lock_duration , recon_lock_nb_match , recon_match_mode };
|
||||
|
||||
TabView tab_view {
|
||||
{ "Main", Color::cyan() , &viewMain },
|
||||
{ "More", Color::green(), &viewMore }
|
||||
};
|
||||
Button button_save {
|
||||
{ 9 * 8, 255, 14 * 8 , 40 },
|
||||
"SAVE"
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -540,7 +540,7 @@ size_t ScannerView::change_mode(uint8_t new_mod) { //Before this, do a scan_thre
|
||||
field_bw.set_selected_index(0);
|
||||
receiver_model.set_am_configuration(field_bw.selected_index());
|
||||
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_am_configuration(n); };
|
||||
receiver_model.set_sampling_rate(2000000);receiver_model.set_baseband_bandwidth(2000000);
|
||||
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000);
|
||||
break;
|
||||
case WFM:
|
||||
bw.emplace_back("16k", 0);
|
||||
|
||||
@@ -245,13 +245,9 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
checkbox_showclock.set_value(!persistent_memory::hide_clock());
|
||||
checkbox_guireturnflag.set_value(persistent_memory::show_gui_return_icon());
|
||||
|
||||
uint32_t backlight_timer = persistent_memory::config_backlight_timer();
|
||||
if (backlight_timer) {
|
||||
checkbox_bloff.set_value(true);
|
||||
options_bloff.set_by_value(backlight_timer);
|
||||
} else {
|
||||
options_bloff.set_selected_index(0);
|
||||
}
|
||||
const auto backlight_config = persistent_memory::config_backlight_timer();
|
||||
checkbox_bloff.set_value(backlight_config.timeout_enabled());
|
||||
options_bloff.set_by_value(backlight_config.timeout_enum());
|
||||
|
||||
if (persistent_memory::clock_with_date()) {
|
||||
options_clockformat.set_selected_index(1);
|
||||
@@ -261,11 +257,11 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
|
||||
|
||||
button_save.on_select = [&nav, this](Button&) {
|
||||
if (checkbox_bloff.value())
|
||||
persistent_memory::set_config_backlight_timer(options_bloff.selected_index() + 1);
|
||||
else
|
||||
persistent_memory::set_config_backlight_timer(0);
|
||||
|
||||
persistent_memory::set_config_backlight_timer({
|
||||
(persistent_memory::backlight_timeout_t)options_bloff.selected_index_value(),
|
||||
checkbox_bloff.value()
|
||||
});
|
||||
|
||||
if (checkbox_showclock.value()){
|
||||
if (options_clockformat.selected_index() == 1)
|
||||
persistent_memory::set_clock_with_date(true);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ff.h"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -210,6 +211,8 @@ private:
|
||||
SetFrequencyCorrectionModel form_collect();
|
||||
};
|
||||
|
||||
using portapack::persistent_memory::backlight_timeout_t;
|
||||
|
||||
class SetUIView : public View {
|
||||
public:
|
||||
SetUIView(NavigationView& nav);
|
||||
@@ -241,13 +244,14 @@ private:
|
||||
{ 52, 7 * 16 + 8 },
|
||||
20,
|
||||
{
|
||||
{ "5 seconds", 5 },
|
||||
{ "15 seconds", 15 },
|
||||
{ "30 seconds", 30 },
|
||||
{ "1 minute", 60 },
|
||||
{ "3 minutes", 180 },
|
||||
{ "5 minutes", 300 },
|
||||
{ "10 minutes", 600 }
|
||||
{ "5 seconds", backlight_timeout_t::Timeout5Sec },
|
||||
{ "15 seconds", backlight_timeout_t::Timeout15Sec },
|
||||
{ "30 seconds", backlight_timeout_t::Timeout30Sec },
|
||||
{ "1 minute", backlight_timeout_t::Timeout60Sec },
|
||||
{ "3 minutes", backlight_timeout_t::Timeout180Sec },
|
||||
{ "5 minutes", backlight_timeout_t::Timeout300Sec },
|
||||
{ "10 minutes", backlight_timeout_t::Timeout600Sec },
|
||||
{ "1 hour", backlight_timeout_t::Timeout3600Sec },
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
@@ -93,7 +94,8 @@ SSTVTXView::~SSTVTXView() {
|
||||
settings.save("tx_sstv", &app_settings);
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void SSTVTXView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace ui {
|
||||
TouchCalibrationView::TouchCalibrationView(
|
||||
NavigationView& nav
|
||||
) : nav { nav },
|
||||
calibration { touch::default_calibration() }
|
||||
calibration { touch::Calibration() }
|
||||
{
|
||||
add_children({
|
||||
&image_calibrate_0,
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
|
||||
|
||||
using namespace portapack;
|
||||
@@ -39,7 +40,8 @@ void TouchTunesView::focus() {
|
||||
|
||||
TouchTunesView::~TouchTunesView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
|
||||
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
|
||||
}
|
||||
|
||||
void TouchTunesView::stop_tx() {
|
||||
|
||||
@@ -226,15 +226,17 @@ void EventDispatcher::handle_rtc_tick() {
|
||||
|
||||
portapack::temperature_logger.second_tick();
|
||||
|
||||
uint32_t backlight_timer = portapack::persistent_memory::config_backlight_timer();
|
||||
if (backlight_timer) {
|
||||
if (portapack::bl_tick_counter == backlight_timer)
|
||||
const auto backlight_timer = portapack::persistent_memory::config_backlight_timer();
|
||||
if (backlight_timer.timeout_enabled()) {
|
||||
if (portapack::bl_tick_counter == backlight_timer.timeout_seconds())
|
||||
set_display_sleep(true);
|
||||
else
|
||||
portapack::bl_tick_counter++;
|
||||
}
|
||||
|
||||
rtc_time::on_tick_second();
|
||||
|
||||
portapack::persistent_memory::cache::persist();
|
||||
}
|
||||
|
||||
ui::Widget* EventDispatcher::touch_widget(ui::Widget* const w, ui::TouchEvent event) {
|
||||
|
||||
+556
-148
@@ -23,166 +23,574 @@
|
||||
#include "freqman.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
using option_t = std::pair<std::string, int32_t>;
|
||||
using options_t = std::vector<option_t>;
|
||||
|
||||
options_t freqman_entry_modulations = {
|
||||
{ "AM", 0 },
|
||||
{ "NFM", 1 },
|
||||
{ "WFM", 2 }
|
||||
};
|
||||
|
||||
options_t freqman_entry_bandwidths[ 4 ] = {
|
||||
{ //AM
|
||||
{ "DSB", 0 },
|
||||
{ "USB", 1 },
|
||||
{ "LSB", 2 },
|
||||
{ "CW" , 3 }
|
||||
},
|
||||
{ //NFM
|
||||
{ "8k5" , 0 },
|
||||
{ "11k" , 1 },
|
||||
{ "16k" , 2 }
|
||||
},
|
||||
{ //WFM
|
||||
{ "16k" , 0 },
|
||||
}
|
||||
};
|
||||
|
||||
options_t freqman_entry_steps = {
|
||||
{ "5KHz (SA AM)" , 5000 },
|
||||
{ "6.25KHz(NFM)" , 6250 },
|
||||
{ "8.33KHz(AIR)" , 8330 },
|
||||
{ "9KHz (EU AM)" , 9000 },
|
||||
{ "10KHz(US AM)" , 10000 },
|
||||
{ "12.5KHz(NFM)" , 12500 },
|
||||
{ "15KHz (HFM)" , 15000 },
|
||||
{ "25KHz (N1)" , 25000 },
|
||||
{ "50KHz (FM1)" , 50000 },
|
||||
{ "100KHz (FM2)" , 100000 },
|
||||
{ "250KHz (N2)" , 250000 },
|
||||
{ "500KHz " , 500000 },
|
||||
{ "1MHz " , 1000000 }
|
||||
};
|
||||
|
||||
options_t freqman_entry_steps_short = {
|
||||
{ "5KHz" , 5000 },
|
||||
{ "6.25KHz" , 6250 },
|
||||
{ "8.33KHz" , 8330 },
|
||||
{ "9KHz" , 9000 },
|
||||
{ "10KHz" , 10000 },
|
||||
{ "12.5KHz" , 12500 },
|
||||
{ "15KHz" , 15000 },
|
||||
{ "25KHz" , 25000 },
|
||||
{ "50KHz" , 50000 },
|
||||
{ "100KHz" , 100000 },
|
||||
{ "250KHz" , 250000 },
|
||||
{ "500KHz" , 500000 },
|
||||
{ "1MHz" , 1000000 }
|
||||
};
|
||||
|
||||
std::vector<std::string> get_freqman_files() {
|
||||
std::vector<std::string> file_list;
|
||||
|
||||
auto files = scan_root_files(u"FREQMAN", u"*.TXT");
|
||||
|
||||
for (auto file : files) {
|
||||
std::string file_name = file.stem().string();
|
||||
// don't propose tmp / hidden files in freqman's list
|
||||
if (file_name.length() && file_name[0] != '.') {
|
||||
file_list.emplace_back(file_name);
|
||||
}
|
||||
}
|
||||
|
||||
return file_list;
|
||||
std::vector<std::string> file_list;
|
||||
|
||||
auto files = scan_root_files(u"FREQMAN", u"*.TXT");
|
||||
|
||||
for (auto file : files) {
|
||||
std::string file_name = file.stem().string();
|
||||
// don't propose tmp / hidden files in freqman's list
|
||||
if (file_name.length() && file_name[0] != '.') {
|
||||
file_list.emplace_back(file_name);
|
||||
}
|
||||
}
|
||||
|
||||
return file_list;
|
||||
};
|
||||
|
||||
bool load_freqman_file(std::string& file_stem, freqman_db &db) {
|
||||
File freqman_file;
|
||||
size_t length, n = 0, file_position = 0;
|
||||
char * pos;
|
||||
char * line_start;
|
||||
char * line_end;
|
||||
std::string description;
|
||||
rf::Frequency frequency_a, frequency_b;
|
||||
char file_data[257];
|
||||
freqman_entry_type type;
|
||||
|
||||
db.clear();
|
||||
|
||||
auto result = freqman_file.open("FREQMAN/" + file_stem + ".TXT");
|
||||
if (result.is_valid())
|
||||
return false;
|
||||
|
||||
while (1) {
|
||||
// Read a 256 bytes block from file
|
||||
freqman_file.seek(file_position);
|
||||
|
||||
memset(file_data, 0, 257);
|
||||
auto read_size = freqman_file.read(file_data, 256);
|
||||
if (read_size.is_error())
|
||||
return false; // Read error
|
||||
|
||||
file_position += 256;
|
||||
|
||||
// Reset line_start to beginning of buffer
|
||||
line_start = file_data;
|
||||
|
||||
if (!strstr(file_data, "f=") && !strstr(file_data, "a="))
|
||||
break;
|
||||
|
||||
// Look for complete lines in buffer
|
||||
while ((line_end = strstr(line_start, "\x0A"))) {
|
||||
// Read frequency
|
||||
pos = strstr(line_start, "f=");
|
||||
frequency_b = 0;
|
||||
type = SINGLE;
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_a = strtoll(pos, nullptr, 10);
|
||||
} else {
|
||||
// ...or range
|
||||
pos = strstr(line_start, "a=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_a = strtoll(pos, nullptr, 10);
|
||||
type = RANGE;
|
||||
pos = strstr(line_start, "b=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_b = strtoll(pos, nullptr, 10);
|
||||
} else
|
||||
frequency_b = 0;
|
||||
} else
|
||||
frequency_a = 0;
|
||||
}
|
||||
|
||||
// Read description until , or LF
|
||||
pos = strstr(line_start, "d=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
length = std::min(strcspn(pos, ",\x0A"), (size_t)FREQMAN_DESC_MAX_LEN);
|
||||
description = string(pos, length);
|
||||
} else
|
||||
description = "-";
|
||||
|
||||
db.push_back({ frequency_a, frequency_b, description, type });
|
||||
n++;
|
||||
|
||||
if (n >= FREQMAN_MAX_PER_FILE) return true;
|
||||
|
||||
line_start = line_end + 1;
|
||||
if (line_start - file_data >= 256) break;
|
||||
}
|
||||
|
||||
if (read_size.value() != 256)
|
||||
break; // End of file
|
||||
|
||||
// Restart at beginning of last incomplete line
|
||||
file_position -= (file_data + 256 - line_start);
|
||||
}
|
||||
|
||||
return true;
|
||||
return load_freqman_file_ex( file_stem , db , true , true , true );
|
||||
/* File freqman_file;
|
||||
size_t length, n = 0, file_position = 0;
|
||||
char * pos;
|
||||
char * line_start;
|
||||
char * line_end;
|
||||
std::string description;
|
||||
rf::Frequency frequency_a, frequency_b;
|
||||
char file_data[257];
|
||||
freqman_entry_type type;
|
||||
|
||||
db.clear();
|
||||
|
||||
auto result = freqman_file.open("FREQMAN/" + file_stem + ".TXT");
|
||||
if (result.is_valid())
|
||||
return false;
|
||||
|
||||
while (1) {
|
||||
// Read a 256 bytes block from file
|
||||
freqman_file.seek(file_position);
|
||||
|
||||
memset(file_data, 0, 257);
|
||||
auto read_size = freqman_file.read(file_data, 256);
|
||||
if (read_size.is_error())
|
||||
return false; // Read error
|
||||
|
||||
file_position += 256;
|
||||
|
||||
// Reset line_start to beginning of buffer
|
||||
line_start = file_data;
|
||||
|
||||
if (!strstr(file_data, "f=") && !strstr(file_data, "a="))
|
||||
break;
|
||||
|
||||
// Look for complete lines in buffer
|
||||
while ((line_end = strstr(line_start, "\x0A"))) {
|
||||
// Read frequency
|
||||
pos = strstr(line_start, "f=");
|
||||
frequency_b = 0;
|
||||
type = SINGLE;
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_a = strtoll(pos, nullptr, 10);
|
||||
} else {
|
||||
// ...or range
|
||||
pos = strstr(line_start, "a=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_a = strtoll(pos, nullptr, 10);
|
||||
type = RANGE;
|
||||
pos = strstr(line_start, "b=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_b = strtoll(pos, nullptr, 10);
|
||||
} else
|
||||
frequency_b = 0;
|
||||
} else
|
||||
frequency_a = 0;
|
||||
}
|
||||
|
||||
// Read description until , or LF
|
||||
pos = strstr(line_start, "d=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
length = std::min(strcspn(pos, ",\x0A"), (size_t)FREQMAN_DESC_MAX_LEN);
|
||||
description = string(pos, length);
|
||||
} else
|
||||
description = "-";
|
||||
|
||||
db.push_back({ frequency_a, frequency_b, description, type , -1 , -1 , -1 , -1 });
|
||||
n++;
|
||||
|
||||
if (n >= FREQMAN_MAX_PER_FILE) return true;
|
||||
|
||||
line_start = line_end + 1;
|
||||
if (line_start - file_data >= 256) break;
|
||||
}
|
||||
|
||||
bool save_freqman_file(std::string& file_stem, freqman_db &db) {
|
||||
File freqman_file;
|
||||
std::string item_string;
|
||||
rf::Frequency frequency_a, frequency_b;
|
||||
|
||||
if (!create_freqman_file(file_stem, freqman_file))
|
||||
return false;
|
||||
|
||||
for (size_t n = 0; n < db.size(); n++) {
|
||||
auto& entry = db[n];
|
||||
if (read_size.value() != 256)
|
||||
break; // End of file
|
||||
|
||||
frequency_a = entry.frequency_a;
|
||||
|
||||
if (entry.type == SINGLE) {
|
||||
// Single
|
||||
|
||||
// TODO: Make to_string_dec_uint be able to return uint64_t's
|
||||
// Please forgive me...
|
||||
item_string = "f=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
|
||||
|
||||
} else {
|
||||
// Range
|
||||
frequency_b = entry.frequency_b;
|
||||
|
||||
item_string = "a=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
|
||||
item_string += ",b=" + to_string_dec_uint(frequency_b / 1000) + to_string_dec_uint(frequency_b % 1000UL, 3, '0');
|
||||
}
|
||||
|
||||
if (entry.description.size())
|
||||
item_string += ",d=" + entry.description;
|
||||
|
||||
freqman_file.write_line(item_string);
|
||||
}
|
||||
|
||||
return true;
|
||||
// Restart at beginning of last incomplete line
|
||||
file_position -= (file_data + 256 - line_start);
|
||||
}
|
||||
return true;
|
||||
*/
|
||||
}
|
||||
|
||||
bool load_freqman_file_ex(std::string& file_stem, freqman_db& db, bool load_freqs , bool load_ranges , bool load_hamradios ) {
|
||||
File freqman_file;
|
||||
size_t length, n = 0, file_position = 0;
|
||||
char * pos;
|
||||
char * line_start;
|
||||
char * line_end;
|
||||
std::string description;
|
||||
rf::Frequency frequency_a, frequency_b;
|
||||
char file_data[257];
|
||||
freqman_entry_type type;
|
||||
freqman_index_t modulation = 0 ;
|
||||
freqman_index_t bandwidth = 0 ;
|
||||
freqman_index_t step = 0 ;
|
||||
freqman_index_t tone = 0 ;
|
||||
|
||||
|
||||
db.clear();
|
||||
|
||||
auto result = freqman_file.open("FREQMAN/" + file_stem + ".TXT");
|
||||
if (result.is_valid())
|
||||
return false;
|
||||
|
||||
while (1) {
|
||||
// Read a 256 bytes block from file
|
||||
freqman_file.seek(file_position);
|
||||
|
||||
memset(file_data, 0, 257);
|
||||
auto read_size = freqman_file.read(file_data, 256);
|
||||
if (read_size.is_error())
|
||||
return false; // Read error
|
||||
|
||||
file_position += 256;
|
||||
|
||||
// Reset line_start to beginning of buffer
|
||||
line_start = file_data;
|
||||
|
||||
if (!strstr(file_data, "f=") && !strstr(file_data, "a=") && !strstr(file_data, "r=") )
|
||||
break;
|
||||
|
||||
// Look for complete lines in buffer
|
||||
while ((line_end = strstr(line_start, "\x0A"))) {
|
||||
|
||||
modulation = -1 ;
|
||||
bandwidth = -1 ;
|
||||
step = -1 ;
|
||||
tone = -1 ;
|
||||
type=SINGLE ;
|
||||
|
||||
frequency_a = frequency_b = 0;
|
||||
// Read frequency
|
||||
pos = strstr(line_start, "f=");
|
||||
if(pos) {
|
||||
pos += 2;
|
||||
frequency_a = strtoll(pos, nullptr, 10);
|
||||
} else {
|
||||
// ...or range
|
||||
pos = strstr(line_start, "a=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_a = strtoll(pos, nullptr, 10);
|
||||
type = RANGE;
|
||||
pos = strstr(line_start, "b=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_b = strtoll(pos, nullptr, 10);
|
||||
} else
|
||||
frequency_b = 0;
|
||||
}else {
|
||||
// ... or hamradio
|
||||
pos = strstr(line_start, "r=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_a = strtoll(pos, nullptr, 10);
|
||||
type = HAMRADIO;
|
||||
pos = strstr(line_start, "t=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
frequency_b = strtoll(pos, nullptr, 10);
|
||||
} else
|
||||
frequency_b = frequency_a ;
|
||||
} else
|
||||
frequency_a = 0;
|
||||
}
|
||||
}
|
||||
// modulation if any
|
||||
pos = strstr(line_start, "m=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
modulation = freqman_entry_get_modulation_from_str( pos );
|
||||
}
|
||||
// bandwidth if any
|
||||
pos = strstr(line_start, "bw=");
|
||||
if (pos) {
|
||||
pos += 3;
|
||||
bandwidth = freqman_entry_get_bandwidth_from_str( modulation , pos );
|
||||
}
|
||||
// step if any
|
||||
pos = strstr(line_start, "s=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
step = freqman_entry_get_step_from_str_short( pos );
|
||||
}
|
||||
// ctcss tone if any
|
||||
/* disabled until better form
|
||||
pos = strstr(line_start, "c=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
tone = tone_key_index_by_value( strtoll( pos , nullptr , 10 ) );
|
||||
} */
|
||||
// Read description until , or LF
|
||||
pos = strstr(line_start, "d=");
|
||||
if (pos) {
|
||||
pos += 2;
|
||||
length = std::min(strcspn(pos, ",\x0A"), (size_t)FREQMAN_DESC_MAX_LEN);
|
||||
description = string(pos, length);
|
||||
} else
|
||||
description = "-";
|
||||
if( (type == SINGLE && load_freqs) || (type == RANGE && load_ranges) || (type == HAMRADIO && load_hamradios) )
|
||||
{
|
||||
db.push_back({ frequency_a, frequency_b, description, type , modulation , bandwidth , step , tone });
|
||||
n++;
|
||||
if (n >= FREQMAN_MAX_PER_FILE) return true;
|
||||
}
|
||||
|
||||
line_start = line_end + 1;
|
||||
if (line_start - file_data >= 256) break;
|
||||
}
|
||||
|
||||
if (read_size.value() != 256)
|
||||
break; // End of file
|
||||
|
||||
// Restart at beginning of last incomplete line
|
||||
file_position -= (file_data + 256 - line_start);
|
||||
}
|
||||
|
||||
/* populate implicitly specified modulation / bandwidth */
|
||||
if( db.size() > 2 )
|
||||
{
|
||||
modulation = db[ 0 ] . modulation;
|
||||
bandwidth = db[ 0 ] . bandwidth;
|
||||
|
||||
for( unsigned int it = 1 ; it < db.size() ; it ++ )
|
||||
{
|
||||
if( db[ it ] . modulation < 0 )
|
||||
{
|
||||
db[ it ] . modulation = modulation ;
|
||||
}
|
||||
else
|
||||
{
|
||||
modulation = db[ it ] . modulation ;
|
||||
}
|
||||
if( db[ it ] . bandwidth < 0 )
|
||||
{
|
||||
db[ it ] . bandwidth = bandwidth ;
|
||||
}
|
||||
else
|
||||
{
|
||||
modulation = db[ it ] . bandwidth ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_freq_string( freqman_entry &entry , std::string &item_string )
|
||||
{
|
||||
rf::Frequency frequency_a, frequency_b;
|
||||
|
||||
frequency_a = entry.frequency_a;
|
||||
if (entry.type == SINGLE) {
|
||||
// Single
|
||||
item_string = "f=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
|
||||
} else if( entry.type == RANGE ) {
|
||||
// Range
|
||||
frequency_b = entry.frequency_b;
|
||||
item_string = "a=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
|
||||
item_string += ",b=" + to_string_dec_uint(frequency_b / 1000) + to_string_dec_uint(frequency_b % 1000UL, 3, '0');
|
||||
if( entry.step >= 0 )
|
||||
{
|
||||
item_string += ",s=" + freqman_entry_get_step_string_short( entry.step );
|
||||
}
|
||||
} else if( entry.type == HAMRADIO ) {
|
||||
frequency_b = entry.frequency_b;
|
||||
item_string = "r=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
|
||||
item_string += ",t=" + to_string_dec_uint(frequency_b / 1000) + to_string_dec_uint(frequency_b % 1000UL, 3, '0');
|
||||
if( entry.tone >= 0 )
|
||||
{
|
||||
item_string += ",c=" + tone_key_string( entry.tone );
|
||||
}
|
||||
}
|
||||
if( entry.modulation >= 0 && (unsigned)entry.modulation < freqman_entry_modulations . size() )
|
||||
{
|
||||
item_string += ",m=" + freqman_entry_get_modulation_string( entry.modulation );
|
||||
if( entry.bandwidth >= 0 && (unsigned)entry.bandwidth < freqman_entry_bandwidths[ entry.modulation ] . size() )
|
||||
{
|
||||
item_string += ",bw=" + freqman_entry_get_bandwidth_string( entry.modulation , entry.bandwidth );
|
||||
}
|
||||
}
|
||||
if (entry.description.size())
|
||||
item_string += ",d=" + entry.description;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool save_freqman_file(std::string &file_stem, freqman_db &db) {
|
||||
|
||||
File freqman_file;
|
||||
|
||||
std::string freq_file_path = "FREQMAN/" + file_stem + ".TXT";
|
||||
std::string tmp_freq_file_path = "FREQMAN/" + file_stem + ".TXT.TMP";
|
||||
|
||||
if( !db.size() )
|
||||
{
|
||||
delete_file( "FREQMAN/"+file_stem+".TXT" );
|
||||
return true ;
|
||||
}
|
||||
|
||||
delete_file( tmp_freq_file_path );
|
||||
auto result = freqman_file.open( tmp_freq_file_path );
|
||||
if ( !result.is_valid() ) {
|
||||
for (size_t n = 0; n < db.size(); n++) {
|
||||
std::string item_string;
|
||||
auto& entry = db[n];
|
||||
get_freq_string( entry , item_string );
|
||||
freqman_file.write_line( item_string );
|
||||
delete &item_string;
|
||||
}
|
||||
delete_file( freq_file_path );
|
||||
rename_file( tmp_freq_file_path , freq_file_path );
|
||||
return true;
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
|
||||
bool create_freqman_file(std::string& file_stem, File& freqman_file) {
|
||||
auto result = freqman_file.create("FREQMAN/" + file_stem + ".TXT");
|
||||
if (result.is_valid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
auto result = freqman_file.create( "FREQMAN/" + file_stem + ".TXT" );
|
||||
|
||||
if (result.is_valid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string freqman_item_string(freqman_entry &entry, size_t max_length) {
|
||||
std::string item_string;
|
||||
std::string item_string;
|
||||
|
||||
if (entry.type == SINGLE) {
|
||||
item_string = to_string_short_freq(entry.frequency_a) + "M: " + entry.description;
|
||||
} else {
|
||||
item_string = "Range: " + entry.description;
|
||||
}
|
||||
|
||||
if (item_string.size() > max_length)
|
||||
return item_string.substr(0, max_length - 3) + "...";
|
||||
|
||||
return item_string;
|
||||
switch( entry.type ){
|
||||
case SINGLE:
|
||||
item_string = to_string_short_freq(entry.frequency_a) + "M: " + entry.description;
|
||||
break;
|
||||
case RANGE:
|
||||
item_string = "R: " + entry.description;
|
||||
break;
|
||||
case HAMRADIO:
|
||||
item_string = "H: " + entry.description;
|
||||
break;
|
||||
default:
|
||||
item_string = "!UNKNOW TYPE " + entry.description;
|
||||
break;
|
||||
}
|
||||
|
||||
if (item_string.size() > max_length)
|
||||
return item_string.substr(0, max_length - 3) + "...";
|
||||
|
||||
return item_string;
|
||||
}
|
||||
|
||||
void freqman_set_modulation_option( OptionsField &option )
|
||||
{
|
||||
option.set_options( freqman_entry_modulations );
|
||||
}
|
||||
|
||||
void freqman_set_bandwidth_option( freqman_index_t modulation , OptionsField &option )
|
||||
{
|
||||
option.set_options( freqman_entry_bandwidths[ modulation ] );
|
||||
}
|
||||
|
||||
void freqman_set_step_option( OptionsField &option )
|
||||
{
|
||||
option.set_options( freqman_entry_steps );
|
||||
}
|
||||
|
||||
void freqman_set_step_option_short( OptionsField &option )
|
||||
{
|
||||
option.set_options( freqman_entry_steps_short );
|
||||
}
|
||||
|
||||
std::string freqman_entry_get_modulation_string( freqman_index_t modulation )
|
||||
{
|
||||
if( modulation < 0 || (unsigned)modulation >= freqman_entry_modulations . size() )
|
||||
{
|
||||
return std::string( "" ); // unknown modulation
|
||||
}
|
||||
return freqman_entry_modulations[ modulation ] . first ;
|
||||
}
|
||||
|
||||
std::string freqman_entry_get_bandwidth_string( freqman_index_t modulation , freqman_index_t bandwidth )
|
||||
{
|
||||
if( modulation < 0 || (unsigned)modulation >= freqman_entry_modulations . size() )
|
||||
{
|
||||
return std::string( "" ); // unknown modulation
|
||||
}
|
||||
if( bandwidth < 0 || (unsigned)bandwidth > freqman_entry_bandwidths[ modulation ] . size() )
|
||||
{
|
||||
return std::string( "" ); // unknown modulation
|
||||
}
|
||||
return freqman_entry_bandwidths[ modulation ][ bandwidth ] . first ;
|
||||
}
|
||||
|
||||
std::string freqman_entry_get_step_string( freqman_index_t step )
|
||||
{
|
||||
if( step < 0 || (unsigned)step >= freqman_entry_steps . size() )
|
||||
{
|
||||
return std::string( "" ); // unknown modulation
|
||||
}
|
||||
return freqman_entry_steps[ step ] . first ;
|
||||
}
|
||||
|
||||
std::string freqman_entry_get_step_string_short( freqman_index_t step )
|
||||
{
|
||||
if( step < 0 || (unsigned)step >= freqman_entry_steps_short . size() )
|
||||
{
|
||||
return std::string( "" ); // unknown modulation
|
||||
}
|
||||
return freqman_entry_steps_short[ step ] . first ;
|
||||
}
|
||||
|
||||
int32_t freqman_entry_get_modulation_value( freqman_index_t modulation )
|
||||
{
|
||||
if( modulation < 0 || (unsigned)modulation >= freqman_entry_modulations . size() )
|
||||
{
|
||||
return -1 ; // unknown modulation
|
||||
}
|
||||
return freqman_entry_modulations[ modulation ] . second ;
|
||||
}
|
||||
|
||||
int32_t freqman_entry_get_bandwidth_value( freqman_index_t modulation , freqman_index_t bandwidth )
|
||||
{
|
||||
if( modulation < 0 || (unsigned)modulation >= freqman_entry_modulations . size() )
|
||||
{
|
||||
return -1 ; // unknown modulation
|
||||
}
|
||||
if( bandwidth < 0 || (unsigned)bandwidth > freqman_entry_bandwidths[ modulation ] . size() )
|
||||
{
|
||||
return -1 ; // unknown bandwidth for modulation
|
||||
}
|
||||
return freqman_entry_bandwidths[ modulation ][ bandwidth ] . second ;
|
||||
}
|
||||
|
||||
int32_t freqman_entry_get_step_value( freqman_index_t step )
|
||||
{
|
||||
if( step < 0 || (unsigned)step >= freqman_entry_steps . size() )
|
||||
{
|
||||
return -1 ; // unknown modulation
|
||||
}
|
||||
return freqman_entry_steps[ step ] . second ;
|
||||
}
|
||||
|
||||
freqman_index_t freqman_entry_get_modulation_from_str( char *str )
|
||||
{
|
||||
if( !str )
|
||||
return -1 ;
|
||||
for( freqman_index_t index = 0 ; (unsigned)index < freqman_entry_modulations . size() ; index ++ )
|
||||
{
|
||||
if( strncmp( freqman_entry_modulations[ index ] . first . c_str() , str , freqman_entry_modulations[ index ] . first . size() ) == 0 )
|
||||
return index ;
|
||||
}
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
freqman_index_t freqman_entry_get_bandwidth_from_str( freqman_index_t modulation , char *str )
|
||||
{
|
||||
if( !str )
|
||||
return -1 ;
|
||||
if( modulation < 0 || (unsigned)modulation >= freqman_entry_modulations . size() )
|
||||
return -1 ;
|
||||
for( freqman_index_t index = 0 ; (unsigned)index < freqman_entry_bandwidths[ modulation ] . size() ; index ++ )
|
||||
{
|
||||
if( strncmp( freqman_entry_bandwidths[ modulation ][ index ] . first . c_str() , str , freqman_entry_bandwidths[ modulation ][ index ] . first . size() ) == 0 )
|
||||
return index ;
|
||||
}
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
freqman_index_t freqman_entry_get_step_from_str( char *str )
|
||||
{
|
||||
if( !str )
|
||||
return -1 ;
|
||||
for( freqman_index_t index = 0 ; (unsigned)index < freqman_entry_steps . size() ; index ++ )
|
||||
{
|
||||
if( strncmp( freqman_entry_steps[ index ] . first . c_str() , str , freqman_entry_steps[ index ] . first . size() ) == 0 )
|
||||
return index ;
|
||||
}
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
freqman_index_t freqman_entry_get_step_from_str_short( char *str )
|
||||
{
|
||||
if( !str )
|
||||
return -1 ;
|
||||
for( freqman_index_t index = 0 ; (unsigned)index < freqman_entry_steps_short . size() ; index ++ )
|
||||
{
|
||||
if( strncmp( freqman_entry_steps_short[ index ] . first . c_str() , str , freqman_entry_steps_short[ index ] . first . size() ) == 0 )
|
||||
return index ;
|
||||
}
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
@@ -20,14 +20,16 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __FREQMAN_H__
|
||||
#define __FREQMAN_H__
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include "file.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "tone_key.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#ifndef __FREQMAN_H__
|
||||
#define __FREQMAN_H__
|
||||
#include "ui_widget.hpp"
|
||||
|
||||
#define FREQMAN_DESC_MAX_LEN 30
|
||||
#define FREQMAN_MAX_PER_FILE 99
|
||||
@@ -35,6 +37,10 @@
|
||||
|
||||
using namespace ui;
|
||||
using namespace std;
|
||||
using namespace tonekey;
|
||||
|
||||
// needs to be signed as -1 means not set
|
||||
typedef int8_t freqman_index_t ;
|
||||
|
||||
enum freqman_error {
|
||||
NO_ERROR = 0,
|
||||
@@ -44,13 +50,23 @@ enum freqman_error {
|
||||
};
|
||||
|
||||
enum freqman_entry_type {
|
||||
SINGLE = 0,
|
||||
RANGE
|
||||
SINGLE = 0, //f=
|
||||
RANGE, //a=,b=
|
||||
HAMRADIO, //r=,t=
|
||||
ERROR_TYPE
|
||||
};
|
||||
|
||||
enum freqman_entry_modulation {
|
||||
AM_MODULATION = 0 ,
|
||||
NFM_MODULATION ,
|
||||
WFM_MODULATION ,
|
||||
MODULATION_DEF ,
|
||||
ERROR_MODULATION
|
||||
};
|
||||
|
||||
//Entry step placed for AlainD freqman version (or any other enhanced version)
|
||||
enum freqman_entry_step {
|
||||
STEP_DEF = 0, // default
|
||||
STEP_DEF = -1, // default
|
||||
AM_US, // 10 kHz AM/CB
|
||||
AM_EUR, // 9 kHz LW/MW
|
||||
NFM_1, // 12,5 kHz (Analogic PMR 446)
|
||||
@@ -63,21 +79,46 @@ enum freqman_entry_step {
|
||||
ERROR_STEP
|
||||
};
|
||||
|
||||
// freqman_entry_step step added, as above, to provide compatibility / future enhancement.
|
||||
struct freqman_entry {
|
||||
rf::Frequency frequency_a { 0 };
|
||||
rf::Frequency frequency_b { 0 };
|
||||
std::string description { };
|
||||
freqman_entry_type type { };
|
||||
freqman_entry_step step { };
|
||||
rf::Frequency frequency_a { 0 }; // 'f=freq' or 'a=freq_start' or 'r=recv_freq'
|
||||
rf::Frequency frequency_b { 0 }; // 'b=freq_end' or 't=tx_freq'
|
||||
std::string description { }; // 'd=desc'
|
||||
freqman_entry_type type { }; // SINGLE,RANGE,HAMRADIO
|
||||
freqman_index_t modulation { }; // AM,NFM,WFM
|
||||
freqman_index_t bandwidth { }; // AM_DSB, ...
|
||||
freqman_index_t step { }; // 5Khz (SA AM,...
|
||||
tone_index tone { }; // 0XZ, 11 1ZB,...
|
||||
};
|
||||
|
||||
using freqman_db = std::vector<freqman_entry>;
|
||||
|
||||
std::vector<std::string> get_freqman_files();
|
||||
bool load_freqman_file(std::string& file_stem, freqman_db& db);
|
||||
bool load_freqman_file_ex(std::string& file_stem, freqman_db& db, bool load_freqs , bool load_ranges , bool load_hamradios );
|
||||
bool get_freq_string( freqman_entry &entry , std::string &item_string );
|
||||
bool save_freqman_file(std::string& file_stem, freqman_db& db);
|
||||
bool create_freqman_file(std::string& file_stem, File& freqman_file);
|
||||
|
||||
std::string freqman_item_string(freqman_entry &item, size_t max_length);
|
||||
|
||||
void freqman_set_bandwidth_option( freqman_index_t modulation , OptionsField &option );
|
||||
void freqman_set_modulation_option( OptionsField &option );
|
||||
void freqman_set_step_option( OptionsField &option );
|
||||
void freqman_set_step_option_short( OptionsField &option );
|
||||
void freqman_set_tone_option( OptionsField &option );
|
||||
|
||||
std::string freqman_entry_get_modulation_string( freqman_index_t modulation );
|
||||
std::string freqman_entry_get_bandwidth_string( freqman_index_t modulation , freqman_index_t bandwidth );
|
||||
std::string freqman_entry_get_step_string( freqman_index_t step );
|
||||
std::string freqman_entry_get_step_string_short( freqman_index_t step );
|
||||
|
||||
int32_t freqman_entry_get_modulation_value( freqman_index_t modulation );
|
||||
int32_t freqman_entry_get_bandwidth_value( freqman_index_t modulation , freqman_index_t bandwidth );
|
||||
int32_t freqman_entry_get_step_value( freqman_index_t step );
|
||||
|
||||
freqman_index_t freqman_entry_get_modulation_from_str( char *str );
|
||||
freqman_index_t freqman_entry_get_bandwidth_from_str( freqman_index_t modulation , char *str );
|
||||
freqman_index_t freqman_entry_get_step_from_str( char *str );
|
||||
freqman_index_t freqman_entry_get_step_from_str_short( char *str );
|
||||
|
||||
#endif/*__FREQMAN_H__*/
|
||||
|
||||
@@ -215,7 +215,7 @@ static int load_config(){
|
||||
static Optional<int> config_value;
|
||||
if(!config_value.is_valid()){
|
||||
int8_t value = portapack::persistent_memory::config_cpld();
|
||||
if((value <= 0 || value >= 4) && sd_card::status() == sd_card::Status::Mounted){
|
||||
if((value <= 0 || value >= 5) && sd_card::status() == sd_card::Status::Mounted){
|
||||
int data = read_file("/hardware/settings.txt");
|
||||
if(data != -1) {
|
||||
config_value = data;
|
||||
@@ -235,14 +235,19 @@ static PortaPackModel portapack_model() {
|
||||
const auto switches_state = get_switches_state();
|
||||
if (switches_state[(size_t)ui::KeyEvent::Up]){
|
||||
save_config(1);
|
||||
model = PortaPackModel::R2_20170522;
|
||||
// model = PortaPackModel::R2_20170522; // Commented these out as they should be set down below anyway
|
||||
}
|
||||
else if (switches_state[(size_t)ui::KeyEvent::Down]){
|
||||
save_config(2);
|
||||
model = PortaPackModel::R1_20150901;
|
||||
// model = PortaPackModel::R1_20150901;
|
||||
}
|
||||
else if (switches_state[(size_t)ui::KeyEvent::Left]){
|
||||
save_config(3);
|
||||
// model = PortaPackModel::R1_20150901;
|
||||
}
|
||||
else if (switches_state[(size_t)ui::KeyEvent::Right]){
|
||||
save_config(4);
|
||||
// model = PortaPackModel::R2_20170522;
|
||||
}
|
||||
else if (switches_state[(size_t)ui::KeyEvent::Select]){
|
||||
save_config(0);
|
||||
@@ -253,6 +258,10 @@ static PortaPackModel portapack_model() {
|
||||
model = PortaPackModel::R2_20170522;
|
||||
} else if (load_config() == 2) {
|
||||
model = PortaPackModel::R1_20150901;
|
||||
} else if (load_config() == 3) {
|
||||
model = PortaPackModel::R1_20150901;
|
||||
} else if (load_config() == 4) {
|
||||
model = PortaPackModel::R2_20170522;
|
||||
} else {
|
||||
if( audio_codec_wm8731.detected() ) {
|
||||
model = PortaPackModel::R1_20150901; // H1R1
|
||||
@@ -457,6 +466,9 @@ bool init() {
|
||||
i2c0.start(i2c_config_fast_clock);
|
||||
chThdSleepMilliseconds(10);
|
||||
|
||||
/* Cache some configuration data from persistent memory. */
|
||||
persistent_memory::cache::init();
|
||||
|
||||
touch::adc::init();
|
||||
controls_init();
|
||||
chThdSleepMilliseconds(10);
|
||||
@@ -475,7 +487,7 @@ bool init() {
|
||||
if( !portapack::cpld::update_if_necessary(portapack_cpld_config()) ) {
|
||||
chThdSleepMilliseconds(10);
|
||||
// If using a "2021/12 QFP100", press and hold the left button while booting. Should only need to do once.
|
||||
if (load_config() != 3){
|
||||
if (load_config() != 3 && load_config() != 4){
|
||||
shutdown_base();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,14 @@ struct serial_format_t {
|
||||
parity_enum parity;
|
||||
uint8_t stop_bits;
|
||||
order_enum bit_order;
|
||||
|
||||
constexpr serial_format_t() :
|
||||
data_bits(7),
|
||||
parity(parity_enum::EVEN),
|
||||
stop_bits(1),
|
||||
bit_order(order_enum::LSB_FIRST)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
size_t symbol_count(const serial_format_t& serial_format);
|
||||
|
||||
@@ -104,8 +104,30 @@ void tone_keys_populate(OptionsField& field) {
|
||||
field.set_options(tone_key_options);
|
||||
}
|
||||
|
||||
float tone_key_frequency(const uint32_t index) {
|
||||
float tone_key_frequency(const tone_index index) {
|
||||
return tone_keys[index].second;
|
||||
}
|
||||
|
||||
std::string tone_key_string( tone_index index ) {
|
||||
if( index < 0 || (unsigned)index >= tone_keys . size() )
|
||||
return std::string( "" );
|
||||
return tone_keys[ index ] .first ;
|
||||
}
|
||||
|
||||
tone_index tone_key_index_by_string( char *str ) {
|
||||
if( !str )
|
||||
return -1 ;
|
||||
for( tone_index index = 0 ; (unsigned)index < tone_keys . size() ; index ++ )
|
||||
{
|
||||
if( tone_keys[ index ] . first . compare( str ) >= 0 )
|
||||
return index ;
|
||||
}
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
/* tone_index tone_key_index_by_value( int32_t freq )
|
||||
{
|
||||
return -1 ;
|
||||
} */
|
||||
|
||||
}
|
||||
|
||||
@@ -30,12 +30,18 @@ using namespace ui;
|
||||
|
||||
namespace tonekey {
|
||||
|
||||
typedef int16_t tone_index ;
|
||||
|
||||
using tone_key_t = std::vector<std::pair<std::string, float>>;
|
||||
|
||||
extern const tone_key_t tone_keys;
|
||||
|
||||
void tone_keys_populate(OptionsField& field);
|
||||
float tone_key_frequency(const uint32_t index);
|
||||
float tone_key_frequency(const tone_index index);
|
||||
|
||||
std::string tone_key_string( const tone_index index );
|
||||
tone_index tone_key_index_by_string( char *str );
|
||||
// tone_index tone_key_index_by_value( int32_t freq );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -76,14 +76,6 @@ ui::Point Calibration::translate(const DigitizerPoint& p) const {
|
||||
return { x_clipped, y_clipped };
|
||||
}
|
||||
|
||||
const Calibration default_calibration() {
|
||||
/* Values derived from one PortaPack H1 unit. */
|
||||
return {
|
||||
{ { { 256, 731 }, { 880, 432 }, { 568, 146 } } },
|
||||
{ { { 32, 48 }, { 208, 168 }, { 120, 288 } } }
|
||||
};
|
||||
};
|
||||
|
||||
void Manager::feed(const Frame& frame) {
|
||||
// touch_debounce.feed(touch_raw);
|
||||
const auto touch_raw = frame.touch;
|
||||
|
||||
@@ -137,6 +137,15 @@ struct Calibration {
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Calibration() :
|
||||
Calibration(
|
||||
/* Values derived from one PortaPack H1 unit. */
|
||||
{ { { 256, 731 }, { 880, 432 }, { 568, 146 } } },
|
||||
{ { { 32, 48 }, { 208, 168 }, { 120, 288 } } }
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
ui::Point translate(const DigitizerPoint& p) const;
|
||||
|
||||
private:
|
||||
@@ -149,8 +158,6 @@ private:
|
||||
int32_t f;
|
||||
};
|
||||
|
||||
const Calibration default_calibration();
|
||||
|
||||
template<size_t N>
|
||||
class Filter {
|
||||
public:
|
||||
|
||||
@@ -247,6 +247,8 @@ public:
|
||||
parent_pos,
|
||||
5,
|
||||
{
|
||||
{ " 10", 10 }, /* Fine tuning SSB voice pitch,in HF and QO-100 sat #669 */
|
||||
{ " 50", 50 }, /* added 50Hz/10Hz,but we do not increase GUI digit decimal */
|
||||
{ " 100", 100 },
|
||||
{ " 1k ", 1000 },
|
||||
{ " 3k ", 3000 }, /* Approximate SSB bandwidth */
|
||||
|
||||
@@ -80,6 +80,21 @@ void RSSI::paint(Painter& painter) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t RSSI::get_min()
|
||||
{
|
||||
return min_ ;
|
||||
}
|
||||
|
||||
int32_t RSSI::get_avg()
|
||||
{
|
||||
return avg_ ;
|
||||
}
|
||||
|
||||
int32_t RSSI::get_max()
|
||||
{
|
||||
return max_ ;
|
||||
}
|
||||
|
||||
void RSSI::set_pitch_rssi(bool enabled) {
|
||||
pitch_rssi_enabled = enabled;
|
||||
if (!enabled) baseband::set_pitch_rssi(0, false);
|
||||
|
||||
@@ -46,6 +46,9 @@ public:
|
||||
}
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
int32_t get_min();
|
||||
int32_t get_avg();
|
||||
int32_t get_max();
|
||||
|
||||
private:
|
||||
int32_t min_;
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include "ui_remote.hpp"
|
||||
#include "ui_scanner.hpp"
|
||||
#include "ui_search.hpp"
|
||||
#include "ui_recon.hpp"
|
||||
#include "ui_sd_wipe.hpp"
|
||||
#include "ui_settings.hpp"
|
||||
#include "ui_siggen.hpp"
|
||||
@@ -65,6 +66,7 @@
|
||||
//#include "ui_test.hpp"
|
||||
#include "ui_tone_search.hpp"
|
||||
#include "ui_touchtunes.hpp"
|
||||
#include "ui_playlist.hpp"
|
||||
#include "ui_view_wav.hpp"
|
||||
#include "ui_whipcalc.hpp"
|
||||
|
||||
@@ -481,6 +483,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
||||
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
|
||||
{ "Radiosnde", ui::Color::green(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
|
||||
{ "TPMS Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
|
||||
{ "Recon", ui::Color::green(), &bitmap_icon_scanner, [&nav](){ nav.push<ReconView>(); } },
|
||||
{ "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSRXView>(); } }
|
||||
/*
|
||||
{ "DMR", ui::Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
@@ -518,6 +521,8 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
|
||||
{ "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } },
|
||||
{ "TEDI/LCR", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push<LCRView>(); } },
|
||||
{ "TouchTune", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<TouchTunesView>(); } },
|
||||
{ "Playlist", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<PlaylistView>(); } },
|
||||
|
||||
//{ "Remote", ui::Color::dark_grey(), &bitmap_icon_remote, [&nav](){ nav.push<RemoteView>(); } },
|
||||
});
|
||||
}
|
||||
@@ -536,9 +541,10 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
|
||||
//{ "Notepad", ui::Color::dark_grey(), &bitmap_icon_notepad, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "Signal gen", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push<SigGenView>(); } },
|
||||
//{ "Tone search", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<ToneSearchView>(); } },
|
||||
{ "WAV viewer", ui::Color::yellow(), &bitmap_icon_soundboard, [&nav](){ nav.push<ViewWavView>(); } },
|
||||
{ "Wav viewer", ui::Color::yellow(), &bitmap_icon_soundboard, [&nav](){ nav.push<ViewWavView>(); } },
|
||||
{ "Antenna length", ui::Color::green(), &bitmap_icon_tools_antenna, [&nav](){ nav.push<WhipCalcView>(); } },
|
||||
{ "Wipe SD Card", ui::Color::red(), &bitmap_icon_tools_wipesd, [&nav](){ nav.push<WipeSDView>(); } },
|
||||
|
||||
{ "Wipe SD card", ui::Color::red(), &bitmap_icon_tools_wipesd, [&nav](){ nav.push<WipeSDView>(); } },
|
||||
});
|
||||
set_max_rows(2); // allow wider buttons
|
||||
}
|
||||
|
||||
@@ -114,6 +114,20 @@ bool load_sram() {
|
||||
return ok;
|
||||
}
|
||||
|
||||
void load_sram_no_verify() {
|
||||
// CoolRunner II family has Hybrid memory CPLD arquitecture (SRAM+NVM)
|
||||
// It seems that after using TX App somehow , I do not why , the CPLD_SRAM part needs to be re_loaded to solve #637 ghost beat
|
||||
// load_sram() it is already called at each boot in portapack.cpp ,including verify CPLD part.
|
||||
// Here we skipped CPLD verify part,just to be quicker (in case any CPLD problem it will be detected in the boot process).
|
||||
|
||||
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
|
||||
hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
|
||||
|
||||
hackrf_cpld.write_sram(hackrf::one::cpld::verify_blocks);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool verify_eeprom() {
|
||||
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
|
||||
hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace hackrf {
|
||||
namespace cpld {
|
||||
|
||||
bool load_sram();
|
||||
void load_sram_no_verify(); // added to solve issue #637 , "ghost" signal at RX , after using any TX App
|
||||
bool verify_eeprom();
|
||||
void init_from_eeprom();
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
#include "utility.hpp"
|
||||
|
||||
#include "memory_map.hpp"
|
||||
using portapack::memory::map::backup_ram;
|
||||
|
||||
#include "crc.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
@@ -67,8 +68,193 @@ using clkout_freq_range_t = range_t<uint32_t>;
|
||||
constexpr clkout_freq_range_t clkout_freq_range { 10, 60000 };
|
||||
constexpr uint32_t clkout_freq_reset_value { 10000 };
|
||||
|
||||
enum data_structure_version_enum : uint32_t {
|
||||
VERSION_CURRENT = 0x10000002,
|
||||
};
|
||||
|
||||
static const uint32_t TOUCH_CALIBRATION_MAGIC = 0x074af82f;
|
||||
|
||||
struct ui_config_t {
|
||||
private:
|
||||
enum bits_t {
|
||||
BacklightTimeoutLSB = 0,
|
||||
BacklightTimeoutEnable = 3,
|
||||
ClkoutFreqLSB = 4,
|
||||
ShowGUIReturnIcon = 20,
|
||||
LoadAppSettings = 21,
|
||||
SaveAppSettings = 22,
|
||||
ShowBiggerQRCode = 23,
|
||||
DisableTouchscreen = 24,
|
||||
HideClock = 25,
|
||||
ClockWithDate = 26,
|
||||
ClkOutEnabled = 27,
|
||||
ConfigSpeaker = 28,
|
||||
StealthMode = 29,
|
||||
ConfigLogin = 30,
|
||||
ConfigSplash = 31,
|
||||
};
|
||||
|
||||
enum bits_mask_t : uint32_t {
|
||||
BacklightTimeoutMask = ((1 << 3) - 1) << bits_t::BacklightTimeoutLSB,
|
||||
ClkoutFreqMask = ((1 << 16) - 1) << bits_t::ClkoutFreqLSB,
|
||||
};
|
||||
|
||||
uint32_t values;
|
||||
|
||||
constexpr bool bit_read(const bits_t n) const {
|
||||
return ((values >> n) & 1) != 0;
|
||||
}
|
||||
|
||||
constexpr void bit_write(const bits_t n, const bool v) {
|
||||
if(bit_read(n) != v) {
|
||||
values ^= 1 << n;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
backlight_config_t config_backlight_timer() {
|
||||
const auto timeout_enum = (backlight_timeout_t)((values & bits_mask_t::BacklightTimeoutMask) >> bits_t::BacklightTimeoutLSB);
|
||||
const bool timeout_enabled = bit_read(bits_t::BacklightTimeoutEnable);
|
||||
return backlight_config_t(timeout_enum, timeout_enabled);
|
||||
}
|
||||
|
||||
void set_config_backlight_timer(const backlight_config_t& new_value) {
|
||||
values = (values & ~bits_mask_t::BacklightTimeoutMask)
|
||||
| ((new_value.timeout_enum() << bits_t::BacklightTimeoutLSB) & bits_mask_t::BacklightTimeoutMask);
|
||||
bit_write(bits_t::BacklightTimeoutEnable, new_value.timeout_enabled());
|
||||
}
|
||||
|
||||
constexpr uint32_t clkout_freq() {
|
||||
uint32_t freq = (values & bits_mask_t::ClkoutFreqMask) >> bits_t::ClkoutFreqLSB;
|
||||
if(freq < clkout_freq_range.minimum || freq > clkout_freq_range.maximum) {
|
||||
values = (values & ~bits_mask_t::ClkoutFreqMask) | (clkout_freq_reset_value << bits_t::ClkoutFreqLSB);
|
||||
return clkout_freq_reset_value;
|
||||
}
|
||||
else {
|
||||
return freq;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void set_clkout_freq(uint32_t freq) {
|
||||
values = (values & ~bits_mask_t::ClkoutFreqMask) | (clkout_freq_range.clip(freq) << bits_t::ClkoutFreqLSB);
|
||||
}
|
||||
|
||||
// ui_config is an uint32_t var storing information bitwise
|
||||
// bits 0-2 store the backlight timer
|
||||
// bits 4-19 (16 bits) store the clkout frequency
|
||||
// bits 21-31 store the different single bit configs depicted below
|
||||
// bit 20 store the display state of the gui return icon, hidden (0) or shown (1)
|
||||
|
||||
constexpr bool show_gui_return_icon() const { // add return icon in touchscreen menue
|
||||
return bit_read(bits_t::ShowGUIReturnIcon);
|
||||
}
|
||||
|
||||
constexpr void set_gui_return_icon(bool v) {
|
||||
bit_write(bits_t::ShowGUIReturnIcon, v);
|
||||
}
|
||||
|
||||
constexpr bool load_app_settings() const { // load (last saved) app settings on startup of app
|
||||
return bit_read(bits_t::LoadAppSettings);
|
||||
}
|
||||
|
||||
constexpr void set_load_app_settings(bool v) {
|
||||
bit_write(bits_t::LoadAppSettings, v);
|
||||
}
|
||||
|
||||
constexpr bool save_app_settings() const { // save app settings when closing app
|
||||
return bit_read(bits_t::SaveAppSettings);
|
||||
}
|
||||
|
||||
constexpr void set_save_app_settings(bool v) {
|
||||
bit_write(bits_t::SaveAppSettings, v);
|
||||
}
|
||||
|
||||
constexpr bool show_bigger_qr_code() const { // show bigger QR code
|
||||
return bit_read(bits_t::ShowBiggerQRCode);
|
||||
}
|
||||
|
||||
constexpr void set_show_bigger_qr_code(bool v) {
|
||||
bit_write(bits_t::ShowBiggerQRCode, v);
|
||||
}
|
||||
|
||||
constexpr bool disable_touchscreen() const { // Option to disable touch screen
|
||||
return bit_read(bits_t::DisableTouchscreen);
|
||||
}
|
||||
|
||||
constexpr void set_disable_touchscreen(bool v) {
|
||||
bit_write(bits_t::DisableTouchscreen, v);
|
||||
}
|
||||
|
||||
constexpr bool hide_clock() const { // clock hidden from main menu
|
||||
return bit_read(bits_t::HideClock);
|
||||
}
|
||||
|
||||
constexpr void set_clock_hidden(bool v) {
|
||||
bit_write(bits_t::HideClock, v);
|
||||
}
|
||||
|
||||
constexpr bool clock_with_date() const { // show clock with date, if not hidden
|
||||
return bit_read(bits_t::ClockWithDate);
|
||||
}
|
||||
|
||||
constexpr void set_clock_with_date(bool v) {
|
||||
bit_write(bits_t::ClockWithDate, v);
|
||||
}
|
||||
|
||||
constexpr bool clkout_enabled() const {
|
||||
return bit_read(bits_t::ClkOutEnabled);
|
||||
}
|
||||
|
||||
constexpr void set_clkout_enabled(bool v) {
|
||||
bit_write(bits_t::ClkOutEnabled, v);
|
||||
}
|
||||
|
||||
constexpr bool config_speaker() const {
|
||||
return bit_read(bits_t::ConfigSpeaker);
|
||||
}
|
||||
|
||||
constexpr void set_config_speaker(bool v) {
|
||||
bit_write(bits_t::ConfigSpeaker, v);
|
||||
}
|
||||
|
||||
constexpr bool stealth_mode() const {
|
||||
return bit_read(bits_t::StealthMode);
|
||||
}
|
||||
|
||||
constexpr void set_stealth_mode(bool v) {
|
||||
bit_write(bits_t::StealthMode, v);
|
||||
}
|
||||
|
||||
constexpr bool config_login() const {
|
||||
return bit_read(bits_t::ConfigLogin);
|
||||
}
|
||||
|
||||
constexpr void set_config_login(bool v) {
|
||||
bit_write(bits_t::ConfigLogin, v);
|
||||
}
|
||||
|
||||
constexpr bool config_splash() const {
|
||||
return bit_read(bits_t::ConfigSplash);
|
||||
}
|
||||
|
||||
constexpr void set_config_splash(bool v) {
|
||||
bit_write(bits_t::ConfigSplash, v);
|
||||
}
|
||||
|
||||
constexpr ui_config_t() :
|
||||
values(
|
||||
(1 << ConfigSplash)
|
||||
| (1 << ConfigSpeaker)
|
||||
| (clkout_freq_reset_value << ClkoutFreqLSB)
|
||||
| (7 << BacklightTimeoutLSB)
|
||||
)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/* struct must pack the same way on M4 and M0 cores. */
|
||||
struct data_t {
|
||||
data_structure_version_enum structure_version;
|
||||
int64_t tuned_frequency;
|
||||
int32_t correction_ppb;
|
||||
uint32_t touch_calibration_magic;
|
||||
@@ -89,7 +275,7 @@ struct data_t {
|
||||
uint32_t playdead_sequence;
|
||||
|
||||
// UI
|
||||
uint32_t ui_config;
|
||||
ui_config_t ui_config;
|
||||
|
||||
uint32_t pocsag_last_address;
|
||||
uint32_t pocsag_ignore_address;
|
||||
@@ -98,11 +284,146 @@ struct data_t {
|
||||
|
||||
// Hardware
|
||||
uint32_t hardware_config;
|
||||
|
||||
// Recon App
|
||||
uint64_t recon_config;
|
||||
|
||||
constexpr data_t() :
|
||||
structure_version(data_structure_version_enum::VERSION_CURRENT),
|
||||
tuned_frequency(tuned_frequency_reset_value),
|
||||
correction_ppb(ppb_reset_value),
|
||||
touch_calibration_magic(TOUCH_CALIBRATION_MAGIC),
|
||||
touch_calibration(touch::Calibration()),
|
||||
|
||||
modem_def_index(0), // TODO: Unused?
|
||||
serial_format(),
|
||||
modem_bw(15000), // TODO: Unused?
|
||||
afsk_mark_freq(afsk_mark_reset_value),
|
||||
afsk_space_freq(afsk_space_reset_value),
|
||||
modem_baudrate(modem_baudrate_reset_value),
|
||||
modem_repeat(modem_repeat_reset_value),
|
||||
|
||||
playdead_magic(), // TODO: Unused?
|
||||
playing_dead(), // TODO: Unused?
|
||||
playdead_sequence(), // TODO: Unused?
|
||||
|
||||
ui_config(),
|
||||
|
||||
pocsag_last_address(0), // TODO: A better default?
|
||||
pocsag_ignore_address(0), // TODO: A better default?
|
||||
|
||||
tone_mix(tone_mix_reset_value),
|
||||
|
||||
hardware_config(0),
|
||||
recon_config(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(data_t) <= backup_ram.size(), "Persistent memory structure too large for VBAT-maintained region");
|
||||
struct backup_ram_t {
|
||||
private:
|
||||
uint32_t regfile[63];
|
||||
uint32_t check_value;
|
||||
|
||||
static data_t* const data = reinterpret_cast<data_t*>(backup_ram.base());
|
||||
static void copy(const backup_ram_t& src, backup_ram_t& dst) {
|
||||
for(size_t i=0; i<63; i++) {
|
||||
dst.regfile[i] = src.regfile[i];
|
||||
}
|
||||
dst.check_value = src.check_value;
|
||||
}
|
||||
|
||||
static void copy_from_data_t(const data_t& src, backup_ram_t& dst) {
|
||||
const uint32_t* const src_words = (uint32_t*)&src;
|
||||
const size_t word_count = (sizeof(data_t) + 3) / 4;
|
||||
for(size_t i=0; i<63; i++) {
|
||||
if(i<word_count) {
|
||||
dst.regfile[i] = src_words[i];
|
||||
} else {
|
||||
dst.regfile[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t compute_check_value() {
|
||||
CRC<32> crc { 0x04c11db7, 0xffffffff, 0xffffffff };
|
||||
for(size_t i=0; i<63; i++) {
|
||||
const auto word = regfile[i];
|
||||
crc.process_byte((word >> 0) & 0xff);
|
||||
crc.process_byte((word >> 8) & 0xff);
|
||||
crc.process_byte((word >> 16) & 0xff);
|
||||
crc.process_byte((word >> 24) & 0xff);
|
||||
}
|
||||
return crc.checksum();
|
||||
}
|
||||
|
||||
public:
|
||||
/* default constructor */
|
||||
backup_ram_t() :
|
||||
check_value(0)
|
||||
{
|
||||
const data_t defaults = data_t();
|
||||
copy_from_data_t(defaults, *this);
|
||||
}
|
||||
|
||||
/* copy-assignment operator */
|
||||
backup_ram_t& operator=(const backup_ram_t& src) {
|
||||
copy(src, *this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Calculate a check value from `this`, and check against
|
||||
* the stored value.
|
||||
*/
|
||||
bool is_valid() {
|
||||
return compute_check_value() == check_value;
|
||||
}
|
||||
|
||||
/* Assuming `this` contains valid data, update the checksum
|
||||
* and copy to the destination.
|
||||
*/
|
||||
void persist_to(backup_ram_t& dst) {
|
||||
check_value = compute_check_value();
|
||||
copy(*this, dst);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(backup_ram_t) == memory::map::backup_ram.size());
|
||||
static_assert(sizeof(data_t) <= sizeof(backup_ram_t) - sizeof(uint32_t));
|
||||
|
||||
static backup_ram_t* const backup_ram = reinterpret_cast<backup_ram_t*>(memory::map::backup_ram.base());
|
||||
|
||||
static backup_ram_t cached_backup_ram;
|
||||
static data_t* const data = reinterpret_cast<data_t*>(&cached_backup_ram);
|
||||
|
||||
namespace cache {
|
||||
|
||||
void defaults() {
|
||||
cached_backup_ram = backup_ram_t();
|
||||
}
|
||||
|
||||
void init() {
|
||||
if(backup_ram->is_valid()) {
|
||||
// Copy valid persistent data into cache.
|
||||
cached_backup_ram = *backup_ram;
|
||||
|
||||
// Check that structure data we copied into cache is the expected
|
||||
// version. If not, initialize cache to defaults.
|
||||
if(data->structure_version != data_structure_version_enum::VERSION_CURRENT) {
|
||||
// TODO: Can provide version-to-version upgrade functions here,
|
||||
// if we want to be fancy.
|
||||
defaults();
|
||||
}
|
||||
} else {
|
||||
// Copy defaults into cache.
|
||||
defaults();
|
||||
}
|
||||
}
|
||||
|
||||
void persist() {
|
||||
cached_backup_ram.persist_to(*backup_ram);
|
||||
}
|
||||
|
||||
} /* namespace cache */
|
||||
|
||||
rf::Frequency tuned_frequency() {
|
||||
rf::tuning_range.reset_if_outside(data->tuned_frequency, tuned_frequency_reset_value);
|
||||
@@ -124,16 +445,14 @@ void set_correction_ppb(const ppb_t new_value) {
|
||||
portapack::clock_manager.set_reference_ppb(clipped_value);
|
||||
}
|
||||
|
||||
static constexpr uint32_t touch_calibration_magic = 0x074af82f;
|
||||
|
||||
void set_touch_calibration(const touch::Calibration& new_value) {
|
||||
data->touch_calibration = new_value;
|
||||
data->touch_calibration_magic = touch_calibration_magic;
|
||||
data->touch_calibration_magic = TOUCH_CALIBRATION_MAGIC;
|
||||
}
|
||||
|
||||
const touch::Calibration& touch_calibration() {
|
||||
if( data->touch_calibration_magic != touch_calibration_magic ) {
|
||||
set_touch_calibration(touch::default_calibration());
|
||||
if( data->touch_calibration_magic != TOUCH_CALIBRATION_MAGIC ) {
|
||||
set_touch_calibration(touch::Calibration());
|
||||
}
|
||||
return data->touch_calibration;
|
||||
}
|
||||
@@ -200,122 +519,116 @@ void set_serial_format(const serial_format_t new_value) {
|
||||
data->serial_format = new_value;
|
||||
}
|
||||
|
||||
// ui_config is an uint32_t var storing information bitwise
|
||||
// bits 0-2 store the backlight timer
|
||||
// bits 4-19 (16 bits) store the clkout frequency
|
||||
// bits 21-31 store the different single bit configs depicted below
|
||||
// bit 20 store the display state of the gui return icon, hidden (0) or shown (1)
|
||||
|
||||
bool show_gui_return_icon(){ // add return icon in touchscreen menue
|
||||
return data->ui_config & (1 << 20);
|
||||
bool show_gui_return_icon() { // add return icon in touchscreen menue
|
||||
return data->ui_config.show_gui_return_icon();
|
||||
}
|
||||
|
||||
bool load_app_settings() { // load (last saved) app settings on startup of app
|
||||
return data->ui_config & (1 << 21);
|
||||
return data->ui_config.load_app_settings();
|
||||
}
|
||||
|
||||
bool save_app_settings() { // save app settings when closing app
|
||||
return data->ui_config & (1 << 22);
|
||||
return data->ui_config.save_app_settings();
|
||||
}
|
||||
|
||||
bool show_bigger_qr_code() { // show bigger QR code
|
||||
return data->ui_config & (1 << 23);
|
||||
return data->ui_config.show_bigger_qr_code();
|
||||
}
|
||||
|
||||
bool disable_touchscreen() { // Option to disable touch screen
|
||||
return data->ui_config & (1 << 24);
|
||||
return data->ui_config.disable_touchscreen();
|
||||
}
|
||||
|
||||
bool hide_clock() { // clock hidden from main menu
|
||||
return data->ui_config & (1 << 25);
|
||||
return data->ui_config.hide_clock();
|
||||
}
|
||||
|
||||
bool clock_with_date() { // show clock with date, if not hidden
|
||||
return data->ui_config & (1 << 26);
|
||||
return data->ui_config.clock_with_date();
|
||||
}
|
||||
|
||||
bool clkout_enabled() {
|
||||
return data->ui_config & (1 << 27);
|
||||
return data->ui_config.clkout_enabled();
|
||||
}
|
||||
|
||||
bool config_speaker() {
|
||||
return data->ui_config & (1 << 28);
|
||||
return data->ui_config.config_speaker();
|
||||
}
|
||||
|
||||
bool stealth_mode() {
|
||||
return data->ui_config & (1 << 29);
|
||||
return data->ui_config.stealth_mode();
|
||||
}
|
||||
|
||||
bool config_login() {
|
||||
return data->ui_config & (1 << 30);
|
||||
return data->ui_config.config_login();
|
||||
}
|
||||
|
||||
bool config_splash() {
|
||||
return data->ui_config & (1 << 31);
|
||||
return data->ui_config.config_splash();
|
||||
}
|
||||
|
||||
uint8_t config_cpld() {
|
||||
return data->hardware_config;
|
||||
}
|
||||
|
||||
uint32_t config_backlight_timer() {
|
||||
const uint32_t timer_seconds[8] = { 0, 5, 15, 30, 60, 180, 300, 600 };
|
||||
return timer_seconds[data->ui_config & 7]; //first three bits, 8 possible values
|
||||
backlight_config_t config_backlight_timer() {
|
||||
return data->ui_config.config_backlight_timer();
|
||||
}
|
||||
|
||||
void set_gui_return_icon(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 20)) | (v << 20);
|
||||
data->ui_config.set_gui_return_icon(v);
|
||||
}
|
||||
|
||||
void set_load_app_settings(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 21)) | (v << 21);
|
||||
data->ui_config.set_load_app_settings(v);
|
||||
}
|
||||
|
||||
void set_save_app_settings(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 22)) | (v << 22);
|
||||
data->ui_config.set_save_app_settings(v);
|
||||
}
|
||||
|
||||
void set_show_bigger_qr_code(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 23)) | (v << 23);
|
||||
data->ui_config.set_show_bigger_qr_code(v);
|
||||
}
|
||||
|
||||
void set_disable_touchscreen(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 24)) | (v << 24);
|
||||
data->ui_config.set_disable_touchscreen(v);
|
||||
}
|
||||
|
||||
void set_clock_hidden(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 25)) | (v << 25);
|
||||
data->ui_config.set_clock_hidden(v);
|
||||
}
|
||||
|
||||
void set_clock_with_date(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 26)) | (v << 26);
|
||||
data->ui_config.set_clock_with_date(v);
|
||||
}
|
||||
|
||||
void set_clkout_enabled(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 27)) | (v << 27);
|
||||
data->ui_config.set_clkout_enabled(v);
|
||||
}
|
||||
|
||||
void set_config_speaker(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 28)) | (v << 28);
|
||||
data->ui_config.set_config_speaker(v);
|
||||
}
|
||||
|
||||
void set_stealth_mode(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 29)) | (v << 29);
|
||||
data->ui_config.set_stealth_mode(v);
|
||||
}
|
||||
|
||||
void set_config_login(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 30)) | (v << 30);
|
||||
data->ui_config.set_config_login(v);
|
||||
}
|
||||
|
||||
void set_config_splash(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 31)) | (v << 31);
|
||||
data->ui_config.set_config_splash(v);
|
||||
}
|
||||
|
||||
void set_config_cpld(uint8_t i) {
|
||||
data->hardware_config = i;
|
||||
}
|
||||
|
||||
void set_config_backlight_timer(uint32_t i) {
|
||||
data->ui_config = (data->ui_config & ~7) | (i & 7);
|
||||
void set_config_backlight_timer(const backlight_config_t& new_value) {
|
||||
data->ui_config.set_config_backlight_timer(new_value);
|
||||
}
|
||||
|
||||
/*void set_config_textentry(uint8_t new_value) {
|
||||
@@ -347,20 +660,68 @@ void set_pocsag_ignore_address(uint32_t address) {
|
||||
}
|
||||
|
||||
uint32_t clkout_freq() {
|
||||
uint16_t freq = (data->ui_config & 0x000FFFF0) >> 4;
|
||||
if(freq < clkout_freq_range.minimum || freq > clkout_freq_range.maximum) {
|
||||
data->ui_config = (data->ui_config & ~0x000FFFF0) | clkout_freq_reset_value << 4;
|
||||
return clkout_freq_reset_value;
|
||||
}
|
||||
else {
|
||||
return freq;
|
||||
}
|
||||
return data->ui_config.clkout_freq();
|
||||
}
|
||||
|
||||
void set_clkout_freq(uint32_t freq) {
|
||||
data->ui_config = (data->ui_config & ~0x000FFFF0) | (clkout_freq_range.clip(freq) << 4);
|
||||
data->ui_config.set_clkout_freq(freq);
|
||||
}
|
||||
|
||||
bool recon_autosave_freqs() {
|
||||
return (data->recon_config & 0x80000000UL) ? true : false;
|
||||
}
|
||||
bool recon_autostart_recon() {
|
||||
return (data->recon_config & 0x40000000UL) ? true : false;
|
||||
}
|
||||
bool recon_continuous() {
|
||||
return (data->recon_config & 0x20000000UL) ? true : false;
|
||||
}
|
||||
bool recon_clear_output() {
|
||||
return (data->recon_config & 0x10000000UL) ? true : false;
|
||||
}
|
||||
bool recon_load_freqs() {
|
||||
return (data->recon_config & 0x08000000UL) ? true : false;
|
||||
}
|
||||
bool recon_load_ranges() {
|
||||
return (data->recon_config & 0x04000000UL) ? true : false;
|
||||
}
|
||||
bool recon_update_ranges_when_recon() {
|
||||
return (data->recon_config & 0x02000000UL) ? true : false;
|
||||
}
|
||||
bool recon_load_hamradios() {
|
||||
return (data->recon_config & 0x01000000UL) ? true : false;
|
||||
}
|
||||
bool recon_match_mode() {
|
||||
return (data->recon_config & 0x00800000UL) ? true : false;
|
||||
}
|
||||
|
||||
void set_recon_autosave_freqs(const bool v ){
|
||||
data->recon_config = (data->recon_config & ~0x80000000UL) | (v << 31);
|
||||
}
|
||||
void set_recon_autostart_recon(const bool v ){
|
||||
data->recon_config = (data->recon_config & ~0x40000000UL) | (v << 30);
|
||||
}
|
||||
void set_recon_continuous(const bool v ){
|
||||
data->recon_config = (data->recon_config & ~0x20000000UL) | (v << 29);
|
||||
}
|
||||
void set_recon_clear_output(const bool v ){
|
||||
data->recon_config = (data->recon_config & ~0x10000000UL) | (v << 28);
|
||||
}
|
||||
void set_recon_load_freqs(const bool v ){
|
||||
data->recon_config = (data->recon_config & ~0x08000000UL) | (v << 27);
|
||||
}
|
||||
void set_recon_load_ranges(const bool v ){
|
||||
data->recon_config = (data->recon_config & ~0x04000000UL) | (v << 26);
|
||||
}
|
||||
void set_recon_update_ranges_when_recon(const bool v ){
|
||||
data->recon_config = (data->recon_config & ~0x02000000UL) | (v << 25);
|
||||
}
|
||||
void set_recon_load_hamradios(const bool v ){
|
||||
data->recon_config = (data->recon_config & ~0x01000000UL) | (v << 24);
|
||||
}
|
||||
void set_recon_match_mode(const bool v ) {
|
||||
data->recon_config = (data->recon_config & ~0x00800000UL) | (v << 23);
|
||||
}
|
||||
|
||||
} /* namespace persistent_memory */
|
||||
} /* namespace portapack */
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "optional.hpp"
|
||||
|
||||
#include "rf_path.hpp"
|
||||
#include "touch.hpp"
|
||||
#include "modems.hpp"
|
||||
@@ -36,6 +38,77 @@ using namespace serializer;
|
||||
namespace portapack {
|
||||
namespace persistent_memory {
|
||||
|
||||
enum backlight_timeout_t {
|
||||
Timeout5Sec = 0,
|
||||
Timeout15Sec = 1,
|
||||
Timeout30Sec = 2,
|
||||
Timeout60Sec = 3,
|
||||
Timeout180Sec = 4,
|
||||
Timeout300Sec = 5,
|
||||
Timeout600Sec = 6,
|
||||
Timeout3600Sec = 7,
|
||||
};
|
||||
|
||||
struct backlight_config_t {
|
||||
public:
|
||||
backlight_config_t() :
|
||||
_timeout_enum(backlight_timeout_t::Timeout600Sec),
|
||||
_timeout_enabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
backlight_config_t(
|
||||
backlight_timeout_t timeout_enum,
|
||||
bool timeout_enabled
|
||||
) :
|
||||
_timeout_enum(timeout_enum),
|
||||
_timeout_enabled(timeout_enabled)
|
||||
{
|
||||
}
|
||||
|
||||
bool timeout_enabled() const {
|
||||
return _timeout_enabled;
|
||||
}
|
||||
|
||||
backlight_timeout_t timeout_enum() const {
|
||||
return _timeout_enum;
|
||||
}
|
||||
|
||||
uint32_t timeout_seconds() const {
|
||||
switch(timeout_enum()) {
|
||||
case Timeout5Sec: return 5;
|
||||
case Timeout15Sec: return 15;
|
||||
case Timeout30Sec: return 30;
|
||||
case Timeout60Sec: return 60;
|
||||
case Timeout180Sec: return 180;
|
||||
case Timeout300Sec: return 300;
|
||||
default:
|
||||
case Timeout600Sec: return 600;
|
||||
case Timeout3600Sec: return 3600;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
backlight_timeout_t _timeout_enum;
|
||||
bool _timeout_enabled;
|
||||
};
|
||||
|
||||
namespace cache {
|
||||
|
||||
/* Set values in cache to sensible defaults. */
|
||||
void defaults();
|
||||
|
||||
/* Load cached settings from values in persistent RAM, replacing with defaults
|
||||
* if persistent RAM contents appear to be invalid. */
|
||||
void init();
|
||||
|
||||
/* Calculate a check value for cached settings, and copy the check value and
|
||||
* settings into persistent RAM. Intended to be called periodically to update
|
||||
* persistent settings with current settings. */
|
||||
void persist();
|
||||
|
||||
} /* namespace cache */
|
||||
|
||||
using ppb_t = int32_t;
|
||||
|
||||
rf::Frequency tuned_frequency();
|
||||
@@ -86,7 +159,7 @@ bool hide_clock();
|
||||
bool clock_with_date();
|
||||
bool config_login();
|
||||
bool config_speaker();
|
||||
uint32_t config_backlight_timer();
|
||||
backlight_config_t config_backlight_timer();
|
||||
bool disable_touchscreen();
|
||||
|
||||
void set_gui_return_icon(bool v);
|
||||
@@ -98,7 +171,7 @@ void set_clock_hidden(bool v);
|
||||
void set_clock_with_date(bool v);
|
||||
void set_config_login(bool v);
|
||||
void set_config_speaker(bool v);
|
||||
void set_config_backlight_timer(uint32_t i);
|
||||
void set_config_backlight_timer(const backlight_config_t& new_value);
|
||||
void set_disable_touchscreen(bool v);
|
||||
|
||||
//uint8_t ui_config_textentry();
|
||||
@@ -115,6 +188,26 @@ void set_clkout_enabled(bool v);
|
||||
uint32_t clkout_freq();
|
||||
void set_clkout_freq(uint32_t freq);
|
||||
|
||||
/* Recon app */
|
||||
bool recon_autosave_freqs();
|
||||
bool recon_autostart_recon();
|
||||
bool recon_continuous();
|
||||
bool recon_clear_output();
|
||||
bool recon_load_freqs();
|
||||
bool recon_load_ranges();
|
||||
bool recon_update_ranges_when_recon();
|
||||
bool recon_load_hamradios();
|
||||
bool recon_match_mode();
|
||||
void set_recon_autosave_freqs(const bool v);
|
||||
void set_recon_autostart_recon(const bool v);
|
||||
void set_recon_continuous(const bool v);
|
||||
void set_recon_clear_output(const bool v);
|
||||
void set_recon_load_freqs(const bool v);
|
||||
void set_recon_load_ranges(const bool v);
|
||||
void set_recon_update_ranges_when_recon(const bool v);
|
||||
void set_recon_load_hamradios(const bool v );
|
||||
void set_recon_match_mode( const bool v );
|
||||
|
||||
} /* namespace persistent_memory */
|
||||
} /* namespace portapack */
|
||||
|
||||
|
||||
@@ -984,6 +984,159 @@ bool Button::on_touch(const TouchEvent event) {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* ButtonWithEncoder ****************************************************************/
|
||||
|
||||
ButtonWithEncoder::ButtonWithEncoder(
|
||||
Rect parent_rect,
|
||||
std::string text,
|
||||
bool instant_exec
|
||||
) : Widget { parent_rect },
|
||||
text_ { text },
|
||||
instant_exec_ { instant_exec }
|
||||
{
|
||||
set_focusable(true);
|
||||
}
|
||||
|
||||
void ButtonWithEncoder::set_text(const std::string value) {
|
||||
text_ = value;
|
||||
set_dirty();
|
||||
}
|
||||
int32_t ButtonWithEncoder::get_encoder_delta() {
|
||||
return encoder_delta ;
|
||||
}
|
||||
void ButtonWithEncoder::set_encoder_delta( const int32_t delta )
|
||||
{
|
||||
encoder_delta = delta ;
|
||||
}
|
||||
|
||||
std::string ButtonWithEncoder::text() const {
|
||||
return text_;
|
||||
}
|
||||
|
||||
void ButtonWithEncoder::paint(Painter& painter) {
|
||||
Color bg, fg;
|
||||
const auto r = screen_rect();
|
||||
|
||||
if (has_focus() || highlighted()) {
|
||||
bg = style().foreground;
|
||||
fg = Color::black();
|
||||
} else {
|
||||
bg = Color::grey();
|
||||
fg = style().foreground;
|
||||
}
|
||||
|
||||
const Style paint_style = { style().font, bg, fg };
|
||||
|
||||
painter.draw_rectangle({r.location(), {r.size().width(), 1}}, Color::light_grey());
|
||||
painter.draw_rectangle({r.location().x(), r.location().y() + r.size().height() - 1, r.size().width(), 1}, Color::dark_grey());
|
||||
painter.draw_rectangle({r.location().x() + r.size().width() - 1, r.location().y(), 1, r.size().height()}, Color::dark_grey());
|
||||
|
||||
painter.fill_rectangle(
|
||||
{ r.location().x(), r.location().y() + 1, r.size().width() - 1, r.size().height() - 2 },
|
||||
paint_style.background
|
||||
);
|
||||
|
||||
const auto label_r = paint_style.font.size_of(text_);
|
||||
painter.draw_string(
|
||||
{ r.location().x() + (r.size().width() - label_r.width()) / 2, r.location().y() + (r.size().height() - label_r.height()) / 2 },
|
||||
paint_style,
|
||||
text_
|
||||
);
|
||||
}
|
||||
|
||||
void ButtonWithEncoder::on_focus() {
|
||||
if( on_highlight )
|
||||
on_highlight(*this);
|
||||
}
|
||||
|
||||
bool ButtonWithEncoder::on_key(const KeyEvent key) {
|
||||
if( key == KeyEvent::Select ) {
|
||||
if( on_select ) {
|
||||
on_select(*this);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if( on_dir ) {
|
||||
return on_dir(*this, key);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ButtonWithEncoder::on_touch(const TouchEvent event) {
|
||||
switch(event.type) {
|
||||
case TouchEvent::Type::Start:
|
||||
set_highlighted(true);
|
||||
set_dirty();
|
||||
if( on_touch_press) {
|
||||
on_touch_press(*this);
|
||||
}
|
||||
if( on_select && instant_exec_ ) {
|
||||
on_select(*this);
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
case TouchEvent::Type::End:
|
||||
set_highlighted(false);
|
||||
set_dirty();
|
||||
if( on_touch_release) {
|
||||
on_touch_release(*this);
|
||||
}
|
||||
if( on_select && !instant_exec_ ) {
|
||||
on_select(*this);
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#if 0
|
||||
switch(event.type) {
|
||||
case TouchEvent::Type::Start:
|
||||
flags.highlighted = true;
|
||||
set_dirty();
|
||||
return true;
|
||||
|
||||
case TouchEvent::Type::Move:
|
||||
{
|
||||
const bool new_highlighted = screen_rect().contains(event.point);
|
||||
if( flags.highlighted != new_highlighted ) {
|
||||
flags.highlighted = new_highlighted;
|
||||
set_dirty();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case TouchEvent::Type::End:
|
||||
if( flags.highlighted ) {
|
||||
flags.highlighted = false;
|
||||
set_dirty();
|
||||
if( on_select ) {
|
||||
on_select(*this);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
bool ButtonWithEncoder::on_encoder(const EncoderEvent delta) {
|
||||
if( delta != 0 )
|
||||
{
|
||||
encoder_delta += delta ;
|
||||
delta_change = true ;
|
||||
on_change();
|
||||
}
|
||||
else
|
||||
delta_change = 0 ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
/* NewButton ****************************************************************/
|
||||
|
||||
NewButton::NewButton(
|
||||
|
||||
@@ -414,6 +414,51 @@ private:
|
||||
bool instant_exec_ { false };
|
||||
};
|
||||
|
||||
|
||||
class ButtonWithEncoder : public Widget {
|
||||
public:
|
||||
std::function<void(ButtonWithEncoder&)> on_select { };
|
||||
std::function<void(ButtonWithEncoder&)> on_touch_release { }; // Executed when releasing touch, after on_select.
|
||||
std::function<void(ButtonWithEncoder&)> on_touch_press { }; // Executed when touching, before on_select.
|
||||
std::function<bool(ButtonWithEncoder&, KeyEvent)> on_dir { };
|
||||
std::function<void(ButtonWithEncoder&)> on_highlight { };
|
||||
|
||||
ButtonWithEncoder(Rect parent_rect, std::string text, bool instant_exec); // instant_exec: Execute on_select when you touching instead of releasing
|
||||
ButtonWithEncoder(
|
||||
Rect parent_rect,
|
||||
std::string text
|
||||
) : ButtonWithEncoder { parent_rect, text, false }
|
||||
{
|
||||
}
|
||||
|
||||
ButtonWithEncoder(
|
||||
) : ButtonWithEncoder { { }, { } }
|
||||
{
|
||||
}
|
||||
|
||||
std::function<void()> on_change { };
|
||||
|
||||
void set_text(const std::string value);
|
||||
int32_t get_encoder_delta();
|
||||
void set_encoder_delta( const int32_t delta );
|
||||
std::string text() const;
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
void on_focus() override;
|
||||
bool on_key(const KeyEvent key) override;
|
||||
bool on_touch(const TouchEvent event) override;
|
||||
bool on_encoder(const EncoderEvent delta) override;
|
||||
|
||||
private:
|
||||
std::string text_;
|
||||
int32_t encoder_delta = 0 ;
|
||||
bool delta_change = 0 ;
|
||||
bool instant_exec_ { false };
|
||||
};
|
||||
|
||||
|
||||
|
||||
class NewButton : public Widget {
|
||||
public:
|
||||
std::function<void(void)> on_select { };
|
||||
|
||||
@@ -95,27 +95,27 @@ struct range_t {
|
||||
const T minimum;
|
||||
const T maximum;
|
||||
|
||||
const T& clip(const T& value) const {
|
||||
constexpr const T& clip(const T& value) const {
|
||||
return std::max(std::min(value, maximum), minimum);
|
||||
}
|
||||
|
||||
void reset_if_outside(T& value, const T& reset_value) const {
|
||||
constexpr void reset_if_outside(T& value, const T& reset_value) const {
|
||||
if( (value < minimum ) ||
|
||||
(value > maximum ) ) {
|
||||
value = reset_value;
|
||||
}
|
||||
}
|
||||
|
||||
bool below_range(const T& value) const {
|
||||
constexpr bool below_range(const T& value) const {
|
||||
return value < minimum;
|
||||
}
|
||||
|
||||
bool contains(const T& value) const {
|
||||
constexpr bool contains(const T& value) const {
|
||||
// TODO: Subtle gotcha here! Range test doesn't include maximum!
|
||||
return (value >= minimum) && (value < maximum);
|
||||
}
|
||||
|
||||
bool out_of_range(const T& value) const {
|
||||
constexpr bool out_of_range(const T& value) const {
|
||||
// TODO: Subtle gotcha here! Range test in contains() doesn't include maximum!
|
||||
return !contains(value);
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+1
-1
Submodule hackrf updated: e6eb4ba29b...dfadf6a31c
@@ -0,0 +1,3 @@
|
||||
##FREQ FILE SAMPLE RATE
|
||||
315000000,SAMPLES/TeslaChargePort_US.C16,500000
|
||||
433920000,SAMPLES/TeslaChargePort_EU_AU.C16,500000
|
||||
Reference in New Issue
Block a user