Compare commits

..

13 Commits

Author SHA1 Message Date
jLynx 215ad4fd4c 1.7.1 (#1037)
* Update past_version.txt

* Update version.txt
2023-05-22 21:21:47 +12:00
Erwin Ried 7150d95a98 cleanup (#1036) 2023-05-22 21:14:35 +12:00
gullradriel 80636c53da fix CONFIG not working if nothing changed and got less flickering by separating text output (#1034)
-fix CONFIG dysfunction if nothing had changed: this was a reminiscence of the nothread conversion
-addressed screen flickering: reduced it by separating two text output
-variables: took out unneeded userpause (reminiscence of the nothread conversion)
-solved problem with manual range not updating description on consecutive clicks
-solved problem with direction changing on 'UNLOCK/SKIPLCK'
2023-05-22 10:49:07 +02:00
jLynx 874d3c251c Update dfu_hackrf_one.bat (#1032) 2023-05-22 13:03:53 +12:00
Kyle Reed 6c541af0fd Move tests, add applicaiton tests. (#1031)
Co-authored-by: kallanreed <kallanreed@outlook.com>
2023-05-21 17:33:12 -07:00
Mark Thompson 4d1269051b Fixed debounce code to handle noisy switch transitions #989 (#1030)
* Fix debounce to handle noisy switch transitions

* Fix debounce to handle noisy switch transitions

* Fix debounce to handle noisy switch transitions

* Removed inline comment to see if Clang checker will be happy

* Test fix for supposed Clang formatting issue
2023-05-22 12:06:37 +12:00
gullradriel be1b2716d6 freq correct unit fix (#1029)
* fix units for frequency offset. It was planned to be a uint32_t since a uint16_t is obviously too short
* took the uint32_t limitation for frequency offset in account
2023-05-21 23:47:02 +02:00
Bernd Herzog 34d46a9d5d added first unit test (#1027)
* added first unit test

* improved unit test names
2023-05-21 23:08:24 +02:00
gullradriel cac3a7cf1e Settings directory fix in Level and Recon (#1028)
* removed unneeded sdcard check and directory creation
* changed settings so they use SETTINGS and a better name. Code beautication
2023-05-21 22:31:03 +02:00
gullradriel 0e86e63e97 Fixing colorisation of wait/lockwait fields (#1026)
* Fixing colorisation of wait/lockwait field
2023-05-21 20:42:54 +02:00
gullradriel c0ff5715de fixing bad range for lock field (#1024)
* fixing bad range for lock field
2023-05-21 09:11:58 +02:00
gullradriel 24ce1b9893 fixed bad copy paste from #1016, thanks @notherngineer (#1023)
fixed bad copy paste from #1016
2023-05-21 08:59:42 +02:00
jLynx edd8e7c3b9 Automatically add world map to SD card files (#1022)
* Testing

* Updated scripts

* Updated removed testing file
2023-05-21 18:42:38 +12:00
32 changed files with 8000 additions and 191 deletions
@@ -47,6 +47,12 @@ jobs:
run: mkdir ${{ github.workspace }}/build
- name: Run the Docker image
run: docker run -e VERSION_STRING=${{ steps.version_date.outputs.date }} -i -v ${{ github.workspace }}:/havoc portapack-dev
- name: Download world map
run: |
wget https://github.com/eried/portapack-mayhem/releases/download/world_map/world_map.zip
- name: Unzip world map
run: |
unzip world_map.zip -d sdcard/ADSB
- name: Create Firmware ZIP
run: |
zip -j firmware.zip build/firmware/portapack-h1_h2-mayhem.bin && cd flashing && zip -r ../firmware.zip *
@@ -31,6 +31,12 @@ jobs:
run: mkdir ${{ github.workspace }}/build
- name: Run the Docker image
run: docker run -e VERSION_STRING=${{ steps.version.outputs.version }} -i -v ${{ github.workspace }}:/havoc portapack-dev
- name: Download world map
run: |
wget https://github.com/eried/portapack-mayhem/releases/download/world_map/world_map.zip
- name: Unzip world map
run: |
unzip world_map.zip -d sdcard/ADSB
- name: Create Firmware ZIP
run: |
zip -j firmware.zip build/firmware/portapack-h1_h2-mayhem.bin && cd flashing && zip -r ../firmware.zip *
+1 -1
View File
@@ -1 +1 @@
v1.6.0
v1.7.0
+1 -1
View File
@@ -1 +1 @@
v1.7.0
v1.7.1
+2 -1
View File
@@ -18,7 +18,7 @@
# Boston, MA 02110-1301, USA.
#
cmake_minimum_required(VERSION 2.8.9)
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0005 NEW)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/firmware/toolchain-arm-cortex-m.cmake)
@@ -58,4 +58,5 @@ set(HACKRF_CPLD_XSVF_PATH ${HACKRF_PATH}/firmware/cpld/sgpio_if/${HACKRF_CPLD_XS
set(HACKRF_FIRMWARE_DFU_IMAGE ${hackrf_usb_BINARY_DIR}/${HACKRF_FIRMWARE_DFU_FILENAME})
set(HACKRF_FIRMWARE_BIN_IMAGE ${hackrf_usb_BINARY_DIR}/${HACKRF_FIRMWARE_BIN_FILENAME})
enable_testing()
add_subdirectory(firmware)
+6 -6
View File
@@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -290,8 +290,8 @@ to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
@@ -329,11 +329,11 @@ necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
Public License instead of this License.
-7
View File
@@ -1,7 +0,0 @@
# License
Portapack Mayhem is distributed under [GPL v3.0](LICENSE), however some sub projects might have different (GPL v3.0 compatible) licenses.
## Other Licenses (compatible with GPL v3.0)
- Most of Portapack Mayhem is distributed under GPL-2.0-or-later. [license](LICENSE.GPL-2.0-or-later)
- ChibiOS is distributed under GPL v3.0. [license](/firmware/chibios/license.txt)
- Portapack-ChibiOS is distributed under Apache-2.0 [license](http://www.apache.org/licenses/LICENSE-2.0)
+1
View File
@@ -35,6 +35,7 @@ set(FIRMWARE_FILENAME ${FIRMWARE_NAME}.bin)
add_subdirectory(application)
add_subdirectory(baseband)
add_subdirectory(test)
# NOTE: Dependencies break if the .bin files aren't included in DEPENDS. WTF, CMake?
add_custom_command(
+6 -18
View File
@@ -29,10 +29,6 @@ using portapack::memory::map::backup_ram;
namespace ui {
bool LevelView::check_sd_card() {
return (sd_card::status() == sd_card::Status::Mounted) ? true : false;
}
void LevelView::focus() {
button_frequency.focus();
}
@@ -74,12 +70,6 @@ LevelView::LevelView(NavigationView& nav)
field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); };
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
// Level directory
if (check_sd_card()) { // Check to see if SD Card is mounted
make_new_directory(u"/LEVEL");
sd_card_mounted = true;
}
change_mode(NFM_MODULATION); // Start on AM
field_mode.set_by_value(NFM_MODULATION); // Reflect the mode into the manual selector
@@ -89,14 +79,12 @@ LevelView::LevelView(NavigationView& nav)
button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>");
// load auto common app settings
if (sd_card_mounted) {
auto rc = settings.load("level", &app_settings);
if (rc == SETTINGS_OK) {
field_lna.set_value(app_settings.lna);
field_vga.set_value(app_settings.vga);
field_rf_amp.set_value(app_settings.rx_amp);
receiver_model.set_rf_amp(app_settings.rx_amp);
}
auto rc = settings.load("level", &app_settings);
if (rc == SETTINGS_OK) {
field_lna.set_value(app_settings.lna);
field_vga.set_value(app_settings.vga);
field_rf_amp.set_value(app_settings.rx_amp);
receiver_model.set_rf_amp(app_settings.rx_amp);
}
button_frequency.on_select = [this, &nav](ButtonWithEncoder& button) {
-2
View File
@@ -97,11 +97,9 @@ class LevelView : public View {
size_t change_mode(freqman_index_t mod_type);
void on_statistics_update(const ChannelStatistics& statistics);
void set_display_freq(int64_t freq);
bool check_sd_card();
int32_t db{0};
long long int MAX_UFREQ = {7200000000}; // maximum usable freq
bool sd_card_mounted = false;
rf::Frequency freq = {0};
Labels labels{
+104 -107
View File
@@ -29,7 +29,30 @@ using portapack::memory::map::backup_ram;
namespace ui {
bool ReconView::ReconSaveFreq(const std::string& freq_file_path, size_t freq_index, bool warn_if_exists) {
void ReconView::colorize_waits() {
// colorize wait on match
if (wait == 0) {
field_wait.set_style(&style_blue);
} else if (wait >= 500) {
field_wait.set_style(&style_white);
} else if (wait > -500 && wait < 500) {
field_wait.set_style(&style_red);
} else if (wait <= -500) {
field_wait.set_style(&style_green);
}
// colorize lock time if in SPARSE mode as in continuous the lock_wait time is disarmed at first lock count
if (recon_match_mode == RECON_MATCH_SPARSE) {
if ((recon_lock_duration / STATS_UPDATE_INTERVAL) <= recon_lock_nb_match) {
field_lock_wait.set_style(&style_yellow);
} else {
field_lock_wait.set_style(&style_white);
}
} else {
field_lock_wait.set_style(&style_white);
}
}
bool ReconView::recon_save_freq(const std::string& freq_file_path, size_t freq_index, bool warn_if_exists) {
File recon_file;
if (frequency_list.size() == 0 || (frequency_list.size() && current_index > (int32_t)frequency_list.size()))
@@ -81,7 +104,7 @@ bool ReconView::ReconSaveFreq(const std::string& freq_file_path, size_t freq_ind
return true;
}
bool ReconView::ReconSetupLoadStrings(const 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, int32_t& volume) {
bool ReconView::recon_load_config_from_sd() {
File settings_file;
size_t length, file_position = 0;
char* pos;
@@ -93,39 +116,37 @@ bool ReconView::ReconSetupLoadStrings(const std::string& source, std::string& in
uint32_t nb_params = RECON_SETTINGS_NB_PARAMS;
std::string params[RECON_SETTINGS_NB_PARAMS];
bool check_sd_card = (sd_card::status() == sd_card::Status::Mounted) ? true : false;
make_new_directory(u"SETTINGS");
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;
auto result = settings_file.open(RECON_CFG_FILE);
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;
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 (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);
}
}
@@ -135,7 +156,7 @@ bool ReconView::ReconSetupLoadStrings(const std::string& source, std::string& in
output_file = "RECON_RESULTS";
recon_lock_duration = RECON_MIN_LOCK_DURATION;
recon_lock_nb_match = RECON_DEF_NB_MATCH;
recon_squelch_level = -14;
squelch = -14;
recon_match_mode = RECON_MATCH_CONTINUOUS;
wait = RECON_DEF_WAIT_DURATION;
volume = 40;
@@ -163,9 +184,9 @@ bool ReconView::ReconSetupLoadStrings(const std::string& source, std::string& in
recon_lock_nb_match = RECON_DEF_NB_MATCH;
if (it > 4)
recon_squelch_level = strtoll(params[4].c_str(), nullptr, 10);
squelch = strtoll(params[4].c_str(), nullptr, 10);
else
recon_squelch_level = -14;
squelch = -14;
if (it > 5)
recon_match_mode = strtoll(params[5].c_str(), nullptr, 10);
@@ -185,17 +206,19 @@ bool ReconView::ReconSetupLoadStrings(const std::string& source, std::string& in
return true;
}
bool ReconView::ReconSetupSaveStrings(const std::string& dest, const std::string& input_file, const 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, int32_t volume) {
bool ReconView::recon_save_config_to_sd() {
File settings_file;
auto result = settings_file.create(dest);
make_new_directory(u"SETTINGS");
auto result = settings_file.create(RECON_CFG_FILE);
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_int(squelch));
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_int(volume));
@@ -207,10 +230,6 @@ void ReconView::audio_output_start() {
this->on_headphone_volume_changed((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
}
bool ReconView::check_sd_card() {
return (sd_card::status() == sd_card::Status::Mounted) ? true : false;
}
void ReconView::recon_redraw() {
if (last_rssi_min != rssi.get_min() || last_rssi_med != rssi.get_avg() || last_rssi_max != rssi.get_max()) {
last_rssi_min = rssi.get_min();
@@ -220,18 +239,16 @@ void ReconView::recon_redraw() {
}
if (last_entry.frequency_a != freq) {
last_entry.frequency_a = freq;
big_display.set("FREQ: " + to_string_short_freq(freq) + " MHz");
big_display.set("FREQ:" + to_string_short_freq(freq) + " MHz");
}
if (last_db != db || last_list_size != frequency_list.size() || last_freq_lock != freq_lock || last_nb_match != recon_lock_nb_match) {
last_freq_lock = freq;
last_list_size = frequency_list.size();
last_db = db;
if (last_nb_match != recon_lock_nb_match || last_freq_lock != freq_lock) {
last_freq_lock = freq_lock;
last_nb_match = recon_lock_nb_match;
text_max.set("/" + to_string_dec_uint(frequency_list.size()) + " " + to_string_dec_int(db) + " db " + to_string_dec_uint(freq_lock) + "/" + to_string_dec_uint(recon_lock_nb_match));
text_nb_locks.set(to_string_dec_uint(freq_lock) + "/" + to_string_dec_uint(recon_lock_nb_match));
if (freq_lock == 0) {
// NO FREQ LOCK, ONGOING STANDARD SCANNING
big_display.set_style(&style_white);
if (!userpause)
if (recon)
button_pause.set_text("<PAUSE>");
else
button_pause.set_text("<RESUME>");
@@ -242,13 +259,17 @@ void ReconView::recon_redraw() {
} else if (freq_lock >= recon_lock_nb_match) {
big_display.set_style(&style_green);
button_pause.set_text("<UNLOCK>");
// FREQ IS STRONG: GREEN and recon will pause when on_statistics_update()
if ((!scanner_mode) && autosave && frequency_list.size() > 0) {
ReconSaveFreq(freq_file_path, current_index, false);
recon_save_freq(freq_file_path, current_index, false);
}
}
}
if (last_db != db || last_list_size != frequency_list.size()) {
last_list_size = frequency_list.size();
last_db = db;
text_max.set("/" + to_string_dec_uint(frequency_list.size()) + " " + to_string_dec_int(db) + " db");
}
}
void ReconView::handle_retune() {
@@ -286,7 +307,7 @@ void ReconView::handle_retune() {
if (last_index != current_index) {
last_index = current_index;
if ((int32_t)frequency_list.size() && current_index < (int32_t)frequency_list.size() && frequency_list[current_index].type == RANGE) {
if (update_ranges) {
if (update_ranges && !manual_mode) {
button_manual_start.set_text(to_string_short_freq(frequency_list[current_index].frequency_a));
frequency_range.min = frequency_list[current_index].frequency_a;
if (frequency_list[current_index].frequency_b != 0) {
@@ -324,9 +345,9 @@ void ReconView::focus() {
}
ReconView::~ReconView() {
ReconSetupSaveStrings("RECON/RECON.CFG", input_file, output_file, recon_lock_duration, recon_lock_nb_match, squelch, recon_match_mode, wait, field_volume.value());
// save app settings
// save app config
recon_save_config_to_sd();
// save app common settings
settings.save("recon", &app_settings);
audio::output::stop();
@@ -352,6 +373,7 @@ ReconView::ReconView(NavigationView& nav)
&rssi,
&text_cycle,
&text_max,
&text_nb_locks,
&desc_cycle,
&big_display,
&freq_stats,
@@ -370,11 +392,6 @@ ReconView::ReconView(NavigationView& nav)
&button_mic_app,
&button_remove});
// Recon directory
if (check_sd_card()) { // Check to see if SD Card is mounted
make_new_directory(u"/RECON");
sd_card_mounted = true;
}
def_step = 0;
// HELPER: Pre-setting a manual range, based on stored frequency
rf::Frequency stored_freq = persistent_memory::tuned_frequency();
@@ -398,7 +415,6 @@ ReconView::ReconView(NavigationView& nav)
load_ranges = persistent_memory::recon_load_ranges();
load_hamradios = persistent_memory::recon_load_hamradios();
update_ranges = persistent_memory::recon_update_ranges_when_recon();
field_volume.set_value(volume);
if (sd_card_mounted) {
// load auto common app settings
@@ -495,7 +511,7 @@ ReconView::ReconView(NavigationView& nav)
}
button_pause.set_text("<PAUSE>"); // Show button for non continuous stop
} else {
if (userpause) {
if (!recon) {
recon_resume();
} else {
recon_pause();
@@ -640,7 +656,6 @@ ReconView::ReconView(NavigationView& nav)
scanner_mode = false;
manual_mode = true;
recon_pause();
if (!frequency_range.min || !frequency_range.max) {
nav_.display_modal("Error", "Both START and END freqs\nneed a value");
} else if (frequency_range.min > frequency_range.max) {
@@ -655,10 +670,10 @@ ReconView::ReconView(NavigationView& nav)
manual_freq_entry.type = RANGE;
manual_freq_entry.description =
"R " + to_string_short_freq(frequency_range.min) + ">" + to_string_short_freq(frequency_range.max) + " S" // current Manual range
+ to_string_short_freq(freqman_entry_get_step_value(def_step)).erase(0, 1); // euquiq: lame kludge to reduce spacing in step freq
manual_freq_entry.frequency_a = frequency_range.min; // min range val
manual_freq_entry.frequency_b = frequency_range.max; // max range val
to_string_short_freq(frequency_range.min).erase(0, 1) + ">" + to_string_short_freq(frequency_range.max).erase(0, 1) + " S:" // current Manual range
+ freqman_entry_get_step_string_short(def_step); // euquiq: lame kludge to reduce spacing in step freq
manual_freq_entry.frequency_a = frequency_range.min; // min range val
manual_freq_entry.frequency_b = frequency_range.max; // max range val
manual_freq_entry.modulation = -1;
manual_freq_entry.bandwidth = -1;
manual_freq_entry.step = def_step;
@@ -677,7 +692,11 @@ ReconView::ReconView(NavigationView& nav)
file_name.set_style(&style_white);
file_name.set("MANUAL RANGE RECON");
desc_cycle.set_style(&style_white);
desc_cycle.set("MANUAL RANGE RECON");
last_entry.modulation = -1;
last_entry.bandwidth = -1;
last_entry.step = -1;
last_index = -1;
current_index = 0;
freq = manual_freq_entry.frequency_a;
@@ -696,7 +715,7 @@ ReconView::ReconView(NavigationView& nav)
button_dir.set_text("FW>");
}
timer = 0;
if (userpause)
if (!recon)
recon_resume();
};
@@ -724,7 +743,7 @@ ReconView::ReconView(NavigationView& nav)
button_add.on_select = [this](ButtonWithEncoder&) { // frequency_list[current_index]
if (!scanner_mode) {
ReconSaveFreq(freq_file_path, current_index, true);
recon_save_freq(freq_file_path, current_index, true);
}
};
@@ -754,9 +773,6 @@ ReconView::ReconView(NavigationView& nav)
button_recon_setup.on_select = [this, &nav](Button&) {
audio::output::stop();
frequency_list.clear();
auto open_view = nav.push<ReconSetupView>(input_file, output_file, recon_lock_duration, recon_lock_nb_match, recon_match_mode);
open_view->on_changed = [this](std::vector<std::string> result) {
input_file = result[0];
@@ -765,8 +781,7 @@ ReconView::ReconView(NavigationView& nav)
recon_lock_duration = strtol(result[2].c_str(), nullptr, 10);
recon_lock_nb_match = strtol(result[3].c_str(), nullptr, 10);
recon_match_mode = strtol(result[4].c_str(), nullptr, 10);
ReconSetupSaveStrings("RECON/RECON.CFG", input_file, output_file, recon_lock_duration, recon_lock_nb_match, squelch, recon_match_mode, wait, field_volume.value());
recon_save_config_to_sd();
autosave = persistent_memory::recon_autosave_freqs();
autostart = persistent_memory::recon_autostart_recon();
@@ -775,48 +790,30 @@ ReconView::ReconView(NavigationView& nav)
load_freqs = persistent_memory::recon_load_freqs();
load_ranges = persistent_memory::recon_load_ranges();
load_hamradios = persistent_memory::recon_load_hamradios();
update_ranges = persistent_memory::recon_update_ranges_when_recon();
field_wait.set_value(wait);
field_lock_wait.set_value(recon_lock_duration);
colorize_waits();
frequency_file_load(false);
if (autostart) {
recon_resume();
} else {
recon_pause();
}
if (userpause != true) {
recon_resume();
}
};
};
field_wait.on_change = [this](int32_t v) {
wait = v;
if (wait == 0) {
field_wait.set_style(&style_blue);
} else if (wait >= 500) {
field_wait.set_style(&style_white);
} else if (wait > -500 && wait < 500) {
field_wait.set_style(&style_red);
} else if (wait <= -500) {
field_wait.set_style(&style_green);
}
colorize_waits();
};
field_lock_wait.on_change = [this](uint32_t v) {
recon_lock_duration = v;
if (recon_match_mode == RECON_MATCH_CONTINUOUS) {
if ((v / STATS_UPDATE_INTERVAL) > recon_lock_nb_match) {
field_lock_wait.set_style(&style_white);
} else if ((v / STATS_UPDATE_INTERVAL) == recon_lock_nb_match) {
field_lock_wait.set_style(&style_yellow);
}
} else // RECON_MATCH_SPARSE
{
field_lock_wait.set_style(&style_white);
}
colorize_waits();
};
field_squelch.on_change = [this](int32_t v) {
@@ -833,12 +830,14 @@ ReconView::ReconView(NavigationView& nav)
file_name.set("=>");
// Loading input and output file from settings
ReconSetupLoadStrings("RECON/RECON.CFG", input_file, output_file, recon_lock_duration, recon_lock_nb_match, squelch, recon_match_mode, wait, volume);
recon_load_config_from_sd();
freq_file_path = "/FREQMAN/" + output_file + ".TXT";
field_squelch.set_value(squelch);
field_wait.set_value(wait);
field_lock_wait.set_value(recon_lock_duration);
colorize_waits();
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
// fill modulation and step options
@@ -860,7 +859,6 @@ ReconView::ReconView(NavigationView& nav)
} else {
recon_pause();
}
recon_redraw();
}
@@ -958,7 +956,7 @@ void ReconView::frequency_file_load(bool stop_all_before) {
break;
}
text_cycle.set_text(to_string_dec_uint(current_index + 1, 3));
if (update_ranges) {
if (update_ranges && !manual_mode) {
button_manual_start.set_text(to_string_short_freq(frequency_list[current_index].frequency_a));
frequency_range.min = frequency_list[current_index].frequency_a;
if (frequency_list[current_index].frequency_b != 0) {
@@ -978,7 +976,7 @@ void ReconView::frequency_file_load(bool stop_all_before) {
void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
db = statistics.max_db;
if (!userpause) {
if (recon) {
if (!timer) {
status = 0;
continuous_lock = false;
@@ -1177,7 +1175,6 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
break;
}
}
// send a pause message with the right freq
if (has_looped && !continuous) {
recon_pause();
}
@@ -1195,7 +1192,6 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
void ReconView::recon_pause() {
timer = 0;
freq_lock = 0;
userpause = true;
continuous_lock = false;
recon = false;
@@ -1208,7 +1204,6 @@ void ReconView::recon_pause() {
void ReconView::recon_resume() {
timer = 0;
freq_lock = 0;
userpause = false;
continuous_lock = false;
recon = true;
@@ -1222,7 +1217,8 @@ void ReconView::on_index_delta(int32_t v) {
if (v > 0) {
fwd = true;
button_dir.set_text("FW>");
} else {
}
if (v < 0) {
fwd = false;
button_dir.set_text("<RW");
}
@@ -1237,7 +1233,8 @@ void ReconView::on_stepper_delta(int32_t v) {
if (v > 0) {
fwd = true;
button_dir.set_text("FW>");
} else {
}
if (v < 0) {
fwd = false;
button_dir.set_text("<RW");
}
+14 -7
View File
@@ -42,6 +42,8 @@
namespace ui {
#define RECON_CFG_FILE "SETTINGS/recon.cfg"
class ReconView : public View {
public:
ReconView(NavigationView& nav);
@@ -109,13 +111,13 @@ class ReconView : public View {
void on_headphone_volume_changed(int32_t v);
void on_index_delta(int32_t v);
void on_stepper_delta(int32_t v);
void colorize_waits();
void recon_redraw();
void handle_retune();
void handle_coded_squelch(const uint32_t value);
bool ReconSetupLoadStrings(const 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, int32_t& volume);
bool ReconSetupSaveStrings(const std::string& dest, const std::string& input_file, const 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, int32_t volume);
bool ReconSaveFreq(const std::string& freq_file_path, size_t index, bool warn_if_exists);
bool recon_load_config_from_sd();
bool recon_save_config_to_sd();
bool recon_save_freq(const std::string& freq_file_path, size_t index, bool warn_if_exists);
jammer::jammer_range_t frequency_range{false, 0, MAX_UFREQ}; // perfect for manual recon task too...
int32_t squelch{0};
int32_t db{0};
@@ -123,7 +125,6 @@ class ReconView : public View {
int32_t wait{RECON_DEF_WAIT_DURATION}; // in msec. if > 0 wait duration after a lock, if < 0 duration is set to 'wait' unless there is no more activity
freqman_db frequency_list = {};
int32_t current_index{0};
bool userpause{false};
bool continuous_lock{false};
std::string input_file = {"RECON"};
std::string output_file = {"RECON_RESULTS"};
@@ -227,15 +228,21 @@ class ReconView : public View {
};
RSSI rssi{
{0 * 16, 2 * 16, SCREEN_W - 8 * 8 + 4, 16},
{0 * 16, 2 * 16, SCREEN_W - 8 * 8 + 4, 14},
};
ButtonWithEncoder text_cycle{
{0, 3 * 16, 4 * 8, 16},
""};
// "/XXX -XXX db" => 12 chars max
Text text_max{
{4 * 8, 3 * 16, SCREEN_W - 7 * 8 - 4 * 8, 16},
{4 * 8, 3 * 16, 12 * 8, 16},
};
// "XX/XX" => 5 chars max
Text text_nb_locks{
{16 * 8, 3 * 16, 5 * 8, 16},
};
Text desc_cycle{
@@ -92,7 +92,7 @@ ReconSetupViewMain::ReconSetupViewMain(NavigationView& nav, Rect parent_rect, st
};
};
void ReconSetupViewMain::Save(std::string& input_file, std::string& 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());
@@ -100,7 +100,7 @@ void ReconSetupViewMain::Save(std::string& input_file, std::string& output_file)
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) {
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());
@@ -162,8 +162,8 @@ ReconSetupView::ReconSetupView(
&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);
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);
+19 -13
View File
@@ -66,7 +66,7 @@ namespace ui {
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 save(std::string& input_file, std::string& output_file);
void focus() override;
private:
@@ -111,7 +111,7 @@ class ReconSetupViewMore : public View {
public:
ReconSetupViewMore(NavigationView& nav, Rect parent_rect, uint32_t _recon_lock_duration, uint32_t _recon_lock_nb_match, uint32_t _recon_match_mode);
void Save(uint32_t& recon_lock_duration, uint32_t& recon_lock_nb_match, 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;
@@ -139,20 +139,20 @@ class ReconSetupViewMore : public View {
{1 * 8, 102},
3,
"auto update m-ranges"};
NumberField field_recon_lock_duration{
{1 * 8, 132}, // position X , Y
4, // number of displayed digits (even empty)
{STATS_UPDATE_INTERVAL, RECON_MAX_LOCK_DURATION}, // range of number
STATS_UPDATE_INTERVAL, // rotary encoder increment
' ', // filling character
false // can loop
};
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)
{-RECON_MAX_LOCK_DURATION, RECON_MAX_LOCK_DURATION}, // range of number
STATS_UPDATE_INTERVAL, // 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,
@@ -160,6 +160,11 @@ class ReconSetupViewMore : public View {
1,
' ',
false};
Text text_recon_lock_nb{
{1 * 8, 162, 25 * 8, 22},
" x (nb lock to match freq)"};
OptionsField field_recon_match_mode{
{1 * 8, 192},
20, // CONTINUOUS MATCH MODE / SPARSE TIMED MATCH MODE
@@ -195,6 +200,7 @@ class ReconSetupView : public View {
TabView tab_view{
{"Main", Color::cyan(), &viewMain},
{"More", Color::green(), &viewMore}};
Button button_save{
{9 * 8, 255, 14 * 8, 40},
"SAVE"};
+4 -4
View File
@@ -398,8 +398,8 @@ SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) {
button_freq_rx_correction.on_select = [this, &nav](Button& button) {
auto new_view = nav.push<FrequencyKeypadView>(portapack::persistent_memory::config_converter_freq());
new_view->on_changed = [this, &button](rf::Frequency f) {
if (f > 4000000)
f = 4000000;
if (f >= MAX_FREQ_CORRECTION)
f = MAX_FREQ_CORRECTION;
portapack::persistent_memory::set_config_freq_rx_correction(f);
// Retune to take converter change in account
receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
@@ -411,8 +411,8 @@ SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) {
button_freq_tx_correction.on_select = [this, &nav](Button& button) {
auto new_view = nav.push<FrequencyKeypadView>(portapack::persistent_memory::config_converter_freq());
new_view->on_changed = [this, &button](rf::Frequency f) {
if (f > 4000000)
f = 4000000;
if (f >= MAX_FREQ_CORRECTION)
f = MAX_FREQ_CORRECTION;
portapack::persistent_memory::set_config_freq_tx_correction(f);
// Retune to take converter change in account
receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
@@ -33,6 +33,8 @@
namespace ui {
#define MAX_FREQ_CORRECTION 4294967295 // maximum possible for an uint32_t
struct SetDateTimeModel {
uint16_t year;
uint8_t month;
+15 -8
View File
@@ -23,17 +23,24 @@
#include "utility.hpp"
// Returns TRUE if button state changed (after debouncing)
bool Debounce::feed(const uint8_t bit) {
history_ = (history_ << 1) | (bit & 1);
if (history_ == 0b00001111) {
state_ = 1;
return true;
if (state_ == 0) {
// Previous button state was 0 (released);
// Has button been held for DEBOUNCE_COUNT ticks?
if ((history_ & DEBOUNCE_MASK) == DEBOUNCE_MASK) {
state_ = 1;
return true;
}
} else {
// Previous button state was 1 (pressed);
// Has button been released for DEBOUNCE_COUNT ticks?
if ((history_ & DEBOUNCE_MASK) == 0) {
state_ = 0;
return true;
}
}
if (history_ == 0b11110000) {
state_ = 0;
return true;
}
return false;
}
+4
View File
@@ -24,6 +24,10 @@
#include <cstdint>
// consecutive # of times button input must be same (<=8)
#define DEBOUNCE_COUNT 4
#define DEBOUNCE_MASK ((1 << DEBOUNCE_COUNT) - 1)
class Debounce {
public:
bool feed(const uint8_t bit);
+1 -1
View File
@@ -206,7 +206,7 @@ int32_t ReceiverModel::tuning_offset() {
}
void ReceiverModel::update_tuning_frequency() {
radio::set_tuning_frequency(persistent_memory::tuned_frequency());
radio::set_tuning_frequency(persistent_memory::tuned_frequency() + tuning_offset());
}
void ReceiverModel::update_antenna_bias() {
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -297,9 +297,9 @@ struct data_t {
int64_t converter_frequency_offset;
// frequency correction
int16_t frequency_rx_correction;
uint32_t frequency_rx_correction;
bool updown_frequency_rx_correction;
int16_t frequency_tx_correction;
uint32_t frequency_tx_correction;
bool updown_frequency_tx_correction;
constexpr data_t()
@@ -795,16 +795,16 @@ bool config_freq_rx_correction_updown() {
void set_freq_rx_correction_updown(bool v) {
data->updown_frequency_rx_correction = v;
}
int16_t config_freq_tx_correction() {
uint32_t config_freq_tx_correction() {
return data->frequency_tx_correction;
}
int16_t config_freq_rx_correction() {
uint32_t config_freq_rx_correction() {
return data->frequency_rx_correction;
}
void set_config_freq_tx_correction(uint16_t v) {
void set_config_freq_tx_correction(uint32_t v) {
data->frequency_tx_correction = v;
}
void set_config_freq_rx_correction(uint16_t v) {
void set_config_freq_rx_correction(uint32_t v) {
data->frequency_rx_correction = v;
}
@@ -189,10 +189,10 @@ bool config_freq_tx_correction_updown();
void set_freq_tx_correction_updown(bool v);
bool config_freq_rx_correction_updown();
void set_freq_rx_correction_updown(bool v);
int16_t config_freq_tx_correction();
int16_t config_freq_rx_correction();
void set_config_freq_tx_correction(uint16_t v);
void set_config_freq_rx_correction(uint16_t v);
uint32_t config_freq_tx_correction();
uint32_t config_freq_rx_correction();
void set_config_freq_tx_correction(uint32_t v);
void set_config_freq_rx_correction(uint32_t v);
void set_clock_hidden(bool v);
void set_clock_with_date(bool v);
void set_config_login(bool v);
+30
View File
@@ -0,0 +1,30 @@
# Copyright (C) 2023 Bernd Herzog, Kyle Reed
#
# 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.
#
project(tests)
set(DOCTESTINC ${PROJECT_SOURCE_DIR}/include)
enable_testing()
add_subdirectory(application)
add_subdirectory(baseband)
add_custom_target(build_tests)
add_dependencies(build_tests application_test baseband_test)
+70
View File
@@ -0,0 +1,70 @@
# Copyright (C) 2023 Bernd Herzog, Kyle Reed
#
# 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.
#
project(application_test)
enable_language(C CXX ASM)
include(${CHIBIOS_PORTAPACK}/boards/PORTAPACK_APPLICATION/board.cmake)
include(${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M0/platform.cmake)
include(${CHIBIOS}/os/hal/hal.cmake)
include(${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M0/port.cmake)
include(${CHIBIOS}/os/kernel/kernel.cmake)
include(${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs.cmake)
include(${CHIBIOS}/test/test.cmake)
set(CMAKE_CXX_COMPILER g++)
add_executable(application_test EXCLUDE_FROM_ALL
${PROJECT_SOURCE_DIR}/main.cpp
${PROJECT_SOURCE_DIR}/test_basics.cpp
${PROJECT_SOURCE_DIR}/test_optional.cpp
)
target_include_directories(application_test PRIVATE
${DOCTESTINC}
${COMMON}
${PORTINC}
${KERNINC}
${TESTINC}
${HALINC}
${PLATFORMINC}
${BOARDINC}
${CHIBIOS}/os/various
${BASEBAND}
)
target_compile_options(application_test PRIVATE
-DLPC43XX
-DLPC43XX_M0
-D__NEWLIB__
-DHACKRF_ONE
-DTOOLCHAIN_GCC
-DTOOLCHAIN_GCC_ARM
-D_RANDOM_TCC=0
-DVERSION_STRING=\"${VERSION}\"
${USE_CPPOPT}
${USE_OPT}
${CPPWARN}
)
add_test(NAME application_test
COMMAND application_test
)
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* 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.
*/
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2023
*
* 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 "doctest.h"
TEST_CASE("Testing test framework") {
REQUIRE(1 == 1);
REQUIRE_FALSE(1 == 2);
}
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2023
*
* 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 "doctest.h"
#include "optional.hpp"
TEST_SUITE_BEGIN("optional");
TEST_CASE("Default instance should not be valid.") {
Optional<int> o;
REQUIRE_FALSE(o.is_valid());
}
TEST_CASE("Instance with value should be valid.") {
Optional<int> o{1};
REQUIRE(o.is_valid());
}
TEST_CASE("value() should return value.") {
Optional<int> o{1};
REQUIRE(o.value() == 1);
}
TEST_SUITE_END();
+66
View File
@@ -0,0 +1,66 @@
# Copyright (C) 2023 Bernd Herzog, Kyle Reed
#
# 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.
#
project(baseband_test)
enable_language(C CXX ASM)
include(${CHIBIOS_PORTAPACK}/boards/PORTAPACK_BASEBAND/board.cmake)
include(${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4/platform.cmake)
include(${CHIBIOS}/os/hal/hal.cmake)
include(${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M4/port.cmake)
include(${CHIBIOS}/os/kernel/kernel.cmake)
include(${CHIBIOS}/test/test.cmake)
set(CMAKE_CXX_COMPILER g++)
add_executable(baseband_test EXCLUDE_FROM_ALL
${PROJECT_SOURCE_DIR}/main.cpp
${PROJECT_SOURCE_DIR}/dsp_fft_test.cpp
${COMMON}/dsp_fft.cpp
)
target_include_directories(baseband_test PRIVATE
${DOCTESTINC}
${COMMON}
${PORTINC}
${KERNINC}
${TESTINC}
${HALINC}
${PLATFORMINC}
${BOARDINC}
${CHIBIOS}/os/various
${BASEBAND}
)
target_compile_options(baseband_test PRIVATE
-DLPC43XX
-DLPC43XX_M4
-D__NEWLIB__
-DHACKRF_ONE
-DTOOLCHAIN_GCC
-DTOOLCHAIN_GCC_ARM
-D_RANDOM_TCC=0
-DVERSION_STRING=\"${VERSION}\"
)
add_test(NAME baseband_test
COMMAND baseband_test
)
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* 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 "dsp_fft.hpp"
#include "doctest.h"
TEST_CASE("ifft successfully calculates dc on zero frequency") {
uint32_t fft_width = 8;
complex16_t* v = new complex16_t[fft_width];
complex16_t* tmp = new complex16_t[fft_width];
v[0] = {1024, 0}; // DC bin
v[1] = {0, 0};
v[2] = {0, 0};
v[3] = {0, 0};
v[4] = {0, 0};
v[5] = {0, 0};
v[6] = {0, 0};
v[7] = {0, 0};
ifft<complex16_t>(v, fft_width, tmp);
CHECK(v[0].real() == 1024);
CHECK(v[1].real() == 1024);
CHECK(v[2].real() == 1024);
CHECK(v[3].real() == 1024);
CHECK(v[4].real() == 1024);
CHECK(v[5].real() == 1024);
CHECK(v[6].real() == 1024);
CHECK(v[7].real() == 1024);
for (uint32_t i = 0; i < fft_width; i++)
CHECK(v[i].imag() == 0);
free(v);
free(tmp);
}
TEST_CASE("ifft successfully calculates pure sine of half the sample rate") {
uint32_t fft_width = 8;
complex16_t* v = new complex16_t[fft_width];
complex16_t* tmp = new complex16_t[fft_width];
v[0] = {0, 0};
v[1] = {0, 0};
v[2] = {0, 0};
v[3] = {0, 0};
v[4] = {1024, 0}; // sample rate /2 bin
v[5] = {0, 0};
v[6] = {0, 0};
v[7] = {0, 0};
ifft<complex16_t>(v, fft_width, tmp);
CHECK(v[0].real() == 1024);
CHECK(v[1].real() == -1024);
CHECK(v[2].real() == 1024);
CHECK(v[3].real() == -1024);
CHECK(v[4].real() == 1024);
CHECK(v[5].real() == -1024);
CHECK(v[6].real() == 1024);
CHECK(v[7].real() == -1024);
for (uint32_t i = 0; i < fft_width; i++)
CHECK(v[i].imag() == 0);
free(v);
free(tmp);
}
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* 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.
*/
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -14,6 +14,6 @@ echo.
pause
echo.
dfu-util-static.exe --device 1fc9:000c --download hackrf_one_usb.dfu --reset
"utils/dfu-util-static.exe" --device 1fc9:000c --download "utils/hackrf_one_usb.dfu" --reset
echo.
pause