Compare commits

...

105 Commits

Author SHA1 Message Date
gullradriel 0e5ae7a6a4 Merge pull request #871 from Brumi-2021/Add_tick_box_sel_common_RX_TX_freq_to_MIC_APP
Add Separated/common freq control in Mic App
2023-04-04 18:53:43 +02:00
Brumi-2021 c867f98117 Add Separated/common freq control in Mic App 2023-04-04 17:26:45 +02:00
gullradriel 54eebedc1f Merge pull request #869 from NotherNgineer/next
#868 TPMS app displays incorrect readings for Type 5 sensors
2023-04-04 07:37:05 +02:00
Mark Thompson 35db368527 Update tpms_packet.cpp 2023-04-03 16:40:07 -05:00
Mark Thompson be691fd278 Fixed TPMS type 5 sensor readings
Fixed issue with temperature & pressure values for OOK-8400-Schrader TPMS sensor type 5 (temperature & pressure were swapped and using wrong conversion ratio).  Tested fix against 14 sensors of this type.
2023-04-03 15:36:10 -05:00
gullradriel 3db3e78b44 Merge pull request #866 from gullradriel/recon-gui-update
Recon gui update
2023-04-03 12:49:22 +02:00
GullCode a48ecccd7d widget size and position adjustement to avoid overlap, changed OPT in favor of CONFIG and gave all the side buttons the same size 2023-04-03 12:46:59 +02:00
GullCode 570775552c fixed peak that was drawing after the rssi widget 2023-04-03 12:45:35 +02:00
gullradriel ecbb232d9c Merge pull request #864 from bernd-herzog/ssd_to_usb
Ssd to usb
2023-04-01 19:58:02 +02:00
gullradriel 0e59e61461 Merge pull request #865 from gullradriel/recon-fix
fixing range frequencies and index skipping
2023-04-01 19:57:31 +02:00
GullCode 7da322f926 fixing range frequencies and index skipping 2023-04-01 19:56:44 +02:00
Bernd Herzog 04392752d1 fixed spelling error 2023-04-01 19:38:38 +02:00
Bernd Herzog db5fcaba44 Merge remote-tracking branch 'origin/next' into ssd_to_usb 2023-04-01 19:24:53 +02:00
Bernd Herzog a8f0c8eac9 refactoring 2023-04-01 19:24:13 +02:00
Bernd Herzog 6fadd70c1d updated ui 2023-04-01 19:16:01 +02:00
Bernd Herzog 8d8d457da2 refactoring 2023-04-01 18:57:53 +02:00
Bernd Herzog 893df7272f refactoring 2023-04-01 18:36:57 +02:00
Bernd Herzog bb90fdc5fc Implemented write 2023-04-01 17:39:08 +02:00
Bernd Herzog 50859171f4 implemented msd read 2023-04-01 17:21:57 +02:00
Bernd Herzog fc1b676ce6 implemented rest of scsi stack 2023-03-31 22:34:55 +02:00
Bernd Herzog 776ac652a8 implemented scsi inquiry 2023-03-31 19:18:39 +02:00
gullradriel c9c438824d Merge pull request #860 from gullradriel/load-save-persistent-memory
Load save persistent memory
2023-03-31 18:25:10 +02:00
GullCode 95eb1e6d59 Loading pmem if enable before displaying splashscreen 2023-03-31 14:24:54 +02:00
GullCode 1f32367495 reset to original since loading is now taking place in navigation 2023-03-31 14:24:29 +02:00
GullCode 0ed5e6542e P.Mem settings menu entry 2023-03-31 14:06:22 +02:00
GullCode 7240d45a4f added on green sdcard load persistent settings 2023-03-31 14:05:49 +02:00
GullCode 17250304e0 indentation & added load & save persistent settings to sdcard 2023-03-31 14:05:33 +02:00
GullCode 835bc49999 Working pmem load flag checkbox 2023-03-30 17:40:17 +02:00
Bernd Herzog a6eb430830 integrated usb stack 2023-03-30 11:46:36 +02:00
Bernd Herzog 8dd68a0811 added copy of hackrf usb stack 2023-03-29 17:05:11 +02:00
Erwin Ried 9540776afd Merge pull request #855 from bernd-herzog/flash_utility
Add new App: flash utility
2023-03-28 15:41:43 +02:00
Bernd Herzog f5d4fce945 added flash utility 2023-03-28 14:39:00 +02:00
gullradriel 8840a6e894 Merge pull request #844 from bernd-herzog/reduce_image_size_lz4
Reduce image size lz4
2023-03-28 07:35:51 +02:00
gullradriel 7ef98f7741 Merge pull request #854 from gullradriel/converter-fix-disable
Fix to force converter icon to be displayed if enabled
2023-03-27 23:06:32 +02:00
GullCode b41be47c9d pesky and non consistent indentation is boring 2023-03-27 23:05:46 +02:00
GullCode 1e2bc703b8 Fix to force converter icon to be displayed if enabled 2023-03-27 23:03:09 +02:00
Bernd Herzog 9115eadd17 added lz4 to dockerfile 2023-03-27 16:22:20 +02:00
gullradriel 05429d3d15 Merge pull request #853 from gullradriel/up-down-convert
Up Down Converter (replacement/update of previous HamItUp function)
2023-03-27 15:39:04 +02:00
GullCode 30c1f9f594 Changed hamitup to converter icons and functions 2023-03-27 14:22:35 +02:00
GullCode f994f8d697 changing logic to take 'up' or 'down' in account 2023-03-27 14:22:07 +02:00
GullCode e045628dab Menu entry for Converter, cleanings of Radio menu 2023-03-27 14:16:03 +02:00
GullCode 17cdb34fea added set of functions for up/down/enable/disable converter 2023-03-27 14:15:28 +02:00
GullCode 9df0f6e9df updated bitmap icons for converter 2023-03-27 14:14:53 +02:00
GullCode 54e4b535cc converters icons 2023-03-27 14:14:11 +02:00
gullradriel d6555a7af0 Merge pull request #852 from gullradriel/recon-minor-update
Recon minor update
2023-03-26 21:06:16 +02:00
GullCode 30004a1c3c cosmetic, ui moves 2023-03-26 21:04:43 +02:00
GullCode 8d60da0a5a updated description of entry / input output file 2023-03-26 15:30:54 +02:00
GullCode 17f30b6f26 Added and fixed go to index 2023-03-26 15:11:27 +02:00
GullCode 3d13ee828e changed text index to button, adding set to index and on_encoder, global indentation 2023-03-24 23:44:16 +01:00
Brumi-2021 9398b12093 Merge pull request #850 from KillerTurtleSoftware/patch-1
Corrected tone_key.cpp Motorola Code
2023-03-24 16:53:37 +01:00
Erwin Ried 61b82645f7 Update problem-upgrading-the-firmware.md 2023-03-24 12:50:54 +01:00
Erwin Ried c285084dcd Update bug_report.md 2023-03-24 12:49:18 +01:00
KillerTurtleSoftware e034c6e66e Corrected tone_key.cpp Motorola Code
Corrected Motorola Code on a few freqs.
2023-03-23 08:46:01 -05:00
gullradriel bb3ba29d22 Merge pull request #849 from gullradriel/level-rssi-minor-fix
Level rssi minor fix
2023-03-23 13:35:04 +01:00
GullCode ad11ab649e Changed default RSSI peak value 2023-03-23 13:34:15 +01:00
GullCode c76c6bd857 Changed default RSSI peak value, position and size of RSSI graph 2023-03-23 13:33:59 +01:00
GullCode 47b770bc3a Changed RSSIGraph drawing system 2023-03-23 13:33:22 +01:00
gullradriel dd8538b8bf Merge pull request #848 from gullradriel/rssi-peak-level-tune
Rssi peak level tune
2023-03-22 14:40:21 +01:00
GullCode 03c9b4aba7 fixed horizontal peak hold, adjusted horizontal and vertical size 2023-03-22 14:38:47 +01:00
GullCode 56526a5710 enabled 1s peak hold on rssi view 2023-03-22 14:38:00 +01:00
GullCode 2d9fe6cf8a Set 1s peak as default, set 32x resolution as default 2023-03-22 14:37:31 +01:00
gullradriel 4ec444688f Merge pull request #846 from gullradriel/audio_app_freq_fix
forcing input freq to be set in all cases
2023-03-22 11:42:15 +01:00
GullCode 2e4a86d7ec forcing input freq to be set in all cases 2023-03-22 11:39:00 +01:00
gullradriel 92b622deac Added HamItUp option (#840)
* Added HamItUp option to allow quick offset of the tuned frequency
* New HamItUp icon for top bar
* HamItUp checkbox status and frequency persistent settings in Settings/Radio
2023-03-22 08:46:58 +01:00
gullradriel 2457ba016f Merge pull request #845 from gullradriel/app-settings-update
Quoted restore frequency at start for audio app
2023-03-22 08:44:01 +01:00
GullCode 4a6c76cc47 Quoted restore frequency at start for a good interactions with other apps calling audio app 2023-03-21 22:45:49 +01:00
Bernd Herzog 7b4662fe4a fixed packing 2023-03-21 22:01:09 +01:00
Bernd Herzog 8fcedb017c fixed script 2023-03-21 21:31:59 +01:00
Bernd Herzog 7b3ab64930 fixed data packing 2023-03-21 21:27:32 +01:00
Bernd Herzog b856b047cc added compression of baseband images 2023-03-21 19:18:38 +01:00
gullradriel ce23c7d882 Merge pull request #841 from gullradriel/looking-glass-update
fixing width too tiny for calculation. It has to be a multiple of 240
2023-03-20 16:45:33 +01:00
GullCode 7eba8fd49b fixing width too tiny for calculation. It has to be a multiple of 240 2023-03-20 16:43:31 +01:00
gullradriel bfdf7660b6 Merge pull request #838 from bernd-herzog/error_handling
improved runtime error details in guru meditation
2023-03-19 08:40:25 +01:00
Bernd Herzog b83f43793c improved runtime error handling 2023-03-18 23:19:23 +01:00
Bernd Herzog ed1c2e1c03 Merge remote-tracking branch 'origin/next' into error_handling 2023-03-18 19:35:22 +01:00
Bernd Herzog caba16a549 Merge remote-tracking branch 'origin/next' into error_handling 2023-03-18 16:39:56 +01:00
gullradriel 5318542021 Merge pull request #836 from gullradriel/looking-glass-update
Looking glass update
2023-03-16 17:41:22 +01:00
GullCode 93f966bdcd Fixing 20MHz boudaries 2023-03-16 12:09:13 +01:00
GullCode 7b5f138dfb Fixing max<min case 2023-03-16 12:03:00 +01:00
GullCode 149cd755ca Restoring min step of 1, forcing 20Mhz minimum wide view 2023-03-16 11:56:24 +01:00
GullCode 63d0201b71 Fixing set freq and min step value 2023-03-16 11:32:26 +01:00
GullCode cf19408784 Merge branch 'next' of github.com:gullradriel/portapack-mayhem into looking-glass-update 2023-03-16 10:40:11 +01:00
gullradriel f882de5eff Merge pull request #835 from gullradriel/recon-update
Recon update
2023-03-16 10:36:24 +01:00
GullCode 49bda24079 added steps config and thus possibility to adjust config / see under 240 MHz 2023-03-16 10:33:36 +01:00
GullCode a1705dd9d4 reoganised things a little, added nb_columns management in ui 2023-03-14 22:23:16 +01:00
GullCode 155543e5d5 Added nb_columns, changed drawing due to column system 2023-03-14 22:22:49 +01:00
gullradriel 62b9fa2b6a Merge pull request #834 from gullradriel/recon-update
Recon minor update, RSSI widget get 'on touch'
2023-03-14 00:28:22 +01:00
GullCode f5427d7fdc UI adjustements 2023-03-14 00:26:25 +01:00
GullCode b8c1e8c4a6 Added on_touch on RSSI widget 2023-03-14 00:26:12 +01:00
gullradriel 7a0d02cb83 Merge pull request #833 from gullradriel/recon-update
Recon minor update
2023-03-13 23:29:37 +01:00
gullradriel c23f03c074 Merge branch 'eried:next' into recon-update 2023-03-13 23:27:44 +01:00
GullCode cfdd12d8a6 aligned OPT to the right 2023-03-13 23:27:04 +01:00
gullradriel d1ab93f644 Merge pull request #832 from gullradriel/recon-update
Recon update
2023-03-13 23:18:26 +01:00
GullCode f7df4f3575 Use rssi focusable, added shortcut to level app, glass app, cut buttons a bit better in the ui, better pause/resume/skiplock/unlock button 2023-03-13 23:14:06 +01:00
GullCode ad4cfe5a44 adding header guard 2023-03-13 23:12:46 +01:00
GullCode 8db44d1a92 fixed a text size, used new rssi focusable property so you can launch the level app by touching or selecting and clicking the rssi bars 2023-03-13 22:56:47 +01:00
GullCode 37cfcb0d5c added focusable ability to rssi field 2023-03-13 22:55:48 +01:00
gullradriel 6a61b9528e Merge pull request #831 from gullradriel/level-app-updates
Level app updates
2023-03-13 15:59:24 +01:00
gullradriel ab58f368b5 Merge branch 'eried:next' into level-app-updates 2023-03-13 15:56:41 +01:00
gullradriel 023ee2a6f5 Merge pull request #830 from bernd-herzog/error_handling
added runtime error details to guru meditation
2023-03-13 15:50:27 +01:00
Bernd Herzog b6011a777b added runtime error details to guru meditation 2023-03-13 15:04:00 +01:00
GullCode 37494500b2 Added display of rssi get delta, swapped audio and steps button for convenience 2023-03-13 14:04:23 +01:00
GullCode f42812c6b4 Added rssi get_delta, better rssi min graph view 2023-03-13 14:03:37 +01:00
GullCode a7acb37a56 added 0.1 and 1Khz steps 2023-03-13 14:02:29 +01:00
gullradriel 69df16d6e2 Level meter (#827)
* added possibility to scale vertically from bottom to top

* Squeleton of Level app from Recon App

* Working LevelApp

* Tweaking peak and display or RSSI chart

* Moved widgets, prepared audio decode, added working ctcss display and peak hold max rssi val

* Added RSSIGraph

* Updated Level to use RSSIGraph

* Graph as lines instead as bars

* correct CTCSS hiding if not in NFM mode

* added back db value and drawing for it. clamped to [-100,20] db

* added back audio, volume, better placement for buttons, db graph

* Using different icon for Level app, unless someone provide a better one

* fixed CTCSS position

---------

Co-authored-by: GullCode <gullradriel@hotmail.com>
2023-03-10 14:25:38 +01:00
88 changed files with 11351 additions and 6209 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ assignees: ''
----
(Please try the latest nightly release before submitting this. You can find the latest nightly verison here: https://github.com/eried/portapack-mayhem/releases)
(Please try the latest nightly release before submitting this. You can find the latest nightly version here: https://github.com/eried/portapack-mayhem/releases)
----
@@ -31,7 +31,7 @@ You can find the list of versions here: https://github.com/eried/portapack-mayhe
**Affected versions**
Please tell us what version you are running.
Also please try the latest nightly release before submitting this.
If your device is still functional, try the latest nightly release before submitting this.
You can find the latest nightly version here https://github.com/eried/portapack-mayhem/releases
**Were you able to update the firmware before?**
+1 -1
View File
@@ -14,7 +14,7 @@ COPY ./ /havocsrc
#Fetch dependencies from APT
RUN apt-get update && \
apt-get install -y tar wget dfu-util cmake python bzip2 curl python3 python3-yaml && \
apt-get install -y tar wget dfu-util cmake python bzip2 lz4 curl python3 python3-yaml && \
apt-get -qy autoremove
#Install current pip from PyPa
+1 -1
View File
@@ -13,7 +13,7 @@ COPY ./ /havocsrc
# Fetch dependencies from APK
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
RUN apk update -U
RUN apk add --no-cache git tar wget cmake curl bzip2 make
RUN apk add --no-cache git tar wget cmake curl bzip2 lz4 make
RUN apk add --no-cache dfu-util ccache icu-data-full
RUN apk add --no-cache python3 py3-pip py3-yaml
RUN apk add --no-cache py3-pyyaml-env-tag
+1 -1
View File
@@ -11,7 +11,7 @@ WORKDIR /havoc/firmware
# Fetch dependencies from APT
RUN apt-get update && \
apt-get install -y git tar wget dfu-util cmake python3 ccache bzip2 curl && \
apt-get install -y git tar wget dfu-util cmake python3 ccache bzip2 liblz4-tool curl && \
apt-get -qy autoremove
#Install current pip from PyPa
+1 -1
View File
@@ -10,7 +10,7 @@ WORKDIR /havoc/firmware
# Fetch dependencies from APK
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
RUN apk update -U
RUN apk add --no-cache git tar wget cmake curl bzip2 make
RUN apk add --no-cache git tar wget cmake curl bzip2 lz4 make
RUN apk add --no-cache dfu-util ccache icu-data-full
RUN apk add --no-cache python3 py3-pip py3-yaml
RUN apk add --no-cache py3-pyyaml-env-tag
+1
View File
@@ -28,6 +28,7 @@ set(CHIBIOS_PORTAPACK ${PROJECT_SOURCE_DIR}/chibios-portapack)
set(EXTRACT_CPLD_DATA ${PROJECT_SOURCE_DIR}/tools/extract_cpld_data.py)
set(MAKE_SPI_IMAGE ${PROJECT_SOURCE_DIR}/tools/make_spi_image.py)
set(MAKE_IMAGE_CHUNK ${PROJECT_SOURCE_DIR}/tools/make_image_chunk.py)
set(LZ4 lz4)
set(FIRMWARE_NAME portapack-h1_h2-mayhem)
set(FIRMWARE_FILENAME ${FIRMWARE_NAME}.bin)
+8 -2
View File
@@ -125,7 +125,7 @@ set(CPPSRC
${COMMON}/cpld_max5.cpp
${COMMON}/cpld_update.cpp
${COMMON}/cpld_xilinx.cpp
${COMMON}/debug.cpp
debug.cpp
${COMMON}/ert_packet.cpp
${COMMON}/event.cpp
${COMMON}/gcc.cpp
@@ -234,6 +234,8 @@ set(CPPSRC
apps/ui_debug.cpp
apps/ui_encoders.cpp
apps/ui_fileman.cpp
apps/ui_flash_utility.cpp
apps/ui_sd_over_usb.cpp
apps/ui_freqman.cpp
apps/ui_jammer.cpp
apps/ui_keyfob.cpp
@@ -274,6 +276,7 @@ set(CPPSRC
apps/soundboard_app.cpp
apps/ui_recon.cpp
apps/ui_recon_settings.cpp
apps/ui_level.cpp
apps/tpms_app.cpp
apps/tpms_app.cpp
protocols/aprs.cpp
@@ -316,7 +319,10 @@ set(TCSRC)
set(TCPPSRC)
# List ASM source files here
set(ASMSRC ${PORTASM})
set(ASMSRC
${PORTASM}
lz4.S
)
set(INCDIR ${CMAKE_CURRENT_BINARY_DIR} ${COMMON} ${PORTINC} ${KERNINC} ${TESTINC}
${HALINC} ${PLATFORMINC} ${BOARDINC}
+1 -1
View File
@@ -166,7 +166,7 @@ public:
void focus() override;
std::string title() const override { return "AIS Boats RX"; };
std::string title() const override { return "AIS RX"; };
private:
static constexpr uint32_t initial_target_frequency = 162025000;
@@ -140,10 +140,10 @@ AnalogAudioView::AnalogAudioView(
field_lna.set_value(app_settings.lna);
field_vga.set_value(app_settings.vga);
receiver_model.set_rf_amp(app_settings.rx_amp);
field_frequency.set_value(app_settings.rx_frequency);
// field_frequency.set_value(app_settings.rx_frequency);
receiver_model.set_configuration_without_init(static_cast<ReceiverModel::Mode>(app_settings.modulation), app_settings.step, app_settings.am_config_index, app_settings.nbfm_config_index, app_settings.wfm_config_index, app_settings.squelch);
}
else field_frequency.set_value(receiver_model.tuning_frequency());
field_frequency.set_value(receiver_model.tuning_frequency());
//Filename Datetime and Frequency
record_view.set_filename_date_frequency(true);
+1 -1
View File
@@ -53,7 +53,7 @@ public:
void focus() override;
std::string title() const override { return "Analog TV RX"; };
std::string title() const override { return "AnalogTV RX"; };
private:
static constexpr ui::Dim header_height = 3 * 16;
+1 -1
View File
@@ -125,7 +125,7 @@ public:
void focus() override;
std::string title() const override { return "ERT Meter RX"; };
std::string title() const override { return "ERT RX"; };
private:
ERTRecentEntries recent { };
+1 -1
View File
@@ -46,7 +46,7 @@ public:
void focus() override;
std::string title() const override { return "Soundboard TX"; };
std::string title() const override { return "Soundbrd TX"; };
private:
NavigationView& nav_;
+2 -2
View File
@@ -102,8 +102,8 @@ public:
void paint(Painter&) override { };
void focus() override;
std::string title() const override { return "TPMS Cars RX"; };
std::string title() const override { return "TPMS RX"; };
private:
static constexpr uint32_t initial_target_frequency = 315000000;
+1 -1
View File
@@ -52,7 +52,7 @@ public:
void focus() override;
std::string title() const override { return "AFSK RX (beta)"; };
std::string title() const override { return "AFSK RX"; };
private:
void on_data(uint32_t value, bool is_data);
+1 -1
View File
@@ -179,7 +179,7 @@ public:
void focus() override;
std::string title() const override { return "BHT Xy/EP TX"; };
std::string title() const override { return "BHT TX"; };
private:
// app save settings
+1 -1
View File
@@ -40,7 +40,7 @@ public:
void focus() override;
std::string title() const override { return "BurgerPgr TX"; };
std::string title() const override { return "BurgerPgrTX"; };
private:
enum tx_modes {
+1 -1
View File
@@ -48,7 +48,7 @@ public:
void load_directory_contents(const std::filesystem::path& dir_path);
std::filesystem::path get_selected_path();
std::string title() const override { return "File manager"; };
std::string title() const override { return "Fileman"; };
protected:
NavigationView& nav_;
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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 "ui_flash_utility.hpp"
#include "portapack_shared_memory.hpp"
namespace ui {
Thread* FlashUtilityView::thread { nullptr };
static constexpr size_t max_filename_length = 26;
FlashUtilityView::FlashUtilityView(NavigationView& nav) : nav_ (nav) {
add_children({
&labels,
&menu_view
});
menu_view.set_parent_rect({ 0, 3 * 8, 240, 33 * 8 });
for (const auto& entry : std::filesystem::directory_iterator(u"FIRMWARE", u"*.bin")) {
auto filename = entry.path().filename();
auto path = entry.path().native();
menu_view.add_item({
filename.string().substr(0, max_filename_length),
ui::Color::red(),
&bitmap_icon_temperature,
[this, path]() {
this->firmware_selected(path);
}
});
}
}
void FlashUtilityView::firmware_selected(std::filesystem::path::string_type path) {
nav_.push<ModalMessageView>(
"Warning!",
"This will replace your\ncurrent firmware.\n\nIf things go wrong you are\nrequired to flash manually\nwith dfu.",
YESNO,
[this, path](bool choice) {
if (choice) {
std::u16string full_path = std::u16string(u"FIRMWARE/") + path;
this->flash_firmware(full_path);
}
}
);
}
void FlashUtilityView::flash_firmware(std::filesystem::path::string_type path) {
ui::Painter painter;
painter.fill_rectangle(
{ 0, 0, portapack::display.width(), portapack::display.height() },
ui::Color::black()
);
painter.draw_string({ 12, 24 }, this->nav_.style(), "This will take 15 seconds.");
painter.draw_string({ 12, 64 }, this->nav_.style(), "Please wait while LEDs RX");
painter.draw_string({ 12, 84 }, this->nav_.style(), "and TX are flashing.");
painter.draw_string({ 12, 124 }, this->nav_.style(), "Then restart the device.");
std::memcpy(&shared_memory.bb_data.data[0], path.c_str(), (path.length() + 1) * 2);
m4_init(portapack::spi_flash::image_tag_flash_utility, portapack::memory::map::m4_code, false);
m0_halt();
}
void FlashUtilityView::focus() {
menu_view.focus();
}
} /* namespace ui */
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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.
*/
#ifndef __UI_FLSH_UITILTY_H__
#define __UI_FLSH_UITILTY_H__
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "string_format.hpp"
#include "ff.h"
#include "baseband_api.hpp"
#include "core_control.hpp"
#include <cstdint>
namespace ui {
class FlashUtilityView : public View {
public:
FlashUtilityView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Flash Utility"; };
private:
NavigationView& nav_;
bool confirmed = false;
static Thread* thread;
Labels labels {
{ { 4, 4 }, "Select firmware to flash:", Color::white() }
};
MenuView menu_view {
{ 0, 2 * 8, 240, 26 * 8 },
true
};
void firmware_selected(std::filesystem::path::string_type path);
void flash_firmware(std::filesystem::path::string_type path);
};
} /* namespace ui */
#endif/*__UI_FLSH_UITILTY_H__*/
+3 -3
View File
@@ -87,7 +87,7 @@ class FrequencySaveView : public FreqManBaseView {
public:
FrequencySaveView(NavigationView& nav, const rf::Frequency value);
std::string title() const override { return "Save frequency"; };
std::string title() const override { return "Save freq."; };
private:
std::string desc_buffer { };
@@ -126,7 +126,7 @@ public:
FrequencyLoadView(NavigationView& nav);
std::string title() const override { return "Load frequency"; };
std::string title() const override { return "Load freq."; };
private:
void refresh_widgets(const bool v);
@@ -137,7 +137,7 @@ public:
FrequencyManagerView(NavigationView& nav);
~FrequencyManagerView();
std::string title() const override { return "Freq. manager"; };
std::string title() const override { return "Freqman"; };
private:
std::string desc_buffer { };
+308
View File
@@ -0,0 +1,308 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2018 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_level.hpp"
#include "ui_fileman.hpp"
#include "file.hpp"
using namespace portapack;
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();
}
LevelView::~LevelView() {
// save app settings
app_settings.lna = field_lna.value();
app_settings.vga = field_vga.value();
app_settings.rx_amp = field_rf_amp.value();
settings.save("level", &app_settings);
receiver_model.disable();
baseband::shutdown();
}
LevelView::LevelView( NavigationView& nav) : nav_ { nav } {
add_children( {
&labels,
&field_lna,
&field_vga,
&field_rf_amp,
&field_volume,
&field_bw,
&field_mode,
&step_mode,
&rssi_resolution,
&button_frequency,
&text_ctcss,
&freq_stats_rssi,
&freq_stats_db,
&audio_mode,
&peak_mode,
&rssi,
&rssi_graph
} );
rssi.set_vertical_rssi( true );
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
//HELPER: Pre-setting a manual range, based on stored frequency
freq = persistent_memory::tuned_frequency();
receiver_model.set_tuning_frequency( freq );
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);
}
}
button_frequency.on_select = [this, &nav](ButtonWithEncoder& button) {
auto new_view = nav_.push<FrequencyKeypadView>(freq);
new_view->on_changed = [this, &button](rf::Frequency f) {
freq = f ;
receiver_model.set_tuning_frequency( f ); // Retune to actual freq
button_frequency.set_text( "<" + to_string_short_freq( freq ) + " MHz>" );
};
};
button_frequency.on_change = [this]() {
int64_t def_step = freqman_entry_get_step_value( step_mode.selected_index() );
freq = freq + ( button_frequency.get_encoder_delta() * def_step );
if( freq < 1 )
{
freq = 1 ;
}
if( freq > ( MAX_UFREQ - def_step ) )
{
freq = MAX_UFREQ ;
}
button_frequency.set_encoder_delta( 0 );
receiver_model.set_tuning_frequency( freq ); // Retune to actual freq
button_frequency.set_text( "<" + to_string_short_freq( freq ) + " MHz>" );
};
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
if( v != -1 )
{
receiver_model.disable();
baseband::shutdown();
change_mode(v);
if( audio_mode.selected_index() != 0 )
{
audio::output::start();
}
receiver_model.enable();
}
};
rssi_resolution.on_change = [this](size_t, OptionsField::value_t v) {
if( v != -1 )
{
rssi_graph.set_nb_columns( v );
}
};
audio_mode.on_change = [this](size_t, OptionsField::value_t v) {
if( v == 0 )
{
audio::output::stop();
}
else if( v == 1 )
{
audio::output::start();
this->on_headphone_volume_changed( (receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99 );
}
else
{
}
};
peak_mode.on_change = [this](size_t, OptionsField::value_t v) {
if( v == 0 )
{
rssi.set_peak( false , 0 );
}
else
{
rssi.set_peak( true , v );
}
};
// default peak value
peak_mode.set_selected_index(2);
rssi_resolution.set_selected_index(1);
//FILL STEP OPTIONS
freqman_set_modulation_option( field_mode );
freqman_set_step_option_short( step_mode );
freq_stats_rssi.set_style(&style_white);
freq_stats_db.set_style(&style_white);
}
void LevelView::on_headphone_volume_changed(int32_t v) {
const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max;
receiver_model.set_headphone_volume(new_volume);
}
void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
static int last_max_db = -1000 ;
static int last_min_rssi = -1000 ;
static int last_avg_rssi = -1000 ;
static int last_max_rssi = -1000 ;
rssi_graph.add_values( rssi.get_min() , rssi.get_avg() , rssi.get_max() , statistics.max_db );
bool refresh_db = false ;
bool refresh_rssi = false ;
if( last_max_db != statistics.max_db )
{
refresh_db = true ;
}
if( last_min_rssi != rssi.get_min() || last_avg_rssi != rssi.get_avg() || last_max_rssi != rssi.get_max() )
{
refresh_rssi = true ;
}
if( refresh_db )
{
last_max_db = statistics.max_db ;
freq_stats_db.set( "Power: "+to_string_dec_int( statistics.max_db )+" db" );
}
if( refresh_rssi )
{
last_min_rssi = rssi.get_min();
last_avg_rssi = rssi.get_avg();
last_max_rssi = rssi.get_max();
freq_stats_rssi.set( "RSSI: "+to_string_dec_int( rssi.get_min() )+"/"+to_string_dec_int( rssi.get_avg() )+"/"+to_string_dec_int( rssi.get_max() )+",dt: "+to_string_dec_int( rssi.get_delta() ) );
}
} /* on_statistic_updates */
size_t LevelView::change_mode( freqman_index_t new_mod ) {
field_bw.on_change = [this](size_t n, OptionsField::value_t) { (void)n; };
switch( new_mod ) {
case AM_MODULATION:
freqman_set_bandwidth_option( new_mod , field_bw );
//bw DSB (0) default
field_bw.set_selected_index(0);
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
receiver_model.set_am_configuration(field_bw.selected_index());
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_am_configuration(n); };
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000);
text_ctcss.set(" ");
break;
case NFM_MODULATION:
freqman_set_bandwidth_option( new_mod , field_bw );
//bw 16k (2) default
field_bw.set_selected_index(2);
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.set_nbfm_configuration(field_bw.selected_index());
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_nbfm_configuration(n); };
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000);
break;
case WFM_MODULATION:
freqman_set_bandwidth_option( new_mod , field_bw );
//bw 200k (0) only/default
field_bw.set_selected_index(0);
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.set_wfm_configuration(field_bw.selected_index());
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_wfm_configuration(n); };
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000);
text_ctcss.set(" ");
break;
default:
break;
}
return step_mode.selected_index();
}
void LevelView::handle_coded_squelch(const uint32_t value) {
static int32_t last_idx = -1 ;
float diff, min_diff = value;
size_t min_idx { 0 };
size_t c;
if( field_mode.selected_index() != NFM_MODULATION )
{
text_ctcss.set(" ");
return ;
}
// Find nearest match
for (c = 0; c < tone_keys.size(); c++) {
diff = abs(((float)value / 100.0) - tone_keys[c].second);
if (diff < min_diff) {
min_idx = c;
min_diff = diff;
}
}
// Arbitrary confidence threshold
if( last_idx < 0 || (unsigned)last_idx != min_idx )
{
last_idx = min_idx ;
if (min_diff < 40)
text_ctcss.set("T: "+tone_keys[min_idx].first);
else
text_ctcss.set(" ");
}
}
} /* namespace ui */
+238
View File
@@ -0,0 +1,238 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2018 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef _UI_LEVEL
#define _UI_LEVEL
#include "ui.hpp"
#include "receiver_model.hpp"
#include "ui_receiver.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "freqman.hpp"
#include "analog_audio_app.hpp"
#include "audio.hpp"
#include "ui_mictx.hpp"
#include "portapack_persistent_memory.hpp"
#include "baseband_api.hpp"
#include "ui_spectrum.hpp"
#include "string_format.hpp"
#include "file.hpp"
#include "app_settings.hpp"
namespace ui {
class LevelView : public View {
public:
LevelView(NavigationView& nav);
~LevelView();
void focus() override;
void big_display_freq( int64_t f );
const Style style_grey { // level
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::grey(),
};
const Style style_white { // level
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::white(),
};
const Style style_yellow { //Found signal
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::yellow(),
};
const Style style_green { //Found signal
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::green(),
};
const Style style_red { //erasing freq
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::red(),
};
const Style style_blue { // quick level, wait == 0
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::blue(),
};
std::string title() const override { return "Level"; };
private:
NavigationView& nav_;
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
{
{ { 0 * 8 , 0 * 16 }, "LNA: VGA: AMP: VOL: ", Color::light_grey() },
{ { 0 * 8 , 1 * 16 }, "BW: MODE: S: ", Color::light_grey() },
};
LNAGainField field_lna {
{ 4 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 11 * 8, 0 * 16 }
};
RFAmpField field_rf_amp {
{ 18 * 8, 0 * 16 }
};
NumberField field_volume {
{ 24 * 8, 0 * 16 },
2,
{ 0, 99 },
1,
' ',
};
OptionsField field_bw {
{ 3 * 8, 1 * 16 },
6,
{ }
};
OptionsField field_mode {
{ 15 * 8, 1 * 16 },
3,
{
}
};
OptionsField step_mode {
{ 16 * 8, 2 * 16 + 4 },
12,
{
}
};
ButtonWithEncoder button_frequency {
{ 0 * 8 , 2 * 16 + 8 , 15 * 8 , 1 * 8 },
""
};
OptionsField audio_mode {
{ 21 * 8, 1 * 16 },
9,
{
{"audio off", 0},
{"audio on",1}
//{"tone on", 2},
//{"tone off", 2},
}
};
Text text_ctcss {
{ 22 * 8, 3 * 16 + 4 , 14 * 8, 1 * 8 },
""
};
// RSSI: XX/XX/XXX,dt: XX
Text freq_stats_rssi {
{ 0 * 8 , 3 * 16 + 4 , 22 * 8, 14 },
};
// Power: -XXX db
Text freq_stats_db {
{ 0 * 8 , 4 * 16 + 4 , 14 * 8, 14 },
};
OptionsField peak_mode {
{ 40 + 10 * 8, 4 * 16 + 4 },
10,
{
{"peak:none", 0},
{"peak:0.25s",250},
{"peak:0.5s",500},
{"peak:1s",1000},
{"peak:3s",3000},
{"peak:5s",5000},
{"peak:10s",10000},
}
};
OptionsField rssi_resolution {
{ 44 + 20 * 8, 4 * 16 + 4},
4,
{
{"16x", 16},
{"32x", 32},
{"64x", 64},
{"128x", 128},
{"240x", 240},
}
};
RSSIGraph rssi_graph { // 240x320 =>
{ 0 , 5 * 16 + 4 , 240 - 5 * 8 , 320 - ( 5 * 16 + 4 ) },
};
RSSI rssi { // 240x320 =>
{ 240 - 5 * 8 , 5 * 16 + 4 , 5 * 8 , 320 - ( 5 * 16 + 4 ) },
};
void handle_coded_squelch(const uint32_t value);
void on_headphone_volume_changed(int32_t v);
MessageHandlerRegistration message_handler_coded_squelch {
Message::ID::CodedSquelch,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const CodedSquelchMessage*>(p);
this->handle_coded_squelch(message.value);
}
};
MessageHandlerRegistration message_handler_stats {
Message::ID::ChannelStatistics,
[this](const Message* const p) {
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
}
};
// app save settings
std::app_settings settings { };
std::app_settings::AppSettings app_settings { };
};
} /* namespace ui */
#endif
@@ -184,6 +184,7 @@ namespace ui
&field_lna,
&field_vga,
&text_range,
&steps_config,
&filter_config,
&field_rf_amp,
&range_presets,
@@ -194,21 +195,71 @@ namespace ui
load_Presets(); // Load available presets from TXT files (or default)
field_frequency_min.set_value(presets_db[0].min); // Defaults to first preset
field_frequency_min.set_step( steps );
field_frequency_min.on_change = [this](int32_t v)
{
if (v >= field_frequency_max.value())
field_frequency_max.set_value(v + 240);
int32_t steps_ = steps ;
if( steps_ < 24 )
steps_ = 24 ;
if( v > 7200 - steps_ )
{
v = 7200 - steps_ ;
field_frequency_min.set_value( v );
}
if (v >= (field_frequency_max.value() - steps_ ) )
field_frequency_max.set_value( v + steps_ );
this->on_range_changed();
};
field_frequency_min.on_select = [this, &nav](NumberField& field) {
auto new_view = nav_.push<FrequencyKeypadView>(field_frequency_min.value()*1000000);
new_view->on_changed = [this, &field](rf::Frequency f) {
int32_t freq = f / 1000000 ;
int32_t steps_ = steps ;
if( steps_ < 24 )
steps_ = 24 ;
if( freq > (7200 - steps_ ) )
freq= 7200 - steps_ ;
field_frequency_min.set_value( freq );
if( field_frequency_max.value() < ( freq + steps_ ) )
field_frequency_max.set_value( freq + steps_ );
this->on_range_changed();
};
};
field_frequency_max.set_value(presets_db[0].max); // Defaults to first preset
field_frequency_max.set_step( steps );
field_frequency_max.on_change = [this](int32_t v)
{
if (v <= field_frequency_min.value())
field_frequency_min.set_value(v - 240);
{
int32_t steps_ = steps ;
if( steps_ < 24 )
steps_ = 24 ;
if( v < steps_ )
{
v = steps_ ;
field_frequency_max.set_value( v );
}
if (v < (field_frequency_min.value() + steps_) )
field_frequency_min.set_value(v - steps_);
this->on_range_changed();
};
field_frequency_max.on_select = [this, &nav](NumberField& field) {
auto new_view = nav_.push<FrequencyKeypadView>(field_frequency_max.value()*1000000);
new_view->on_changed = [this, &field](rf::Frequency f) {
int32_t steps_ = steps ;
if( steps_ < 24 )
steps_ = 24 ;
int32_t freq = f / 1000000 ;
if( freq < 24 )
freq = 24 ;
field_frequency_max.set_value( freq );
if( field_frequency_min.value() > ( freq - steps) )
field_frequency_min.set_value( freq - steps );
this->on_range_changed();
};
};
field_lna.set_value(receiver_model.lna());
field_lna.on_change = [this](int32_t v)
{
@@ -221,11 +272,13 @@ namespace ui
this->on_vga_changed(v_db);
};
filter_config.set_selected_index(0);
filter_config.on_change = [this](size_t n, OptionsField::value_t v)
steps_config.set_selected_index(3); //default of 250 Mhz steps
steps_config.on_change = [this](size_t n, OptionsField::value_t v)
{
(void)n;
min_color_power = v;
field_frequency_min.set_step( v );
field_frequency_max.set_step( v );
steps = v ;
};
range_presets.on_change = [this](size_t n, OptionsField::value_t v)
+184 -169
View File
@@ -1,187 +1,202 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2020 euquiq
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2020 euquiq
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "portapack.hpp"
#include "baseband_api.hpp"
#include "receiver_model.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "string_format.hpp"
#include "analog_audio_app.hpp"
#include "spectrum_color_lut.hpp"
#ifndef _UI_GLASS
#define _UI_GLASS
namespace ui
{
#define LOOKING_GLASS_SLICE_WIDTH 20000000 // Each slice bandwidth 20 MHz
#define MHZ_DIV 1000000
#define X2_MHZ_DIV 2000000
#include "ui.hpp"
#include "portapack.hpp"
#include "baseband_api.hpp"
#include "receiver_model.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "string_format.hpp"
#include "analog_audio_app.hpp"
#include "spectrum_color_lut.hpp"
class GlassView : public View
{
public:
GlassView(NavigationView &nav);
namespace ui
{
#define LOOKING_GLASS_SLICE_WIDTH 20000000 // Each slice bandwidth 20 MHz
#define MHZ_DIV 1000000
#define X2_MHZ_DIV 2000000
GlassView( const GlassView &);
GlassView& operator=(const GlassView &nav);
class GlassView : public View
{
public:
GlassView(NavigationView &nav);
~GlassView();
std::string title() const override { return "Looking Glass"; };
GlassView( const GlassView &);
GlassView& operator=(const GlassView &nav);
void on_show() override;
void on_hide() override;
void focus() override;
~GlassView();
std::string title() const override { return "LookingGlass"; };
private:
NavigationView& nav_;
void on_show() override;
void on_hide() override;
void focus() override;
struct preset_entry
{
rf::Frequency min{};
rf::Frequency max{};
std::string label{};
};
private:
NavigationView& nav_;
std::vector<preset_entry> presets_db{};
void on_channel_spectrum(const ChannelSpectrum& spectrum);
void do_timers();
void on_range_changed();
void on_lna_changed(int32_t v_db);
void on_vga_changed(int32_t v_db);
void add_spectrum_pixel(Color color);
void PlotMarker(rf::Frequency pos);
void load_Presets();
void txtline_process(std::string& line);
void populate_Presets();
void presets_Default();
rf::Frequency f_min { 0 }, f_max { 0 };
rf::Frequency search_span { 0 };
rf::Frequency f_center { 0 };
rf::Frequency f_center_ini { 0 };
rf::Frequency marker_pixel_step { 0 };
rf::Frequency each_bin_size { LOOKING_GLASS_SLICE_WIDTH / 240 };
rf::Frequency bins_Hz_size { 0 };
uint8_t min_color_power { 0 };
uint32_t pixel_index { 0 };
std::array<Color, 240> spectrum_row = { 0 };
ChannelSpectrumFIFO* fifo { nullptr };
uint8_t max_power = 0;
Labels labels{
{{0, 0}, "MIN: MAX: LNA VGA ", Color::light_grey()},
{{0, 1 * 16}, " RANGE: FILTER: AMP:", Color::light_grey()},
{{0, 2 * 16}, "PRESET:", Color::light_grey()},
{{0, 3 * 16}, "MARKER: MHz +/- MHz", Color::light_grey()},
{{0, 4 * 16}, "RESOLUTION: (fft trigger)", Color::light_grey()}
};
NumberField field_frequency_min {
{ 4 * 8, 0 * 16 },
4,
{ 0, 6960 },
240,
' '
};
NumberField field_frequency_max {
{ 13 * 8, 0 * 16 },
4,
{ 240, 7200 },
240,
' '
};
LNAGainField field_lna {
{ 21 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 27 * 8, 0 * 16 }
};
Text text_range{
{7 * 8, 1 * 16, 4 * 8, 16},
""};
OptionsField filter_config{
{19 * 8, 1 * 16},
4,
struct preset_entry
{
{"OFF ", 0},
{"MID ", 118}, //85 +25 (110) + a bit more to kill all blue
{"HIGH", 202}, //168 + 25 (193)
}};
rf::Frequency min{};
rf::Frequency max{};
std::string label{};
};
RFAmpField field_rf_amp{
{29 * 8, 1 * 16}};
std::vector<preset_entry> presets_db{};
OptionsField range_presets{
{7 * 8, 2 * 16},
20,
{
{" NONE (WIFI 2.4GHz)", 0},
}};
void on_channel_spectrum(const ChannelSpectrum& spectrum);
void do_timers();
void on_range_changed();
void on_lna_changed(int32_t v_db);
void on_vga_changed(int32_t v_db);
void add_spectrum_pixel(Color color);
void PlotMarker(rf::Frequency pos);
void load_Presets();
void txtline_process(std::string& line);
void populate_Presets();
void presets_Default();
NumberField field_marker{
{7 * 8, 3 * 16},
4,
{0, 7200},
25,
' '};
rf::Frequency f_min { 0 }, f_max { 0 };
rf::Frequency search_span { 0 };
rf::Frequency f_center { 0 };
rf::Frequency f_center_ini { 0 };
rf::Frequency marker_pixel_step { 0 };
rf::Frequency each_bin_size { LOOKING_GLASS_SLICE_WIDTH / 240 };
rf::Frequency bins_Hz_size { 0 };
uint8_t min_color_power { 0 };
uint32_t pixel_index { 0 };
std::array<Color, 240> spectrum_row = { 0 };
ChannelSpectrumFIFO* fifo { nullptr };
uint8_t max_power = 0;
int32_t steps = 250 ; // default of 250 Mhz steps
Text text_marker_pm{
{20 * 8, 3 * 16, 2 * 8, 16},
""};
Labels labels{
{{0, 0}, "MIN: MAX: LNA VGA ", Color::light_grey()},
{{0, 1 * 16}, " RANGE: FILTER: AMP:", Color::light_grey()},
{{0, 2 * 16}, "PRESET:", Color::light_grey()},
{{0, 3 * 16}, "MARKER: MHz +/- MHz", Color::light_grey()},
{{0, 4 * 16}, "RESOLUTION: STEPS:", Color::light_grey()}
};
NumberField field_trigger{
{11 * 8, 4 * 16},
3,
{2, 128},
2,
' '};
NumberField field_frequency_min {
{ 4 * 8, 0 * 16 },
4,
{ 0, 7199 },
1, // number of steps by encoder delta
' '
};
NumberField field_frequency_max {
{ 13 * 8, 0 * 16 },
4,
{ 1, 7200 },
1, // number of steps by encoder delta
' '
};
LNAGainField field_lna {
{ 21 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 27 * 8, 0 * 16 }
};
Text text_range{
{7 * 8, 1 * 16, 4 * 8, 16},
""};
OptionsField steps_config{
{ 22 * 8, 4 * 16},
4,
{
{"1", 1},
{"50", 50},
{"100", 100},
{"250", 250},
{"500", 500},
{"1000", 1000},
}};
OptionsField filter_config{
{19 * 8, 1 * 16},
4,
{
{"OFF ", 0},
{"MID ", 118}, //85 +25 (110) + a bit more to kill all blue
{"HIGH", 202}, //168 + 25 (193)
}};
RFAmpField field_rf_amp{
{29 * 8, 1 * 16}};
OptionsField range_presets{
{7 * 8, 2 * 16},
20,
{
{" NONE (WIFI 2.4GHz)", 0},
}};
NumberField field_marker{
{7 * 8, 3 * 16},
4,
{0, 7200},
25,
' '};
Text text_marker_pm{
{20 * 8, 3 * 16, 2 * 8, 16},
""};
NumberField field_trigger{
{11 * 8, 4 * 16},
3,
{2, 128},
2,
' '};
MessageHandlerRegistration message_handler_spectrum_config {
Message::ID::ChannelSpectrumConfig,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const ChannelSpectrumConfigMessage*>(p);
this->fifo = message.fifo;
}
};
MessageHandlerRegistration message_handler_frame_sync {
Message::ID::DisplayFrameSync,
[this](const Message* const) {
if( this->fifo ) {
ChannelSpectrum channel_spectrum;
while( fifo->out(channel_spectrum) ) {
this->on_channel_spectrum(channel_spectrum);
}
}
}
};
};
}
MessageHandlerRegistration message_handler_spectrum_config {
Message::ID::ChannelSpectrumConfig,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const ChannelSpectrumConfigMessage*>(p);
this->fifo = message.fifo;
}
};
MessageHandlerRegistration message_handler_frame_sync {
Message::ID::DisplayFrameSync,
[this](const Message* const) {
if( this->fifo ) {
ChannelSpectrum channel_spectrum;
while( fifo->out(channel_spectrum) ) {
this->on_channel_spectrum(channel_spectrum);
}
}
}
};
};
}
#endif
+25 -5
View File
@@ -180,7 +180,10 @@ void MicTXView::rxaudio(bool is_on) {
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
// receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out.
receiver_model.set_tuning_frequency(rx_frequency); // Now with seperate controls!
if (bool_same_F_tx_rx_enabled) // when stop TX ,define to which freq RX we return
receiver_model.set_tuning_frequency(tx_frequency); // Update freq also for RX = TX
else
receiver_model.set_tuning_frequency(rx_frequency); // Now with seperate freq controls!
receiver_model.set_lna(rx_lna);
receiver_model.set_vga(rx_vga);
receiver_model.set_rf_amp(rx_amp);
@@ -237,6 +240,7 @@ MicTXView::MicTXView(
&field_frequency,
&options_tone_key,
&check_rogerbeep,
&check_common_freq_tx_rx, // added to handle common or separate freq- TX/RX
&check_rxactive,
&field_volume,
&field_rxbw,
@@ -266,6 +270,7 @@ MicTXView::MicTXView(
&field_frequency,
&options_tone_key,
&check_rogerbeep,
&check_common_freq_tx_rx, // added to handle common or separate freq- TX/RX
&check_rxactive,
&field_volume,
&field_rxbw,
@@ -332,8 +337,12 @@ MicTXView::MicTXView(
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_change = [this](rf::Frequency f) {
tx_frequency = f;
if(!rx_enabled)
if(!rx_enabled) { // not activated receiver. just update freq TX
transmitter_model.set_tuning_frequency(f);
} else { // activated receiver.
if (bool_same_F_tx_rx_enabled) // user selected common freq- TX = RX
receiver_model.set_tuning_frequency(f); //Update common freq also for RX
}
};
field_frequency.on_edit = [this, &nav]() {
focused_ui = 0;
@@ -341,8 +350,12 @@ MicTXView::MicTXView(
auto new_view = nav.push<FrequencyKeypadView>(tx_frequency);
new_view->on_changed = [this](rf::Frequency f) {
tx_frequency = f;
if(!rx_enabled)
if(!rx_enabled) {
transmitter_model.set_tuning_frequency(f);
} else {
if (bool_same_F_tx_rx_enabled)
receiver_model.set_tuning_frequency(f); //Update freq also for RX
}
this->field_frequency.set_value(f);
set_dirty();
};
@@ -511,6 +524,13 @@ MicTXView::MicTXView(
rogerbeep_enabled = v;
};
check_common_freq_tx_rx.on_select = [this](Checkbox&, bool v) {
bool_same_F_tx_rx_enabled = v;
field_rxfrequency.hidden(v); //Hide or show separated freq RX field . (When no hide user can enter down indep. freq for RX)
set_dirty(); //Refresh GUI interface
receiver_model.set_tuning_frequency(v ? tx_frequency : rx_frequency); // To go to the proper tuned freq. when toggling it
};
field_va_level.on_change = [this](int32_t v) {
va_level = v;
vumeter.set_mark(v);
@@ -563,12 +583,12 @@ MicTXView::MicTXView(
rx_frequency = receiver_model.tuning_frequency();
field_rxfrequency.set_value(rx_frequency);
field_rxfrequency.set_step(receiver_model.frequency_step());
field_rxfrequency.on_change = [this](rf::Frequency f) {
field_rxfrequency.on_change = [this](rf::Frequency f) { // available when field rxfrequency not hidden => user selected separated freq RX/TX-
rx_frequency = f;
if(rx_enabled)
receiver_model.set_tuning_frequency(f);
};
field_rxfrequency.on_edit = [this, &nav]() {
field_rxfrequency.on_edit = [this, &nav]() { // available when field rxfrequency not hidden => user selected separated freq RX/TX-
focused_ui = 1;
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(rx_frequency);
+18 -10
View File
@@ -80,6 +80,7 @@ private:
bool va_enabled { false };
bool ptt_enabled { true };
bool rogerbeep_enabled { false };
bool bool_same_F_tx_rx_enabled { false };
bool rx_enabled { false };
uint32_t tone_key_index { };
float mic_gain { 1.0 };
@@ -123,9 +124,9 @@ private:
{ {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() },
{ { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() },
{ { 7 * 8, 23 * 8 }, "VOL:", Color::light_grey() },
{ {14 * 8, 23 * 8 }, "RXBW:", Color::light_grey() }, //we remove the label "FM" because we will display all MOD types RX_BW.
{ {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() },
{ { 5 * 8, 25 * 8 }, "F:", Color::light_grey() },
{ {14 * 8, 23 * 8 }, "RXBW:", Color::light_grey() }, //we remove the label "FM" because we will display all MOD types RX_BW.
{ {20 * 8, 25 * 8 }, "SQ:", Color::light_grey() },
{ { 5 * 8, 25 * 8 }, "F_RX:", Color::light_grey() },
{ { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()},
{ {12 * 8, 27 * 8 }, "VGA:", Color::light_grey()},
{ {19 * 8, 27 * 8 }, "AMP:", Color::light_grey()}
@@ -145,8 +146,8 @@ private:
{ { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() },
{ { (6 * 8)+4, 23 * 8 }, "VOL:", Color::light_grey() },
{ {14 * 8, 23 * 8 }, "RXBW:", Color::light_grey() }, //we remove the label "FM" because we will display all MOD types RX_BW.
{ {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() },
{ { 5 * 8, 25 * 8 }, "F:", Color::light_grey() },
{ {20 * 8, 25 * 8 }, "SQ:", Color::light_grey() },
{ { 5 * 8, 25 * 8 }, "F_RX:", Color::light_grey() },
{ { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()},
{ {12 * 8, 27 * 8 }, "VGA:", Color::light_grey()},
{ {19 * 8, 27 * 8 }, "AMP:", Color::light_grey()}
@@ -287,7 +288,7 @@ OptionsField options_wm8731_boost_mode {
};
Checkbox check_rogerbeep {
{ 3 * 8, ( 16 * 8 ) + 4 },
{ 3 * 8, ( 16 * 8 ) + 7 },
10,
"Roger beep",
false
@@ -295,11 +296,18 @@ OptionsField options_wm8731_boost_mode {
Checkbox check_rxactive {
{ 3 * 8, ( 21 * 8 ) - 4 },
8,
18, // it was 8, but if it is string size should be 18
"RX audio listening",
false
};
Checkbox check_common_freq_tx_rx {
{ 18 * 8, ( 16* 8 ) + 7 },
8,
"F = F_RX",
false
};
NumberField field_volume {
{ 11* 8, 23 * 8 },
2,
@@ -319,7 +327,7 @@ OptionsField options_wm8731_boost_mode {
};
NumberField field_squelch {
{ 20 * 8, 25 * 8 },
{ 23 * 8, 25 * 8 },
2,
{ 0, 99 },
1,
@@ -327,7 +335,7 @@ OptionsField options_wm8731_boost_mode {
};
FrequencyField field_rxfrequency {
{ 7 * 8, 25 * 8 },
{ 10 * 8, 25 * 8 },
};
NumberField field_rxlna {
@@ -347,7 +355,7 @@ OptionsField options_wm8731_boost_mode {
};
NumberField field_rxamp {
{ 23 * 8, 27 * 8 },
{ 24 * 8, 27 * 8 },
1,
{ 0, 1 },
1,
File diff suppressed because it is too large Load Diff
+327 -300
View File
@@ -31,6 +31,8 @@
#include "analog_audio_app.hpp"
#include "audio.hpp"
#include "ui_mictx.hpp"
#include "ui_level.hpp"
#include "ui_looking_glass_app.hpp"
#include "portapack_persistent_memory.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
@@ -40,363 +42,388 @@
namespace ui {
class ReconThread {
public:
ReconThread(freqman_db *database );
~ReconThread();
class ReconThread {
public:
ReconThread(freqman_db *database );
~ReconThread();
void set_recon(const bool v);
void set_freq_delete(const bool v);
bool is_recon();
void set_recon(const bool v);
void set_freq_delete(const bool v);
bool is_recon();
void set_lock_duration( const uint32_t v );
uint32_t get_lock_duration();
void set_lock_nb_match( const uint32_t v );
void set_match_mode( const uint32_t v );
uint32_t get_lock_nb_match();
void set_lock_duration( const uint32_t v );
uint32_t get_lock_duration();
void set_lock_nb_match( const uint32_t v );
void set_match_mode( const uint32_t v );
uint32_t get_lock_nb_match();
void set_freq_lock(const uint32_t v);
uint32_t is_freq_lock();
int64_t get_current_freq();
void set_freq_lock(const uint32_t v);
uint32_t is_freq_lock();
int64_t get_current_freq();
void set_stepper(const int64_t v);
void set_stepper(const int64_t v);
void set_index_stepper(const int64_t v);
void change_recon_direction();
bool get_recon_direction();
void set_recon_direction( const bool v);
void change_recon_direction();
bool get_recon_direction();
void set_recon_direction( const bool v);
void set_continuous(const bool v);
void set_continuous(const bool v);
void set_default_modulation( freqman_index_t index );
freqman_index_t get_current_modulation();
void set_default_bandwidth( freqman_index_t index );
freqman_index_t get_current_bandwidth();
void set_default_step( freqman_index_t index );
void set_freq_index( int16_t index );
int16_t get_freq_index();
void set_default_modulation( freqman_index_t index );
freqman_index_t get_current_modulation();
void set_default_bandwidth( freqman_index_t index );
freqman_index_t get_current_bandwidth();
void set_default_step( freqman_index_t index );
void set_freq_index( int16_t index );
int16_t get_freq_index();
void run();
void stop();
void run();
void stop();
ReconThread(const ReconThread&) = delete;
ReconThread(ReconThread&&) = delete;
ReconThread& operator=(const ReconThread&) = delete;
ReconThread& operator=(ReconThread&&) = delete;
ReconThread(const ReconThread&) = delete;
ReconThread(ReconThread&&) = delete;
ReconThread& operator=(const ReconThread&) = delete;
ReconThread& operator=(ReconThread&&) = delete;
private:
freqman_db &frequency_list_ ;
Thread* thread { nullptr };
int64_t freq = 0 ;
uint32_t step = 0 ;
freqman_index_t def_modulation = 0 ;
freqman_index_t def_bandwidth = 0 ;
freqman_index_t def_step = 0 ;
tone_index tone = 0 ;
freqman_entry last_entry = { } ;
int16_t frequency_index = 0 ;
private:
freqman_db &frequency_list_ ;
Thread* thread { nullptr };
int64_t freq = 0 ;
uint32_t step = 0 ;
freqman_index_t def_modulation = 0 ;
freqman_index_t def_bandwidth = 0 ;
freqman_index_t def_step = 0 ;
tone_index tone = 0 ;
freqman_entry last_entry = { } ;
int16_t frequency_index = 0 ;
bool _recon { true };
bool _freq_delete { false };
bool _fwd { true };
bool _continuous { true };
int64_t _stepper { 0 };
int32_t _freq_lock { 0 };
uint32_t _lock_duration { 50 };
uint32_t _lock_nb_match { 10 };
static msg_t static_fn(void* arg);
};
bool _recon { true };
bool _freq_delete { false };
bool _fwd { true };
bool _continuous { true };
bool entry_has_changed = false ;
int64_t _stepper { 0 };
int64_t _index_stepper { 0 };
int32_t _freq_lock { 0 };
uint32_t _lock_duration { 50 };
uint32_t _lock_nb_match { 10 };
static msg_t static_fn(void* arg);
};
class ReconView : public View {
public:
ReconView(NavigationView& nav);
~ReconView();
class ReconView : public View {
public:
ReconView(NavigationView& nav);
~ReconView();
void focus() override;
void focus() override;
void big_display_freq( int64_t f );
void big_display_freq( int64_t f );
const Style style_grey { // recon
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::grey(),
};
const Style style_grey { // recon
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::grey(),
};
const Style style_white { // recon
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::white(),
};
const Style style_white { // recon
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::white(),
};
const Style style_yellow { //Found signal
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::yellow(),
};
const Style style_yellow { //Found signal
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::yellow(),
};
const Style style_green { //Found signal
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::green(),
};
const Style style_green { //Found signal
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::green(),
};
const Style style_red { //erasing freq
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::red(),
};
const Style style_red { //erasing freq
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::red(),
};
const Style style_blue { // quick recon, wait == 0
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::blue(),
};
const Style style_blue { // quick recon, wait == 0
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::blue(),
};
std::string title() const override { return "Recon"; };
std::string title() const override { return "Recon"; };
//void set_parent_rect(const Rect new_parent_rect) override;
//void set_parent_rect(const Rect new_parent_rect) override;
private:
NavigationView& nav_;
private:
NavigationView& nav_;
void start_recon_thread();
size_t change_mode( freqman_index_t mod_type);
void show_max( bool refresh_display = false );
void recon_pause();
void recon_resume();
void user_pause();
void user_resume();
void frequency_file_load( bool stop_all_before = false);
void on_statistics_update(const ChannelStatistics& statistics);
void on_headphone_volume_changed(int32_t v);
void set_display_freq( int64_t freq );
void handle_retune( int64_t freq , uint32_t index );
bool check_sd_card();
void start_recon_thread();
size_t change_mode( freqman_index_t mod_type);
void show_max( bool refresh_display = false );
void recon_pause();
void recon_resume();
void user_pause();
void user_resume();
void frequency_file_load( bool stop_all_before = false);
void on_statistics_update(const ChannelStatistics& statistics);
void on_headphone_volume_changed(int32_t v);
void set_display_freq( int64_t freq );
void handle_retune( int64_t freq , uint32_t index );
bool check_sd_card();
void handle_coded_squelch(const uint32_t value);
jammer::jammer_range_t frequency_range { false, 0, 0 }; //perfect for manual recon task too...
int32_t squelch { 0 };
int32_t db { 0 };
int32_t timer { 0 };
int32_t wait { 5000 }; // in msec. if > 0 wait duration after a lock, if < 0 duration is set to 'wait' unless there is no more activity
uint32_t lock_wait { 500 }; // in msec. Represent the maximum amount of time we will wait for a lock to complete before switching to next
int32_t def_step { 0 };
freqman_db frequency_list = { };
uint32_t current_index { 0 };
bool userpause { false };
bool continuous_lock { false };
std::string input_file = { "RECON" };
std::string output_file = { "RECON_RESULTS" };
bool autosave = { true };
bool autostart = { true };
bool continuous = { true };
bool filedelete = { true };
bool load_freqs = { true };
bool load_ranges = { true };
bool load_hamradios = { true };
bool update_ranges = { true };
bool fwd = { true };
// maximum usable freq
long long int MAX_UFREQ = { 7200000000 };
uint32_t recon_lock_nb_match = { 10 };
uint32_t recon_lock_duration = { 50 };
uint32_t recon_match_mode = { 0 };
bool scanner_mode { false };
bool manual_mode { false };
bool sd_card_mounted = false ;
int32_t volume = 40 ;
jammer::jammer_range_t frequency_range { false, 0, 0 }; //perfect for manual recon task too...
int32_t squelch { 0 };
int32_t db { 0 };
int32_t timer { 0 };
int32_t wait { 5000 }; // in msec. if > 0 wait duration after a lock, if < 0 duration is set to 'wait' unless there is no more activity
uint32_t lock_wait { 500 }; // in msec. Represent the maximum amount of time we will wait for a lock to complete before switching to next
int32_t def_step { 0 };
freqman_db frequency_list = { };
uint32_t current_index { 0 };
bool userpause { false };
bool continuous_lock { false };
std::string input_file = { "RECON" };
std::string output_file = { "RECON_RESULTS" };
bool autosave = { true };
bool autostart = { true };
bool continuous = { true };
bool filedelete = { true };
bool load_freqs = { true };
bool load_ranges = { true };
bool load_hamradios = { true };
bool update_ranges = { true };
bool fwd = { true };
// maximum usable freq
long long int MAX_UFREQ = { 7200000000 };
uint32_t recon_lock_nb_match = { 10 };
uint32_t recon_lock_duration = { 50 };
uint32_t recon_match_mode = { 0 };
bool scanner_mode { false };
bool manual_mode { false };
bool sd_card_mounted = false ;
int32_t volume = 40 ;
Labels labels
{
{ { 0 * 8 , 0 * 16 }, "LNA: VGA: AMP: VOL: ", Color::light_grey() },
{ { 0 * 8 , 1 * 16 }, "BW: SQ: W,L: , ", Color::light_grey() },
{ { 3 * 8 , 10 * 16 }, "START END MANUAL", Color::light_grey() },
{ { 0 * 8 , (26 * 8) + 4 }, "MODE:", Color::light_grey() },
{ { 11 * 8 , (26 * 8) + 4 }, "STEP:", Color::light_grey() },
};
Labels labels
{
{ { 0 * 8 , 0 * 16 }, "LNA: VGA: AMP: VOL: ", Color::light_grey() },
{ { 0 * 8 , 1 * 16 }, "BW: SQ: W,L: , ", Color::light_grey() },
{ { 3 * 8 , 10 * 16 }, "START END MANUAL", Color::light_grey() },
{ { 0 * 8 , (26 * 8) + 4 }, "MODE:", Color::light_grey() },
{ { 11 * 8 , (26 * 8) + 4 }, "STEP:", Color::light_grey() },
};
LNAGainField field_lna {
{ 4 * 8, 0 * 16 }
};
LNAGainField field_lna {
{ 4 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 11 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 11 * 8, 0 * 16 }
};
RFAmpField field_rf_amp {
{ 18 * 8, 0 * 16 }
};
RFAmpField field_rf_amp {
{ 18 * 8, 0 * 16 }
};
NumberField field_volume {
{ 24 * 8, 0 * 16 },
2,
{ 0, 99 },
1,
' ',
};
NumberField field_volume {
{ 24 * 8, 0 * 16 },
2,
{ 0, 99 },
1,
' ',
};
OptionsField field_bw {
{ 3 * 8, 1 * 16 },
6,
{ }
};
OptionsField field_bw {
{ 3 * 8, 1 * 16 },
6,
{ }
};
NumberField field_squelch {
{ 12 * 8, 1 * 16 },
3,
{ -90, 20 },
1,
' ',
};
NumberField field_squelch {
{ 12 * 8, 1 * 16 },
3,
{ -90, 20 },
1,
' ',
};
NumberField field_wait {
{ 20 * 8, 1 * 16 },
5,
{ -9000, 9000 },
100,
' ',
};
NumberField field_wait {
{ 20 * 8, 1 * 16 },
5,
{ -9000, 9000 },
100,
' ',
};
NumberField field_lock_wait {
{ 26 * 8, 1 * 16 },
4,
{ 100 , 9000 },
100,
' ',
};
NumberField field_lock_wait {
{ 26 * 8, 1 * 16 },
4,
{ 100 , 9000 },
100,
' ',
};
RSSI rssi {
{ 0 * 16, 2 * 16, 15 * 16, 8 },
};
RSSI rssi {
{ 0 * 16, 2 * 16, 240 - 8 * 8 + 4 , 16 },
};
Text text_cycle {
{ 0, 3 * 16, 3 * 8, 16 },
};
ButtonWithEncoder text_cycle {
{ 0, 3 * 16, 4 * 8, 16 },
""
};
Text text_max {
{ 3 * 8, 3 * 16, 20 * 8 , 16 },
};
Text text_max {
{ 4 * 8, 3 * 16, 240 - 7 * 8 - 4 * 8 , 16 },
};
Text desc_cycle {
{0, 4 * 16, 240, 16 },
};
Text desc_cycle {
{0, 4 * 16, 240 , 16 },
};
/* BigFrequency big_display { //Show frequency in glamour
{ 4, 7 * 16 - 8 , 28 * 8, 52 },
0
}; */
/* BigFrequency big_display { //Show frequency in glamour
{ 4, 7 * 16 - 8 , 28 * 8, 52 },
0
}; */
Text big_display { //Show frequency in text mode
{ 0, 5 * 16 , 28 * 8, 16 },
};
Text big_display { //Show frequency in text mode
{ 0, 5 * 16 , 23 * 8, 16 },
};
Text freq_stats { //Show frequency stats in text mode
{ 0, 6 * 16 , 28 * 8, 16 },
};
Text freq_stats { //Show frequency stats in text mode
{ 0, 6 * 16 , 23 * 8, 16 },
};
Text text_timer { //Show frequency stats in text mode
{ 0, 7 * 16 , 28 * 8, 16 },
};
// TIMER: 9999
Text text_timer { //Show frequency stats in text mode
{ 0, 7 * 16 , 11 * 8, 16 },
};
Button button_recon_setup {
{ 25 * 8 , 2 * 16 + 8 , 4 * 8, 28 },
"OPT"
};
// T: Senn. 32.000k
Text text_ctcss {
{ 12 * 8 + 4, 7 * 16 , 14 * 8, 1 * 8 },
""
};
Button button_scanner_mode {
{ 21 * 8 , 8 * 16 , 9 * 8, 28 },
"RECON"
};
Button button_recon_setup {
{ 240 - 7 * 8 , 2 * 16 , 7 * 8, 28 },
"CONFIG"
};
Text file_name { //Show file used
{ 0 , 8 * 16 + 4 , 20 * 8, 16 },
};
Button button_looking_glass {
{ 240 - 7 * 8 , 5 * 16 , 7 * 8, 28 },
"GLASS"
};
// Button can be RECON or SCANNER
Button button_scanner_mode {
{ 240 - 7 * 8 , 8 * 16 , 7 * 8, 28 },
"RECON"
};
Text file_name { //Show file used
{ 0 , 8 * 16 + 6 , 240 - 7 * 8, 16 },
};
ButtonWithEncoder button_manual_start {
{ 0 * 8, 11 * 16, 11 * 8, 28 },
""
};
ButtonWithEncoder button_manual_end {
{ 12 * 8 - 6, 11 * 16, 11 * 8, 28 },
""
};
Button button_manual_recon {
{ 23 * 8 - 3, 11 * 16, 7 * 8 , 28 },
"SEARCH"
};
OptionsField field_mode {
{ 5 * 8, (26 * 8) + 4 },
6,
{
}
};
OptionsField step_mode {
{ 17 * 8, (26 * 8) + 4 },
12,
{
}
};
ButtonWithEncoder button_pause {
{ 0, (15 * 16) - 4, 72, 28 },
"PAUSE"
};
ButtonWithEncoder button_manual_start {
{ 0 * 8, 11 * 16, 11 * 8, 28 },
""
};
Button button_audio_app {
{ 84, (15 * 16) - 4, 72, 28 },
"AUDIO"
};
ButtonWithEncoder button_manual_end {
{ 12 * 8 - 6, 11 * 16, 11 * 8, 28 },
""
};
ButtonWithEncoder button_add {
{ 168, (15 * 16) - 4, 72, 28 },
"<STORE>"
};
Button button_manual_recon {
{ 23 * 8 - 3, 11 * 16, 7 * 8 , 28 },
"SEARCH"
};
Button button_dir {
{ 0, (35 * 8) - 4, 34, 28 },
"FW>"
};
OptionsField field_mode {
{ 5 * 8, (26 * 8) + 4 },
6,
{
}
};
OptionsField step_mode {
{ 17 * 8, (26 * 8) + 4 },
12,
{
}
};
ButtonWithEncoder button_pause {
{ 0, (15 * 16) - 4, 72, 28 },
"PAUSE"
};
Button button_restart {
{ 38, (35 * 8) - 4, 34, 28 },
"RST"
};
Button button_audio_app {
{ 84, (15 * 16) - 4, 72, 28 },
"AUDIO"
};
Button button_mic_app {
{ 84, (35 * 8) - 4, 72, 28 },
"MIC TX"
};
ButtonWithEncoder button_add {
{ 168, (15 * 16) - 4, 72, 28 },
"<STORE>"
};
ButtonWithEncoder button_remove {
{ 168, (35 * 8) - 4, 72, 28 },
"<REMOVE>"
};
Button button_dir {
{ 0, (35 * 8) - 4, 34, 28 },
"FW>"
};
std::unique_ptr<ReconThread> recon_thread { };
Button button_restart {
{ 38, (35 * 8) - 4, 34, 28 },
"RST"
};
MessageHandlerRegistration message_handler_coded_squelch {
Message::ID::CodedSquelch,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const CodedSquelchMessage*>(p);
this->handle_coded_squelch(message.value);
}
};
MessageHandlerRegistration message_handler_retune {
Message::ID::Retune,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const RetuneMessage*>(p);
this->handle_retune(message.freq,message.range);
}
};
Button button_mic_app {
{ 84, (35 * 8) - 4, 72, 28 },
"MIC TX"
};
ButtonWithEncoder button_remove {
{ 168, (35 * 8) - 4, 72, 28 },
"<REMOVE>"
};
std::unique_ptr<ReconThread> recon_thread { };
MessageHandlerRegistration message_handler_retune {
Message::ID::Retune,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const RetuneMessage*>(p);
this->handle_retune(message.freq,message.range);
}
};
MessageHandlerRegistration message_handler_stats {
Message::ID::ChannelStatistics,
[this](const Message* const p) {
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
}
};
// app save settings
std::app_settings settings { };
std::app_settings::AppSettings app_settings { };
};
MessageHandlerRegistration message_handler_stats {
Message::ID::ChannelStatistics,
[this](const Message* const p) {
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
}
};
// app save settings
std::app_settings settings { };
std::app_settings::AppSettings app_settings { };
};
} /* namespace ui */
+232 -232
View File
@@ -34,268 +34,268 @@ using namespace portapack;
namespace ui {
bool ReconSetupLoadStrings( std::string source, std::string &input_file , std::string &output_file , uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , int32_t &recon_squelch_level , uint32_t &recon_match_mode , int32_t &wait , uint32_t &lock_wait , int32_t &volume )
{
File settings_file;
size_t length, file_position = 0;
char * pos;
char * line_start;
char * line_end;
char file_data[257];
bool ReconSetupLoadStrings( std::string source, std::string &input_file , std::string &output_file , uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , int32_t &recon_squelch_level , uint32_t &recon_match_mode , int32_t &wait , uint32_t &lock_wait , int32_t &volume )
{
File settings_file;
size_t length, file_position = 0;
char * pos;
char * line_start;
char * line_end;
char file_data[257];
uint32_t it = 0 ;
uint32_t nb_params = 9 ;
std::string params[ 9 ];
uint32_t it = 0 ;
uint32_t nb_params = 9 ;
std::string params[ 9 ];
bool check_sd_card = (sd_card::status() == sd_card::Status::Mounted) ? true : false ;
bool check_sd_card = (sd_card::status() == sd_card::Status::Mounted) ? true : false ;
if( check_sd_card )
{
auto result = settings_file.open( source );
if( !result.is_valid() )
{
while( it < nb_params )
{
// Read a 256 bytes block from file
settings_file.seek(file_position);
memset(file_data, 0, 257);
auto read_size = settings_file.read(file_data, 256);
if (read_size.is_error())
break ;
file_position += 256;
// Reset line_start to beginning of buffer
line_start = file_data;
pos=line_start;
while ((line_end = strstr(line_start, "\x0A"))) {
length = line_end - line_start - 1 ;
params[ it ] = string( pos , length );
it ++ ;
line_start = line_end + 1;
pos=line_start ;
if (line_start - file_data >= 256)
break;
if( it >= nb_params )
break ;
}
if (read_size.value() != 256)
break; // End of file
if( check_sd_card )
{
auto result = settings_file.open( source );
if( !result.is_valid() )
{
while( it < nb_params )
{
// Read a 256 bytes block from file
settings_file.seek(file_position);
memset(file_data, 0, 257);
auto read_size = settings_file.read(file_data, 256);
if (read_size.is_error())
break ;
file_position += 256;
// Reset line_start to beginning of buffer
line_start = file_data;
pos=line_start;
while ((line_end = strstr(line_start, "\x0A"))) {
length = line_end - line_start - 1 ;
params[ it ] = string( pos , length );
it ++ ;
line_start = line_end + 1;
pos=line_start ;
if (line_start - file_data >= 256)
break;
if( it >= nb_params )
break ;
}
if (read_size.value() != 256)
break; // End of file
// Restart at beginning of last incomplete line
file_position -= (file_data + 256 - line_start);
}
}
// Restart at beginning of last incomplete line
file_position -= (file_data + 256 - line_start);
}
}
}
}
if( it > 0 )
input_file = params[ 0 ];
else
input_file = "RECON" ;
if( it > 0 )
input_file = params[ 0 ];
else
input_file = "RECON" ;
if( it > 1 )
output_file= params[ 1 ];
else
output_file = "RECON_RESULTS" ;
if( it > 1 )
output_file= params[ 1 ];
else
output_file = "RECON_RESULTS" ;
if( it > 2 )
recon_lock_duration = strtoll( params[ 2 ].c_str() , nullptr , 10 );
else
recon_lock_duration = 50 ;
if( it > 2 )
recon_lock_duration = strtoll( params[ 2 ].c_str() , nullptr , 10 );
else
recon_lock_duration = 50 ;
if( it > 3 )
recon_lock_nb_match = strtoll( params[ 3 ].c_str() , nullptr , 10 );
else
recon_lock_nb_match = 10 ;
if( it > 3 )
recon_lock_nb_match = strtoll( params[ 3 ].c_str() , nullptr , 10 );
else
recon_lock_nb_match = 10 ;
if( it > 4 )
recon_squelch_level = strtoll( params[ 4 ].c_str() , nullptr , 10 );
else
recon_squelch_level = -14 ;
if( it > 4 )
recon_squelch_level = strtoll( params[ 4 ].c_str() , nullptr , 10 );
else
recon_squelch_level = -14 ;
if( it > 5 )
recon_match_mode = strtoll( params[ 5 ].c_str() , nullptr , 10 );
else
recon_match_mode = 0 ;
if( it > 5 )
recon_match_mode = strtoll( params[ 5 ].c_str() , nullptr , 10 );
else
recon_match_mode = 0 ;
if( it > 6 )
wait = strtoll( params[ 6 ].c_str() , nullptr , 10 );
else
wait = 5000 ;
if( it > 6 )
wait = strtoll( params[ 6 ].c_str() , nullptr , 10 );
else
wait = 5000 ;
if( it > 7 )
lock_wait = strtoll( params[ 7 ].c_str() , nullptr , 10 );
else
lock_wait = 1000 ;
if( it > 7 )
lock_wait = strtoll( params[ 7 ].c_str() , nullptr , 10 );
else
lock_wait = 1000 ;
if( it > 8 )
volume = strtoll( params[ 8 ].c_str() , nullptr , 10 );
else
volume = 40 ;
if( it > 8 )
volume = strtoll( params[ 8 ].c_str() , nullptr , 10 );
else
volume = 40 ;
if( it < nb_params )
{
/* bad number of params, signal defaults */
return false ;
}
return true ;
}
if( it < nb_params )
{
/* bad number of params, signal defaults */
return false ;
}
return true ;
}
bool ReconSetupSaveStrings( std::string dest, std::string input_file , std::string output_file , uint32_t recon_lock_duration , uint32_t recon_lock_nb_match , int32_t recon_squelch_level , uint32_t recon_match_mode , int32_t wait , uint32_t lock_wait , int32_t volume )
{
File settings_file;
bool ReconSetupSaveStrings( std::string dest, std::string input_file , std::string output_file , uint32_t recon_lock_duration , uint32_t recon_lock_nb_match , int32_t recon_squelch_level , uint32_t recon_match_mode , int32_t wait , uint32_t lock_wait , int32_t volume )
{
File settings_file;
auto result = settings_file.create( dest );
if( result.is_valid() )
return false ;
settings_file.write_line( input_file );
settings_file.write_line( output_file );
settings_file.write_line( to_string_dec_uint( recon_lock_duration ) );
settings_file.write_line( to_string_dec_uint( recon_lock_nb_match ) );
settings_file.write_line( to_string_dec_int( recon_squelch_level ) );
settings_file.write_line( to_string_dec_uint( recon_match_mode ) );
settings_file.write_line( to_string_dec_int( wait ) );
settings_file.write_line( to_string_dec_uint( lock_wait ) );
settings_file.write_line( to_string_dec_int( volume ) );
return true ;
}
auto result = settings_file.create( dest );
if( result.is_valid() )
return false ;
settings_file.write_line( input_file );
settings_file.write_line( output_file );
settings_file.write_line( to_string_dec_uint( recon_lock_duration ) );
settings_file.write_line( to_string_dec_uint( recon_lock_nb_match ) );
settings_file.write_line( to_string_dec_int( recon_squelch_level ) );
settings_file.write_line( to_string_dec_uint( recon_match_mode ) );
settings_file.write_line( to_string_dec_int( wait ) );
settings_file.write_line( to_string_dec_uint( lock_wait ) );
settings_file.write_line( to_string_dec_int( volume ) );
return true ;
}
ReconSetupViewMain::ReconSetupViewMain( NavigationView &nav , Rect parent_rect , std::string input_file , std::string output_file ) : View( parent_rect ) , _input_file { input_file } , _output_file { output_file }
{
hidden(true);
add_children({
&button_load_freqs,
&text_input_file,
&button_save_freqs,
&button_output_file,
&checkbox_autosave_freqs,
&checkbox_autostart_recon,
&checkbox_continuous,
&checkbox_clear_output
});
ReconSetupViewMain::ReconSetupViewMain( NavigationView &nav , Rect parent_rect , std::string input_file , std::string output_file ) : View( parent_rect ) , _input_file { input_file } , _output_file { output_file }
{
hidden(true);
add_children({
&button_load_freqs,
&text_input_file,
&button_save_freqs,
&button_output_file,
&checkbox_autosave_freqs,
&checkbox_autostart_recon,
&checkbox_continuous,
&checkbox_clear_output
});
checkbox_autosave_freqs.set_value( persistent_memory::recon_autosave_freqs() );
checkbox_autostart_recon.set_value( persistent_memory::recon_autostart_recon() );
checkbox_continuous.set_value( persistent_memory::recon_continuous() );
checkbox_clear_output.set_value( persistent_memory::recon_clear_output() );
checkbox_autosave_freqs.set_value( persistent_memory::recon_autosave_freqs() );
checkbox_autostart_recon.set_value( persistent_memory::recon_autostart_recon() );
checkbox_continuous.set_value( persistent_memory::recon_continuous() );
checkbox_clear_output.set_value( persistent_memory::recon_clear_output() );
text_input_file.set( _input_file );
button_output_file.set_text( _output_file );
text_input_file.set( _input_file );
button_output_file.set_text( _output_file );
button_load_freqs.on_select = [this, &nav](Button&) {
auto open_view = nav.push<FileLoadView>(".TXT");
open_view->on_changed = [this,&nav](std::filesystem::path new_file_path) {
std::string dir_filter = "FREQMAN/";
std::string str_file_path = new_file_path.string();
if (str_file_path.find(dir_filter) != string::npos) { // assert file from the FREQMAN folder
// get the filename without txt extension so we can use load_freqman_file fcn
_input_file = new_file_path.stem().string();
text_input_file.set( _input_file );
} else {
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
}
};
};
button_load_freqs.on_select = [this, &nav](Button&) {
auto open_view = nav.push<FileLoadView>(".TXT");
open_view->on_changed = [this,&nav](std::filesystem::path new_file_path) {
std::string dir_filter = "FREQMAN/";
std::string str_file_path = new_file_path.string();
if (str_file_path.find(dir_filter) != string::npos) { // assert file from the FREQMAN folder
// get the filename without txt extension so we can use load_freqman_file fcn
_input_file = new_file_path.stem().string();
text_input_file.set( _input_file );
} else {
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
}
};
};
button_save_freqs.on_select = [this, &nav](Button&) {
auto open_view = nav.push<FileLoadView>(".TXT");
open_view->on_changed = [this,&nav](std::filesystem::path new_file_path) {
std::string dir_filter = "FREQMAN/";
std::string str_file_path = new_file_path.string();
if (str_file_path.find(dir_filter) != string::npos) { // assert file from the FREQMAN folder
_output_file = new_file_path.stem().string();
button_output_file.set_text( _output_file );
} else {
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
}
};
};
button_save_freqs.on_select = [this, &nav](Button&) {
auto open_view = nav.push<FileLoadView>(".TXT");
open_view->on_changed = [this,&nav](std::filesystem::path new_file_path) {
std::string dir_filter = "FREQMAN/";
std::string str_file_path = new_file_path.string();
if (str_file_path.find(dir_filter) != string::npos) { // assert file from the FREQMAN folder
_output_file = new_file_path.stem().string();
button_output_file.set_text( _output_file );
} else {
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
}
};
};
button_output_file.on_select =[this, &nav](Button&) {
text_prompt( nav, _output_file , 28 ,
[this](std::string& buffer) {
_output_file = buffer ;
button_output_file.set_text( _output_file );
} );
};
};
button_output_file.on_select =[this, &nav](Button&) {
text_prompt( nav, _output_file , 28 ,
[this](std::string& buffer) {
_output_file = buffer ;
button_output_file.set_text( _output_file );
} );
};
};
void ReconSetupViewMain::Save( std::string &input_file , std::string &output_file ) {
persistent_memory::set_recon_autosave_freqs(checkbox_autosave_freqs.value());
persistent_memory::set_recon_autostart_recon(checkbox_autostart_recon.value());
persistent_memory::set_recon_continuous(checkbox_continuous.value());
persistent_memory::set_recon_clear_output(checkbox_clear_output.value());
input_file=_input_file ;
output_file=_output_file ;
};
void ReconSetupViewMore::Save( uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , uint32_t &recon_match_mode ) {
persistent_memory::set_recon_load_freqs(checkbox_load_freqs.value());
persistent_memory::set_recon_load_ranges(checkbox_load_ranges.value());
persistent_memory::set_recon_load_hamradios(checkbox_load_hamradios.value());
persistent_memory::set_recon_update_ranges_when_recon(checkbox_update_ranges_when_recon.value());
recon_lock_duration = field_recon_lock_duration.value();
recon_lock_nb_match = field_recon_lock_nb_match.value();
recon_match_mode = field_recon_match_mode . selected_index_value() ;
};
void ReconSetupViewMain::Save( std::string &input_file , std::string &output_file ) {
persistent_memory::set_recon_autosave_freqs(checkbox_autosave_freqs.value());
persistent_memory::set_recon_autostart_recon(checkbox_autostart_recon.value());
persistent_memory::set_recon_continuous(checkbox_continuous.value());
persistent_memory::set_recon_clear_output(checkbox_clear_output.value());
input_file=_input_file ;
output_file=_output_file ;
};
void ReconSetupViewMore::Save( uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , uint32_t &recon_match_mode ) {
persistent_memory::set_recon_load_freqs(checkbox_load_freqs.value());
persistent_memory::set_recon_load_ranges(checkbox_load_ranges.value());
persistent_memory::set_recon_load_hamradios(checkbox_load_hamradios.value());
persistent_memory::set_recon_update_ranges_when_recon(checkbox_update_ranges_when_recon.value());
recon_lock_duration = field_recon_lock_duration.value();
recon_lock_nb_match = field_recon_lock_nb_match.value();
recon_match_mode = field_recon_match_mode . selected_index_value() ;
};
void ReconSetupViewMain::focus() {
button_load_freqs.focus();
}
void ReconSetupViewMain::focus() {
button_load_freqs.focus();
}
ReconSetupViewMore::ReconSetupViewMore( NavigationView &nav , Rect parent_rect , uint32_t recon_lock_duration , uint32_t recon_lock_nb_match , uint32_t recon_match_mode ) : View( parent_rect ), _recon_lock_duration { recon_lock_duration } , _recon_lock_nb_match { recon_lock_nb_match } , _recon_match_mode { recon_match_mode }
{
(void)nav;
hidden(true);
ReconSetupViewMore::ReconSetupViewMore( NavigationView &nav , Rect parent_rect , uint32_t recon_lock_duration , uint32_t recon_lock_nb_match , uint32_t recon_match_mode ) : View( parent_rect ), _recon_lock_duration { recon_lock_duration } , _recon_lock_nb_match { recon_lock_nb_match } , _recon_match_mode { recon_match_mode }
{
(void)nav;
hidden(true);
add_children({
&checkbox_load_freqs,
&checkbox_load_ranges,
&checkbox_load_hamradios,
&checkbox_update_ranges_when_recon,
&text_recon_lock_duration,
&field_recon_lock_duration,
&text_recon_lock_nb,
&field_recon_lock_nb_match,
&field_recon_match_mode,
});
add_children({
&checkbox_load_freqs,
&checkbox_load_ranges,
&checkbox_load_hamradios,
&checkbox_update_ranges_when_recon,
&text_recon_lock_duration,
&field_recon_lock_duration,
&text_recon_lock_nb,
&field_recon_lock_nb_match,
&field_recon_match_mode,
});
checkbox_load_freqs.set_value( persistent_memory::recon_load_freqs() );
checkbox_load_ranges.set_value( persistent_memory::recon_load_ranges() );
checkbox_load_hamradios.set_value( persistent_memory::recon_load_hamradios() );
checkbox_update_ranges_when_recon.set_value( persistent_memory::recon_update_ranges_when_recon() );
field_recon_lock_duration.set_value( _recon_lock_duration );
field_recon_lock_nb_match.set_value( _recon_lock_nb_match );
field_recon_match_mode.set_by_value( _recon_match_mode );
};
checkbox_load_freqs.set_value( persistent_memory::recon_load_freqs() );
checkbox_load_ranges.set_value( persistent_memory::recon_load_ranges() );
checkbox_load_hamradios.set_value( persistent_memory::recon_load_hamradios() );
checkbox_update_ranges_when_recon.set_value( persistent_memory::recon_update_ranges_when_recon() );
field_recon_lock_duration.set_value( _recon_lock_duration );
field_recon_lock_nb_match.set_value( _recon_lock_nb_match );
field_recon_match_mode.set_by_value( _recon_match_mode );
};
void ReconSetupViewMore::focus() {
checkbox_load_freqs.focus();
}
void ReconSetupViewMore::focus() {
checkbox_load_freqs.focus();
}
void ReconSetupView::focus() {
viewMain.focus();
}
void ReconSetupView::focus() {
viewMain.focus();
}
ReconSetupView::ReconSetupView(
NavigationView& nav , std::string _input_file , std::string _output_file , uint32_t _recon_lock_duration , uint32_t _recon_lock_nb_match , uint32_t _recon_match_mode ) : nav_ { nav } , input_file { _input_file } , output_file { _output_file } , recon_lock_duration { _recon_lock_duration } , recon_lock_nb_match { _recon_lock_nb_match } , recon_match_mode { _recon_match_mode }
{
add_children({
&tab_view,
&viewMain,
&viewMore,
&button_save
});
ReconSetupView::ReconSetupView(
NavigationView& nav , std::string _input_file , std::string _output_file , uint32_t _recon_lock_duration , uint32_t _recon_lock_nb_match , uint32_t _recon_match_mode ) : nav_ { nav } , input_file { _input_file } , output_file { _output_file } , recon_lock_duration { _recon_lock_duration } , recon_lock_nb_match { _recon_lock_nb_match } , recon_match_mode { _recon_match_mode }
{
add_children({
&tab_view,
&viewMain,
&viewMore,
&button_save
});
button_save.on_select = [this,&nav](Button&) {
viewMain.Save( input_file , output_file );
viewMore.Save( recon_lock_duration , recon_lock_nb_match , recon_match_mode );
std::vector<std::string> messages ;
messages.push_back( input_file );
messages.push_back( output_file );
messages.push_back( to_string_dec_uint( recon_lock_duration ) );
messages.push_back( to_string_dec_uint( recon_lock_nb_match ) );
messages.push_back( to_string_dec_uint( recon_match_mode ) );
on_changed( messages );
nav.pop();
};
}
button_save.on_select = [this,&nav](Button&) {
viewMain.Save( input_file , output_file );
viewMore.Save( recon_lock_duration , recon_lock_nb_match , recon_match_mode );
std::vector<std::string> messages ;
messages.push_back( input_file );
messages.push_back( output_file );
messages.push_back( to_string_dec_uint( recon_lock_duration ) );
messages.push_back( to_string_dec_uint( recon_lock_nb_match ) );
messages.push_back( to_string_dec_uint( recon_match_mode ) );
on_changed( messages );
nav.pop();
};
}
} /* namespace ui */
+134 -134
View File
@@ -29,166 +29,166 @@
namespace ui {
bool ReconSetupLoadStrings( std::string source, std::string &input_file , std::string &output_file , uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , int32_t &recon_squelch_level , uint32_t &recon_match_mode , int32_t &wait , uint32_t &lock_wait , int32_t &volume );
bool ReconSetupSaveStrings( std::string dest, const std::string input_file , const std::string output_file , const uint32_t recon_lock_duration , const uint32_t recon_lock_nb_match , int32_t recon_squelch_level , uint32_t recon_match_mode , int32_t wait , uint32_t lock_wait , int32_t volume );
bool ReconSetupLoadStrings( std::string source, std::string &input_file , std::string &output_file , uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , int32_t &recon_squelch_level , uint32_t &recon_match_mode , int32_t &wait , uint32_t &lock_wait , int32_t &volume );
bool ReconSetupSaveStrings( std::string dest, const std::string input_file , const std::string output_file , const uint32_t recon_lock_duration , const uint32_t recon_lock_nb_match , int32_t recon_squelch_level , uint32_t recon_match_mode , int32_t wait , uint32_t lock_wait , int32_t volume );
class ReconSetupViewMain : public View {
public:
ReconSetupViewMain( NavigationView& nav, Rect parent_rect , std::string input_file , std::string output_file );
void Save( std::string &input_file , std::string &output_file );
void focus() override;
class ReconSetupViewMain : public View {
public:
ReconSetupViewMain( NavigationView& nav, Rect parent_rect , std::string input_file , std::string output_file );
void Save( std::string &input_file , std::string &output_file );
void focus() override;
private:
std::string _input_file = { "RECON" };
std::string _output_file = { "RECON_RESULTS" };
private:
std::string _input_file = { "RECON" };
std::string _output_file = { "RECON_RESULTS" };
Button button_load_freqs {
{ 1 * 8 , 12 , 18 * 8 , 22 },
"select input file"
};
Text text_input_file {
{ 1 * 8 , 4 + 2 * 16, 18 * 8, 22 },
"RECON"
};
Button button_load_freqs {
{ 1 * 8 , 12 , 18 * 8 , 22 },
"select input file"
};
Text text_input_file {
{ 1 * 8 , 4 + 2 * 16, 18 * 8, 22 },
"RECON"
};
Button button_save_freqs {
{ 1 * 8 , 4 * 16 - 8 , 18 * 8 , 22 },
"select output file"
};
Button button_output_file {
{ 1 * 8 , 5 * 16 - 2, 18 * 8, 22 },
"RECON_RESULTS"
};
Button button_save_freqs {
{ 1 * 8 , 4 * 16 - 8 , 18 * 8 , 22 },
"select output file"
};
Button button_output_file {
{ 1 * 8 , 5 * 16 - 2, 18 * 8, 22 },
"RECON_RESULTS"
};
Checkbox checkbox_autosave_freqs {
{ 1 * 8, 7 * 16 - 4 },
3,
"autosave freqs"
};
Checkbox checkbox_autosave_freqs {
{ 1 * 8, 7 * 16 - 4 },
3,
"autosave freqs"
};
Checkbox checkbox_autostart_recon {
{ 1 * 8, 9 * 16 - 4 },
3,
"autostart recon"
};
Checkbox checkbox_autostart_recon {
{ 1 * 8, 9 * 16 - 4 },
3,
"autostart recon"
};
Checkbox checkbox_continuous {
{ 1 * 8, 11 * 16 - 4 },
3,
"continuous"
};
Checkbox checkbox_clear_output {
{ 1 * 8, 13 * 16 - 4 },
3,
"clear output at start"
};
};
Checkbox checkbox_continuous {
{ 1 * 8, 11 * 16 - 4 },
3,
"continuous"
};
Checkbox checkbox_clear_output {
{ 1 * 8, 13 * 16 - 4 },
3,
"clear output at start"
};
};
class ReconSetupViewMore : public View {
public:
ReconSetupViewMore( NavigationView& nav, Rect parent_rect , const uint32_t _recon_lock_duration , const uint32_t _recon_lock_nb_match , const uint32_t _recon_match_mode );
class ReconSetupViewMore : public View {
public:
ReconSetupViewMore( NavigationView& nav, Rect parent_rect , const uint32_t _recon_lock_duration , const uint32_t _recon_lock_nb_match , const uint32_t _recon_match_mode );
void Save( uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , uint32_t &recon_match_mode );
void Save( uint32_t &recon_lock_duration , uint32_t &recon_lock_nb_match , uint32_t &recon_match_mode );
void focus() override;
void focus() override;
private:
private:
const uint32_t _recon_lock_duration = 50 ;
const uint32_t _recon_lock_nb_match = 10 ;
const uint32_t _recon_match_mode = 0 ;
const uint32_t _recon_lock_duration = 50 ;
const uint32_t _recon_lock_nb_match = 10 ;
const uint32_t _recon_match_mode = 0 ;
Checkbox checkbox_load_freqs {
{ 1 * 8, 12 },
3,
"input: load freqs"
};
Checkbox checkbox_load_freqs {
{ 1 * 8, 12 },
3,
"input: load freqs"
};
Checkbox checkbox_load_ranges {
{ 1 * 8, 42 },
3,
"input: load ranges"
};
Checkbox checkbox_load_ranges {
{ 1 * 8, 42 },
3,
"input: load ranges"
};
Checkbox checkbox_load_hamradios {
{ 1 * 8, 72 },
3,
"input: load hamradios"
};
Checkbox checkbox_load_hamradios {
{ 1 * 8, 72 },
3,
"input: load hamradios"
};
Checkbox checkbox_update_ranges_when_recon {
{ 1 * 8, 102 },
3,
"auto update m-ranges"
};
Text text_recon_lock_duration {
{ 1 * 8 , 132 , 22 * 8 , 22 },
" ms (lock duration)"
};
NumberField field_recon_lock_duration {
{ 1 * 8, 132 }, // position X , Y
4, // number of displayed digits (even empty)
{ 50 , 990 }, // range of number
10, // rotary encoder increment
' ', // filling character
false // can loop
};
Text text_recon_lock_nb {
{ 1 * 8 , 162 , 25 * 8 , 22 },
" x (nb lock to match freq)"
};
NumberField field_recon_lock_nb_match {
{ 1 * 8, 162 },
4,
{ 1, 99 },
1,
' ',
false
};
OptionsField field_recon_match_mode {
{ 1 * 8, 192 },
20, // CONTINUOUS MATCH MODE / SPARSE TIMED MATCH MODE
{
{ "SQL MATCH: CONTINOUS" , 0 },
{ "SQL MATCH: SPARSE" , 1 }
}
};
};
Checkbox checkbox_update_ranges_when_recon {
{ 1 * 8, 102 },
3,
"auto update m-ranges"
};
Text text_recon_lock_duration {
{ 1 * 8 , 132 , 22 * 8 , 22 },
" ms (lock duration)"
};
NumberField field_recon_lock_duration {
{ 1 * 8, 132 }, // position X , Y
4, // number of displayed digits (even empty)
{ 50 , 990 }, // range of number
10, // rotary encoder increment
' ', // filling character
false // can loop
};
Text text_recon_lock_nb {
{ 1 * 8 , 162 , 25 * 8 , 22 },
" x (nb lock to match freq)"
};
NumberField field_recon_lock_nb_match {
{ 1 * 8, 162 },
4,
{ 1, 99 },
1,
' ',
false
};
OptionsField field_recon_match_mode {
{ 1 * 8, 192 },
20, // CONTINUOUS MATCH MODE / SPARSE TIMED MATCH MODE
{
{ "SQL MATCH: CONTINOUS" , 0 },
{ "SQL MATCH: SPARSE" , 1 }
}
};
};
class ReconSetupView : public View {
public:
ReconSetupView( NavigationView& nav , std::string _input_file , std::string _output_file , const uint32_t _recon_lock_duration , const uint32_t _recon_lock_nb_match , const uint32_t _recon_match_mode );
class ReconSetupView : public View {
public:
ReconSetupView( NavigationView& nav , std::string _input_file , std::string _output_file , const uint32_t _recon_lock_duration , const uint32_t _recon_lock_nb_match , const uint32_t _recon_match_mode );
std::function<void( std::vector<std::string> messages )> on_changed { };
std::function<void( std::vector<std::string> messages )> on_changed { };
void focus() override;
void focus() override;
std::string title() const override { return "Recon setup"; };
std::string title() const override { return "Recon setup"; };
private:
private:
NavigationView& nav_ ;
NavigationView& nav_ ;
std::string input_file = { "RECON" };
std::string output_file = { "RECON_RESULTS" };
uint32_t recon_lock_duration = 50 ;
uint32_t recon_lock_nb_match = 10 ;
uint32_t recon_match_mode = 0 ;
std::string input_file = { "RECON" };
std::string output_file = { "RECON_RESULTS" };
uint32_t recon_lock_duration = 50 ;
uint32_t recon_lock_nb_match = 10 ;
uint32_t recon_match_mode = 0 ;
Rect view_rect = { 0, 3 * 8, 240, 230 };
Rect view_rect = { 0, 3 * 8, 240, 230 };
ReconSetupViewMain viewMain{ nav_ , view_rect , input_file , output_file };
ReconSetupViewMore viewMore{ nav_ , view_rect , recon_lock_duration , recon_lock_nb_match , recon_match_mode };
ReconSetupViewMain viewMain{ nav_ , view_rect , input_file , output_file };
ReconSetupViewMore viewMore{ nav_ , view_rect , recon_lock_duration , recon_lock_nb_match , recon_match_mode };
TabView tab_view {
{ "Main", Color::cyan() , &viewMain },
{ "More", Color::green(), &viewMore }
};
Button button_save {
{ 9 * 8, 255, 14 * 8 , 40 },
"SAVE"
};
};
TabView tab_view {
{ "Main", Color::cyan() , &viewMain },
{ "More", Color::green(), &viewMore }
};
Button button_save {
{ 9 * 8, 255, 14 * 8 , 40 },
"SAVE"
};
};
} /* namespace ui */
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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 "ui_sd_over_usb.hpp"
#include "portapack_shared_memory.hpp"
namespace ui {
SdOverUsbView::SdOverUsbView(NavigationView& nav) : nav_ (nav) {
add_children({
&labels,
&button_run
});
button_run.on_select = [this](Button&) {
ui::Painter painter;
painter.fill_rectangle(
{ 0, 0, portapack::display.width(), portapack::display.height() },
ui::Color::black()
);
painter.draw_bitmap(
{ portapack::display.width()/2-8, portapack::display.height()/2-8 },
bitmap_icon_hackrf,
ui::Color::yellow(),
ui::Color::black()
);
sdcDisconnect(&SDCD1);
sdcStop(&SDCD1);
portapack::shutdown(true);
m4_init(portapack::spi_flash::image_tag_usb_sd, portapack::memory::map::m4_code, false);
m0_halt();
/* will not return*/
};
}
void SdOverUsbView::focus() {
button_run.focus();
}
} /* namespace ui */
@@ -0,0 +1,64 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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.
*/
#ifndef __UI_SD_OVER_USB_H__
#define __UI_SD_OVER_USB_H__
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "string_format.hpp"
#include "ff.h"
#include "baseband_api.hpp"
#include "core_control.hpp"
#include <cstdint>
namespace ui {
class SdOverUsbView : public View {
public:
SdOverUsbView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Flash Utility"; };
private:
NavigationView& nav_;
Labels labels {
{ { 3 * 8, 2 * 16 }, "Click Run to start the", Color::white() },
{ { 3 * 8, 3 * 16 }, "USB Mass Storage Mode.", Color::white() },
{ { 3 * 8, 5 * 16 }, "It can take up to 20s", Color::white() },
{ { 3 * 8, 6 * 16 }, "for the drive to be", Color::white() },
{ { 3 * 8, 7 * 16 }, "available.", Color::white() },
};
Button button_run {
{ 9 * 8, 15 * 16, 12 * 8, 3 * 16 },
"Run"
};
};
} /* namespace ui */
#endif /*__UI_SD_OVER_USB_H__*/
+1 -1
View File
@@ -38,7 +38,7 @@ public:
~WipeSDView();
void focus() override;
std::string title() const override { return "Wipe SD Card"; };
std::string title() const override { return "Wipe sdcard"; };
private:
NavigationView& nav_;
+488 -313
View File
@@ -38,353 +38,528 @@ using namespace portapack;
#include "ui_font_fixed_8x16.hpp"
#include "cpld_update.hpp"
#include "freqman.hpp"
namespace ui {
SetDateTimeView::SetDateTimeView(
NavigationView& nav
) {
button_save.on_select = [&nav, this](Button&){
const auto model = this->form_collect();
const rtc::RTC new_datetime {
model.year, model.month, model.day,
model.hour, model.minute, model.second
SetDateTimeView::SetDateTimeView(
NavigationView& nav
) {
button_save.on_select = [&nav, this](Button&){
const auto model = this->form_collect();
const rtc::RTC new_datetime {
model.year, model.month, model.day,
model.hour, model.minute, model.second
};
rtcSetTime(&RTCD1, &new_datetime);
nav.pop();
},
button_cancel.on_select = [&nav](Button&){
nav.pop();
},
add_children({
&labels,
&field_year,
&field_month,
&field_day,
&field_hour,
&field_minute,
&field_second,
&button_save,
&button_cancel,
});
rtc::RTC datetime;
rtcGetTime(&RTCD1, &datetime);
SetDateTimeModel model {
datetime.year(),
datetime.month(),
datetime.day(),
datetime.hour(),
datetime.minute(),
datetime.second()
};
rtcSetTime(&RTCD1, &new_datetime);
nav.pop();
},
button_cancel.on_select = [&nav](Button&){
nav.pop();
},
add_children({
&labels,
&field_year,
&field_month,
&field_day,
&field_hour,
&field_minute,
&field_second,
&button_save,
&button_cancel,
});
rtc::RTC datetime;
rtcGetTime(&RTCD1, &datetime);
SetDateTimeModel model {
datetime.year(),
datetime.month(),
datetime.day(),
datetime.hour(),
datetime.minute(),
datetime.second()
};
form_init(model);
}
void SetDateTimeView::focus() {
button_cancel.focus();
}
void SetDateTimeView::form_init(const SetDateTimeModel& model) {
field_year.set_value(model.year);
field_month.set_value(model.month);
field_day.set_value(model.day);
field_hour.set_value(model.hour);
field_minute.set_value(model.minute);
field_second.set_value(model.second);
}
SetDateTimeModel SetDateTimeView::form_collect() {
return {
.year = static_cast<uint16_t>(field_year.value()),
.month = static_cast<uint8_t>(field_month.value()),
.day = static_cast<uint8_t>(field_day.value()),
.hour = static_cast<uint8_t>(field_hour.value()),
.minute = static_cast<uint8_t>(field_minute.value()),
.second = static_cast<uint8_t>(field_second.value())
};
}
SetRadioView::SetRadioView(
NavigationView& nav
) {
button_cancel.on_select = [&nav](Button&){
nav.pop();
};
const auto reference = portapack::clock_manager.get_reference();
std::string source_name("---");
switch(reference.source) {
case ClockManager::ReferenceSource::Xtal: source_name = "HackRF"; break;
case ClockManager::ReferenceSource::PortaPack: source_name = "PortaPack"; break;
case ClockManager::ReferenceSource::External: source_name = "External"; break;
form_init(model);
}
value_source.set(source_name);
value_source_frequency.set(to_string_dec_uint(reference.frequency / 1000000, 2) + "." + to_string_dec_uint((reference.frequency % 1000000) / 100, 4, '0') + " MHz");
void SetDateTimeView::focus() {
button_cancel.focus();
}
label_source.set_style(&style_text);
value_source.set_style(&style_text);
value_source_frequency.set_style(&style_text);
void SetDateTimeView::form_init(const SetDateTimeModel& model) {
field_year.set_value(model.year);
field_month.set_value(model.month);
field_day.set_value(model.day);
field_hour.set_value(model.hour);
field_minute.set_value(model.minute);
field_second.set_value(model.second);
}
add_children({
&label_source,
&value_source,
&value_source_frequency,
});
SetDateTimeModel SetDateTimeView::form_collect() {
return {
.year = static_cast<uint16_t>(field_year.value()),
.month = static_cast<uint8_t>(field_month.value()),
.day = static_cast<uint8_t>(field_day.value()),
.hour = static_cast<uint8_t>(field_hour.value()),
.minute = static_cast<uint8_t>(field_minute.value()),
.second = static_cast<uint8_t>(field_second.value())
};
}
SetRadioView::SetRadioView(
NavigationView& nav
) {
button_cancel.on_select = [&nav](Button&){
nav.pop();
};
const auto reference = portapack::clock_manager.get_reference();
std::string source_name("---");
switch(reference.source) {
case ClockManager::ReferenceSource::Xtal: source_name = "HackRF"; break;
case ClockManager::ReferenceSource::PortaPack: source_name = "PortaPack"; break;
case ClockManager::ReferenceSource::External: source_name = "External"; break;
}
value_source.set(source_name);
value_source_frequency.set(to_string_dec_uint(reference.frequency / 1000000, 2) + "." + to_string_dec_uint((reference.frequency % 1000000) / 100, 4, '0') + " MHz");
label_source.set_style(&style_text);
value_source.set_style(&style_text);
value_source_frequency.set_style(&style_text);
if( reference.source == ClockManager::ReferenceSource::Xtal ) {
add_children({
&labels_correction,
&field_ppm,
});
&label_source,
&value_source,
&value_source_frequency,
});
if( reference.source == ClockManager::ReferenceSource::Xtal ) {
add_children({
&labels_correction,
&field_ppm,
});
}
add_children({
&check_clkout,
&field_clkout_freq,
&labels_clkout_khz,
&value_freq_step,
&labels_bias,
&check_bias,
&button_save,
&button_cancel
});
SetFrequencyCorrectionModel model {
static_cast<int8_t>(portapack::persistent_memory::correction_ppb() / 1000) , 0
};
form_init(model);
check_clkout.set_value(portapack::persistent_memory::clkout_enabled());
check_clkout.on_select = [this](Checkbox&, bool v) {
clock_manager.enable_clock_output(v);
portapack::persistent_memory::set_clkout_enabled(v);
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
};
field_clkout_freq.set_value(portapack::persistent_memory::clkout_freq());
value_freq_step.set_style(&style_text);
field_clkout_freq.on_select = [this](NumberField&) {
freq_step_khz++;
if(freq_step_khz > 3) {
freq_step_khz = 0;
}
switch(freq_step_khz) {
case 0:
value_freq_step.set(" |");
break;
case 1:
value_freq_step.set(" | ");
break;
case 2:
value_freq_step.set(" | ");
break;
case 3:
value_freq_step.set("| ");
break;
}
field_clkout_freq.set_step(pow(10, freq_step_khz));
};
check_bias.set_value(portapack::get_antenna_bias());
check_bias.on_select = [this](Checkbox&, bool v) {
portapack::set_antenna_bias(v);
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
};
button_save.on_select = [this, &nav](Button&){
const auto model = this->form_collect();
portapack::persistent_memory::set_correction_ppb(model.ppm * 1000);
portapack::persistent_memory::set_clkout_freq(model.freq);
clock_manager.enable_clock_output(portapack::persistent_memory::clkout_enabled());
nav.pop();
};
}
add_children({
&check_clkout,
&field_clkout_freq,
&labels_clkout_khz,
&value_freq_step,
&labels_bias,
&check_bias,
&button_save,
&button_cancel
});
void SetRadioView::focus() {
button_save.focus();
}
SetFrequencyCorrectionModel model {
static_cast<int8_t>(portapack::persistent_memory::correction_ppb() / 1000) , 0
};
void SetRadioView::form_init(const SetFrequencyCorrectionModel& model) {
field_ppm.set_value(model.ppm);
}
form_init(model);
check_clkout.set_value(portapack::persistent_memory::clkout_enabled());
check_clkout.on_select = [this](Checkbox&, bool v) {
clock_manager.enable_clock_output(v);
portapack::persistent_memory::set_clkout_enabled(v);
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
};
field_clkout_freq.set_value(portapack::persistent_memory::clkout_freq());
value_freq_step.set_style(&style_text);
field_clkout_freq.on_select = [this](NumberField&) {
freq_step_khz++;
if(freq_step_khz > 3) {
freq_step_khz = 0;
}
switch(freq_step_khz) {
case 0:
value_freq_step.set(" |");
break;
case 1:
value_freq_step.set(" | ");
break;
case 2:
value_freq_step.set(" | ");
break;
case 3:
value_freq_step.set("| ");
break;
}
field_clkout_freq.set_step(pow(10, freq_step_khz));
};
check_bias.set_value(portapack::get_antenna_bias());
check_bias.on_select = [this](Checkbox&, bool v) {
portapack::set_antenna_bias(v);
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
};
button_save.on_select = [this, &nav](Button&){
const auto model = this->form_collect();
portapack::persistent_memory::set_correction_ppb(model.ppm * 1000);
portapack::persistent_memory::set_clkout_freq(model.freq);
clock_manager.enable_clock_output(portapack::persistent_memory::clkout_enabled());
nav.pop();
};
}
void SetRadioView::focus() {
button_save.focus();
}
void SetRadioView::form_init(const SetFrequencyCorrectionModel& model) {
field_ppm.set_value(model.ppm);
}
SetFrequencyCorrectionModel SetRadioView::form_collect() {
return {
.ppm = static_cast<int8_t>(field_ppm.value()),
.freq = static_cast<uint32_t>(field_clkout_freq.value()),
};
}
SetUIView::SetUIView(NavigationView& nav) {
add_children({
&checkbox_disable_touchscreen,
&checkbox_speaker,
&checkbox_bloff,
&options_bloff,
&checkbox_showsplash,
&checkbox_showclock,
&options_clockformat,
&checkbox_guireturnflag,
&button_save,
&button_cancel
});
checkbox_disable_touchscreen.set_value(persistent_memory::disable_touchscreen());
checkbox_speaker.set_value(persistent_memory::config_speaker());
checkbox_showsplash.set_value(persistent_memory::config_splash());
checkbox_showclock.set_value(!persistent_memory::hide_clock());
checkbox_guireturnflag.set_value(persistent_memory::show_gui_return_icon());
const auto backlight_config = persistent_memory::config_backlight_timer();
checkbox_bloff.set_value(backlight_config.timeout_enabled());
options_bloff.set_by_value(backlight_config.timeout_enum());
if (persistent_memory::clock_with_date()) {
options_clockformat.set_selected_index(1);
} else {
options_clockformat.set_selected_index(0);
SetFrequencyCorrectionModel SetRadioView::form_collect() {
return {
.ppm = static_cast<int8_t>(field_ppm.value()),
.freq = static_cast<uint32_t>(field_clkout_freq.value()),
};
}
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_config_backlight_timer({
(persistent_memory::backlight_timeout_t)options_bloff.selected_index_value(),
checkbox_bloff.value()
});
if (checkbox_showclock.value()){
if (options_clockformat.selected_index() == 1)
persistent_memory::set_clock_with_date(true);
else
persistent_memory::set_clock_with_date(false);
SetUIView::SetUIView(NavigationView& nav) {
add_children({
&checkbox_disable_touchscreen,
&checkbox_speaker,
&checkbox_bloff,
&options_bloff,
&checkbox_showsplash,
&checkbox_showclock,
&options_clockformat,
&checkbox_guireturnflag,
&button_save,
&button_cancel
});
checkbox_disable_touchscreen.set_value(persistent_memory::disable_touchscreen());
checkbox_speaker.set_value(persistent_memory::config_speaker());
checkbox_showsplash.set_value(persistent_memory::config_splash());
checkbox_showclock.set_value(!persistent_memory::hide_clock());
checkbox_guireturnflag.set_value(persistent_memory::show_gui_return_icon());
const auto backlight_config = persistent_memory::config_backlight_timer();
checkbox_bloff.set_value(backlight_config.timeout_enabled());
options_bloff.set_by_value(backlight_config.timeout_enum());
if (persistent_memory::clock_with_date()) {
options_clockformat.set_selected_index(1);
} else {
options_clockformat.set_selected_index(0);
}
if (checkbox_speaker.value()) audio::output::speaker_mute(); //Just mute audio if speaker is disabled
persistent_memory::set_config_speaker(checkbox_speaker.value()); //Store Speaker status
StatusRefreshMessage message { }; //Refresh status bar with/out speaker
EventDispatcher::send_message(message);
persistent_memory::set_config_splash(checkbox_showsplash.value());
persistent_memory::set_clock_hidden(!checkbox_showclock.value());
persistent_memory::set_gui_return_icon(checkbox_guireturnflag.value());
persistent_memory::set_disable_touchscreen(checkbox_disable_touchscreen.value());
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetUIView::focus() {
button_save.focus();
}
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_config_backlight_timer({
(persistent_memory::backlight_timeout_t)options_bloff.selected_index_value(),
checkbox_bloff.value()
});
if (checkbox_showclock.value()){
if (options_clockformat.selected_index() == 1)
persistent_memory::set_clock_with_date(true);
else
persistent_memory::set_clock_with_date(false);
}
if (checkbox_speaker.value()) audio::output::speaker_mute(); //Just mute audio if speaker is disabled
persistent_memory::set_config_speaker(checkbox_speaker.value()); //Store Speaker status
StatusRefreshMessage message { }; //Refresh status bar with/out speaker
EventDispatcher::send_message(message);
persistent_memory::set_config_splash(checkbox_showsplash.value());
persistent_memory::set_clock_hidden(!checkbox_showclock.value());
persistent_memory::set_gui_return_icon(checkbox_guireturnflag.value());
persistent_memory::set_disable_touchscreen(checkbox_disable_touchscreen.value());
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetUIView::focus() {
button_save.focus();
}
// ---------------------------------------------------------
// Appl. Settings
// ---------------------------------------------------------
SetAppSettingsView::SetAppSettingsView(NavigationView& nav) {
add_children({
&checkbox_load_app_settings,
&checkbox_save_app_settings,
&button_save,
&button_cancel
});
checkbox_load_app_settings.set_value(persistent_memory::load_app_settings());
checkbox_save_app_settings.set_value(persistent_memory::save_app_settings());
// ---------------------------------------------------------
// Appl. Settings
// ---------------------------------------------------------
SetAppSettingsView::SetAppSettingsView(NavigationView& nav) {
add_children({
&checkbox_load_app_settings,
&checkbox_save_app_settings,
&button_save,
&button_cancel
});
checkbox_load_app_settings.set_value(persistent_memory::load_app_settings());
checkbox_save_app_settings.set_value(persistent_memory::save_app_settings());
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_load_app_settings(checkbox_load_app_settings.value());
persistent_memory::set_save_app_settings(checkbox_save_app_settings.value());
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_load_app_settings(checkbox_load_app_settings.value());
persistent_memory::set_save_app_settings(checkbox_save_app_settings.value());
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetAppSettingsView::focus() {
button_save.focus();
}
void SetAppSettingsView::focus() {
button_save.focus();
}
SetAudioView::SetAudioView(NavigationView& nav) {
add_children({
&labels,
&field_tone_mix,
&button_save,
&button_cancel
});
// ---------------------------------------------------------
// Converter Settings
// ---------------------------------------------------------
SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) {
add_children({
&check_show_converter,
&check_converter,
&converter_mode,
&button_converter_freq,
&button_save,
&button_cancel
});
field_tone_mix.set_value(persistent_memory::tone_mix());
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_tone_mix(field_tone_mix.value());
nav.pop();
};
check_show_converter.set_value(!portapack::persistent_memory::config_hide_converter());
check_show_converter.on_select = [this](Checkbox&, bool v) {
portapack::persistent_memory::set_config_hide_converter(!v);
if( !v )
{
check_converter.set_value(false);
}
// Retune to take converter change in account
receiver_model.set_tuning_frequency( portapack::persistent_memory::tuned_frequency() );
//Refresh status bar with/out converter
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
check_converter.set_value(portapack::persistent_memory::config_converter());
check_converter.on_select = [this](Checkbox&, bool v) {
if( v )
{
check_show_converter.set_value(true);
portapack::persistent_memory::set_config_hide_converter(false);
}
portapack::persistent_memory::set_config_converter(v);
// Retune to take converter change in account
receiver_model.set_tuning_frequency( portapack::persistent_memory::tuned_frequency() );
//Refresh status bar with/out converter
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
};
void SetAudioView::focus() {
button_save.focus();
}
converter_mode.set_by_value( portapack::persistent_memory::config_updown_converter() );
converter_mode.on_change = [this](size_t, OptionsField::value_t v) {
portapack::persistent_memory::set_config_updown_converter( v );
//Refresh status bar with icon up or down
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
};
SetQRCodeView::SetQRCodeView(NavigationView& nav) {
add_children({
&checkbox_bigger_qr,
&button_save,
&button_cancel
});
button_converter_freq.set_text( to_string_short_freq( portapack::persistent_memory::config_converter_freq() ) + "MHz");
button_converter_freq.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) {
portapack::persistent_memory::set_config_converter_freq( f );
// Retune to take converter change in account
receiver_model.set_tuning_frequency( portapack::persistent_memory::tuned_frequency() );
button_converter_freq.set_text( "<" + to_string_short_freq( f ) + " MHz>" );
};
};
checkbox_bigger_qr.set_value(persistent_memory::show_bigger_qr_code());
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_show_bigger_qr_code(checkbox_bigger_qr.value());
nav.pop();
};
button_save.on_select = [&nav, this](Button&) {
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
void SetConverterSettingsView::focus() {
button_save.focus();
}
}
// ---------------------------------------------------------
// Persistent Memory Settings
// ---------------------------------------------------------
SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) {
add_children({
&text_pmem_about,
&text_pmem_informations,
&text_pmem_status,
&check_load_mem_at_startup,
&button_save_mem_to_file,
&button_load_mem_from_file,
&button_return
});
void SetQRCodeView::focus() {
button_save.focus();
}
bool load_mem_at_startup = false ;
File pmem_flag_file_handle ;
std::string pmem_flag_file = "/SETTINGS/PMEM_FILEFLAG" ;
auto result = pmem_flag_file_handle.open(pmem_flag_file);
if(!result.is_valid())
{
load_mem_at_startup = true ;
}
check_load_mem_at_startup.set_value(load_mem_at_startup);
check_load_mem_at_startup.on_select = [this](Checkbox&, bool v) {
File pmem_flag_file_handle ;
std::string pmem_flag_file = "/SETTINGS/PMEM_FILEFLAG" ;
if( v )
{
auto result = pmem_flag_file_handle.open(pmem_flag_file);
if(result.is_valid())
{
auto result = pmem_flag_file_handle.create(pmem_flag_file); //third: create if it is not there
if( !result.is_valid() )
{
text_pmem_status.set("pmem flag file created");
}
else
{
text_pmem_status.set("!err. creating pmem flagfile!");
}
}
else
{
text_pmem_status.set("pmem flag already present");
}
}
else
{
auto result = delete_file( pmem_flag_file );
if( result != 0 )
{
text_pmem_status.set("!err. deleting pmem flagfile!");
}
else
{
text_pmem_status.set("pmem flag file deleted");
}
}
};
// ---------------------------------------------------------
// Settings main menu
// ---------------------------------------------------------
SettingsMenuView::SettingsMenuView(NavigationView& nav) {
if( portapack::persistent_memory::show_gui_return_icon() )
{
add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } } } );
}
add_items({
{ "Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav](){ nav.push<SetAudioView>(); } },
{ "Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav](){ nav.push<SetRadioView>(); } },
{ "User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [&nav](){ nav.push<SetUIView>(); } },
{ "Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [&nav](){ nav.push<SetDateTimeView>(); } },
{ "Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav](){ nav.push<TouchCalibrationView>(); } },
{ "App Settings", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav](){ nav.push<SetAppSettingsView>(); } },
{ "QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav](){ nav.push<SetQRCodeView>(); } }
});
set_max_rows(2); // allow wider buttons
}
button_save_mem_to_file.on_select = [&nav, this](Button&) {
if( !portapack::persistent_memory::save_persistent_settings_to_file("SETTINGS/pmem_settings") )
{
text_pmem_status.set("!problem saving settings!");
}
else
{
text_pmem_status.set("settings saved");
}
};
button_load_mem_from_file.on_select = [&nav, this](Button&) {
if( !portapack::persistent_memory::load_persistent_settings_from_file("SETTINGS/pmem_settings") )
{
text_pmem_status.set("!problem loading settings!");
}
else
{
text_pmem_status.set("settings loaded");
//Refresh status bar with icon up or down
StatusRefreshMessage message { };
EventDispatcher::send_message(message);
}
};
button_return.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetPersistentMemoryView::focus() {
button_return.focus();
}
//
// Audio settings
//
SetAudioView::SetAudioView(NavigationView& nav) {
add_children({
&labels,
&field_tone_mix,
&button_save,
&button_cancel
});
field_tone_mix.set_value(persistent_memory::tone_mix());
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_tone_mix(field_tone_mix.value());
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetAudioView::focus() {
button_save.focus();
}
SetQRCodeView::SetQRCodeView(NavigationView& nav) {
add_children({
&checkbox_bigger_qr,
&button_save,
&button_cancel
});
checkbox_bigger_qr.set_value(persistent_memory::show_bigger_qr_code());
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_show_bigger_qr_code(checkbox_bigger_qr.value());
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetQRCodeView::focus() {
button_save.focus();
}
// ---------------------------------------------------------
// Settings main menu
// ---------------------------------------------------------
SettingsMenuView::SettingsMenuView(NavigationView& nav) {
if( portapack::persistent_memory::show_gui_return_icon() )
{
add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } } } );
}
add_items({
{ "Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav](){ nav.push<SetAudioView>(); } },
{ "Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav](){ nav.push<SetRadioView>(); } },
{ "User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [&nav](){ nav.push<SetUIView>(); } },
{ "Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [&nav](){ nav.push<SetDateTimeView>(); } },
{ "Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav](){ nav.push<TouchCalibrationView>(); } },
{ "App Settings", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav](){ nav.push<SetAppSettingsView>(); } },
{ "Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav](){ nav.push<SetConverterSettingsView>(); } },
{ "QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav](){ nav.push<SetQRCodeView>(); } },
{ "P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav](){ nav.push<SetPersistentMemoryView>(); } },
});
set_max_rows(2); // allow wider buttons
}
} /* namespace ui */
+101 -6
View File
@@ -124,7 +124,7 @@ public:
void focus() override;
std::string title() const override { return "Radio settings"; };
std::string title() const override { return "Radio"; };
private:
const Style style_text {
@@ -154,7 +154,7 @@ private:
{ { 6 * 8, 4 * 16 }, "PPM", Color::light_grey() },
};
Checkbox check_clkout {
Checkbox check_clkout {
{ 18, (6 * 16 - 4) },
13,
"Enable CLKOUT"
@@ -193,7 +193,7 @@ private:
};
Checkbox check_bias {
{ 28, 13 * 16 },
{ 18, 12 * 16 },
5,
"Turn on bias voltage"
};
@@ -219,7 +219,7 @@ public:
void focus() override;
std::string title() const override { return "UI settings"; };
std::string title() const override { return "UI"; };
private:
@@ -299,7 +299,7 @@ public:
void focus() override;
std::string title() const override { return "App Settings"; };
std::string title() const override { return "AppSettings"; };
private:
@@ -326,13 +326,60 @@ private:
};
};
class SetConverterSettingsView : public View {
public:
SetConverterSettingsView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Converter"; };
private:
Checkbox check_show_converter {
{ 18, 4 * 16},
19,
"show/hide converter"
};
Checkbox check_converter {
{ 18, 6 * 16},
7,
"enable/disable converter"
};
OptionsField converter_mode {
{ 18 , 8 * 16 + 4 },
0,
{
{" + ",0}, // up converter
{" - ",1} // down converter
}
};
Button button_converter_freq {
{ 18 + 4 * 8 , 8 * 16 , 16 * 8 , 24 },
"",
};
Button button_save {
{ 2 * 8, 16 * 16, 12 * 8, 32 },
"Save"
};
Button button_cancel {
{ 16 * 8, 16 * 16, 12 * 8, 32 },
"Cancel",
};
};
class SetAudioView : public View {
public:
SetAudioView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Audio settings"; };
std::string title() const override { return "Audio"; };
private:
Labels labels {
@@ -385,6 +432,54 @@ private:
};
};
class SetPersistentMemoryView : public View {
public:
SetPersistentMemoryView(NavigationView& nav);
void focus() override;
std::string title() const override { return "P.Mem Mgmt"; };
private:
Text text_pmem_about {
{ 0, 1 * 16, 240 , 16 },
"PersistentMemory from/to SD"
};
Text text_pmem_informations {
{ 0, 2 * 16, 240 , 16 },
"use: when no/dead coin bat."
};
Text text_pmem_status {
{ 0, 3 * 16, 240 , 16 },
""
};
Checkbox check_load_mem_at_startup {
{ 18, 6 * 16},
19,
"load from sd at startup"
};
Button button_save_mem_to_file {
{ 0, 9 * 16, 240, 32 },
"save p.mem to sdcard"
};
Button button_load_mem_from_file {
{ 0, 12 * 16, 240, 32 },
"load p.mem from sdcard"
};
Button button_return {
{ 16 * 8, 16 * 16, 12 * 8, 32 },
"Return",
};
};
class SettingsMenuView : public BtnGridView {
public:
SettingsMenuView(NavigationView& nav);
+1 -1
View File
@@ -62,7 +62,7 @@ public:
void focus() override;
std::string title() const override { return "Radiosonde RX"; };
std::string title() const override { return "Radiosnd RX"; };
+1 -1
View File
@@ -53,7 +53,7 @@ public:
void focus() override;
void paint(Painter&) override;
std::string title() const override { return "SSTV TX (beta)"; };
std::string title() const override { return "SSTV TX"; };
private:
NavigationView& nav_;
+1 -1
View File
@@ -110,7 +110,7 @@ public:
void focus() override;
std::string title() const override { return "TouchTunes TX"; };
std::string title() const override { return "TouchTunes"; };
private:
uint32_t scan_button_index { };
+1 -1
View File
@@ -37,7 +37,7 @@ namespace ui
public:
WhipCalcView(NavigationView &nav);
void focus() override;
std::string title() const override { return "Antenna length"; };
std::string title() const override { return "Ant. length"; };
private:
const double speed_of_light_mps = 299792458.0; // m/s
File diff suppressed because it is too large Load Diff
+9 -10
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
@@ -28,22 +29,20 @@ using namespace lpc43xx;
#include "message.hpp"
#include "baseband_api.hpp"
#include "lz4.h"
#include <cstring>
/* TODO: OK, this is cool, but how do I put the M4 to sleep so I can switch to
* a different image? Other than asking the old image to sleep while the M0
* makes changes?
*
* I suppose I could force M4MEMMAP to an invalid memory reason which would
* cause an exception and effectively halt the M4. But that feels gross.
*/
void m4_init(const portapack::spi_flash::image_tag_t image_tag, const portapack::memory::region_t to, const bool full_reset) {
const portapack::spi_flash::chunk_t* chunk = reinterpret_cast<const portapack::spi_flash::chunk_t*>(portapack::spi_flash::images.base());
while(chunk->tag) {
if( chunk->tag == image_tag ) {
/* Initialize M4 code RAM */
std::memcpy(reinterpret_cast<void*>(to.base()), &chunk->data[0], chunk->length);
if(chunk->tag == image_tag) {
const void *src = &chunk->data[0];
void *dst = reinterpret_cast<void*>(to.base());
/* extract and initialize M4 code RAM */
unlz4_len(src, dst, chunk->compressed_data_size);
/* M4 core is assumed to be sleeping with interrupts off, so we can mess
* with its address space and RAM without concern.
+203
View File
@@ -0,0 +1,203 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* 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 "debug.hpp"
#include <ch.h>
#include <hal.h>
#include <string>
#include "ui_painter.hpp"
#include "portapack.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "string_format.hpp"
void runtime_error(LED);
std::string number_to_hex_string(uint32_t);
void draw_line(int32_t, const char *, regarm_t);
static bool error_shown = false;
void draw_guru_meditation_header(uint8_t source, const char *hint) {
ui::Painter painter;
ui::Style style_default {
.font = ui::font::fixed_8x16,
.background = ui::Color::black(),
.foreground = ui::Color::white()
};
painter.fill_rectangle(
{ 0, 0, portapack::display.width(), portapack::display.height() },
ui::Color::red()
);
constexpr int border = 8;
painter.fill_rectangle(
{ border, border, portapack::display.width() - (border * 2), portapack::display.height() - (border * 2) },
ui::Color::black()
);
// NOTE: in situations like a hard fault it seems not possible to write strings longer than 16 characters.
painter.draw_string({ 48, 24 }, style_default, "M? Guru");
painter.draw_string({ 48 + 8*8, 24 }, style_default, "Meditation");
if (source == CORTEX_M0)
painter.draw_string({ 48 + 8, 24 }, style_default, "0");
if (source == CORTEX_M4)
painter.draw_string({ 48 + 8, 24 }, style_default, "4");
painter.draw_string({ 15, 55 }, style_default, "Hint: ");
painter.draw_string({ 15 + 8*8, 55 }, style_default, hint);
}
void draw_guru_meditation(uint8_t source, const char *hint) {
if(error_shown == false){
error_shown = true;
draw_guru_meditation_header(source, hint);
}
if (source == CORTEX_M0)
runtime_error(hackrf::one::led_rx);
if (source == CORTEX_M4)
runtime_error(hackrf::one::led_tx);
}
void draw_guru_meditation(uint8_t source, const char *hint, struct extctx *ctxp, uint32_t cfsr = 0) {
if(error_shown == false)
{
error_shown = true;
draw_guru_meditation_header(source, hint);
if (ctxp != nullptr) {
int i = 0;
draw_line(80 + i++ * 20, "r0:", ctxp->r0);
draw_line(80 + i++ * 20, "r1:", ctxp->r1);
draw_line(80 + i++ * 20, "r2:", ctxp->r2);
draw_line(80 + i++ * 20, "r3:", ctxp->r3);
draw_line(80 + i++ * 20, "r12:", ctxp->r12);
// NOTE: run for M0
// # arm-none-eabi-gdb --batch --eval-command="x/8i 0x<link_register_value_here>" firmware/application/application.elf
// or for M4
// # arm-none-eabi-gdb --batch --eval-command="x/8i 0x<link_register_value_here>" firmware/baseband/<image_name_here>.elf
// to see whats causing the fault.
draw_line(80 + i++ * 20, "lr:", ctxp->lr_thd);
draw_line(80 + i++ * 20, "pc:", ctxp->pc);
// see SCB_CFSR_* in libopencm3/cm3/scb.h for details
if (cfsr != 0)
draw_line(80 + i++ * 20, "cfsr:", (void *)cfsr);
}
}
if (source == CORTEX_M0)
runtime_error(hackrf::one::led_rx);
if (source == CORTEX_M4)
runtime_error(hackrf::one::led_tx);
}
void draw_line(int32_t y_offset, const char *label, regarm_t value){
ui::Painter painter;
ui::Style style_default {
.font = ui::font::fixed_8x16,
.background = ui::Color::black(),
.foreground = ui::Color::white()
};
painter.draw_string({ 15, y_offset }, style_default, label);
painter.draw_string({ 15 + 8*8, y_offset }, style_default, to_string_hex((uint32_t)value, 8));
}
void runtime_error(LED led) {
led.off();
while(true) {
volatile size_t n = 1000000U;
while(n--);
led.toggle();
}
}
extern "C" {
#if CH_DBG_ENABLED
void port_halt(void) {
port_disable();
if (dbg_panic_msg == nullptr)
dbg_panic_msg = "system halted";
draw_guru_meditation(CORTEX_M0, dbg_panic_msg);
}
#endif
CH_IRQ_HANDLER(MemManageVector) {
#if CH_DBG_ENABLED
chDbgPanic("MemManage");
#else
chSysHalt();
#endif
}
CH_IRQ_HANDLER(BusFaultVector) {
#if CH_DBG_ENABLED
chDbgPanic("BusFault");
#else
chSysHalt();
#endif
}
CH_IRQ_HANDLER(UsageFaultVector) {
#if CH_DBG_ENABLED
chDbgPanic("UsageFault");
#else
chSysHalt();
#endif
}
CH_IRQ_HANDLER(HardFaultVector) {
#if CH_DBG_ENABLED
CH_IRQ_PROLOGUE();
struct extctx *ctxp;
port_lock_from_isr();
if ((uint32_t)_saved_lr & 0x04)
ctxp = (struct extctx *)__get_PSP();
else
ctxp = (struct extctx *)__get_MSP();
port_disable();
auto stack_space_left = get_free_stack_space();
if (stack_space_left < 16)
draw_guru_meditation(CORTEX_M0, "Stack Overflow", ctxp);
draw_guru_meditation(CORTEX_M0, "Hard Fault", ctxp);
CH_IRQ_EPILOGUE();
#else
chSysHalt();
#endif
}
} /* extern "C" */
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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.
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include "hackrf_gpio.hpp"
extern void draw_guru_meditation(uint8_t, const char *);
extern void draw_guru_meditation(uint8_t, const char *, struct extctx *, uint32_t);
extern uint32_t __process_stack_base__;
extern uint32_t __process_stack_end__;
#define CRT0_STACKS_FILL_PATTERN 0x55555555
inline uint32_t get_free_stack_space(){
uint32_t *p;
for (p = &__process_stack_base__; *p == CRT0_STACKS_FILL_PATTERN && p < &__process_stack_end__; p++);
auto stack_space_left = p - &__process_stack_base__;
return stack_space_left;
}
#endif/*__DEBUG_H__*/
+9 -31
View File
@@ -23,6 +23,7 @@
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
#include "debug.hpp"
#include "sd_card.hpp"
#include "rtc_time.hpp"
@@ -141,37 +142,14 @@ eventmask_t EventDispatcher::wait() {
void EventDispatcher::dispatch(const eventmask_t events) {
if( shared_memory.m4_panic_msg[0] != 0 ) {
halt = true;
}
if( halt ) {
if( shared_memory.m4_panic_msg[0] != 0 ) {
painter.fill_rectangle(
{ 0, 0, portapack::display.width(), portapack::display.height() },
ui::Color::red()
);
constexpr int border = 8;
painter.fill_rectangle(
{ border, border, portapack::display.width() - (border * 2), portapack::display.height() - (border * 2) },
ui::Color::black()
);
painter.draw_string({ 48, 24 }, top_widget->style(), "M4 Guru Meditation");
shared_memory.m4_panic_msg[sizeof(shared_memory.m4_panic_msg) - 1] = 0;
const std::string message = shared_memory.m4_panic_msg;
const int x_offset = (portapack::display.width() - (message.size() * 8)) / 2;
constexpr int y_offset = (portapack::display.height() - 16) / 2;
painter.draw_string(
{ x_offset, y_offset },
top_widget->style(),
message
);
shared_memory.m4_panic_msg[0] = 0;
}
return;
if (shared_memory.bb_data.data[0] == 0)
draw_guru_meditation(CORTEX_M4, shared_memory.m4_panic_msg);
else
draw_guru_meditation(
CORTEX_M4,
shared_memory.m4_panic_msg,
(struct extctx *)&shared_memory.bb_data.data[8],
*(uint32_t *)&shared_memory.bb_data.data[4]);
}
if( events & EVT_MASK_APPLICATION ) {
-1
View File
@@ -98,7 +98,6 @@ private:
static bool is_running;
bool sd_card_present = false;
static bool display_sleep;
bool halt = false;
bool in_key_event = false;
eventmask_t wait();
+4
View File
@@ -51,6 +51,8 @@ options_t freqman_entry_bandwidths[ 4 ] = {
};
options_t freqman_entry_steps = {
{ "0.1KHz " , 100 },
{ "1KHz " , 1000 },
{ "5KHz (SA AM)" , 5000 },
{ "6.25KHz(NFM)" , 6250 },
{ "8.33KHz(AIR)" , 8330 },
@@ -68,6 +70,8 @@ options_t freqman_entry_steps = {
};
options_t freqman_entry_steps_short = {
{ "0.1KHz" , 100 },
{ "1KHz" , 1000 },
{ "5KHz" , 5000 },
{ "6.25KHz" , 6250 },
{ "8.33KHz" , 8330 },
+70
View File
@@ -0,0 +1,70 @@
/* source: https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/lz4-decompression-routine-for-cortex-m0-and-later */
.syntax unified
.cpu cortex-m0
.thumb
/* License: Public Domain - I cannot be held responsible for what it does or does not do if you use it, whether it's modified or not. */
/* Entry point = unlz4. On entry: r0 = source, r1 = destination. The first two bytes of the source must contain the length of the compressed data. */
.func unlz4
.global unlz4,unlz4_len
.type unlz4,%function
.type unlz4_len,%function
.thumb_func
unlz4: ldrh r2,[r0] /* get length of compressed data */
adds r0,r0,#2 /* advance source pointer */
.thumb_func
unlz4_len: push {r4-r6,lr} /* save r4, r5, r6 and return-address */
adds r5,r2,r0 /* point r5 to end of compressed data */
getToken: ldrb r6,[r0] /* get token */
adds r0,r0,#1 /* advance source pointer */
lsrs r4,r6,#4 /* get literal length, keep token in r6 */
beq getOffset /* jump forward if there are no literals */
bl getLength /* get length of literals */
movs r2,r0 /* point r2 to literals */
bl copyData /* copy literals (r2=src, r1=dst, r4=len) */
movs r0,r2 /* update source pointer */
getOffset: ldrb r3,[r0,#0] /* get match offset's low byte */
subs r2,r1,r3 /* subtract from destination; this will become the match position */
ldrb r3,[r0,#1] /* get match offset's high byte */
lsls r3,r3,#8 /* shift to high byte */
subs r2,r2,r3 /* subtract from match position */
adds r0,r0,#2 /* advance source pointer */
lsls r4,r6,#28 /* get rid of token's high 28 bits */
lsrs r4,r4,#28 /* move the 4 low bits back where they were */
bl getLength /* get length of match data */
adds r4,r4,#4 /* minimum match length is 4 bytes */
bl copyData /* copy match data (r2=src, r1=dst, r4=len) */
cmp r0,r5 /* check if we've reached the end of the compressed data */
blt getToken /* if not, go get the next token */
pop {r4-r6,pc} /* restore r4, r5 and r6, then return */
.thumb_func
getLength: cmp r4,#0x0f /* if length is 15, then more length info follows */
bne gotLength /* jump forward if we have the complete length */
getLengthLoop: ldrb r3,[r0] /* read another byte */
adds r0,r0,#1 /* advance source pointer */
adds r4,r4,r3 /* add byte to length */
cmp r3,#0xff /* check if end reached */
beq getLengthLoop /* if not, go round loop */
gotLength: bx lr /* return */
.thumb_func
copyData: rsbs r4,r4,#0 /* index = -length */
subs r2,r2,r4 /* point to end of source */
subs r1,r1,r4 /* point to end of destination */
copyDataLoop: ldrb r3,[r2,r4] /* read byte from source_end[-index] */
strb r3,[r1,r4] /* store byte in destination_end[-index] */
adds r4,r4,#1 /* increment index */
bne copyDataLoop /* keep going until index wraps to 0 */
bx lr /* return */
.size unlz4,.-unlz4
.endfunc
/* 42 narrow instructions = 84 bytes */
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
@@ -19,7 +20,17 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifndef __LZ4_H__
#define __LZ4_H__
#endif/*__DEBUG_H__*/
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void unlz4_len(const void *aSource, void *aDestination, uint32_t aLength);
#ifdef __cplusplus
}
#endif
#endif /*__LZ4_H__*/
+5 -3
View File
@@ -515,11 +515,13 @@ bool init() {
return true;
}
void shutdown() {
void shutdown(const bool leave_screen_on) {
gpdma::controller.disable();
backlight()->off();
display.shutdown();
if (!leave_screen_on) {
backlight()->off();
display.shutdown();
}
radio::disable();
audio::shutdown();
+1 -1
View File
@@ -63,7 +63,7 @@ void set_antenna_bias(const bool v);
bool get_antenna_bias();
bool init();
void shutdown();
void shutdown(const bool leave_screen_on = false);
Backlight* backlight();
+15 -1
View File
@@ -40,6 +40,7 @@ using namespace hackrf::one;
#include "cpld_update.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
namespace radio {
@@ -168,7 +169,20 @@ void set_direction(const rf::Direction new_direction) {
}
bool set_tuning_frequency(const rf::Frequency frequency) {
const auto tuning_config = tuning::config::create(frequency);
rf::Frequency final_frequency = frequency ;
// if feature is enabled
if( portapack::persistent_memory::config_converter() ) {
//downconvert
if( portapack::persistent_memory::config_updown_converter() )
{
final_frequency = frequency - portapack::persistent_memory::config_converter_freq();
}
else //upconvert
{
final_frequency = frequency + portapack::persistent_memory::config_converter_freq();
}
}
const auto tuning_config = tuning::config::create(final_frequency);
if( tuning_config.is_valid() ) {
first_if.disable();
+3 -3
View File
@@ -38,12 +38,12 @@ const tone_key_t tone_keys = {
{ "8 YB", 88.500 },
{ "9 ZZ", 91.500 },
{ "10 ZA", 94.800 },
{ "11 1ZB", 97.400 },
{ "12 21Z", 100.000 },
{ "11 ZB", 97.400 },
{ "12 1Z", 100.000 },
{ "13 1A", 103.500 },
{ "14 1B", 107.200 },
{ "15 2Z", 110.900 },
{ "16 2Z", 114.800 },
{ "16 2A", 114.800 },
{ "17 2B", 118.800 },
{ "18 3Z", 123.000 },
{ "19 3A", 127.300 },
+441 -67
View File
@@ -26,85 +26,459 @@
#include <algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
namespace ui {
void RSSI::paint(Painter& painter) {
const auto r = screen_rect();
RSSI::RSSI(
Rect parent_rect,
bool instant_exec
) : Widget { parent_rect },
instant_exec_ { instant_exec }
{
}
constexpr int rssi_sample_range = 256;
constexpr float rssi_voltage_min = 0.4;
constexpr float rssi_voltage_max = 2.2;
constexpr float adc_voltage_max = 3.3;
constexpr int raw_min = rssi_sample_range * rssi_voltage_min / adc_voltage_max;
constexpr int raw_max = rssi_sample_range * rssi_voltage_max / adc_voltage_max;
constexpr int raw_delta = raw_max - raw_min;
const range_t<int> x_avg_range { 0, r.width() - 1 };
const auto x_avg = x_avg_range.clip((avg_ - raw_min) * r.width() / raw_delta);
const range_t<int> x_min_range { 0, x_avg };
const auto x_min = x_min_range.clip((min_ - raw_min) * r.width() / raw_delta);
const range_t<int> x_max_range { x_avg + 1, r.width() };
const auto x_max = x_max_range.clip((max_ - raw_min) * r.width() / raw_delta);
void RSSI::paint(Painter& painter) {
const auto r = screen_rect();
const Rect r0 { r.left(), r.top(), x_min, r.height() };
painter.fill_rectangle(
r0,
Color::blue()
);
constexpr int rssi_sample_range = 256;
//constexpr float rssi_voltage_min = 0.4;
constexpr float rssi_voltage_max = 2.2;
constexpr float adc_voltage_max = 3.3;
//constexpr int raw_min = rssi_sample_range * rssi_voltage_min / adc_voltage_max;
constexpr int raw_min = 0 ;
constexpr int raw_max = rssi_sample_range * rssi_voltage_max / adc_voltage_max;
constexpr int raw_delta = raw_max - raw_min;
const Rect r1 { r.left() + x_min, r.top(), x_avg - x_min, r.height() };
painter.fill_rectangle(
r1,
Color::red()
);
const Rect r2 { r.left() + x_avg, r.top(), 1, r.height() };
painter.fill_rectangle(
r2,
Color::white()
);
if( !vertical_rssi_enabled )
{
// horizontal left to right level meters
const range_t<int> x_avg_range { 0, r.width() - 1 };
const int16_t x_avg = x_avg_range.clip((avg_ - raw_min) * r.width() / raw_delta);
const range_t<int> x_min_range { 0, x_avg };
const int16_t x_min = x_min_range.clip((min_ - raw_min) * r.width() / raw_delta);
const range_t<int> x_max_range { x_avg + 1, r.width() - 1 };
const int16_t x_max = x_max_range.clip((max_ - raw_min) * r.width() / raw_delta);
const int16_t peak = x_max_range.clip((peak_ - raw_min) * r.width() / raw_delta);
const Rect r3 { r.left() + x_avg + 1, r.top(), x_max - (x_avg + 1), r.height() };
painter.fill_rectangle(
r3,
Color::red()
);
// x_min
const Rect r0 { r.left(), r.top(), x_min, r.height() };
painter.fill_rectangle(
r0,
Color::blue()
);
const Rect r4 { r.left() + x_max, r.top(), r.width() - x_max, r.height() };
painter.fill_rectangle(
r4,
Color::black()
);
if (pitch_rssi_enabled) {
baseband::set_pitch_rssi((avg_ - raw_min) * 2000 / raw_delta, true);
}
}
// x_avg
const Rect r1 { r.left() + x_min, r.top(), x_avg - x_min, r.height() };
painter.fill_rectangle(
r1,
Color::red()
);
int32_t RSSI::get_min()
{
return min_ ;
}
// x_avg middle marker
const Rect r2 { r.left() + x_avg, r.top(), 1, r.height() };
painter.fill_rectangle(
r2,
Color::white()
);
int32_t RSSI::get_avg()
{
return avg_ ;
}
// x_max
const Rect r3 { r.left() + x_avg + 1, r.top(), x_max - (x_avg + 1), r.height() };
painter.fill_rectangle(
r3,
Color::red()
);
int32_t RSSI::get_max()
{
return max_ ;
}
// filling last part in black
const Rect r4 { r.left() + x_max, r.top(), r.width() - x_max, r.height() };
painter.fill_rectangle(
r4,
Color::black()
);
void RSSI::set_pitch_rssi(bool enabled) {
pitch_rssi_enabled = enabled;
if (!enabled) baseband::set_pitch_rssi(0, false);
}
// show green peak value
if( peak_enabled )
{
const Rect r5 { r.left() + peak - 3 , r.top() , 3 , r.height() };
painter.fill_rectangle(
r5,
Color::green()
);
}
}
else
{
// vertical bottom to top level meters
const range_t<int> y_avg_range { 0, r.height() - 1 };
const int16_t y_avg = y_avg_range.clip((avg_ - raw_min) * r.height() / raw_delta);
const range_t<int> y_min_range { 0, y_avg };
const int16_t y_min = y_min_range.clip((min_ - raw_min) * r.height() / raw_delta);
const range_t<int> y_max_range { y_avg + 1, r.height() - 1 };
const int16_t y_max = y_max_range.clip((max_ - raw_min) * r.height() / raw_delta);
const range_t<int> peak_range { 0, r.height() - 1 };
const int16_t peak = peak_range.clip((peak_ - raw_min) * r.height() / raw_delta);
void RSSI::on_statistics_update(const RSSIStatistics& statistics) {
min_ = statistics.min;
avg_ = statistics.accumulator / statistics.count;
max_ = statistics.max;
set_dirty();
}
// y_min
const Rect r0 { r.left(), r.bottom() - y_min, r.width() , y_min };
painter.fill_rectangle(
r0,
Color::blue()
);
// y_avg
const Rect r1 { r.left(), r.bottom() - y_avg , r.width() , y_avg - y_min };
painter.fill_rectangle(
r1,
Color::red()
);
// y_avg middle marker
const Rect r2 { r.left(), r.bottom() - y_avg , r.width() , 1 };
painter.fill_rectangle(
r2,
Color::white()
);
// y_max
const Rect r3 { r.left(), r.bottom() - y_max , r.width() , y_max - y_avg };
//const Rect r3 { r.left(), r.bottom() - y_max , r.width() , y_max - y_avg - 1 };
painter.fill_rectangle(
r3,
Color::red()
);
// fill last part of level in black
const Rect r4 { r.left(), r.top() , r.width() , r.height() - y_max };
painter.fill_rectangle(
r4,
Color::black()
);
// show green peak value if enabled
if( peak_enabled )
{
const Rect r5 { r.left(), r.bottom() - peak - 3 , r.width() , 3 };
painter.fill_rectangle(
r5,
Color::green()
);
}
}
if (pitch_rssi_enabled) {
baseband::set_pitch_rssi((avg_ - raw_min) * 2000 / raw_delta, true);
}
if( has_focus() || highlighted() )
{
const Rect r6 { r.left(), r.top(), r.width(), r.height() };
painter.draw_rectangle(
r6,
Color::white()
);
}
}
int16_t RSSI::get_min()
{
return min_ ;
}
int16_t RSSI::get_avg()
{
return avg_ ;
}
int16_t RSSI::get_max()
{
return max_ ;
}
int16_t RSSI::get_delta()
{
return max_ - min_ ;
}
void RSSI::set_pitch_rssi(bool enabled) {
pitch_rssi_enabled = enabled;
if (!enabled) baseband::set_pitch_rssi(0, false);
}
void RSSI::set_vertical_rssi(bool enabled) {
if( enabled )
vertical_rssi_enabled = true ;
else
vertical_rssi_enabled = false ;
}
void RSSI::set_peak(bool enabled, size_t duration) {
peak_enabled = enabled ;
peak_duration = duration ;
}
void RSSI::on_statistics_update(const RSSIStatistics& statistics) {
min_ = statistics.min;
avg_ = statistics.accumulator / statistics.count;
max_ = statistics.max;
if( peak_enabled )
{
peak_duration_ = peak_duration_ + 100 ;
if( max_ > peak_ )
{
peak_ = max_ ;
}
if( peak_duration_ > peak_duration )
{
peak_duration_ = 0 ;
peak_ = max_ ;
}
}
set_dirty();
}
void RSSIGraph::paint(Painter& painter) {
const auto r = screen_rect();
RSSIGraph_entry& prev_entry = graph_list[0];
int xpos = 0 , prev_xpos = r.width();
for( int n = 1 ; (unsigned)n <= graph_list.size() ; n++ )
{
xpos = ( r.width() * (graph_list.size() - n ) ) / graph_list.size() ;
int size = abs( xpos - prev_xpos );
RSSIGraph_entry& entry = graph_list[ n - 1 ];
// black
const Rect r0{ r.right() - prev_xpos , r.top() , size , r.height() };
painter.fill_rectangle(
r0,
Color::black());
// y_max
int top_y_val = max( entry.rssi_max , prev_entry.rssi_max );
int width_y = abs( entry.rssi_max - prev_entry.rssi_max );
if( width_y == 0 )
width_y = 1 ;
const Point p1v{ r.right() - prev_xpos , r.bottom() - top_y_val };
painter.draw_vline(
p1v,
width_y,
Color::red());
const Point p1h{ r.right() - prev_xpos , r.bottom() - entry.rssi_max };
painter.draw_hline(
p1h,
size,
Color::red());
// y_avg
top_y_val = max( entry.rssi_avg , prev_entry.rssi_avg );
width_y = abs( entry.rssi_avg - prev_entry.rssi_avg );
if( width_y == 0 )
width_y = 1 ;
const Point p2v{ r.right() - prev_xpos , r.bottom() - top_y_val };
painter.draw_vline(
p2v,
width_y,
Color::white());
const Point p2h{ r.right() - prev_xpos , r.bottom() - entry.rssi_avg };
painter.draw_hline(
p2h,
size,
Color::white());
// y_min
top_y_val = max( entry.rssi_min , prev_entry.rssi_min );
width_y = abs( entry.rssi_min - prev_entry.rssi_min );
if( width_y == 0 )
width_y = 1 ;
const Point p3v{ r.right() - prev_xpos , r.bottom() - top_y_val };
painter.draw_vline(
p3v,
width_y,
Color::blue());
const Point p3h{ r.right() - prev_xpos , r.bottom() - entry.rssi_min };
painter.draw_hline(
p3h,
size,
Color::blue());
// hack to display db
top_y_val = max( entry.db , prev_entry.db );
width_y = abs( entry.db - prev_entry.db );
if( width_y == 0 )
width_y = 1 ;
const Point p4v{ r.right() - prev_xpos , r.bottom() - top_y_val };
painter.draw_vline(
p4v,
width_y,
Color::green());
const Point p4h{ r.right() - prev_xpos , r.bottom() - entry.db };
painter.draw_hline(
p4h,
size,
Color::green());
prev_entry = entry ;
prev_xpos = xpos ;
}
}
/*void RSSIGraph::paintOld(Painter& painter) {
const auto r = screen_rect();
int16_t size = r.width() / nb_columns ;
int16_t top_y_val = 0 ;
int16_t width_y = 0 ;
if( size < 1 )
size = 1 ;
int xpos = r.right() ;
for ( int n = 2 ; (unsigned)n <= graph_list.size(); n++) {
auto& entry = graph_list[graph_list.size()-n];
auto& prev_entry = graph_list[graph_list.size()-(n-1)];
// black
const Rect r0{ xpos - size , r.top() , size , r.height() };
painter.fill_rectangle(
r0,
Color::black());
// y_max
top_y_val = max( entry.rssi_max , prev_entry.rssi_max );
width_y = abs( entry.rssi_max - prev_entry.rssi_max );
if( width_y == 0 )
width_y = 1 ;
const Rect r1{ xpos - size , r.bottom() - top_y_val , size , width_y };
painter.fill_rectangle(
r1,
Color::red());
// y_avg
top_y_val = max( entry.rssi_avg , prev_entry.rssi_avg );
width_y = abs( entry.rssi_avg - prev_entry.rssi_avg );
if( width_y == 0 )
width_y = 1 ;
const Rect r2{ xpos - size , r.bottom() - top_y_val , size , width_y };
painter.fill_rectangle(
r2,
Color::white());
// y_min
top_y_val = max( entry.rssi_min , prev_entry.rssi_min );
width_y = abs( entry.rssi_min - prev_entry.rssi_min );
if( width_y == 0 )
width_y = 1 ;
const Rect r3{ xpos - size , r.bottom() - top_y_val , size , width_y };
painter.fill_rectangle(
r3,
Color::blue());
// hack to display db
top_y_val = max( entry.db , prev_entry.db );
width_y = abs( entry.db - prev_entry.db );
if( width_y == 0 )
width_y = 1 ;
const Rect r4{ xpos - size , r.bottom() - top_y_val , size , width_y };
painter.fill_rectangle(
r4,
Color::green());
xpos = xpos - size ;
}
if( xpos > r.left() )
{
const Rect r5{ r.left() , r.top() , xpos - r.left() , r.height() };
painter.fill_rectangle(
r5,
Color::black());
}
}*/
void RSSIGraph::add_values(int16_t rssi_min, int16_t rssi_avg, int16_t rssi_max, int16_t db )
{
const auto r = screen_rect();
constexpr int rssi_sample_range = 256;
//constexpr float rssi_voltage_min = 0.4;
constexpr float rssi_voltage_max = 2.2;
constexpr float adc_voltage_max = 3.3;
//constexpr int raw_min = rssi_sample_range * rssi_voltage_min / adc_voltage_max;
constexpr int raw_min = 0 ;
constexpr int raw_max = rssi_sample_range * rssi_voltage_max / adc_voltage_max;
constexpr int raw_delta = raw_max - raw_min;
// vertical bottom to top level meters
const range_t<int> y_avg_range { 0, r.height() - 1 };
const int16_t y_avg = y_avg_range.clip((rssi_avg - raw_min) * r.height() / raw_delta);
const range_t<int> y_min_range { 0, y_avg };
const int16_t y_min = y_min_range.clip((rssi_min - raw_min) * r.height() / raw_delta);
const range_t<int> y_max_range { y_avg + 1, r.height() - 1 };
const int16_t y_max = y_max_range.clip((rssi_max - raw_min) * r.height() / raw_delta);
const range_t<int> db_range { -80 , 10 };
int16_t db_ = db_range.clip( db );
db_ = db_ - 10 ;
db_ = db_ * r.height() / 90 ;
db_ = r.height() + db_ ;
graph_list . push_back( { y_min, y_avg, y_max , db_ } );
while( graph_list.size() > nb_columns )
{
graph_list.erase( graph_list.begin() );
}
set_dirty();
}
void RSSIGraph::set_nb_columns( int16_t nb )
{
nb_columns = nb ;
}
void RSSI::on_focus() {
if( on_highlight )
on_highlight(*this);
}
bool RSSI::on_key(const KeyEvent key) {
if( key == KeyEvent::Select ) {
if( on_select ) {
on_select(*this);
return true;
}
} else {
if( on_dir ) {
return on_dir(*this, key);
}
}
return false;
}
bool RSSI::on_touch(const TouchEvent event) {
switch(event.type) {
case TouchEvent::Type::Start:
set_highlighted(true);
set_dirty();
if( on_touch_press) {
on_touch_press(*this);
}
if( on_select && instant_exec_ ) {
on_select(*this);
}
return true;
case TouchEvent::Type::End:
set_highlighted(false);
set_dirty();
if( on_touch_release) {
on_touch_release(*this);
}
if( on_select && !instant_exec_ ) {
on_select(*this);
}
return true;
default:
return false;
}
}
} /* namespace ui */
+86 -41
View File
@@ -25,56 +25,101 @@
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_painter.hpp"
#include "event_m0.hpp"
#include "message.hpp"
#include <cstdint>
namespace ui {
class RSSI : public Widget {
public:
RSSI(
const Rect parent_rect
) : Widget { parent_rect },
min_ { 0 },
avg_ { 0 },
max_ { 0 }
{
}
class RSSI : public Widget {
public:
std::function<void(RSSI&)> on_select { };
std::function<void(RSSI&)> on_touch_release { }; // Executed when releasing touch, after on_select.
std::function<void(RSSI&)> on_touch_press { }; // Executed when touching, before on_select.
std::function<bool(RSSI&, KeyEvent)> on_dir { };
std::function<void(RSSI&)> on_highlight { };
void paint(Painter& painter) override;
int32_t get_min();
int32_t get_avg();
int32_t get_max();
private:
int32_t min_;
int32_t avg_;
int32_t max_;
bool pitch_rssi_enabled = false;
RSSI(Rect parent_rect, bool instant_exec); // instant_exec: Execute on_select when you touching instead of releasing
RSSI(
Rect parent_rect
) : RSSI { parent_rect, false }
{
}
MessageHandlerRegistration message_handler_stats {
Message::ID::RSSIStatistics,
[this](const Message* const p) {
this->on_statistics_update(static_cast<const RSSIStatisticsMessage*>(p)->statistics);
}
};
MessageHandlerRegistration message_handler_pitch_rssi {
Message::ID::PitchRSSIConfigure,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const PitchRSSIConfigureMessage*>(p);
this->set_pitch_rssi(message.enabled);
}
};
RSSI(
) : RSSI { { }, { } }
{
}
void on_statistics_update(const RSSIStatistics& statistics);
void set_pitch_rssi(bool enabled);
};
int16_t get_min();
int16_t get_avg();
int16_t get_max();
int16_t get_delta();
void set_vertical_rssi(bool enabled);
void set_peak(bool enabled, size_t duration);
void paint(Painter& painter) override;
void on_focus() override;
bool on_key(const KeyEvent key) override;
bool on_touch(const TouchEvent event) override;
private:
int16_t min_ = 0;
int16_t avg_ = 0;
int16_t max_ = 0;
int16_t peak_ = 0 ;
size_t peak_duration_ = 0 ;
bool instant_exec_ { false };
bool pitch_rssi_enabled = false;
bool vertical_rssi_enabled = false; // scale [vertically/from bottom to top]
// instead of [horizontally/from left to right]
bool peak_enabled = false;
size_t peak_duration = 1000; // peak duration in msec before being reset to actual max_rssi
MessageHandlerRegistration message_handler_stats {
Message::ID::RSSIStatistics,
[this](const Message* const p) {
this->on_statistics_update(static_cast<const RSSIStatisticsMessage*>(p)->statistics);
}
};
MessageHandlerRegistration message_handler_pitch_rssi {
Message::ID::PitchRSSIConfigure,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const PitchRSSIConfigureMessage*>(p);
this->set_pitch_rssi(message.enabled);
}
};
void on_statistics_update(const RSSIStatistics& statistics);
void set_pitch_rssi(bool enabled);
};
struct RSSIGraph_entry {
int16_t rssi_min { 0 };
int16_t rssi_avg { 0 };
int16_t rssi_max { 0 };
int16_t db { 0 };
};
using RSSIGraphList = std::vector<RSSIGraph_entry>;
class RSSIGraph : public Widget {
public:
RSSIGraph(
const Rect parent_rect
) : Widget { parent_rect }
{
}
void paint(Painter& painter) override;
void add_values(int16_t rssi_min, int16_t rssi_avg, int16_t rssi_max, int16_t db );
void set_nb_columns( int16_t nb );
private:
uint16_t nb_columns = 16 ;
RSSIGraphList graph_list { } ;
};
}
+123 -43
View File
@@ -58,6 +58,7 @@
#include "ui_scanner.hpp"
#include "ui_search.hpp"
#include "ui_recon.hpp"
#include "ui_level.hpp"
#include "ui_sd_wipe.hpp"
#include "ui_settings.hpp"
#include "ui_siggen.hpp"
@@ -69,6 +70,8 @@
#include "ui_playlist.hpp"
#include "ui_view_wav.hpp"
#include "ui_whipcalc.hpp"
#include "ui_flash_utility.hpp"
#include "ui_sd_over_usb.hpp"
//#include "acars_app.hpp"
#include "ais_app.hpp"
@@ -110,6 +113,7 @@ SystemStatusView::SystemStatusView(
&button_back,
&title,
&button_title,
&button_converter,
&button_speaker,
&button_stealth,
//&button_textentry,
@@ -125,6 +129,24 @@ SystemStatusView::SystemStatusView(
else
button_speaker.hidden(true);
if( portapack::persistent_memory::config_hide_converter() )
{
button_converter.hidden(true);
}
else
{
button_converter.hidden(false);
if( portapack::persistent_memory::config_converter() )
{
button_converter.set_foreground(Color::red());
}
else
{
button_converter.set_foreground(Color::light_grey());
}
}
button_back.id = -1; // Special ID used by FocusManager
title.set_style(&style_systemstatus);
@@ -147,6 +169,10 @@ SystemStatusView::SystemStatusView(
this->on_title();
};
button_converter.on_select = [this](ImageButton&) {
this->on_converter();
};
button_speaker.on_select = [this](ImageButton&) {
this->on_speaker();
};
@@ -178,6 +204,34 @@ SystemStatusView::SystemStatusView(
}
void SystemStatusView::refresh() {
if( portapack::persistent_memory::config_hide_converter() )
{
button_converter.hidden(true);
}
else
{
if( portapack::persistent_memory::config_updown_converter() )
{
button_converter.set_bitmap(&bitmap_icon_downconvert);
}
else
{
button_converter.set_bitmap(&bitmap_icon_upconvert);
}
button_converter.hidden(false);
if( portapack::persistent_memory::config_converter() )
{
button_converter.set_foreground(Color::red());
}
else
{
button_converter.set_foreground(Color::light_grey());
}
}
// Retune to take converter change in account
receiver_model.set_tuning_frequency( portapack::persistent_memory::tuned_frequency() );
transmitter_model.set_tuning_frequency( portapack::persistent_memory::tuned_frequency() );
if (!portapack::persistent_memory::config_speaker()) {
button_speaker.set_foreground(Color::light_grey());
button_speaker.set_bitmap(&bitmap_icon_speaker_mute);
@@ -186,6 +240,7 @@ void SystemStatusView::refresh() {
else {
button_speaker.hidden(true);
}
if (portapack::get_antenna_bias()) {
button_bias_tee.set_bitmap(&bitmap_icon_biast_on);
button_bias_tee.set_foreground(ui::Color::yellow());
@@ -201,6 +256,7 @@ void SystemStatusView::refresh() {
button_clock_status.set_bitmap(&bitmap_icon_clk_int);
// button_bias_tee.set_foreground(ui::Color::green());
}
if(portapack::persistent_memory::clkout_enabled()) {
button_clock_status.set_foreground(ui::Color::green());
} else {
@@ -238,6 +294,20 @@ void SystemStatusView::set_title(const std::string new_value) {
}
}
void SystemStatusView::on_converter() {
if(!portapack::persistent_memory::config_converter())
{
portapack::persistent_memory::set_config_converter( true );
button_converter.set_foreground(Color::red());
}
else
{
portapack::persistent_memory::set_config_converter( false );
button_converter.set_foreground(Color::light_grey());
}
receiver_model.set_tuning_frequency( portapack::persistent_memory::tuned_frequency() ); // Retune
}
void SystemStatusView::on_speaker() {
if (!portapack::speaker_mode)
{
@@ -466,25 +536,26 @@ void NavigationView::focus() {
/* ReceiversMenuView *****************************************************/
ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
if( portapack::persistent_memory::show_gui_return_icon() )
{
add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } );
}
add_items( {
{ "ADS-B", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBRxView>(); }, },
//{ "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ACARSAppView>(); }, },
{ "AIS Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
{ "AFSK", ui::Color::yellow(), &bitmap_icon_modem, [&nav](){ nav.push<AFSKRxView>(); } },
{ "BTLE", ui::Color::yellow(), &bitmap_icon_btle, [&nav](){ nav.push<BTLERxView>(); } },
{ "NRF", ui::Color::yellow(), &bitmap_icon_nrf, [&nav](){ nav.push<NRFRxView>(); } },
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push<AnalogAudioView>(); } },
{ "Analog TV", ui::Color::yellow(), &bitmap_icon_sstv, [&nav](){ nav.push<AnalogTvView>(); } },
{ "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
{ "Radiosnde", ui::Color::green(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
{ "TPMS Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
{ "Recon", ui::Color::green(), &bitmap_icon_scanner, [&nav](){ nav.push<ReconView>(); } },
{ "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSRXView>(); } }
if( portapack::persistent_memory::show_gui_return_icon() )
{
add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } );
}
add_items( {
{ "ADS-B", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBRxView>(); }, },
//{ "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ACARSAppView>(); }, },
{ "AIS Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
{ "AFSK", ui::Color::yellow(), &bitmap_icon_modem, [&nav](){ nav.push<AFSKRxView>(); } },
{ "BTLE", ui::Color::yellow(), &bitmap_icon_btle, [&nav](){ nav.push<BTLERxView>(); } },
{ "NRF", ui::Color::yellow(), &bitmap_icon_nrf, [&nav](){ nav.push<NRFRxView>(); } },
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push<AnalogAudioView>(); } },
{ "Analog TV", ui::Color::yellow(), &bitmap_icon_sstv, [&nav](){ nav.push<AnalogTvView>(); } },
{ "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
{ "Radiosnde", ui::Color::green(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
{ "TPMS Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
{ "Recon", ui::Color::green(), &bitmap_icon_scanner, [&nav](){ nav.push<ReconView>(); } },
{ "Level", ui::Color::green(), &bitmap_icon_options_radio, [&nav](){ nav.push<LevelView>(); } },
{ "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSRXView>(); } }
/*
{ "DMR", ui::Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push<NotImplementedView>(); } },
{ "SIGFOX", ui::Color::dark_grey(), &bitmap_icon_fox, [&nav](){ nav.push<NotImplementedView>(); } }, // SIGFRXView
@@ -499,30 +570,29 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
/* TransmittersMenuView **************************************************/
TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
if( portapack::persistent_memory::show_gui_return_icon() )
{
add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } );
}
add_items({
{ "ADS-B [S]", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBTxView>(); } },
{ "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
{ "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push<BHTView>(); } },
{ "GPS Sim", ui::Color::yellow(), &bitmap_icon_gps_sim, [&nav](){ nav.push<GpsSimAppView>(); } },
{ "Jammer", ui::Color::green(), &bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
{ "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); } },
{ "LGE tool", ui::Color::yellow(), &bitmap_icon_lge, [&nav](){ nav.push<LGEView>(); } },
if( portapack::persistent_memory::show_gui_return_icon() )
{
add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } );
}
add_items({
{ "ADS-B [S]", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBTxView>(); } },
{ "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
{ "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push<BHTView>(); } },
{ "GPS Sim", ui::Color::yellow(), &bitmap_icon_gps_sim, [&nav](){ nav.push<GpsSimAppView>(); } },
{ "Jammer", ui::Color::green(), &bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
{ "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); } },
{ "LGE tool", ui::Color::yellow(), &bitmap_icon_lge, [&nav](){ nav.push<LGEView>(); } },
{ "Morse", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push<MorseView>(); } },
{ "BurgerPgr", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push<CoasterPagerView>(); } },
{ "BurgerPgr", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push<CoasterPagerView>(); } },
//{ "Nuoptix DTMF", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push<NuoptixView>(); } },
{ "OOK", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<EncodersView>(); } },
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGTXView>(); } },
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGTXView>(); } },
{ "RDS", ui::Color::green(), &bitmap_icon_rds, [&nav](){ nav.push<RDSView>(); } },
{ "Soundbrd", ui::Color::green(), &bitmap_icon_soundboard,[&nav](){ nav.push<SoundBoardView>(); } },
{ "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } },
{ "TEDI/LCR", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push<LCRView>(); } },
{ "Soundbrd", ui::Color::green(), &bitmap_icon_soundboard,[&nav](){ nav.push<SoundBoardView>(); } },
{ "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } },
{ "TEDI/LCR", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push<LCRView>(); } },
{ "TouchTune", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<TouchTunesView>(); } },
{ "Playlist", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<PlaylistView>(); } },
{ "Playlist", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<PlaylistView>(); } },
//{ "Remote", ui::Color::dark_grey(), &bitmap_icon_remote, [&nav](){ nav.push<RemoteView>(); } },
});
}
@@ -530,10 +600,10 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
/* UtilitiesMenuView *****************************************************/
UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
if( portapack::persistent_memory::show_gui_return_icon() )
{
add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } );
}
if( portapack::persistent_memory::show_gui_return_icon() )
{
add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } );
}
add_items({
//{ "Test app", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<TestView>(); } },
{ "Freq. manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push<FrequencyManagerView>(); } },
@@ -545,6 +615,8 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
{ "Antenna length", ui::Color::green(), &bitmap_icon_tools_antenna, [&nav](){ nav.push<WhipCalcView>(); } },
{ "Wipe SD card", ui::Color::red(), &bitmap_icon_tools_wipesd, [&nav](){ nav.push<WipeSDView>(); } },
{ "Flash Utility", ui::Color::red(), &bitmap_icon_temperature, [&nav](){ nav.push<FlashUtilityView>(); } },
{ "SD over USB", ui::Color::yellow(), &bitmap_icon_hackrf, [&nav](){ nav.push<SdOverUsbView>(); } },
});
set_max_rows(2); // allow wider buttons
}
@@ -568,7 +640,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
{ "Transmit", ui::Color::cyan(), &bitmap_icon_transmit, [&nav](){ nav.push<TransmittersMenuView>(); } },
{ "Capture", ui::Color::red(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
{ "Replay", ui::Color::green(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } },
{ "Search", ui::Color::yellow(), &bitmap_icon_search, [&nav](){ nav.push<SearchView>(); } },
{ "Search", ui::Color::yellow(), &bitmap_icon_search, [&nav](){ nav.push<SearchView>(); } },
{ "Scanner", ui::Color::yellow(), &bitmap_icon_scanner, [&nav](){ nav.push<ScannerView>(); } },
{ "Microphone", ui::Color::yellow(), &bitmap_icon_microphone,[&nav](){ nav.push<MicTXView>(); } },
{ "Looking Glass", ui::Color::yellow(), &bitmap_icon_looking, [&nav](){ nav.push<GlassView>(); } },
@@ -651,6 +723,14 @@ SystemView::SystemView(
navigation_view.push<SystemMenuView>();
File pmem_flag_file_handle ;
std::string pmem_flag_file = "/SETTINGS/PMEM_FILEFLAG" ;
auto result = pmem_flag_file_handle.open(pmem_flag_file);
if(!result.is_valid())
{
portapack::persistent_memory::load_persistent_settings_from_file("SETTINGS/pmem_settings");
}
if (portapack::persistent_memory::config_splash())
{
navigation_view.push<BMPView>();
+9 -1
View File
@@ -142,11 +142,18 @@ namespace ui
Color::dark_grey()};
ImageButton button_speaker{
{17 * 8, 0, 2 * 8, 1 * 16},
{15 * 8, 0, 2 * 8, 1 * 16},
&bitmap_icon_speaker_mute,
Color::light_grey(),
Color::dark_grey()};
ImageButton button_converter{
{17 * 8, 0, 2 * 8, 1 * 16},
&bitmap_icon_upconvert,
Color::light_grey(),
Color::dark_grey()
};
ImageButton button_stealth{
{19 * 8, 0, 2 * 8, 1 * 16},
&bitmap_icon_stealth,
@@ -187,6 +194,7 @@ namespace ui
SDCardStatusView sd_card_status_view{
{28 * 8, 0 * 16, 2 * 8, 1 * 16}};
void on_converter();
void on_speaker();
void on_stealth();
void on_bias_tee();
+67 -8
View File
@@ -90,8 +90,6 @@ set(CSRC
${PORTSRC}
${KERNSRC}
${TESTSRC}
${HALSRC}
${PLATFORMSRC}
${BOARDSRC}
)
@@ -139,7 +137,7 @@ set(CPPSRC
audio_stats_collector.cpp
${COMMON}/utility.cpp
${COMMON}/chibios_cpp.cpp
${COMMON}/debug.cpp
debug.cpp
${COMMON}/gcc.cpp
tone_gen.cpp
)
@@ -189,7 +187,7 @@ set(AOPT)
set(TOPT "-mthumb -DTHUMB")
# Define C warning options here
set(CWARN "-Wall -Wextra -Wstrict-prototypes")
set(CWARN "-Wall -Wextra")
# Define C++ warning options here
set(CPPWARN "-Wall -Wextra")
@@ -262,10 +260,11 @@ macro(DeclareTargets chunk_tag name)
project("baseband_${name}")
include(${RULESPATH}/rules.cmake)
add_executable(${PROJECT_NAME}.elf $<TARGET_OBJECTS:baseband_shared> ${MODE_CPPSRC})
add_executable(${PROJECT_NAME}.elf $<TARGET_OBJECTS:baseband_shared> ${MODE_CPPSRC} ${HALSRC} ${PLATFORMSRC})
set_target_properties(${PROJECT_NAME}.elf PROPERTIES LINK_DEPENDS ${LDSCRIPT})
add_definitions(${DEFS})
include_directories(. ${INCDIR})
target_compile_definitions(${PROJECT_NAME}.elf PUBLIC "-DBASEBAND_${name}")
include_directories(. ${INCDIR} ${MODE_INCDIR})
link_directories(${LLIBDIR})
target_link_libraries(${PROJECT_NAME}.elf ${LIBS})
target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map)
@@ -273,7 +272,8 @@ macro(DeclareTargets chunk_tag name)
add_custom_command(
OUTPUT ${PROJECT_NAME}.bin ${PROJECT_NAME}.img
COMMAND ${CMAKE_OBJCOPY} -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
COMMAND ${MAKE_IMAGE_CHUNK} ${PROJECT_NAME}.bin ${chunk_tag} ${PROJECT_NAME}.img
COMMAND ${LZ4} -f -9 ${PROJECT_NAME}.bin ${PROJECT_NAME}.lz4
COMMAND ${MAKE_IMAGE_CHUNK} ${PROJECT_NAME}.lz4 ${chunk_tag} ${PROJECT_NAME}.img
DEPENDS ${PROJECT_NAME}.elf ${MAKE_IMAGE_CHUNK}
VERBATIM
)
@@ -504,11 +504,70 @@ set(MODE_CPPSRC
)
DeclareTargets(PWFM wfm_audio)
### Flash Utility
include(${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs.cmake)
set(MODE_INCDIR ${FATFSINC})
set(MODE_CPPSRC
proc_flash_utility.cpp
w25q80bv.cpp
${FATFSSRC}
)
DeclareTargets(PFUT flash_utility)
### SD over USB
set(MODE_INCDIR
${HACKRF_PATH}/firmware
${HACKRF_PATH}/firmware/common
${HACKRF_PATH}/firmware/libopencm3/include
)
set(MODE_CPPSRC
sd_over_usb/proc_sd_over_usb.cpp
sd_over_usb/scsi.c
sd_over_usb/diskio.c
sd_over_usb/sd_over_usb.c
sd_over_usb/usb_descriptor.c
sd_over_usb/hackrf_core.c
${HACKRF_PATH}/firmware/common/usb.c
${HACKRF_PATH}/firmware/common/usb_queue.c
${HACKRF_PATH}/firmware/hackrf_usb/usb_device.c
${HACKRF_PATH}/firmware/hackrf_usb/usb_endpoint.c
${HACKRF_PATH}/firmware/common/usb_request.c
${HACKRF_PATH}/firmware/common/usb_standard_request.c
${HACKRF_PATH}/firmware/common/platform_detect.c
${HACKRF_PATH}/firmware/common/gpio_lpc.c
${HACKRF_PATH}/firmware/common/firmware_info.c
${HACKRF_PATH}/firmware/common/si5351c.c
${HACKRF_PATH}/firmware/common/i2c_bus.c
${HACKRF_PATH}/firmware/common/mixer.c
${HACKRF_PATH}/firmware/common/clkin.c
${HACKRF_PATH}/firmware/common/spi_bus.c
${HACKRF_PATH}/firmware/common/sgpio.c
${HACKRF_PATH}/firmware/common/rf_path.c
${HACKRF_PATH}/firmware/common/i2c_lpc.c
${HACKRF_PATH}/firmware/common/spi_ssp.c
${HACKRF_PATH}/firmware/common/rffc5071_spi.c
${HACKRF_PATH}/firmware/common/rffc5071.c
${HACKRF_PATH}/firmware/common/clkin.c
${HACKRF_PATH}/firmware/common/gpdma.c
${HACKRF_PATH}/firmware/libopencm3/lib/cm3/nvic.c
${HACKRF_PATH}/firmware/libopencm3/lib/cm3/sync.c
${HACKRF_PATH}/firmware/libopencm3/lib/lpc43xx/scu.c
${HACKRF_PATH}/firmware/libopencm3/lib/lpc43xx/timer.c
${HACKRF_PATH}/firmware/libopencm3/lib/lpc43xx/i2c.c
)
DeclareTargets(PUSB sd_over_usb)
### HackRF "factory" firmware
add_custom_command(
OUTPUT hackrf.img
COMMAND ${MAKE_IMAGE_CHUNK} ${HACKRF_FIRMWARE_BIN_IMAGE} HRF1 hackrf.img 98304
COMMAND ${LZ4} -f -9 ${HACKRF_FIRMWARE_BIN_IMAGE} hackrf.lz4
COMMAND ${MAKE_IMAGE_CHUNK} hackrf.lz4 HRF1 hackrf.img
DEPENDS ${HACKRF_FIRMWARE_BIN_FILENAME} ${MAKE_IMAGE_CHUNK}
VERBATIM
)
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
@@ -26,60 +27,41 @@
#include "portapack_shared_memory.hpp"
#if defined(LPC43XX_M0)
static void debug_indicate_error_init() {
// TODO: Get knowledge of LED GPIO port/bit from shared place.
LPC_GPIO->CLR[2] = (1 << 2);
}
void write_m4_panic_msg(const char *panic_message, struct extctx *ctxp) {
if (ctxp == nullptr) {
shared_memory.bb_data.data[0] = 0;
}
else {
shared_memory.bb_data.data[0] = 1;
*((uint32_t *)&shared_memory.bb_data.data[4]) = SCB->CFSR;
memcpy(&shared_memory.bb_data.data[8], ctxp, sizeof(struct extctx));
}
static void debug_indicate_error_update() {
// Flash RX (yellow) LED to indicate baseband error.
// TODO: Get knowledge of LED GPIO port/bit from shared place.
LPC_GPIO->NOT[2] = (1 << 2);
}
#endif
#if defined(LPC43XX_M4)
static void debug_indicate_error_init() {
// TODO: Get knowledge of LED GPIO port/bit from shared place.
LPC_GPIO->CLR[2] = (1 << 8);
}
static void debug_indicate_error_update() {
// Flash TX (red) LED to indicate baseband error.
// TODO: Get knowledge of LED GPIO port/bit from shared place.
LPC_GPIO->NOT[2] = (1 << 8);
}
#endif
static void runtime_error() {
debug_indicate_error_init();
while(true) {
volatile size_t n = 1000000U;
while(n--);
debug_indicate_error_update();
for(size_t i=0; i<sizeof(shared_memory.m4_panic_msg); i++) {
if( *panic_message == 0 ) {
shared_memory.m4_panic_msg[i] = 0;
} else {
shared_memory.m4_panic_msg[i] = *(panic_message++);
}
}
}
extern "C" {
#if CH_DBG_ENABLED
void port_halt(void) {
// Copy debug panic message to M0 region.
const auto* p = dbg_panic_msg;
for(size_t i=0; i<sizeof(shared_memory.m4_panic_msg); i++) {
if( *p == 0 ) {
shared_memory.m4_panic_msg[i] = 0;
} else {
shared_memory.m4_panic_msg[i] = *(p++);
}
}
port_disable();
runtime_error();
}
#if defined(LPC43XX_M4)
if (dbg_panic_msg == nullptr)
dbg_panic_msg = "system halted";
write_m4_panic_msg(dbg_panic_msg, nullptr);
while (true) {
HALT_IF_DEBUGGING();
}
}
#endif
CH_IRQ_HANDLER(MemManageVector) {
#if CH_DBG_ENABLED
chDbgPanic("MemManage");
@@ -103,6 +85,36 @@ CH_IRQ_HANDLER(UsageFaultVector) {
chSysHalt();
#endif
}
CH_IRQ_HANDLER(HardFaultVector) {
#if CH_DBG_ENABLED
regarm_t _saved_lr;
asm volatile ("mov %0, lr" : "=r" (_saved_lr) : : "memory");
struct extctx *ctxp;
port_lock_from_isr();
if ((uint32_t)_saved_lr & 0x04)
ctxp = (struct extctx *)__get_PSP();
else
ctxp = (struct extctx *)__get_MSP();
volatile uint32_t stack_space_left = get_free_stack_space();
if (stack_space_left < 16)
write_m4_panic_msg("Stack Overflow", ctxp);
else write_m4_panic_msg("Hard Fault", ctxp);
port_disable();
while (true) {
HALT_IF_DEBUGGING();
}
#else
chSysHalt();
#endif
}
}
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include <ch.h>
extern uint32_t __process_stack_base__;
extern uint32_t __process_stack_end__;
#define CRT0_STACKS_FILL_PATTERN 0x55555555
inline uint32_t get_free_stack_space(){
uint32_t *p;
for (p = &__process_stack_base__; *p == CRT0_STACKS_FILL_PATTERN && p < &__process_stack_end__; p++);
auto stack_space_left = p - &__process_stack_base__;
return stack_space_left;
}
/* Executes a breakpoint only when a debugger is attached. */
#define HALT_IF_DEBUGGING() \
do { \
if ((*(volatile uint32_t *)0xE000EDF0) & (1 << 0)) { \
__asm__ __volatile__("bkpt 1"); \
} \
} while (0)
/* Stops execution until a debugger is attached. */
#define HALT_UNTIL_DEBUGGING() \
while (!((*(volatile uint32_t *)0xE000EDF0) & (1 << 0))) {} \
__asm__ __volatile__("bkpt 1")
#endif/*__DEBUG_H__*/
+4
View File
@@ -119,7 +119,11 @@
* @brief Enables the SDC subsystem.
*/
#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
#if defined(BASEBAND_flash_utility) || defined(BASEBAND_sd_over_usb)
#define HAL_USE_SDC TRUE
#else
#define HAL_USE_SDC FALSE
#endif /* BASEBAND_flash_utility */
#endif
/**
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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 "ch.h"
#include "hal.h"
#include "ff.h"
#include "w25q80bv.hpp"
#include "debug.hpp"
#include "portapack_shared_memory.hpp"
#define PAGE_LEN 256U
#define NUM_PAGES 4096U
void initialize_flash();
void erase_flash();
void initialize_sdcard();
void write_firmware(FIL *);
void write_page(size_t, uint8_t *, size_t);
int main() {
const TCHAR *filename = reinterpret_cast<const TCHAR *>(&shared_memory.bb_data.data[0]);
initialize_flash();
palSetPad(LED_PORT, LEDRX_PAD);
erase_flash();
initialize_sdcard();
FIL firmware_file;
if (f_open(&firmware_file, filename, FA_READ) != FR_OK) chDbgPanic("no file");
palSetPad(LED_PORT, LEDTX_PAD);
write_firmware(&firmware_file);
palClearPad(LED_PORT, LEDTX_PAD);
palClearPad(LED_PORT, LEDRX_PAD);
f_close(&firmware_file);
while(1)
__WFE();
return 0;
}
void initialize_flash() {
w25q80bv::disable_spifi();
w25q80bv::initialite_spi();
w25q80bv::setup();
w25q80bv::wait_for_device();
w25q80bv::wait_not_busy();
}
void erase_flash() {
w25q80bv::remove_write_protection();
w25q80bv::wait_not_busy();
w25q80bv::erase_chip();
w25q80bv::wait_not_busy();
}
void initialize_sdcard() {
static FATFS fs;
sdcStart(&SDCD1, nullptr);
if (sdcConnect(&SDCD1) == CH_FAILED) chDbgPanic("no sd card #1");
if (f_mount(&fs, reinterpret_cast<const TCHAR*>(_T("")), 1) != FR_OK) chDbgPanic("no sd card #2");
}
void write_firmware(FIL *firmware_file) {
uint8_t *data_buffer = &shared_memory.bb_data.data[0];
for (size_t page_index = 0; page_index < NUM_PAGES; page_index++) {
if (page_index % 32 == 0)
palTogglePad(LED_PORT, LEDTX_PAD);
size_t bytes_read;
if (f_read(firmware_file, data_buffer, PAGE_LEN, &bytes_read) != FR_OK) chDbgPanic("no data");
if (bytes_read > 0)
write_page(page_index, data_buffer, bytes_read);
if (bytes_read < PAGE_LEN)
return;
}
}
void write_page(size_t page_index, uint8_t *data_buffer, size_t data_length) {
w25q80bv::wait_not_busy();
w25q80bv::remove_write_protection();
w25q80bv::wait_not_busy();
w25q80bv::write(page_index, data_buffer, data_length);
w25q80bv::wait_not_busy();
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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 "diskio.h"
#include "ch.h"
#include "hal.h"
uint32_t get_capacity(void) {
return mmcsdGetCardCapacity(&SDCD1);
}
bool_t read_block(uint32_t startblk, uint8_t *buf, uint32_t n) {
return sdcRead(&SDCD1, startblk, buf, n);
}
bool_t write_block(uint32_t startblk, uint8_t *buf, uint32_t n) {
return sdcWrite(&SDCD1, startblk, buf, n);
}
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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.
*/
#ifndef __DISKIO_H__
#define __DISKIO_H__
#include <stdint.h>
#include <chtypes.h>
uint32_t get_capacity(void);
bool_t read_block(uint32_t startblk, uint8_t *buf, uint32_t n);
bool_t write_block(uint32_t startblk, uint8_t *buf, uint32_t n);
#endif /* __DISKIO_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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 "ch.h"
#include "hal.h"
extern "C" {
void start_usb(void);
void irq_usb(void);
void usb_transfer(void);
CH_IRQ_HANDLER(Vector60) {
irq_usb();
}
}
int main() {
sdcStart(&SDCD1, nullptr);
if (sdcConnect(&SDCD1) == CH_FAILED) chDbgPanic("no sd card #1");
start_usb();
while (true) {
usb_transfer();
}
return 0;
}
+274
View File
@@ -0,0 +1,274 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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 "scsi.h"
#include "diskio.h"
volatile bool usb_bulk_block_done = false;
void usb_bulk_block_cb(void* user_data, unsigned int bytes_transferred) {
usb_bulk_block_done = true;
(void)user_data;
(void)bytes_transferred;
}
void usb_send_bulk(void* const data, const uint32_t maximum_length) {
usb_bulk_block_done = false;
usb_transfer_schedule_block(
&usb_endpoint_bulk_in,
data,
maximum_length,
usb_bulk_block_cb,
NULL);
while (!usb_bulk_block_done);
}
void usb_receive_bulk(void* const data, const uint32_t maximum_length) {
usb_bulk_block_done = false;
usb_transfer_schedule_block(
&usb_endpoint_bulk_out,
data,
maximum_length,
usb_bulk_block_cb,
NULL);
while (!usb_bulk_block_done);
}
void usb_send_csw(msd_cbw_t *msd_cbw_data, uint8_t status) {
msd_csw_t csw = {
.signature = MSD_CSW_SIGNATURE,
.tag = msd_cbw_data->tag,
.data_residue = 0,
.status = status
};
memcpy(&usb_bulk_buffer[0], &csw, sizeof(msd_csw_t));
usb_send_bulk(&usb_bulk_buffer[0], sizeof(msd_csw_t));
}
uint8_t handle_inquiry(msd_cbw_t *msd_cbw_data) {
(void)msd_cbw_data;
scsi_inquiry_response_t ret = {
0x00, /* direct access block device */
0x80, /* removable */
0x00, //0x04, /* SPC-2 */
0x00, //0x02, /* response data format */
0x20, /* response has 0x20 + 4 bytes */
0x00,
0x00,
0x00,
"Mayhem",
"Portapack MSD",
{'v','1','.','6'}
};
memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_inquiry_response_t));
usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_inquiry_response_t));
return 0;
}
uint8_t handle_inquiry_serial_number(msd_cbw_t *msd_cbw_data) {
(void)msd_cbw_data;
scsi_unit_serial_number_inquiry_response_t ret = {
.peripheral = 0x00,
.page_code = 0x80,
.reserved = 0,
.page_length = 0x08,
.serialNumber = "Mayhem"
};
memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_unit_serial_number_inquiry_response_t));
usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_unit_serial_number_inquiry_response_t));
return 0;
}
uint8_t read_format_capacities(msd_cbw_t *msd_cbw_data) {
uint16_t len = msd_cbw_data->cmd_data[7] << 8 | msd_cbw_data->cmd_data[8];
if (len != 0) {
size_t num_blocks = get_capacity();
scsi_read_format_capacities_response_t ret = {
.header = {0, 0, 0, 1 * 8 /* num_entries * 8 */},
.blocknum = {((num_blocks) >> 24)& 0xff, ((num_blocks) >> 16)& 0xff, ((num_blocks) >> 8)& 0xff, num_blocks & 0xff},
.blocklen = {0b10 /* formated */, 0, (512) >> 8, 0},
};
memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_read_format_capacities_response_t));
usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_read_format_capacities_response_t));
}
return 0;
}
uint8_t read_capacity10(msd_cbw_t *msd_cbw_data) {
(void)msd_cbw_data;
size_t num_blocks = get_capacity();
scsi_read_capacity10_response_t ret = {
.last_block_addr = cpu_to_be32(num_blocks - 1),
.block_size = cpu_to_be32(512)
};
memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_read_capacity10_response_t));
usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_read_capacity10_response_t));
return 0;
}
uint8_t request_sense(msd_cbw_t *msd_cbw_data) {
(void)msd_cbw_data;
scsi_sense_response_t ret = {
.byte = { 0x70, 0, SCSI_SENSE_KEY_GOOD, 0,
0, 0, 0, 8,
0, 0 ,0 ,0,
SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER, 0, 0,
0, 0 }
};
memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_sense_response_t));
usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_sense_response_t));
return 0;
}
uint8_t mode_sense6(msd_cbw_t *msd_cbw_data) {
(void)msd_cbw_data;
scsi_mode_sense6_response_t ret = {
.byte = {
sizeof(scsi_mode_sense6_response_t) - 1,
0,
0,
0 }
};
memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_mode_sense6_response_t));
usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_mode_sense6_response_t));
return 0;
}
static data_request_t decode_data_request(const uint8_t *cmd) {
data_request_t req;
uint32_t lba;
uint16_t blk;
memcpy(&lba, &cmd[2], sizeof(lba));
memcpy(&blk, &cmd[7], sizeof(blk));
req.first_lba = be32_to_cpu(lba);
req.blk_cnt = be16_to_cpu(blk);
return req;
}
uint8_t data_read10(msd_cbw_t *msd_cbw_data) {
data_request_t req = decode_data_request(msd_cbw_data->cmd_data);
for (size_t block_index = 0; block_index < req.blk_cnt; block_index++) {
read_block(req.first_lba + block_index, &usb_bulk_buffer[0], 1 /* n blocks */);
usb_send_bulk(&usb_bulk_buffer[0], 512);
}
return 0;
}
uint8_t data_write10(msd_cbw_t *msd_cbw_data) {
data_request_t req = decode_data_request(msd_cbw_data->cmd_data);
for (size_t block_index = 0; block_index < req.blk_cnt; block_index++) {
usb_receive_bulk(&usb_bulk_buffer[0], 512);
write_block(req.first_lba + block_index, &usb_bulk_buffer[0], 1 /* n blocks */);
}
return 0;
}
void scsi_command(msd_cbw_t *msd_cbw_data) {
uint8_t status = 1;
switch (msd_cbw_data->cmd_data[0]) {
case SCSI_CMD_INQUIRY:
if ((msd_cbw_data->cmd_data[1] & 0b1) && msd_cbw_data->cmd_data[2] == 0x80) {
status = handle_inquiry_serial_number(msd_cbw_data);
}
else if ((msd_cbw_data->cmd_data[1] & 0b11) || msd_cbw_data->cmd_data[2] != 0) {
status = 1;
}
else {
status = handle_inquiry(msd_cbw_data);
}
break;
case SCSI_CMD_REQUEST_SENSE:
status = request_sense(msd_cbw_data);
break;
case SCSI_CMD_READ_CAPACITY_10:
status = read_capacity10(msd_cbw_data);
break;
case SCSI_CMD_READ_10:
status = data_read10(msd_cbw_data);
break;
case SCSI_CMD_WRITE_10:
status = data_write10(msd_cbw_data);
break;
case SCSI_CMD_TEST_UNIT_READY:
status = 0;
break;
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
status = 0;
break;
case SCSI_CMD_MODE_SENSE_6:
status = mode_sense6(msd_cbw_data);
break;
case SCSI_CMD_READ_FORMAT_CAPACITIES:
status = read_format_capacities(msd_cbw_data);
break;
case SCSI_CMD_VERIFY_10:
status = 0;
break;
}
usb_send_csw(msd_cbw_data, status);
}
+197
View File
@@ -0,0 +1,197 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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.
*/
#ifndef __SCSI_H__
#define __SCSI_H__
#include <stddef.h>
#include <common/usb.h>
#include <common/usb_request.h>
#include <common/usb_standard_request.h>
#include <hackrf_usb/usb_device.h>
#include <hackrf_usb/usb_endpoint.h>
#include <libopencm3/lpc43xx/m4/nvic.h>
#include <libopencm3/lpc43xx/cgu.h>
#include "platform_detect.h"
#include "hackrf_core.h"
#include "usb_bulk_buffer.h"
#define MSD_CBW_SIGNATURE 0x43425355
#define MSD_CSW_SIGNATURE 0x53425355
#define SCSI_CMD_TEST_UNIT_READY 0x00
#define SCSI_CMD_REQUEST_SENSE 0x03
#define SCSI_CMD_INQUIRY 0x12
#define SCSI_CMD_MODE_SENSE_6 0x1A
#define SCSI_CMD_START_STOP_UNIT 0x1B
#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
#define SCSI_CMD_READ_CAPACITY_10 0x25
#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
#define SCSI_CMD_READ_10 0x28
#define SCSI_CMD_WRITE_10 0x2A
#define SCSI_CMD_VERIFY_10 0x2F
#define SCSI_SENSE_KEY_GOOD 0x00
#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
#define SCSI_SENSE_KEY_NOT_READY 0x02
#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28
#define SCSI_ASENSE_WRITE_PROTECTED 0x27
#define SCSI_ASENSE_FORMAT_ERROR 0x31
#define SCSI_ASENSE_INVALID_COMMAND 0x20
#define SCSI_ASENSE_LBA_OUT_OF_RANGE 0x21
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
#define SCSI_ASENSEQ_NO_QUALIFIER 0x00
#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
#define SCSI_ASENSEQ_INIT_COMMAND_REQUIRED 0x02
#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
#define MSD_CBW_SIGNATURE 0x43425355
#define MSD_CSW_SIGNATURE 0x53425355
#define USB_TRANSFER_SIZE 0x2000
typedef struct {
uint32_t signature;
uint32_t tag;
uint32_t data_len;
uint8_t flags;
uint8_t lun;
uint8_t cmd_len;
uint8_t cmd_data[16];
} __attribute__((packed)) msd_cbw_t;
typedef struct {
uint8_t peripheral;
uint8_t removable;
uint8_t version;
uint8_t response_data_format;
uint8_t additional_length;
uint8_t sccstp;
uint8_t bqueetc;
uint8_t cmdque;
uint8_t vendorID[8];
uint8_t productID[16];
uint8_t productRev[4];
} scsi_inquiry_response_t;
typedef struct {
uint32_t signature;
uint32_t tag;
uint32_t data_residue;
uint8_t status;
} __attribute__((packed)) msd_csw_t;
typedef struct {
uint8_t header[4];
uint8_t blocknum[4];
uint8_t blocklen[4];
} scsi_read_format_capacities_response_t;
typedef struct {
uint32_t last_block_addr;
uint32_t block_size;
} scsi_read_capacity10_response_t;
typedef struct {
uint8_t byte[18];
} scsi_sense_response_t;
typedef struct {
uint8_t byte[4];
} scsi_mode_sense6_response_t;
typedef struct {
uint32_t first_lba;
uint16_t blk_cnt;
} data_request_t;
typedef struct {
uint8_t peripheral;
uint8_t page_code;
uint8_t reserved;
uint8_t page_length;
uint8_t serialNumber[8];
} scsi_unit_serial_number_inquiry_response_t;
static inline uint16_t bswap_16(const uint16_t x)
__attribute__ ((warn_unused_result))
__attribute__ ((const))
__attribute__ ((always_inline));
static inline uint16_t bswap_16(const uint16_t x) {
uint8_t tmp;
union { uint16_t x; uint8_t b[2]; } data;
data.x = x;
tmp = data.b[0];
data.b[0] = data.b[1];
data.b[1] = tmp;
return data.x;
}
static inline uint32_t bswap_32(const uint32_t x)
__attribute__ ((warn_unused_result))
__attribute__ ((const))
__attribute__ ((always_inline));
static inline uint32_t bswap_32(const uint32_t x) {
uint8_t tmp;
union { uint32_t x; uint8_t b[4]; } data;
data.x = x;
tmp = data.b[0];
data.b[0] = data.b[3];
data.b[3] = tmp;
tmp = data.b[1];
data.b[1] = data.b[2];
data.b[2] = tmp;
return data.x;
}
#define be16_to_cpu(x) bswap_16(x)
#define be32_to_cpu(x) bswap_32(x)
#define cpu_to_be16(x) bswap_16(x)
#define cpu_to_be32(x) bswap_32(x)
void scsi_command(msd_cbw_t *msd_cbw_data);
#endif /* __SCSI_H__ */
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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 "sd_over_usb.h"
#include "scsi.h"
bool scsi_running = false;
usb_request_status_t report_max_lun(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage)
{
if (stage == USB_TRANSFER_STAGE_SETUP) {
endpoint->buffer[0] = 0;
usb_transfer_schedule_block(
endpoint->in,
&endpoint->buffer,
1,
NULL,
NULL);
usb_transfer_schedule_ack(endpoint->out);
scsi_running = true;
}
return USB_REQUEST_STATUS_OK;
}
usb_request_status_t usb_class_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) {
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
volatile uint8_t request = endpoint->setup.request;
if (request == 0xFE)
return report_max_lun(endpoint, stage);
return status;
}
const usb_request_handlers_t usb_request_handlers = {
.standard = usb_standard_request,
.class = usb_class_request,
.vendor = 0,
.reserved = 0
};
void usb_configuration_changed(usb_device_t* const device) {
(void)device;
usb_endpoint_init(&usb_endpoint_bulk_in);
usb_endpoint_init(&usb_endpoint_bulk_out);
}
void start_usb(void) {
detect_hardware_platform();
pin_setup();
cpu_clock_init();
usb_set_configuration_changed_cb(usb_configuration_changed);
usb_peripheral_reset();
usb_device_init(0, &usb_device);
usb_queue_init(&usb_endpoint_control_out_queue);
usb_queue_init(&usb_endpoint_control_in_queue);
usb_queue_init(&usb_endpoint_bulk_out_queue);
usb_queue_init(&usb_endpoint_bulk_in_queue);
usb_endpoint_init(&usb_endpoint_control_out);
usb_endpoint_init(&usb_endpoint_control_in);
nvic_set_priority(NVIC_USB0_IRQ, 255);
usb_run(&usb_device);
}
void stop_usb(void) {
usb_peripheral_reset();
}
void irq_usb(void) {
usb0_isr();
}
volatile bool transfer_complete = false;
void scsi_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred)
{
(void)user_data;
(void)bytes_transferred;
transfer_complete = true;
}
void usb_transfer(void) {
if (scsi_running) {
transfer_complete = false;
usb_transfer_schedule_block(
&usb_endpoint_bulk_out,
&usb_bulk_buffer[0x4000],
USB_TRANSFER_SIZE,
scsi_bulk_transfer_complete,
NULL);
while (!transfer_complete);
msd_cbw_t *msd_cbw_data = (msd_cbw_t *) &usb_bulk_buffer[0x4000];
if (msd_cbw_data->signature == MSD_CBW_SIGNATURE){
scsi_command(msd_cbw_data);
}
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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.
*/
#ifndef __USB_SD_OVER_USB_H__
#define __USB_SD_OVER_USB_H__
#include <stddef.h>
#include <common/usb.h>
#include <common/usb_request.h>
#include <common/usb_standard_request.h>
#include <hackrf_usb/usb_device.h>
#include <hackrf_usb/usb_endpoint.h>
#include <libopencm3/lpc43xx/m4/nvic.h>
#include <libopencm3/lpc43xx/cgu.h>
#include "platform_detect.h"
#include "hackrf_core.h"
#include "usb_bulk_buffer.h"
void start_usb(void);
void stop_usb(void);
void irq_usb(void);
void usb_transfer(void);
#endif /* __USB_SD_OVER_USB_H__ */
@@ -0,0 +1,39 @@
/*
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
* Copyright 2012 Jared Boone
* Copyright 2013 Benjamin Vernoux
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __USB_BULK_BUFFER_H__
#define __USB_BULK_BUFFER_H__
#include <stdbool.h>
#include <stdint.h>
#define USB_BULK_BUFFER_SIZE 0x8000
#define USB_BULK_BUFFER_MASK 0x7FFF
/* Address of usb_bulk_buffer is set in ldscripts. If you change the name of this
* variable, it won't be where it needs to be in the processor's address space,
* unless you also adjust the ldscripts.
*/
extern uint8_t usb_bulk_buffer[USB_BULK_BUFFER_SIZE];
#endif /*__USB_BULK_BUFFER_H__*/
@@ -0,0 +1,322 @@
/*
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
* Copyright 2012 Jared Boone
*
* This file is part of HackRF.
*
* 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 <stdint.h>
#include "usb_type.h"
#include "usb_descriptor.h"
#define USB_VENDOR_ID (0x1D50)
#ifdef HACKRF_ONE
#define USB_PRODUCT_ID (0x6089)
#elif JAWBREAKER
#define USB_PRODUCT_ID (0x604B)
#elif RAD1O
#define USB_PRODUCT_ID (0xCC15)
#else
#define USB_PRODUCT_ID (0xFFFF)
#endif
#define USB_API_VERSION (0x0107)
#define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF)
#define USB_MAX_PACKET0 (64)
#define USB_MAX_PACKET_BULK_FS (64)
#define USB_MAX_PACKET_BULK_HS (512)
#define USB_BULK_IN_EP_ADDR (0x81)
#define USB_BULK_OUT_EP_ADDR (0x02)
#define USB_STRING_LANGID (0x0409)
uint8_t usb_descriptor_device[] = {
18, // bLength
USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType
USB_WORD(0x0200), // bcdUSB
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
USB_MAX_PACKET0, // bMaxPacketSize0
USB_WORD(USB_VENDOR_ID), // idVendor
USB_WORD(USB_PRODUCT_ID), // idProduct
USB_WORD(USB_API_VERSION), // bcdDevice
0x01, // iManufacturer
0x02, // iProduct
0x04, // iSerialNumber
0x01 // bNumConfigurations
};
uint8_t usb_descriptor_device_qualifier[] = {
10, // bLength
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, // bDescriptorType
USB_WORD(0x0200), // bcdUSB
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
64, // bMaxPacketSize0
0x01, // bNumOtherSpeedConfigurations
0x00 // bReserved
};
uint8_t usb_descriptor_configuration_full_speed[] = {
9, // bLength
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
USB_WORD(32), // wTotalLength
0x01, // bNumInterfaces
0x01, // bConfigurationValue
0x00, // iConfiguration
0x80, // bmAttributes: USB-powered
250, // bMaxPower: 500mA
9, // bLength
USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType
0x00, // bInterfaceNumber
0x00, // bAlternateSetting
0x02, // bNumEndpoints
0x08, // bInterfaceClass: vendor-specific
0x06, // bInterfaceSubClass
0x50, // bInterfaceProtocol: vendor-specific
0x00, // iInterface
7, // bLength
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
USB_BULK_IN_EP_ADDR, // bEndpointAddress
0x02, // bmAttributes: BULK
USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize
0x00, // bInterval: no NAK
7, // bLength
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
USB_BULK_OUT_EP_ADDR, // bEndpointAddress
0x02, // bmAttributes: BULK
USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize
0x00, // bInterval: no NAK
0, // TERMINATOR
};
uint8_t usb_descriptor_configuration_high_speed[] = {
9, // bLength
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
USB_WORD(32), // wTotalLength
0x01, // bNumInterfaces
0x01, // bConfigurationValue
0x00, // iConfiguration
0x80, // bmAttributes: USB-powered
250, // bMaxPower: 500mA
9, // bLength
USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType
0x00, // bInterfaceNumber
0x00, // bAlternateSetting
0x02, // bNumEndpoints
0x08, // bInterfaceClass: vendor-specific
0x06, // bInterfaceSubClass
0x50, // bInterfaceProtocol: vendor-specific
0x00, // iInterface
7, // bLength
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
USB_BULK_IN_EP_ADDR, // bEndpointAddress
0x02, // bmAttributes: BULK
USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize
0x00, // bInterval: no NAK
7, // bLength
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
USB_BULK_OUT_EP_ADDR, // bEndpointAddress
0x02, // bmAttributes: BULK
USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize
0x00, // bInterval: no NAK
0, // TERMINATOR
};
uint8_t usb_descriptor_string_languages[] = {
0x04, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
USB_WORD(USB_STRING_LANGID), // wLANGID
};
// clang-format off
uint8_t usb_descriptor_string_manufacturer[] = {
40, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'G', 0x00,
'r', 0x00,
'e', 0x00,
'a', 0x00,
't', 0x00,
' ', 0x00,
'S', 0x00,
'c', 0x00,
'o', 0x00,
't', 0x00,
't', 0x00,
' ', 0x00,
'G', 0x00,
'a', 0x00,
'd', 0x00,
'g', 0x00,
'e', 0x00,
't', 0x00,
's', 0x00,
};
uint8_t usb_descriptor_string_product[] = {
#ifdef HACKRF_ONE
43, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'P', 0x00,
'o', 0x00,
'r', 0x00,
't', 0x00,
'a', 0x00,
'P', 0x00,
'a', 0x00,
'c', 0x00,
'k', 0x00,
' ', 0x00,
'M', 0x00,
'a', 0x00,
'y', 0x00,
'h', 0x00,
'e', 0x00,
'm', 0x00,
#elif JAWBREAKER
36, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'H', 0x00,
'a', 0x00,
'c', 0x00,
'k', 0x00,
'R', 0x00,
'F', 0x00,
' ', 0x00,
'J', 0x00,
'a', 0x00,
'w', 0x00,
'b', 0x00,
'r', 0x00,
'e', 0x00,
'a', 0x00,
'k', 0x00,
'e', 0x00,
'r', 0x00,
#elif RAD1O
12, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'r', 0x00,
'a', 0x00,
'd', 0x00,
'1', 0x00,
'o', 0x00,
#else
14, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'H', 0x00,
'a', 0x00,
'c', 0x00,
'k', 0x00,
'R', 0x00,
'F', 0x00,
#endif
};
uint8_t usb_descriptor_string_config_description[] = {
24, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'T', 0x00,
'r', 0x00,
'a', 0x00,
'n', 0x00,
's', 0x00,
'c', 0x00,
'e', 0x00,
'i', 0x00,
'v', 0x00,
'e', 0x00,
'r', 0x00,
};
#ifdef DFU_MODE
uint8_t usb_descriptor_string_serial_number[] = {
30, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'R', 0x00,
'u', 0x00,
'n', 0x00,
'n', 0x00,
'i', 0x00,
'n', 0x00,
'g', 0x00,
'F', 0x00,
'r', 0x00,
'o', 0x00,
'm', 0x00,
'R', 0x00,
'A', 0x00,
'M', 0x00,
};
#else
uint8_t usb_descriptor_string_serial_number[USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN];
#endif
uint8_t* usb_descriptor_strings[] = {
usb_descriptor_string_languages,
usb_descriptor_string_manufacturer,
usb_descriptor_string_product,
usb_descriptor_string_config_description,
usb_descriptor_string_serial_number,
0, // TERMINATOR
};
uint8_t wcid_string_descriptor[] = {
18, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'M', 0x00,
'S', 0x00,
'F', 0x00,
'T', 0x00,
'1', 0x00,
'0', 0x00,
'0', 0x00,
USB_WCID_VENDOR_REQ, // vendor request code for further descriptor
0x00
};
uint8_t wcid_feature_descriptor[] = {
0x28, 0x00, 0x00, 0x00, // bLength
USB_WORD(0x0100), // WCID version
USB_WORD(0x0004), // WICD descriptor index
0x01, // bNumSections
0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Reserved
0x00, // bInterfaceNumber
0x01, // Reserved
'W', 'I', 'N', 'U', 'S', 'B', 0x00,0x00, // Compatible ID, padded with zeros
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Sub-compatible ID
0x00,0x00,0x00,0x00,0x00,0x00 // Reserved
};
@@ -0,0 +1,42 @@
/*
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
* Copyright 2012 Jared Boone
*
* This file is part of HackRF.
*
* 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 <stdint.h>
extern uint8_t usb_descriptor_device[];
extern uint8_t usb_descriptor_device_qualifier[];
extern uint8_t usb_descriptor_configuration_full_speed[];
extern uint8_t usb_descriptor_configuration_high_speed[];
extern uint8_t usb_descriptor_string_languages[];
extern uint8_t usb_descriptor_string_manufacturer[];
extern uint8_t usb_descriptor_string_product[];
#define USB_DESCRIPTOR_STRING_SERIAL_LEN 32
#define USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN \
(USB_DESCRIPTOR_STRING_SERIAL_LEN * 2 + 2) /* UTF-16LE */
extern uint8_t usb_descriptor_string_serial_number[];
extern uint8_t* usb_descriptor_strings[];
#define USB_WCID_VENDOR_REQ 0x19
extern uint8_t wcid_string_descriptor[];
extern uint8_t wcid_feature_descriptor[];
+165
View File
@@ -0,0 +1,165 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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 "w25q80bv.hpp"
#include "debug.hpp"
namespace w25q80bv {
void disable_spifi(){
RESET_CTRL1 = RESET_CTRL1_SPIFI_RST;
}
void initialite_spi(){
palSetPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
palOutputPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
const uint32_t clock_prescale_rate = 2;
const uint32_t serial_clock_rate = 2;
SSP_CR1(SSP0_BASE) = 0;
SSP_CPSR(SSP0_BASE) = clock_prescale_rate;
SSP_CR0(SSP0_BASE) = (serial_clock_rate << 8) | SSP_DATA_8BITS;
SSP_CR1(SSP0_BASE) = SSP_ENABLE;
}
void setup() {
/* Init SPIFI GPIO to Normal GPIO */
MMIO32(PIN_GROUP3 + PIN3) = (SCU_SSP_IO | SCU_CONF_FUNCTION2);
MMIO32(PIN_GROUP3 + PIN4) = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
MMIO32(PIN_GROUP3 + PIN5) = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
MMIO32(PIN_GROUP3 + PIN6) = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
MMIO32(PIN_GROUP3 + PIN7) = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
MMIO32(PIN_GROUP3 + PIN8) = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
/* configure SSP pins */
MMIO32(SCU_SSP0_CIPO) = (SCU_SSP_IO | SCU_CONF_FUNCTION5);
MMIO32(SCU_SSP0_COPI) = (SCU_SSP_IO | SCU_CONF_FUNCTION5);
MMIO32(SCU_SSP0_SCK) = (SCU_SSP_IO | SCU_CONF_FUNCTION2);
/* configure GPIO pins */
MMIO32(SCU_FLASH_HOLD) = SCU_GPIO_FAST;
MMIO32(SCU_FLASH_WP) = SCU_GPIO_FAST;
MMIO32(SCU_SSP0_CS) = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
//remove hardware write protection
/* drive CS, HOLD, and WP pins high */
palSetPad(W25Q80BV_HOLD_PORT, W25Q80BV_HOLD_PAD);
palSetPad(W25Q80BV_WP_PORT, W25Q80BV_WP_PAD);
/* Set GPIO pins as outputs. */
palOutputPad(W25Q80BV_HOLD_PORT, W25Q80BV_HOLD_PAD);
palOutputPad(W25Q80BV_WP_PORT, W25Q80BV_WP_PAD);
}
void wait_for_device() {
uint8_t device_id;
do {
device_id = get_device_id();
} while (device_id != W25Q80BV_DEVICE_ID_RES &&
device_id != W25Q16DV_DEVICE_ID_RES);
}
void wait_not_busy() {
while (get_status() & W25Q80BV_STATUS_BUSY) {HALT_IF_DEBUGGING();}
}
void remove_write_protection() {
uint8_t data[] = {W25Q80BV_WRITE_ENABLE};
palClearPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
for (size_t j = 0; j < 1; j++) {
data[j] = spi_ssp_transfer_word(data[j]);
}
palSetPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
while (!(get_status() & W25Q80BV_STATUS_WEL)) {HALT_IF_DEBUGGING();}
}
uint32_t spi_ssp_transfer_word(const uint32_t data) {
while ((SSP_SR(SSP0_BASE) & SSP_SR_TNF) == 0) {HALT_IF_DEBUGGING();}
SSP_DR(SSP0_BASE) = data;
while (SSP_SR(SSP0_BASE) & SSP_SR_BSY) {HALT_IF_DEBUGGING();}
while ((SSP_SR(SSP0_BASE) & SSP_SR_RNE) == 0) {HALT_IF_DEBUGGING();}
return SSP_DR(SSP0_BASE);
}
uint8_t get_status() {
uint8_t data[] = {W25Q80BV_READ_STATUS1, 0xFF};
palClearPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
for (size_t j = 0; j < 2; j++) {
data[j] = spi_ssp_transfer_word(data[j]);
}
palSetPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
return data[1];
}
uint8_t get_device_id() {
uint8_t data[] = {W25Q80BV_DEVICE_ID, 0xFF, 0xFF, 0xFF, 0xFF};
palClearPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
for (size_t j = 0; j < 5; j++) {
data[j] = spi_ssp_transfer_word(data[j]);
}
palSetPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
return data[4];
}
void erase_chip() {
uint8_t data[] = {W25Q80BV_CHIP_ERASE};
palClearPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
for (size_t j = 0; j < 1; j++) {
data[j] = spi_ssp_transfer_word(data[j]);
}
palSetPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
}
void write(size_t page_index, uint8_t *data_buffer, size_t length) {
size_t page_len = 256U;
size_t addr = page_index * page_len;
uint8_t header[] = {
W25Q80BV_PAGE_PROGRAM,
(uint8_t)((addr & 0xFF0000) >> 16),
(uint8_t)((addr & 0xFF00) >> 8),
(uint8_t)(addr & 0xFF)
};
palClearPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
for (size_t j = 0; j < 4; j++) {
header[j] = spi_ssp_transfer_word(header[j]);
}
for (size_t j = 0; j < length; j++) {
data_buffer[j] = spi_ssp_transfer_word(data_buffer[j]);
}
palSetPad(W25Q80BV_SELECT_PORT, W25Q80BV_SELECT_PAD);
}
}
+140
View File
@@ -0,0 +1,140 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* 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.
*/
#ifndef __W25Q80BV_H__
#define __W25Q80BV_H__
#include "ch.h"
#include "hal.h"
#define RGU_BASE 0x40053000
#define RESET_CTRL1 MMIO32(RGU_BASE + 0x104)
#define RESET_CTRL1_SPIFI_RST_SHIFT (21)
#define RESET_CTRL1_SPIFI_RST (1 << RESET_CTRL1_SPIFI_RST_SHIFT)
#define W25Q80BV_WRITE_ENABLE 0x06
#define W25Q80BV_CHIP_ERASE 0xC7
#define W25Q80BV_DEVICE_ID 0xAB
#define W25Q80BV_PAGE_PROGRAM 0x02
#define PERIPH_BASE_APB0 0x40080000
#define SCU_BASE (PERIPH_BASE_APB0 + 0x06000)
#define MMIO32(addr) (*(volatile uint32_t *)(addr))
#define PIN_GROUP3 (SCU_BASE + 0x180)
#define PIN3 0x00C
#define PIN4 0x010
#define PIN5 0x014
#define PIN6 0x018
#define PIN7 0x01C
#define PIN8 0x020
#define BIT0 (1<<0)
#define BIT1 (1<<1)
#define BIT2 (1<<2)
#define BIT3 (1<<3)
#define BIT4 (1<<4)
#define BIT5 (1<<5)
#define BIT6 (1<<6)
#define BIT7 (1<<7)
#define BIT8 (1<<8)
#define SCU_CONF_EPUN_DIS_PULLUP (BIT4)
#define SCU_CONF_EHS_FAST (BIT5)
#define SCU_CONF_EZI_EN_IN_BUFFER (BIT6)
#define SCU_CONF_ZIF_DIS_IN_GLITCH_FILT (BIT7)
#define SCU_GPIO_FAST (SCU_CONF_EPUN_DIS_PULLUP | \
SCU_CONF_EHS_FAST | \
SCU_CONF_EZI_EN_IN_BUFFER | \
SCU_CONF_ZIF_DIS_IN_GLITCH_FILT)
#define SCU_SSP_IO SCU_GPIO_FAST
#define SCU_CONF_FUNCTION0 (0x0)
#define SCU_CONF_FUNCTION2 (0x2)
#define SCU_CONF_FUNCTION4 (0x4)
#define SCU_CONF_FUNCTION5 (0x5)
#define SCU_SSP0_CIPO (PIN_GROUP3 + PIN6)
#define SCU_SSP0_COPI (PIN_GROUP3 + PIN7)
#define SCU_SSP0_SCK (PIN_GROUP3 + PIN3)
#define SCU_SSP0_CS (PIN_GROUP3 + PIN8)
#define SCU_FLASH_HOLD (PIN_GROUP3 + PIN4)
#define SCU_FLASH_WP (PIN_GROUP3 + PIN5)
#define W25Q80BV_DEVICE_ID_RES 0x13 /* Expected device_id for W25Q80BV */
#define W25Q16DV_DEVICE_ID_RES 0x14 /* Expected device_id for W25Q16DV */
#define SSP_CR1(port) MMIO32(port + 0x004)
#define PERIPH_BASE_APB0 0x40080000
#define SSP0_BASE (PERIPH_BASE_APB0 + 0x03000)
#define SSP_CPSR(port) MMIO32(port + 0x010)
#define SSP_CR0(port) MMIO32(port + 0x000)
#define SSP_ENABLE BIT1
#define SSP_DATA_8BITS 0x7
#define palSetPad(port, pad) (LPC_GPIO->SET[(port)] = 1 << (pad))
#define palClearPad(port, pad) (LPC_GPIO->CLR[(port)] = 1 << (pad))
#define palOutputPad(port, pad) (LPC_GPIO->DIR[(port)] |= 1 << (pad))
#define palTogglePad(port, pad) (LPC_GPIO->NOT[(port)] |= 1 << (pad))
#define W25Q80BV_SELECT_PORT 5
#define W25Q80BV_SELECT_PAD 11
#define W25Q80BV_WP_PORT 1
#define W25Q80BV_WP_PAD 15
#define W25Q80BV_HOLD_PORT 1
#define W25Q80BV_HOLD_PAD 14
#define LED_PORT 2
#define LEDRX_PAD 2
#define LEDTX_PAD 8
#define W25Q80BV_STATUS_BUSY 0x01
#define W25Q80BV_STATUS_WEL 0x02
#define W25Q80BV_READ_STATUS1 0x05
#define W25Q80BV_READ_STATUS2 0x35
#define PERIPH_BASE_APB0 0x40080000
#define SSP0_BASE (PERIPH_BASE_APB0 + 0x03000)
#define SSP_DR(port) MMIO32(port + 0x008)
#define SSP_SR(port) MMIO32(port + 0x00C)
#define SSP_SR_TNF BIT1
#define SSP_SR_RNE BIT2
#define SSP_SR_BSY BIT4
namespace w25q80bv {
void disable_spifi();
uint8_t get_status();
void wait_for_device();
void wait_not_busy();
uint32_t spi_ssp_transfer_word(const uint32_t data);
void initialite_spi();
void setup();
void remove_write_protection();
uint8_t get_device_id();
void erase_chip();
void write(size_t page_index, uint8_t *data_buffer, size_t length);
}
#endif/*__W25Q80BV_H__*/
@@ -25,8 +25,10 @@ MEMORY
{
flash (rx) : org = 0x00000000, len = 32752 /* Local SRAM @ 0x10080000 */
ram (rwx) : org = 0x10000000, len = 96k /* Local SRAM @ 0x10000000 */
ram_usb (rwx) : org = 0x20008000, len = 32K
}
usb_bulk_buffer = ORIGIN(ram_usb);
__ram_start__ = ORIGIN(ram);
__ram_size__ = LENGTH(ram);
__ram_end__ = __ram_start__ + __ram_size__;
+8 -2
View File
@@ -26,11 +26,17 @@
#include <ch.h>
void* operator new(size_t size) {
return chHeapAlloc(0x0, size);
void *p = chHeapAlloc(0x0, size);
if (p == nullptr)
chDbgPanic("Out of Memory");
return p;
}
void* operator new[](size_t size) {
return chHeapAlloc(0x0, size);
void *p = chHeapAlloc(0x0, size);
if (p == nullptr)
chDbgPanic("Out of Memory");
return p;
}
void operator delete(void* p) noexcept {
File diff suppressed because it is too large Load Diff
+153 -139
View File
@@ -36,179 +36,193 @@ using namespace modems;
using namespace serializer;
namespace portapack {
namespace persistent_memory {
enum backlight_timeout_t {
Timeout5Sec = 0,
Timeout15Sec = 1,
Timeout30Sec = 2,
Timeout60Sec = 3,
Timeout180Sec = 4,
Timeout300Sec = 5,
Timeout600Sec = 6,
Timeout3600Sec = 7,
};
namespace persistent_memory {
struct backlight_config_t {
public:
backlight_config_t() :
_timeout_enum(backlight_timeout_t::Timeout600Sec),
_timeout_enabled(false)
{
}
enum backlight_timeout_t {
Timeout5Sec = 0,
Timeout15Sec = 1,
Timeout30Sec = 2,
Timeout60Sec = 3,
Timeout180Sec = 4,
Timeout300Sec = 5,
Timeout600Sec = 6,
Timeout3600Sec = 7,
};
backlight_config_t(
backlight_timeout_t timeout_enum,
bool timeout_enabled
) :
_timeout_enum(timeout_enum),
_timeout_enabled(timeout_enabled)
{
}
struct backlight_config_t {
public:
backlight_config_t() :
_timeout_enum(backlight_timeout_t::Timeout600Sec),
_timeout_enabled(false)
{
}
bool timeout_enabled() const {
return _timeout_enabled;
}
backlight_config_t(
backlight_timeout_t timeout_enum,
bool timeout_enabled
) :
_timeout_enum(timeout_enum),
_timeout_enabled(timeout_enabled)
{
}
backlight_timeout_t timeout_enum() const {
return _timeout_enum;
}
bool timeout_enabled() const {
return _timeout_enabled;
}
uint32_t timeout_seconds() const {
switch(timeout_enum()) {
case Timeout5Sec: return 5;
case Timeout15Sec: return 15;
case Timeout30Sec: return 30;
case Timeout60Sec: return 60;
case Timeout180Sec: return 180;
case Timeout300Sec: return 300;
default:
case Timeout600Sec: return 600;
case Timeout3600Sec: return 3600;
}
}
backlight_timeout_t timeout_enum() const {
return _timeout_enum;
}
private:
backlight_timeout_t _timeout_enum;
bool _timeout_enabled;
};
uint32_t timeout_seconds() const {
switch(timeout_enum()) {
case Timeout5Sec: return 5;
case Timeout15Sec: return 15;
case Timeout30Sec: return 30;
case Timeout60Sec: return 60;
case Timeout180Sec: return 180;
case Timeout300Sec: return 300;
default:
case Timeout600Sec: return 600;
case Timeout3600Sec: return 3600;
}
}
namespace cache {
private:
backlight_timeout_t _timeout_enum;
bool _timeout_enabled;
};
/* Set values in cache to sensible defaults. */
void defaults();
namespace cache {
/* Load cached settings from values in persistent RAM, replacing with defaults
* if persistent RAM contents appear to be invalid. */
void init();
/* Set values in cache to sensible defaults. */
void defaults();
/* Calculate a check value for cached settings, and copy the check value and
* settings into persistent RAM. Intended to be called periodically to update
* persistent settings with current settings. */
void persist();
/* Load cached settings from values in persistent RAM, replacing with defaults
* if persistent RAM contents appear to be invalid. */
void init();
} /* namespace cache */
/* Calculate a check value for cached settings, and copy the check value and
* settings into persistent RAM. Intended to be called periodically to update
* persistent settings with current settings. */
void persist();
using ppb_t = int32_t;
} /* namespace cache */
rf::Frequency tuned_frequency();
void set_tuned_frequency(const rf::Frequency new_value);
using ppb_t = int32_t;
ppb_t correction_ppb();
void set_correction_ppb(const ppb_t new_value);
rf::Frequency tuned_frequency();
void set_tuned_frequency(const rf::Frequency new_value);
void set_touch_calibration(const touch::Calibration& new_value);
const touch::Calibration& touch_calibration();
ppb_t correction_ppb();
void set_correction_ppb(const ppb_t new_value);
serial_format_t serial_format();
void set_serial_format(const serial_format_t new_value);
void set_touch_calibration(const touch::Calibration& new_value);
const touch::Calibration& touch_calibration();
int32_t tone_mix();
void set_tone_mix(const int32_t new_value);
serial_format_t serial_format();
void set_serial_format(const serial_format_t new_value);
int32_t afsk_mark_freq();
void set_afsk_mark(const int32_t new_value);
int32_t tone_mix();
void set_tone_mix(const int32_t new_value);
int32_t afsk_space_freq();
void set_afsk_space(const int32_t new_value);
int32_t afsk_mark_freq();
void set_afsk_mark(const int32_t new_value);
int32_t modem_baudrate();
void set_modem_baudrate(const int32_t new_value);
int32_t afsk_space_freq();
void set_afsk_space(const int32_t new_value);
uint8_t modem_repeat();
void set_modem_repeat(const uint32_t new_value);
int32_t modem_baudrate();
void set_modem_baudrate(const int32_t new_value);
uint32_t playing_dead();
void set_playing_dead(const uint32_t new_value);
uint8_t modem_repeat();
void set_modem_repeat(const uint32_t new_value);
uint32_t playdead_sequence();
void set_playdead_sequence(const uint32_t new_value);
uint32_t playing_dead();
void set_playing_dead(const uint32_t new_value);
bool stealth_mode();
void set_stealth_mode(const bool v);
uint32_t playdead_sequence();
void set_playdead_sequence(const uint32_t new_value);
uint8_t config_cpld();
void set_config_cpld(uint8_t i);
bool stealth_mode();
void set_stealth_mode(const bool v);
bool config_splash();
bool show_gui_return_icon();
bool load_app_settings();
bool save_app_settings();
bool show_bigger_qr_code();
bool hide_clock();
bool clock_with_date();
bool config_login();
bool config_speaker();
backlight_config_t config_backlight_timer();
bool disable_touchscreen();
uint8_t config_cpld();
void set_config_cpld(uint8_t i);
void set_gui_return_icon(bool v);
void set_load_app_settings(bool v);
void set_save_app_settings(bool v);
void set_show_bigger_qr_code(bool v);
void set_config_splash(bool v);
void set_clock_hidden(bool v);
void set_clock_with_date(bool v);
void set_config_login(bool v);
void set_config_speaker(bool v);
void set_config_backlight_timer(const backlight_config_t& new_value);
void set_disable_touchscreen(bool v);
bool config_splash();
bool config_hide_converter();
bool config_converter();
bool config_updown_converter();
int64_t config_converter_freq();
bool show_gui_return_icon();
bool load_app_settings();
bool save_app_settings();
bool show_bigger_qr_code();
bool hide_clock();
bool clock_with_date();
bool config_login();
bool config_speaker();
backlight_config_t config_backlight_timer();
bool disable_touchscreen();
//uint8_t ui_config_textentry();
//void set_config_textentry(uint8_t new_value);
void set_gui_return_icon(bool v);
void set_load_app_settings(bool v);
void set_save_app_settings(bool v);
void set_show_bigger_qr_code(bool v);
void set_config_splash(bool v);
void set_config_hide_converter(bool v);
void set_config_converter(bool v);
void set_config_updown_converter(const bool v);
void set_config_converter_freq(const int64_t v );
void set_clock_hidden(bool v);
void set_clock_with_date(bool v);
void set_config_login(bool v);
void set_config_speaker(bool v);
void set_config_backlight_timer(const backlight_config_t& new_value);
void set_disable_touchscreen(bool v);
uint32_t pocsag_last_address();
void set_pocsag_last_address(uint32_t address);
//uint8_t ui_config_textentry();
//void set_config_textentry(uint8_t new_value);
uint32_t pocsag_ignore_address();
void set_pocsag_ignore_address(uint32_t address);
uint32_t pocsag_last_address();
void set_pocsag_last_address(uint32_t address);
bool clkout_enabled();
void set_clkout_enabled(bool v);
uint32_t clkout_freq();
void set_clkout_freq(uint32_t freq);
uint32_t pocsag_ignore_address();
void set_pocsag_ignore_address(uint32_t address);
/* Recon app */
bool recon_autosave_freqs();
bool recon_autostart_recon();
bool recon_continuous();
bool recon_clear_output();
bool recon_load_freqs();
bool recon_load_ranges();
bool recon_update_ranges_when_recon();
bool recon_load_hamradios();
bool recon_match_mode();
void set_recon_autosave_freqs(const bool v);
void set_recon_autostart_recon(const bool v);
void set_recon_continuous(const bool v);
void set_recon_clear_output(const bool v);
void set_recon_load_freqs(const bool v);
void set_recon_load_ranges(const bool v);
void set_recon_update_ranges_when_recon(const bool v);
void set_recon_load_hamradios(const bool v );
void set_recon_match_mode( const bool v );
bool clkout_enabled();
void set_clkout_enabled(bool v);
uint32_t clkout_freq();
void set_clkout_freq(uint32_t freq);
/* Recon app */
bool recon_autosave_freqs();
bool recon_autostart_recon();
bool recon_continuous();
bool recon_clear_output();
bool recon_load_freqs();
bool recon_load_ranges();
bool recon_update_ranges_when_recon();
bool recon_load_hamradios();
bool recon_match_mode();
void set_recon_autosave_freqs(const bool v);
void set_recon_autostart_recon(const bool v);
void set_recon_continuous(const bool v);
void set_recon_clear_output(const bool v);
void set_recon_load_freqs(const bool v);
void set_recon_load_ranges(const bool v);
void set_recon_update_ranges_when_recon(const bool v);
void set_recon_load_hamradios(const bool v );
void set_recon_match_mode( const bool v );
// sd persisting settings
int save_persistent_settings_to_file( std::string filename );
int load_persistent_settings_from_file( std::string filename );
} /* namespace persistent_memory */
} /* namespace persistent_memory */
} /* namespace portapack */
#endif/*__PORTAPACK_PERSISTENT_MEMORY_H__*/
+3
View File
@@ -106,6 +106,8 @@ constexpr image_tag_t image_tag_gps { 'P', 'G', 'P', 'S' };
constexpr image_tag_t image_tag_siggen { 'P', 'S', 'I', 'G' };
constexpr image_tag_t image_tag_sstv_tx { 'P', 'S', 'T', 'X' };
constexpr image_tag_t image_tag_tones { 'P', 'T', 'O', 'N' };
constexpr image_tag_t image_tag_flash_utility { 'P', 'F', 'U', 'T' };
constexpr image_tag_t image_tag_usb_sd { 'P', 'U', 'S', 'B' };
constexpr image_tag_t image_tag_noop { 'P', 'N', 'O', 'P' };
@@ -114,6 +116,7 @@ constexpr image_tag_t image_tag_hackrf { 'H', 'R', 'F', '1' };
struct chunk_t {
const image_tag_t tag;
const uint32_t length;
const uint32_t compressed_data_size;
const uint8_t data[];
const chunk_t* next() const {
+4 -4
View File
@@ -100,8 +100,8 @@ Optional<Reading> Packet::reading_ook_8k4_schrader() const {
* Preamble: 01*40
* System ID: 01100101, ??*20 (not really sure what this data is)
* ID: 32 Manchester symbols
* Value: 8 Manchester symbols (temperature?)
* Value: 8 Manchester symbols (pressure?)
* Value: 8 Manchester symbols (pressure)
* Value: 8 Manchester symbols (temperature)
* Checksum: 8 Manchester symbols (uint8_t sum of bytes starting with system ID)
*/
/* NOTE: First four bits of packet are consumed in preamble detection.
@@ -123,8 +123,8 @@ Optional<Reading> Packet::reading_ook_8k4_schrader() const {
return Reading {
Reading::Type::GMC_96,
(uint32_t)id,
Pressure { static_cast<int>(value_1) * 4 / 3 },
Temperature { static_cast<int>(value_0) - 56 }
Pressure { static_cast<int>(value_0) * 11 / 4 },
Temperature { static_cast<int>(value_1) - 61 }
};
} else {
return { };
Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

+22 -17
View File
@@ -27,7 +27,7 @@ import struct
usage_message = """
PortaPack image chunk writer
Usage: <command> <input_binary> <four-characer tag> <output_tagged_binary> [<chunk max size>]
Usage: <command> <input_binary> <four-characer tag> <output_tagged_binary>
"""
def read_image(path):
@@ -41,17 +41,33 @@ def write_image(data, path):
f.write(data)
f.close()
input_image_max_length = 32768
if len(sys.argv) in (4, 5):
if len(sys.argv) == 4:
input_image = read_image(sys.argv[1])
input_image = bytearray(input_image)
tag = tuple(map(ord, sys.argv[2]))
output_path = sys.argv[3]
if len(sys.argv) == 5:
input_image_max_length = int(sys.argv[4])
if input_image[4] & 8 == 8:
input_image = input_image[15:]
else:
input_image = input_image[7:]
if (len(input_image) & 3) != 0:
for i in range(4 - (len(input_image) & 3)):
input_image.append(0)
output_image = bytearray()
output_image += struct.pack('<4BI', tag[0], tag[1], tag[2], tag[3], len(input_image) - 4)
output_image += input_image
write_image(output_image, output_path)
elif len(sys.argv) == 2:
input_image = bytearray()
null_image = bytearray()
tag = (0, 0, 0, 0)
output_path = sys.argv[1]
null_image += struct.pack('<4BI', tag[0], tag[1], tag[2], tag[3], 0)
write_image(null_image, output_path)
else:
print(usage_message)
sys.exit(-1)
@@ -59,14 +75,3 @@ else:
if len(tag) != 4:
print(usage_message)
sys.exit(-2)
if len(input_image) > input_image_max_length:
raise RuntimeError('image size of %d exceeds device size of %d bytes' % (len(input_image), input_image_max_length))
if (len(input_image) & 3) != 0:
raise RuntimeError('image size of %d is not multiple of four' % (len(input_image,)))
output_image = bytearray()
output_image += struct.pack('<4BI', tag[0], tag[1], tag[2], tag[3], len(input_image))
output_image += input_image
write_image(output_image, output_path)
+1 -1
Submodule hackrf updated: b42a185503...ae71cb5b7a
Binary file not shown.
Binary file not shown.