Compare commits

...

9 Commits

Author SHA1 Message Date
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
26 changed files with 7751 additions and 140 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 *
+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)
+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{
+74 -75
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();
@@ -245,7 +264,7 @@ void ReconView::recon_redraw() {
// 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);
}
}
}
@@ -324,9 +343,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();
@@ -370,11 +389,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 +412,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
@@ -724,7 +737,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);
}
};
@@ -766,7 +779,7 @@ ReconView::ReconView(NavigationView& nav)
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();
@@ -778,7 +791,9 @@ ReconView::ReconView(NavigationView& nav)
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) {
@@ -794,29 +809,12 @@ ReconView::ReconView(NavigationView& nav)
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 +831,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 +860,6 @@ ReconView::ReconView(NavigationView& nav)
} else {
recon_pause();
}
recon_redraw();
}
+6 -4
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};
@@ -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() {
@@ -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