Compare commits

...

44 Commits

Author SHA1 Message Date
Erwin Ried 554db24b1f Merge branch 'next' 2020-11-01 17:27:45 +01:00
Erwin Ried 2fa6df596a New icon and shortcut 2020-11-01 17:26:29 +01:00
Erwin Ried aeefecf5c6 Version bump 2020-10-31 22:00:19 +01:00
Erwin Ried 06d4916144 Merge pull request #187 from rascafr/rascafr/scanner-app-load-frequency-files
Scanner app - Load custom frequency files
2020-10-27 22:03:26 +01:00
Erwin Ried 911f0c8881 Merge pull request #213 from euquiq/Fix-APRS-TX-app
Fix aprs tx app
2020-10-27 21:57:50 +01:00
Erwin Ried 01cfd360fe Merge pull request #215 from euquiq/looking_glass_full_bw_cascade_scanner
New "looking Glass" app
2020-10-27 21:57:11 +01:00
euquiq 13ce56f7bf Added "RESOLUTION" parameter
Discord User jteich did some investigation (Thanks!) and helped me understanding this rather obscure parameter:

Internally, is called "TRIGGER", and is passed into the baseband when configuring the desired spectrum sample rate.

Please forgive me in advance if this explanation is not 100% correct. It's only my interpretation, based on my own observation and jteich's comments over Discord chat.

This trigger parameter apparently determines the amount of data over time used for calculating the signal's power inside each specttrum's bin, before considering it "done".

In short, if you lower this resolution value then the cascade will tend to be rendered a bit faster, while kind of blind to tiny signals.

On the other hand, a bigger value will help rendering and distinguishing different signals on the cascade.

Too big a value can easily clutter up the cascade. But then it may be a "blessing" when inspecting higher freuqencies -where hackrf is more deaf"

The default value of 32 is quite decent. But then, now you can experiment with it. Cheers
2020-10-26 23:43:35 -03:00
euquiq 210ec9dd1b Looking Glass with PRESETS
Added a PRESETS.TXT file (inside /LOOKINGGLASS folder).

Also optimized the way the spectrum signal is integrated into the cascade.

Added provision for ranges lower than 240MHz but I am afraid that at this time it will not be advisable to lower ranges any more than 240MHz, since some artifacts and frequency running - moving out of place- occurs.

I can only hope that someone with a better understanding of hackrf's inner code can fix this issue and perhaps enhance the scanning speed.

I found some "original commenting" inside the code:

	// TODO: Move more low-level radio control stuff to M4. It'll enable tighter
	// synchronization for things like wideband (sweeping) spectrum analysis, and
	// protocols that need quick RX/TX turn-around.

Which makes me think that there are things "missing"  from the portapack side of the code, for allowing serious speed sweeping. So I am concluding that with current "portapack framework" this might be "the best possible thing".

It is to be noted that the "new" internal sweep mode code is signed by:

 * Copyright 2016 Mike Walters, Dominic Spill
 *
 * This file is part of HackRF.

Maybe Mike or Dominic can be contacted and hopefully lend a hand on enhancing this code.
2020-10-26 12:53:10 -03:00
Erwin Ried 47c5c1e9e5 Update generate_world_map.bin.py
Fix for https://github.com/eried/portapack-mayhem/issues/217
2020-10-24 22:38:43 +02:00
Erwin Ried 1207bac215 Ignore python venvs 2020-10-24 22:26:31 +02:00
Erwin Ried 94fcab19d9 Merge pull request #214 from dqs105/clkout_enable
Add options for enabling CLKOUT.
2020-10-24 22:19:39 +02:00
dqs105 7ca322fed4 Added options for tuning CLKOUT freq.
- Now we have variable CLKOUT.
- CLKOUT can be set between 10kHz and 60MHz.
(The output signal will become mostly sine shape when reaching 50MHz.)
- Click on freq setting field to change tuning step.
2020-10-24 00:24:05 +08:00
euquiq 3e1d726064 Enhancement and bug
Added a nicer MARKER (thanks to XSX(H1) contributor for the suggestion)

Fixed a bug that made the screen scroll from top, when using a popup "window" and returning (like, when pressing the DC VOLTAGE enable / disable" button on top bar) THanks to GregoryFenton for the testing and bug spotting!
2020-10-23 12:19:57 -03:00
euquiq 01ba7a57ea New "looking Glass" app
Capable of showing a cascade with full bandwidth scan. You can select Min and Max Mhz for the cascade.

You can move a marker so to (aproximately) know  a particular frequency on the cascade. If you press the select button, the app will jump into the RX -> AUDIO app, already tuned into the just "marked" frequency.

This first version SURELY has space for lots of optimizations and improvement in general.
2020-10-21 13:21:34 -03:00
dqs105 699504a703 Removed trailing spaces. 2020-10-14 20:35:51 +08:00
dqs105 48ccc1e988 Merge branch 'clkout_enable' of https://github.com/dqs105/portapack-mayhem into upstream 2020-10-14 20:15:36 +08:00
euquiq 95f7eda9c5 APRS TX app is working fine now!
Several old bugs squashed.

On the APRS side, most notably, SSID numbers where shifted left twice, instead of once, and bits 5,6 where not properly set.

On AX.25 side, the bit stuffing part of the encoder was not placing the zero bit on the right place.

Finally, I changed APRS icon from ORANGE to GREEN, since even this may be a simple app, now it's doing its work as intended.
2020-10-10 20:24:11 -03:00
Erwin Ried 4306ba5d83 Updated models 2020-10-07 20:44:09 +02:00
eried 530789f963 Create README.md 2020-10-07 10:05:37 +02:00
eried ebe6675a3a Adding files of the printed case 2020-10-07 10:03:04 +02:00
Erwin Ried af3130faa8 Merge pull request #205 from texasyojimbo/next
TIMEFREQ.TXT
2020-10-03 01:15:30 +02:00
AD5NL 3419ece682 Create TIMEFREQ.TXT
HF Time and frequency standard stations
2020-10-02 16:47:04 -05:00
euquiq b22448de75 Fixes SSID value error on APX TX
Values where left bit-shifted upon being entered by the user, so resulting SSID being transmitted was a different number.  This shifting was happening both on Source and Destination SSID values.
2020-09-28 17:54:27 -03:00
Erwin Ried 98ba332cda Version bump 2020-09-25 03:34:51 +02:00
Erwin Ried f3503e6844 Fix for the freezing when no on_touch_release function 2020-09-25 03:34:05 +02:00
Erwin Ried 883a62238d Version bump 2020-09-24 22:04:59 +02:00
Erwin Ried 9021e43041 Create FUNDING.yml 2020-09-24 11:06:30 +02:00
Erwin Ried e75dfdaf2d Merge pull request #196 from strijar/morse_tx
Bug fix
2020-09-24 10:33:06 +02:00
Белоусов Олег cafc4fdec4 Bug fix 2020-09-24 11:04:00 +03:00
Erwin Ried 99af859e13 Default null for on touch release and press
Fixes https://github.com/eried/portapack-mayhem/issues/194
2020-09-24 03:15:40 +02:00
Erwin Ried 4f2b306784 Merge pull request #195 from strijar/morse_tx
Morse TX - speed in WPS and repeat loop
2020-09-22 21:54:51 +02:00
Белоусов Олег 25ba2f1391 Morse TX loops 2020-09-22 16:12:46 +03:00
Белоусов Олег a5a3ba184a Morse TX speed in WPS 2020-09-22 11:46:44 +03:00
Erwin Ried 17cb092978 Merge pull request #191 from dqs105/siggen_fix
SigGen "Stop after" freeze fix & stronger CW signal
2020-09-20 15:08:26 +02:00
Erwin Ried 1ff027ed01 Merge pull request #192 from RobertoD91/next
Add VHF marine frequence on SD
2020-09-20 15:06:22 +02:00
dqs105 e89b7683ef Fixed "Stop After" freeze & stronger CW signal 2020-09-19 14:24:40 +08:00
dqs105 1029322405 Fix "Stop After" Freeze. 2020-09-19 14:22:28 +08:00
Roberto d280054093 Add VHF marine frequence on SD 2020-09-19 00:10:53 +02:00
dqs105 66a841e079 combine clkout_config => ui_config 2020-09-17 12:47:34 +08:00
dqs105 b15b781039 Added options for enabling CLKOUT.
- CLKOUT can be enabled in Radio settings and status bar.
- Fixed a typo(I believe) in ui_navigation.
2020-09-16 19:27:56 +08:00
Rascafr f95467d71b loaded_file_name goes back to default 'scanner' file if load step fails 2020-09-11 22:17:40 +02:00
Rascafr 200c57f990 Save new frequencies into the default / user loaded freqman txt file 2020-09-11 22:15:35 +02:00
Rascafr d2c66f4515 Removed confirmation modal after load is successful 2020-09-11 22:07:12 +02:00
Rascafr dbdb0bd379 Added ui_scanner load button for any .txt frequency file 2020-09-11 21:11:42 +02:00
34 changed files with 2994 additions and 2009 deletions
+12
View File
@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://salt.bountysource.com/checkout/amount?team=portapack-mayhem
+4 -1
View File
@@ -63,4 +63,7 @@ CMakeFiles/
# Host OS leftovers
.DS_Store
/firmware/CMakeCache.txt
/firmware/CMakeCache.txt
# Python env
env/
+1
View File
@@ -231,6 +231,7 @@ set(CPPSRC
apps/ui_keyfob.cpp
apps/ui_lcr.cpp
apps/lge_app.cpp
apps/ui_looking_glass_app.cpp
apps/ui_mictx.cpp
apps/ui_modemsetup.cpp
apps/ui_morse.cpp
+1
View File
@@ -82,6 +82,7 @@ private:
6,
SymField::SYMFIELD_ALPHANUM
};
NumberField num_ssid_dest {
{ 19 * 8, 2 * 16 },
2,
@@ -0,0 +1,334 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2020 euquiq
*
* 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_looking_glass_app.hpp"
using namespace portapack;
namespace ui
{
void GlassView::focus() {
field_marker.focus();
}
GlassView::~GlassView() {
receiver_model.set_sampling_rate(3072000); // Just a hack to avoid hanging other apps
receiver_model.disable();
baseband::shutdown();
}
void GlassView::on_lna_changed(int32_t v_db) {
receiver_model.set_lna(v_db);
}
void GlassView::on_vga_changed(int32_t v_db) {
receiver_model.set_vga(v_db);
}
void GlassView::add_spectrum_pixel(Color color)
{
spectrum_row[pixel_index++] = color;
if (pixel_index == 240) //got an entire waterfall line
{
const auto draw_y = display.scroll(1); //Scroll 1 pixel down
display.draw_pixels( {{0, draw_y}, {240, 1}}, spectrum_row); //new line at top
pixel_index = 0; //Start New cascade line
}
}
//Apparently, the spectrum object returns an array of 256 bins
//Each having the radio signal power for it's corresponding frequency slot
void GlassView::on_channel_spectrum(const ChannelSpectrum &spectrum)
{
baseband::spectrum_streaming_stop();
// Convert bins of this spectrum slice into a representative max_power and when enough, into pixels
// Spectrum.db has 256 bins. Center 12 bins are ignored (DC spike is blanked) Leftmost and rightmost 2 bins are ignored
// All things said and done, we actually need 240 of those bins:
for(uint8_t bin = 0; bin < 240; bin++)
{
if (bin < 120) {
if (spectrum.db[134 + bin] > max_power)
max_power = spectrum.db[134 + bin];
}
else
{
if (spectrum.db[bin - 118] > max_power)
max_power = spectrum.db[bin - 118];
}
bins_Hz_size += each_bin_size; //add this bin Hz count into the "pixel fulfilled bag of Hz"
if (bins_Hz_size >= marker_pixel_step) //new pixel fullfilled
{
if (min_color_power < max_power)
add_spectrum_pixel(spectrum_rgb3_lut[max_power]); //Pixel will represent max_power
else
add_spectrum_pixel(0); //Filtered out, show black
max_power = 0;
if (!pixel_index) //Received indication that a waterfall line has been completed
{
bins_Hz_size = 0; //Since this is an entire pixel line, we don't carry "Pixels into next bin"
break;
} else {
bins_Hz_size -= marker_pixel_step; //reset bins size, but carrying the eventual excess Hz into next pixel
}
}
}
if (pixel_index)
f_center += SEARCH_SLICE_WIDTH; //Move into the next bandwidth slice NOTE: spectrum.sampling_rate = SEARCH_SLICE_WIDTH
else
f_center = f_center_ini; //Start a new sweep
receiver_model.set_tuning_frequency(f_center); //tune rx for this slice
baseband::spectrum_streaming_start(); //Do the RX
}
void GlassView::on_hide()
{
baseband::spectrum_streaming_stop();
display.scroll_disable();
}
void GlassView::on_show()
{
display.scroll_set_area( 109, 319); //Restart scroll on the correct coordinates
baseband::spectrum_streaming_start();
}
void GlassView::on_range_changed()
{
f_min = field_frequency_min.value();
f_max = field_frequency_max.value();
search_span = f_max - f_min;
field_marker.set_range(f_min, f_max); //Move the marker between range
field_marker.set_value(f_min + (search_span / 2)); //Put MARKER AT MIDDLE RANGE
text_range.set(to_string_dec_uint(search_span));
f_min = (f_min)*MHZ_DIV; //Transpose into full frequency realm
f_max = (f_max)*MHZ_DIV;
search_span = search_span * MHZ_DIV;
marker_pixel_step = search_span / 240; //Each pixel value in Hz
text_marker_pm.set(to_string_dec_uint((marker_pixel_step / X2_MHZ_DIV) + 1)); // Give idea of +/- marker precision
int32_t marker_step = marker_pixel_step / MHZ_DIV;
if (!marker_step)
field_marker.set_step(1); //in case selected range is less than 240 (pixels)
else
field_marker.set_step(marker_step); //step needs to be a pixel wide.
f_center_ini = f_min + (SEARCH_SLICE_WIDTH / 2); //Initial center frequency for sweep
f_center_ini += SEARCH_SLICE_WIDTH; //euquiq: Why do I need to move the center ???!!! (shift needed for marker accuracy)
PlotMarker(field_marker.value()); //Refresh marker on screen
f_center = f_center_ini; //Reset sweep into first slice
pixel_index = 0; //reset pixel counter
max_power = 0;
bins_Hz_size = 0; //reset amount of Hz filled up by pixels
baseband::set_spectrum(SEARCH_SLICE_WIDTH, field_trigger.value());
receiver_model.set_tuning_frequency(f_center_ini); //tune rx for this slice
}
void GlassView::PlotMarker(rf::Frequency pos)
{
pos = pos * MHZ_DIV;
pos -= f_min;
pos = pos / marker_pixel_step; //Real pixel
portapack::display.fill_rectangle({0, 100, 240, 8}, Color::black()); //Clear old marker and whole marker rectangle btw
portapack::display.fill_rectangle({pos - 2, 100, 5, 3}, Color::red()); //Red marker middle
portapack::display.fill_rectangle({pos - 1, 103, 3, 3}, Color::red()); //Red marker middle
portapack::display.fill_rectangle({pos, 106, 1, 2}, Color::red()); //Red marker middle
}
GlassView::GlassView(
NavigationView &nav) : nav_(nav)
{
baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
add_children({&labels,
&field_frequency_min,
&field_frequency_max,
&field_lna,
&field_vga,
&text_range,
&filter_config,
&field_rf_amp,
&range_presets,
&field_marker,
&text_marker_pm,
&field_trigger
});
load_Presets(); //Load available presets from TXT files (or default)
field_frequency_min.set_value(presets_db[0].min); //Defaults to first preset
field_frequency_min.on_change = [this](int32_t v) {
if (v >= field_frequency_max.value())
field_frequency_max.set_value(v + 240);
this->on_range_changed();
};
field_frequency_max.set_value(presets_db[0].max); //Defaults to first preset
field_frequency_max.on_change = [this](int32_t v) {
if (v <= field_frequency_min.value())
field_frequency_min.set_value(v - 240);
this->on_range_changed();
};
field_lna.set_value(receiver_model.lna());
field_lna.on_change = [this](int32_t v) {
this->on_lna_changed(v);
};
field_vga.set_value(receiver_model.vga());
field_vga.on_change = [this](int32_t v_db) {
this->on_vga_changed(v_db);
};
filter_config.set_selected_index(0);
filter_config.on_change = [this](size_t n, OptionsField::value_t v) {
min_color_power = v;
};
range_presets.on_change = [this](size_t n, OptionsField::value_t v) {
field_frequency_min.set_value(presets_db[v].min,false);
field_frequency_max.set_value(presets_db[v].max,false);
this->on_range_changed();
};
field_marker.on_change = [this](int32_t v) {
PlotMarker(v); //Refresh marker on screen
};
field_marker.on_select = [this](NumberField&) {
f_center = field_marker.value();
f_center = f_center * MHZ_DIV;
receiver_model.set_tuning_frequency(f_center); //Center tune rx in marker freq.
receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.pop();
nav_.push<AnalogAudioView>(); //Jump into audio view
};
field_trigger.set_value(32); //Defaults to 32, as normal triggering resolution
field_trigger.on_change = [this](int32_t v) {
baseband::set_spectrum(SEARCH_SLICE_WIDTH, v);
};
display.scroll_set_area( 109, 319);
baseband::set_spectrum(SEARCH_SLICE_WIDTH, field_trigger.value()); //trigger:
// Discord User jteich: WidebandSpectrum::on_message to set the trigger value. In WidebandSpectrum::execute ,
// it keeps adding the output of the fft to the buffer until "trigger" number of calls are made,
//at which time it pushes the buffer up with channel_spectrum.feed
on_range_changed();
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.set_sampling_rate(SEARCH_SLICE_WIDTH); //20mhz
receiver_model.set_baseband_bandwidth(SEARCH_SLICE_WIDTH); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz
receiver_model.set_squelch_level(0);
receiver_model.enable();
}
void GlassView::load_Presets() {
File presets_file; //LOAD /WHIPCALC/ANTENNAS.TXT from microSD
auto result = presets_file.open("LOOKINGGLASS/PRESETS.TXT");
presets_db.clear(); //Start with fresh db
if (result.is_valid()) {
presets_Default(); //There is no txt, store a default range
} else {
std::string line; //There is a txt file
char one_char[1]; //Read it char by char
for (size_t pointer=0; pointer < presets_file.size();pointer++) {
presets_file.seek(pointer);
presets_file.read(one_char, 1);
if ((int)one_char[0] > 31) { //ascii space upwards
line += one_char[0]; //Add it to the textline
}
else if (one_char[0] == '\n') { //New Line
txtline_process(line); //make sense of this textline
line.clear(); //Ready for next textline
}
}
if (line.length() > 0) txtline_process(line); //Last line had no newline at end ?
if (!presets_db.size()) presets_Default(); //no antenna on txt, use default
}
populate_Presets();
}
void GlassView::txtline_process(std::string& line)
{
if (line.find("#") != std::string::npos) return; //Line is just a comment
size_t comma = line.find(","); //Get first comma position
if (comma == std::string::npos) return; //No comma at all
size_t previous = 0;
preset_entry new_preset;
new_preset.min = std::stoi(line.substr(0,comma));
if (!new_preset.min) return; //No frequency!
previous = comma + 1;
comma = line.find(",",previous); //Search for next delimiter
if (comma == std::string::npos) return; //No comma at all
new_preset.max = std::stoi(line.substr(previous,comma - previous));
if (!new_preset.max) return; //No frequency!
new_preset.label = line.substr(comma + 1);
if (new_preset.label.size() == 0) return; //No label ?
presets_db.push_back(new_preset); //Add this preset.
}
void GlassView::populate_Presets()
{
using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>;
options_t entries;
for (preset_entry preset : presets_db)
{ //go thru all available presets
entries.emplace_back(preset.label,entries.size());
}
range_presets.set_options(entries);
}
void GlassView::presets_Default()
{
presets_db.clear();
presets_db.push_back({2320, 2560, "DEFAULT WIFI 2.4GHz"});
}
}
@@ -0,0 +1,183 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2020 euquiq
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "portapack.hpp"
#include "baseband_api.hpp"
#include "receiver_model.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "string_format.hpp"
#include "analog_audio_app.hpp"
#include "spectrum_color_lut.hpp"
namespace ui
{
#define SEARCH_SLICE_WIDTH 20000000 // Each slice bandwidth 20 MHz
#define MHZ_DIV 1000000
#define X2_MHZ_DIV 2000000
class GlassView : public View
{
public:
GlassView(NavigationView &nav);
~GlassView();
std::string title() const override { return "Looking Glass"; };
void on_show() override;
void on_hide() override;
void focus() override;
private:
NavigationView& nav_;
struct preset_entry
{
rf::Frequency min{};
rf::Frequency max{};
std::string label{};
};
std::vector<preset_entry> presets_db{};
void on_channel_spectrum(const ChannelSpectrum& spectrum);
void do_timers();
void on_range_changed();
void on_lna_changed(int32_t v_db);
void on_vga_changed(int32_t v_db);
void add_spectrum_pixel(Color color);
void PlotMarker(rf::Frequency pos);
void load_Presets();
void txtline_process(std::string& line);
void populate_Presets();
void presets_Default();
rf::Frequency f_min { 0 }, f_max { 0 };
rf::Frequency search_span { 0 };
rf::Frequency f_center { 0 };
rf::Frequency f_center_ini { 0 };
rf::Frequency marker_pixel_step { 0 };
rf::Frequency each_bin_size { SEARCH_SLICE_WIDTH / 240 };
rf::Frequency bins_Hz_size { 0 };
uint8_t min_color_power { 0 };
uint32_t pixel_index { 0 };
std::array<Color, 240> spectrum_row = { 0 };
ChannelSpectrumFIFO* fifo { nullptr };
uint8_t max_power = 0;
Labels labels{
{{0, 0}, "MIN: MAX: LNA VGA ", Color::light_grey()},
{{0, 1 * 16}, " RANGE: FILTER: AMP:", Color::light_grey()},
{{0, 2 * 16}, "PRESET:", Color::light_grey()},
{{0, 3 * 16}, "MARKER: MHz +/- MHz", Color::light_grey()},
{{0, 4 * 16}, "RESOLUTION: (fft trigger)", Color::light_grey()}
};
NumberField field_frequency_min {
{ 4 * 8, 0 * 16 },
4,
{ 0, 6960 },
240,
' '
};
NumberField field_frequency_max {
{ 13 * 8, 0 * 16 },
4,
{ 240, 7200 },
240,
' '
};
LNAGainField field_lna {
{ 21 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 27 * 8, 0 * 16 }
};
Text text_range{
{7 * 8, 1 * 16, 4 * 8, 16},
""};
OptionsField filter_config{
{19 * 8, 1 * 16},
4,
{
{"OFF ", 0},
{"MID ", 118}, //85 +25 (110) + a bit more to kill all blue
{"HIGH", 202}, //168 + 25 (193)
}};
RFAmpField field_rf_amp{
{29 * 8, 1 * 16}};
OptionsField range_presets{
{7 * 8, 2 * 16},
20,
{
{" NONE (WIFI 2.4GHz)", 0},
}};
NumberField field_marker{
{7 * 8, 3 * 16},
4,
{0, 7200},
25,
' '};
Text text_marker_pm{
{20 * 8, 3 * 16, 2 * 8, 16},
""};
NumberField field_trigger{
{11 * 8, 4 * 16},
3,
{2, 128},
2,
' '};
MessageHandlerRegistration message_handler_spectrum_config {
Message::ID::ChannelSpectrumConfig,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const ChannelSpectrumConfigMessage*>(p);
this->fifo = message.fifo;
}
};
MessageHandlerRegistration message_handler_frame_sync {
Message::ID::DisplayFrameSync,
[this](const Message* const) {
if( this->fifo ) {
ChannelSpectrum channel_spectrum;
while( fifo->out(channel_spectrum) ) {
this->on_channel_spectrum(channel_spectrum);
}
}
}
};
};
}
+63 -7
View File
@@ -69,6 +69,25 @@ static msg_t ookthread_fn(void * arg) {
return 0;
}
static msg_t loopthread_fn(void * arg) {
MorseView * arg_c = (MorseView*)arg;
uint32_t wait = arg_c->loop;
chRegSetThreadName("loopthread");
for (uint32_t i = 0; i < wait; i++) {
if (chThdShouldTerminate()) break;
arg_c->on_loop_progress(i, false);
chThdSleepMilliseconds(1000);
}
arg_c->on_loop_progress(0, true);
chThdExit(0);
return 0;
}
void MorseView::on_set_text(NavigationView& nav) {
text_prompt(nav, buffer, 28);
}
@@ -115,9 +134,9 @@ bool MorseView::start_tx() {
void MorseView::update_tx_duration() {
uint32_t duration_ms;
time_unit_ms = field_time_unit.value();
time_unit_ms = 1200 / field_speed.value();
symbol_count = morse_encode(message, time_unit_ms, field_tone.value(), &time_units);
if (symbol_count) {
duration_ms = time_units * time_unit_ms;
text_tx_duration.set(to_string_dec_uint(duration_ms / 1000) + "." + to_string_dec_uint((duration_ms / 100) % 10, 1) + "s ");
@@ -130,7 +149,28 @@ void MorseView::on_tx_progress(const uint32_t progress, const bool done) {
if (done) {
transmitter_model.disable();
progressbar.set_value(0);
tx_view.set_transmitting(false);
if (loop && run) {
text_tx_duration.set("wait");
progressbar.set_max(loop);
progressbar.set_value(0);
if (loopthread) {
chThdRelease(loopthread);
loopthread = nullptr;
}
loopthread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO, loopthread_fn, this);
} else {
tx_view.set_transmitting(false);
}
} else
progressbar.set_value(progress);
}
void MorseView::on_loop_progress(const uint32_t progress, const bool done) {
if (done) {
start_tx();
} else
progressbar.set_value(progress);
}
@@ -152,9 +192,10 @@ MorseView::MorseView(
&labels,
&checkbox_foxhunt,
&options_foxhunt,
&field_time_unit,
&field_speed,
&field_tone,
&options_modulation,
&options_loop,
&text_tx_duration,
&text_message,
&button_message,
@@ -163,9 +204,10 @@ MorseView::MorseView(
});
// Default settings
field_time_unit.set_value(50); // 50ms unit
field_speed.set_value(15); // 15wps
field_tone.set_value(700); // 700Hz FM tone
options_modulation.set_selected_index(0); // CW mode
options_loop.set_selected_index(0); // Off
checkbox_foxhunt.on_select = [this](Checkbox&, bool value) {
foxhunt_mode = value;
@@ -182,8 +224,12 @@ MorseView::MorseView(
options_modulation.on_change = [this](size_t i, int32_t) {
modulation = (modulation_t)i;
};
options_loop.on_change = [this](size_t i, uint32_t n) {
loop = n;
};
field_time_unit.on_change = [this](int32_t) {
field_speed.on_change = [this](int32_t) {
update_tx_duration();
};
@@ -199,12 +245,22 @@ MorseView::MorseView(
};
tx_view.on_start = [this]() {
if (start_tx())
if (start_tx()) {
run = true;
tx_view.set_transmitting(true);
}
};
tx_view.on_stop = [this]() {
run = false;
if (ookthread) chThdTerminate(ookthread);
if (loopthread) {
chThdTerminate(loopthread);
chThdWait(loopthread);
loopthread = nullptr;
}
transmitter_model.disable();
baseband::kill_tone();
tx_view.set_transmitting(false);
+23 -4
View File
@@ -54,11 +54,13 @@ public:
void paint(Painter& painter) override;
void on_tx_progress(const uint32_t progress, const bool done);
void on_loop_progress(const uint32_t progress, const bool done);
std::string title() const override { return "Morse TX"; };
uint32_t time_unit_ms { 0 };
size_t symbol_count { 0 };
uint32_t loop { 0 };
private:
NavigationView& nav_;
std::string buffer { "PORTAPACK" };
@@ -77,12 +79,15 @@ private:
void set_foxhunt(size_t i);
Thread * ookthread { nullptr };
Thread * loopthread { nullptr };
bool foxhunt_mode { false };
bool run { false };
Labels labels {
{ { 4 * 8, 6 * 8 }, "Time unit: ms", Color::light_grey() },
{ { 4 * 8, 6 * 8 }, "Speed: wps", Color::light_grey() },
{ { 4 * 8, 8 * 8 }, "Tone: Hz", Color::light_grey() },
{ { 4 * 8, 10 * 8 }, "Modulation:", Color::light_grey() },
{ { 4 * 8, 12 * 8 }, "Loop:", Color::light_grey() },
{ { 1 * 8, 25 * 8 }, "TX will last", Color::light_grey() }
};
@@ -109,10 +114,10 @@ private:
}
};
NumberField field_time_unit {
{ 14 * 8, 6 * 8 },
NumberField field_speed {
{ 10 * 8, 6 * 8 },
3,
{ 10, 999 },
{ 10, 45 },
1,
' '
};
@@ -133,6 +138,20 @@ private:
{ "FM", 1 }
}
};
OptionsField options_loop {
{ 9 * 8, 12 * 8 },
6,
{
{ "Off", 0 },
{ "5 sec", 5 },
{ "10 sec", 10 },
{ "30 sec", 30 },
{ "1 min", 60 },
{ "3 min", 180 },
{ "5 min", 300 }
}
};
Text text_tx_duration {
{ 14 * 8, 25 * 8, 4 * 8, 16 },
+52 -14
View File
@@ -21,6 +21,7 @@
*/
#include "ui_scanner.hpp"
#include "ui_fileman.hpp"
using namespace portapack;
@@ -182,6 +183,7 @@ ScannerView::ScannerView(
&field_bw,
&field_squelch,
&field_wait,
&button_load,
&rssi,
&text_cycle,
&text_max,
@@ -211,6 +213,25 @@ ScannerView::ScannerView(
frequency_range.max = stored_freq + 1000000;
button_manual_end.set_text(to_string_short_freq(frequency_range.max));
button_load.on_select = [this, &nav](Button&) {
// load txt files from the FREQMAN folder
auto open_view = nav.push<FileLoadView>(".TXT");
open_view->on_changed = [this](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
scan_pause();
// get the filename without txt extension so we can use load_freqman_file fcn
std::string str_file_name = new_file_path.stem().string();
frequency_file_load(str_file_name, true);
} else {
nav_.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
}
};
};
button_manual_start.on_select = [this, &nav](Button& button) {
auto new_view = nav_.push<FrequencyKeypadView>(frequency_range.min);
new_view->on_changed = [this, &button](rf::Frequency f) {
@@ -314,7 +335,8 @@ ScannerView::ScannerView(
button_add.on_select = [this](Button&) { //frequency_list[current_index]
File scanner_file;
auto result = scanner_file.open("FREQMAN/SCANNER.TXT"); //First search if freq is already in txt
std::string freq_file_path = "FREQMAN/" + loaded_file_name + ".TXT";
auto result = scanner_file.open(freq_file_path); //First search if freq is already in txt
if (!result.is_valid()) {
std::string frequency_to_add = "f="
+ to_string_dec_uint(frequency_list[current_index] / 1000)
@@ -342,12 +364,12 @@ ScannerView::ScannerView(
big_display.set(frequency_list[current_index]); //After showing an error
}
else {
auto result = scanner_file.append("FREQMAN/SCANNER.TXT"); //Second: append if it is not there
auto result = scanner_file.append(freq_file_path); //Second: append if it is not there
scanner_file.write_line(frequency_to_add + ",d=ADD FQ");
}
} else
{
nav_.display_modal("Error", "Cannot open SCANNER.TXT\nfor appending freq.");
nav_.display_modal("Error", "Cannot open " + loaded_file_name + ".TXT\nfor appending freq.");
big_display.set(frequency_list[current_index]); //After showing an error
}
};
@@ -357,22 +379,37 @@ ScannerView::ScannerView(
field_squelch.on_change = [this](int32_t v) { squelch = v; }; field_squelch.set_value(-10);
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); };
// LEARN FREQUENCIES
std::string scanner_txt = "SCANNER";
if ( load_freqman_file(scanner_txt, database) ) {
frequency_file_load(scanner_txt);
}
void ScannerView::frequency_file_load(std::string file_name, bool stop_all_before) {
// stop everything running now if required
if (stop_all_before) {
scan_thread->stop();
frequency_list.clear(); // clear the existing frequency list (expected behavior)
description_list.clear();
def_step = step_mode.selected_index_value(); //Use def_step from manual selector
}
if ( load_freqman_file(file_name, database) ) {
loaded_file_name = file_name; // keep loaded filename in memory
for(auto& entry : database) { // READ LINE PER LINE
if (frequency_list.size() < MAX_DB_ENTRY) { //We got space!
if (entry.type == RANGE) { //RANGE
switch (entry.step) {
case AM_US: def_step = 10000; break ;
case AM_EUR:def_step = 9000; break ;
case NFM_1: def_step = 12500; break ;
case NFM_2: def_step = 6250; break ;
case FM_1: def_step = 100000; break ;
case FM_2: def_step = 50000; break ;
case N_1: def_step = 25000; break ;
case N_2: def_step = 250000; break ;
case AIRBAND:def_step= 8330; break ;
case AM_US: def_step = 10000; break ;
case AM_EUR:def_step = 9000; break ;
case NFM_1: def_step = 12500; break ;
case NFM_2: def_step = 6250; break ;
case FM_1: def_step = 100000; break ;
case FM_2: def_step = 50000; break ;
case N_1: def_step = 25000; break ;
case N_2: def_step = 250000; break ;
case AIRBAND:def_step= 8330; break ;
}
frequency_list.push_back(entry.frequency_a); //Store starting freq and description
description_list.push_back("R" + to_string_short_freq(entry.frequency_a)
@@ -398,7 +435,8 @@ ScannerView::ScannerView(
}
else
{
desc_cycle.set(" NO SCANNER.TXT FILE ..." );
loaded_file_name = 'SCANNER'; // back to the default frequency file
desc_cycle.set(" NO " + file_name + ".TXT FILE ..." );
}
audio::output::stop();
step_mode.set_by_value(def_step); //Impose the default step into the manual step selector
+7
View File
@@ -126,6 +126,7 @@ private:
void scan_pause();
void scan_resume();
void user_resume();
void frequency_file_load(std::string file_name, bool stop_all_before = false);
void on_statistics_update(const ChannelStatistics& statistics);
void on_headphone_volume_changed(int32_t v);
@@ -137,6 +138,7 @@ private:
uint32_t wait { 0 };
size_t def_step { 0 };
freqman_db database { };
std::string loaded_file_name;
uint32_t current_index { 0 };
bool userpause { false };
@@ -278,6 +280,11 @@ private:
"ADD FQ"
};
Button button_load {
{ 24 * 8, 3 * 16 - 8, 6 * 8, 22 },
"Load"
};
Button button_remove {
{ 168, (35 * 8) - 4, 72, 28 },
"DEL FQ"
+40
View File
@@ -144,6 +144,10 @@ SetRadioView::SetRadioView(
}
add_children({
&check_clkout,
&field_clkout_freq,
&labels_clkout_khz,
&value_freq_step,
&labels_bias,
&check_bias,
&button_done,
@@ -156,6 +160,39 @@ SetRadioView::SetRadioView(
form_init(model);
check_clkout.set_value(portapack::persistent_memory::clkout_enabled());
check_clkout.on_select = [this](Checkbox&, bool v) {
clock_manager.enable_clock_output(v);
portapack::persistent_memory::set_clkout_enabled(v);
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
};
field_clkout_freq.set_value(portapack::persistent_memory::clkout_freq());
value_freq_step.set_style(&style_text);
field_clkout_freq.on_select = [this](NumberField&) {
freq_step_khz++;
if(freq_step_khz > 3) {
freq_step_khz = 0;
}
switch(freq_step_khz) {
case 0:
value_freq_step.set(" |");
break;
case 1:
value_freq_step.set(" | ");
break;
case 2:
value_freq_step.set(" | ");
break;
case 3:
value_freq_step.set("| ");
break;
}
field_clkout_freq.set_step(pow(10, freq_step_khz));
};
check_bias.set_value(portapack::get_antenna_bias());
check_bias.on_select = [this](Checkbox&, bool v) {
portapack::set_antenna_bias(v);
@@ -166,6 +203,8 @@ SetRadioView::SetRadioView(
button_done.on_select = [this, &nav](Button&){
const auto model = this->form_collect();
portapack::persistent_memory::set_correction_ppb(model.ppm * 1000);
portapack::persistent_memory::set_clkout_freq(model.freq);
clock_manager.enable_clock_output(portapack::persistent_memory::clkout_enabled());
nav.pop();
};
}
@@ -181,6 +220,7 @@ void SetRadioView::form_init(const SetFrequencyCorrectionModel& model) {
SetFrequencyCorrectionModel SetRadioView::form_collect() {
return {
.ppm = static_cast<int8_t>(field_ppm.value()),
.freq = static_cast<uint32_t>(field_clkout_freq.value()),
};
}
+28 -3
View File
@@ -114,6 +114,7 @@ private:
struct SetFrequencyCorrectionModel {
int8_t ppm;
uint32_t freq;
};
class SetRadioView : public View {
@@ -130,6 +131,7 @@ private:
.background = Color::black(),
.foreground = Color::light_grey(),
};
uint8_t freq_step_khz = 3;
Text label_source {
{ 0, 1 * 16, 17 * 8, 16 },
@@ -147,8 +149,31 @@ private:
};
Labels labels_correction {
{ { 2 * 8, 4 * 16 }, "Frequency correction:", Color::light_grey() },
{ { 6 * 8, 5 * 16 }, "PPM", Color::light_grey() },
{ { 2 * 8, 3 * 16 }, "Frequency correction:", Color::light_grey() },
{ { 6 * 8, 4 * 16 }, "PPM", Color::light_grey() },
};
Checkbox check_clkout {
{ 18, (6 * 16 - 4) },
13,
"Enable CLKOUT"
};
NumberField field_clkout_freq {
{ 20 * 8, 6 * 16 },
5,
{ 10, 60000 },
1000,
' '
};
Labels labels_clkout_khz {
{ { 26 * 8, 6 * 16 }, "kHz", Color::light_grey() }
};
Text value_freq_step {
{ 21 * 8, (7 * 16 ), 4 * 8, 16 },
"| "
};
Labels labels_bias {
@@ -159,7 +184,7 @@ private:
};
NumberField field_ppm {
{ 2 * 8, 5 * 16 },
{ 2 * 8, 4 * 16 },
3,
{ -50, 50 },
1,
+10 -2
View File
@@ -43,7 +43,11 @@ SigGenView::~SigGenView() {
}
void SigGenView::update_config() {
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), options_shape.selected_index_value(), field_stop.value());
if(checkbox_stop.value())
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), options_shape.selected_index_value(), field_stop.value());
else
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), options_shape.selected_index_value(), 0);
}
void SigGenView::update_tone() {
@@ -68,8 +72,10 @@ void SigGenView::start_tx() {
void SigGenView::on_tx_progress(const uint32_t progress, const bool done) {
(void) progress;
if (done)
if (done) {
transmitter_model.disable();
tx_view.set_transmitting(false);
}
}
SigGenView::SigGenView(
@@ -98,6 +104,8 @@ SigGenView::SigGenView(
options_shape.set_selected_index(0);
text_shape.set(shape_strings[0]);
field_stop.set_value(1);
symfield_tone.set_sym(1, 1); // Default: 1000 Hz
symfield_tone.on_change = [this]() {
if (auto_update)
File diff suppressed because it is too large Load Diff
+19
View File
@@ -21,6 +21,7 @@
#include "clock_manager.hpp"
#include "portapack_persistent_memory.hpp"
#include "portapack_io.hpp"
#include "hackrf_hal.hpp"
@@ -463,3 +464,21 @@ void ClockManager::stop_audio_pll() {
cgu::pll0audio::power_down();
while( cgu::pll0audio::is_locked() );
}
void ClockManager::enable_clock_output(bool enable) {
if(enable) {
clock_generator.enable_output(clock_generator_output_clkout);
if(portapack::persistent_memory::clkout_freq() < 1000) {
clock_generator.set_ms_frequency(clock_generator_output_clkout, portapack::persistent_memory::clkout_freq() * 128000, si5351_vco_f, 7);
} else {
clock_generator.set_ms_frequency(clock_generator_output_clkout, portapack::persistent_memory::clkout_freq() * 1000, si5351_vco_f, 0);
}
} else {
clock_generator.disable_output(clock_generator_output_clkout);
}
if(enable)
clock_generator.set_clock_control(clock_generator_output_clkout, si5351_clock_control_common[clock_generator_output_clkout].ms_src(get_reference_clock_generator_pll(reference.source)).clk_pdn(ClockControl::ClockPowerDown::Power_On));
else
clock_generator.set_clock_control(clock_generator_output_clkout, ClockControl::power_off());
}
+2
View File
@@ -79,6 +79,8 @@ public:
Reference get_reference() const;
void enable_clock_output(bool enable);
private:
I2C& i2c0;
si5351::Si5351& clock_generator;
+6 -2
View File
@@ -38,9 +38,13 @@ void make_aprs_frame(const char * src_address, const uint32_t src_ssid,
char address[14] = { 0 };
memcpy(&address[0], dest_address, 6);
address[6] = (dest_ssid & 15) << 1;
memcpy(&address[7], src_address, 6);
address[13] = (src_ssid & 15) << 1;
//euquiq: According to ax.25 doc section 2.2.13.x.x and 2.4.1.2
// SSID need bits 5.6 set, so later when shifted it will end up being 011xxxx0 (xxxx = SSID number)
// Notice that if need to signal usage of AX.25 V2.0, (dest_ssid | 112); (MSb will need to be set at the end)
address[6] = (dest_ssid | 48);
address[13] = (src_ssid | 48);
frame.make_ui_frame(address, 0x03, protocol_id_t::NO_LAYER3, payload);
}
+20 -15
View File
@@ -51,32 +51,37 @@ void AX25Frame::NRZI_add_bit(const uint32_t bit) {
}
}
void AX25Frame::add_byte(uint8_t byte, bool is_flag, bool is_data) {
uint32_t bit;
void AX25Frame::add_byte(uint8_t byte, bool is_flag, bool is_data)
{
bool bit;
if (is_data)
crc_ccitt.process_byte(byte);
for (uint32_t i = 0; i < 8; i++) {
for (uint32_t i = 0; i < 8; i++)
{
bit = (byte >> i) & 1;
NRZI_add_bit(bit);
if (bit)
{
ones_counter++;
if ((ones_counter == 5) && (!is_flag))
{
NRZI_add_bit(0);
ones_counter = 0;
}
}
else
ones_counter = 0;
if ((ones_counter == 6) && (!is_flag)) {
NRZI_add_bit(0);
ones_counter = 0;
}
NRZI_add_bit(bit);
}
}
void AX25Frame::flush() {
void AX25Frame::flush()
{
if (bit_counter)
*bb_data_ptr = current_byte << (7 - bit_counter);
*bb_data_ptr = current_byte << (8 - bit_counter); //euquiq: This was 7 but there are 8 bits
};
void AX25Frame::add_flag() {
+30 -8
View File
@@ -81,7 +81,7 @@
#include "tpms_app.hpp"
#include "core_control.hpp"
#include "ui_looking_glass_app.hpp"
#include "file.hpp"
#include "png_writer.hpp"
@@ -113,7 +113,7 @@ SystemStatusView::SystemStatusView(
&button_camera,
&button_sleep,
&button_bias_tee,
&image_clock_status,
&button_clock_status,
&sd_card_status_view,
});
@@ -168,6 +168,10 @@ SystemStatusView::SystemStatusView(
DisplaySleepMessage message;
EventDispatcher::send_message(message);
};
button_clock_status.on_select = [this](ImageButton&) {
this->on_clk();
};
}
void SystemStatusView::refresh() {
@@ -188,11 +192,16 @@ void SystemStatusView::refresh() {
}
if (portapack::clock_manager.get_reference().source == ClockManager::ReferenceSource::External) {
image_clock_status.set_bitmap(&bitmap_icon_clk_ext);
button_bias_tee.set_foreground(ui::Color::green());
button_clock_status.set_bitmap(&bitmap_icon_clk_ext);
// button_bias_tee.set_foreground(ui::Color::green()); Typo?
} else {
image_clock_status.set_bitmap(&bitmap_icon_clk_int);
button_bias_tee.set_foreground(ui::Color::light_grey());
button_clock_status.set_bitmap(&bitmap_icon_clk_int);
// button_bias_tee.set_foreground(ui::Color::green());
}
if(portapack::persistent_memory::clkout_enabled()) {
button_clock_status.set_foreground(ui::Color::green());
} else {
button_clock_status.set_foreground(ui::Color::light_grey());
}
set_dirty();
@@ -302,6 +311,18 @@ void SystemStatusView::on_camera() {
}
}
void SystemStatusView::on_clk() {
bool v = portapack::persistent_memory::clkout_enabled();
if(v) {
v = false;
} else {
v = true;
}
portapack::clock_manager.enable_clock_output(v);
portapack::persistent_memory::set_clkout_enabled(v);
refresh();
}
void SystemStatusView::on_title() {
if(nav_.is_top())
nav_.push<AboutView>();
@@ -464,7 +485,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
add_items({
//{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } },
{ "ADS-B [S]", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBTxView>(); } },
{ "APRS", ui::Color::orange(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
{ "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
{ "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push<BHTView>(); } },
{ "GPS Sim", ui::Color::yellow(), &bitmap_icon_gps_sim, [&nav](){ nav.push<GpsSimAppView>(); } },
{ "Jammer", ui::Color::yellow(), &bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
@@ -522,8 +543,9 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
{ "Capture", ui::Color::red(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
{ "Replay", ui::Color::green(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } },
{ "Calls", ui::Color::yellow(), &bitmap_icon_search, [&nav](){ nav.push<SearchView>(); } },
{ "Scanner", ui::Color::green(), &bitmap_icon_scanner, [&nav](){ nav.push<ScannerView>(); } },
{ "Scanner", ui::Color::yellow(), &bitmap_icon_scanner, [&nav](){ nav.push<ScannerView>(); } },
{ "Microphone", ui::Color::yellow(), &bitmap_icon_microphone,[&nav](){ nav.push<MicTXView>(); } },
{ "Looking Glass", ui::Color::yellow(), &bitmap_icon_looking, [&nav](){ nav.push<GlassView>(); } },
{ "Tools", ui::Color::cyan(), &bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesMenuView>(); } },
{ "Options", ui::Color::cyan(), &bitmap_icon_setup, [&nav](){ nav.push<SettingsMenuView>(); } },
{ "Debug", ui::Color::light_grey(), &bitmap_icon_debug, [&nav](){ nav.push<DebugMenuView>(); } },
+3 -2
View File
@@ -180,7 +180,7 @@ private:
Color::dark_grey()
};
Image image_clock_status {
ImageButton button_clock_status {
{ 27 * 8, 0 * 16, 2 * 8, 1 * 16 },
&bitmap_icon_clk_int,
Color::light_grey(),
@@ -198,6 +198,7 @@ private:
void on_camera();
void on_title();
void refresh();
void on_clk();
MessageHandlerRegistration message_handler_refresh {
Message::ID::StatusRefresh,
@@ -213,7 +214,7 @@ public:
InformationView(NavigationView& nav);
private:
static constexpr auto version_string = "v1.2.1";
static constexpr auto version_string = "v1.3.0";
NavigationView& nav_;
Rectangle backdrop {
+2 -1
View File
@@ -33,6 +33,7 @@ void SigGenProcessor::execute(const buffer_c8_t& buffer) {
for (size_t i = 0; i < buffer.count; i++) {
if (!sample_count && auto_off) {
configured = false;
txprogress_message.done = true;
shared_memory.application_queue.push(txprogress_message);
} else
@@ -40,7 +41,7 @@ void SigGenProcessor::execute(const buffer_c8_t& buffer) {
if (tone_shape == 0) {
// CW
re = 0;
re = 127;
im = 0;
} else {
@@ -63,6 +63,10 @@ using modem_repeat_range_t = range_t<int32_t>;
constexpr modem_repeat_range_t modem_repeat_range { 1, 99 };
constexpr int32_t modem_repeat_reset_value { 5 };
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 };
/* struct must pack the same way on M4 and M0 cores. */
struct data_t {
int64_t tuned_frequency;
@@ -287,5 +291,28 @@ void set_pocsag_ignore_address(uint32_t address) {
data->pocsag_ignore_address = address;
}
bool clkout_enabled() {
return (data->ui_config & 0x08000000UL);
}
void set_clkout_enabled(bool enable) {
data->ui_config = (data->ui_config & ~0x08000000UL) | (enable << 27);
}
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;
}
}
void set_clkout_freq(uint32_t freq) {
data->ui_config = (data->ui_config & ~0x000FFFF0) | (clkout_freq_range.clip(freq) << 4);
}
} /* namespace persistent_memory */
} /* namespace portapack */
@@ -93,6 +93,11 @@ void set_pocsag_last_address(uint32_t address);
uint32_t pocsag_ignore_address();
void set_pocsag_ignore_address(uint32_t address);
bool clkout_enabled();
void set_clkout_enabled(bool enable);
uint32_t clkout_freq();
void set_clkout_freq(uint32_t freq);
} /* namespace persistent_memory */
} /* namespace portapack */
+3 -3
View File
@@ -913,12 +913,12 @@ bool Button::on_touch(const TouchEvent event) {
case TouchEvent::Type::End:
set_highlighted(false);
set_dirty();
if( on_select && !instant_exec_ ) {
on_select(*this);
}
if( on_touch_release) {
on_touch_release(*this);
}
if( on_select && !instant_exec_ ) {
on_select(*this);
}
return true;
default:
Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

+6 -2
View File
@@ -33,6 +33,8 @@ pix = im.load()
outfile.write(struct.pack('H', im.size[0]))
outfile.write(struct.pack('H', im.size[1]))
print("Generating: \t" + outfile.name + "\n from\t\t" + im.filename + "\n please wait...");
for y in range (0, im.size[1]):
line = ''
for x in range (0, im.size[0]):
@@ -45,6 +47,8 @@ for y in range (0, im.size[1]):
# pixel_lcd = (pix[x, y][0] >> 5) << 5
# pixel_lcd |= (pix[x, y][1] >> 5) << 2
# pixel_lcd |= (pix[x, y][2] >> 6)
line += struct.pack('H', pixel_lcd)
outfile.write(line)
line += str(struct.pack('H', pixel_lcd))
outfile.write(line.encode('utf-8'))
print(str(y) + '/' + str(im.size[1]) + '\r', end="")
print("Ready.");
@@ -0,0 +1,7 @@
Enclosure
https://www.thingiverse.com/thing:4260973
Cover
https://www.thingiverse.com/thing:4278961
+14
View File
@@ -0,0 +1,14 @@
f=2500000,d=WWV/BPM 2 MHz
f=5000000,d=WWV/BPM 5 MHz
f=10000000,d=WWV/BPM 10 MHz
f=15000000,d=WWV/BPM 15 MHz
f=20000000,d=WWV 20 MHz
f=3300000,d=CHU 3 MHz
f=7850000,d=CHU 7 MHz
f=14670000,d=CHU 14 MHz
f=3810000,d=HD2IOA 3 MHz
f=4996000,d=RWM 4 MHz
f=9996000,d=RWM 9 MHz
f=14996000,d=RWM 14 MHz
f=4998000,d=EBC 4 MHz
f=15006000,d=EBC 15 MHz
+114
View File
@@ -0,0 +1,114 @@
f=160650000,d=VHF CH01 RX
f=156050000,d=VHF CH01 TX
f=160700000,d=VHF CH02 RX
f=156100000,d=VHF CH02 TX
f=160750000,d=VHF CH03 RX
f=156150000,d=VHF CH03 TX
f=160800000,d=VHF CH04 RX
f=156200000,d=VHF CH04 TX
f=160850000,d=VHF CH05 RX
f=156250000,d=VHF CH05 TX
f=156300000,d=VHF CH06 RX
f=156300000,d=VHF CH06 TX
f=160950000,d=VHF CH07 RX
f=156350000,d=VHF CH07 TX
f=156400000,d=VHF CH08 RX
f=156400000,d=VHF CH08 TX
f=156450000,d=VHF CH09 RX
f=156450000,d=VHF CH09 TX
f=156500000,d=VHF CH10 RX
f=156500000,d=VHF CH10 TX
f=156550000,d=VHF CH11 RX
f=156550000,d=VHF CH11 TX
f=156600000,d=VHF CH12 RX
f=156600000,d=VHF CH12 TX
f=156650000,d=VHF CH13 RX
f=156650000,d=VHF CH13 TX
f=156700000,d=VHF CH14 RX
f=156700000,d=VHF CH14 TX
f=156750000,d=VHF CH15 RX
f=156750000,d=VHF CH15 TX
f=156800000,d=VHF CH16 RX
f=156800000,d=VHF CH16 TX
f=156850000,d=VHF CH17 RX
f=156850000,d=VHF CH17 TX
f=161500000,d=VHF CH18 RX
f=156900000,d=VHF CH18 TX
f=161550000,d=VHF CH19 RX
f=156950000,d=VHF CH19 TX
f=161600000,d=VHF CH20 RX
f=157000000,d=VHF CH20 TX
f=161650000,d=VHF CH21 RX
f=157050000,d=VHF CH21 TX
f=161700000,d=VHF CH22 RX
f=157100000,d=VHF CH22 TX
f=161750000,d=VHF CH23 RX
f=157150000,d=VHF CH23 TX
f=161800000,d=VHF CH24 RX
f=157200000,d=VHF CH24 TX
f=161850000,d=VHF CH25 RX
f=157250000,d=VHF CH25 TX
f=161900000,d=VHF CH26 RX
f=157300000,d=VHF CH26 TX
f=161950000,d=VHF CH27 RX
f=157350000,d=VHF CH27 TX
f=162000000,d=VHF CH28 RX
f=157400000,d=VHF CH28 TX
f=160625000,d=VHF CH60 RX
f=156025000,d=VHF CH60 TX
f=160675000,d=VHF CH61 RX
f=156075000,d=VHF CH61 TX
f=160725000,d=VHF CH62 RX
f=156125000,d=VHF CH62 TX
f=160775000,d=VHF CH63 RX
f=156175000,d=VHF CH63 TX
f=160825000,d=VHF CH64 RX
f=156225000,d=VHF CH64 TX
f=160875000,d=VHF CH65 RX
f=156275000,d=VHF CH65 TX
f=160925000,d=VHF CH66 RX
f=156325000,d=VHF CH66 TX
f=156375000,d=VHF CH67 RX
f=156375000,d=VHF CH67 TX
f=156425000,d=VHF CH68 RX
f=156425000,d=VHF CH68 TX
f=156475000,d=VHF CH69 RX
f=156475000,d=VHF CH69 TX
f=156525000,d=VHF CH70 RX
f=156525000,d=VHF CH70 TX
f=156575000,d=VHF CH71 RX
f=156575000,d=VHF CH71 TX
f=156625000,d=VHF CH72 RX
f=156625000,d=VHF CH72 TX
f=156675000,d=VHF CH73 RX
f=156675000,d=VHF CH73 TX
f=156725000,d=VHF CH74 RX
f=156725000,d=VHF CH74 TX
f=156775000,d=VHF CH75 RX
f=156775000,d=VHF CH75 TX
f=156825000,d=VHF CH76 RX
f=156825000,d=VHF CH76 TX
f=156875000,d=VHF CH77 RX
f=156875000,d=VHF CH77 TX
f=161525000,d=VHF CH78 RX
f=156925000,d=VHF CH78 TX
f=161575000,d=VHF CH79 RX
f=156975000,d=VHF CH79 TX
f=161625000,d=VHF CH80 RX
f=157025000,d=VHF CH80 TX
f=161675000,d=VHF CH81 RX
f=157075000,d=VHF CH81 TX
f=161725000,d=VHF CH82 RX
f=157125000,d=VHF CH82 TX
f=161775000,d=VHF CH83 RX
f=157175000,d=VHF CH83 TX
f=161825000,d=VHF CH84 RX
f=157225000,d=VHF CH84 TX
f=161875000,d=VHF CH85 RX
f=157275000,d=VHF CH85 TX
f=161925000,d=VHF CH86 RX
f=157325000,d=VHF CH86 TX
f=157375000,d=VHF CH87 RX
f=157375000,d=VHF CH87 TX
f=157425000,d=VHF CH88 RX
f=157425000,d=VHF CH88 TX
+11
View File
@@ -0,0 +1,11 @@
# INI,END,DESCRIPTION
# (Freq range in MHz, min separation 240MHz)
# (Description up to 20 char)
# (fields comma delimiter)
260,500,315/433 MHz KEYFOBS
2320,2560,BL / WIFI 2.4GHz
5160,5900,WIFI 5GHz
10,7250,FULL RANGE
140,380,VHF MICS AND MARINE
390,420,RADIOSONDES
420,660,UHF MICS