Compare commits

...

137 Commits

Author SHA1 Message Date
jLynx 8ba5715db0 Update version.txt 2023-05-06 08:03:59 +12:00
jLynx c7e8506ad0 Update past_version.txt 2023-05-06 08:03:44 +12:00
gullradriel 8cb0a91bb5 Merge pull request #958 from gullradriel/recon-skip-fix
fix skip consecutive match
2023-05-05 17:03:00 +02:00
GullCode 1bcbefeb96 fix skip consecutive match 2023-05-05 17:01:08 +02:00
gullradriel 31031edbd1 Merge pull request #956 from bernd-herzog/boot_improvements
removed need for cpld mode setup for QFP100
2023-05-05 15:37:58 +02:00
bernd-herzog 7116f92d07 fixed spelling 2023-05-05 13:39:04 +02:00
bernd-herzog df8e79f9e6 refactoring 2023-05-05 12:58:28 +02:00
bernd-herzog e80e4e3bfd refactoring 2023-05-05 12:58:14 +02:00
bernd-herzog da6c6bb03c refactoring 2023-05-05 12:46:59 +02:00
bernd-herzog 75718c79b9 removed need for cpld mode setup for QFP100 2023-05-05 11:15:49 +02:00
gullradriel 9b263def37 Merge pull request #954 from gullradriel/recon-fix
Recon fix
2023-05-04 15:27:47 +02:00
GullCode c7d88da1a6 restoring bad substitue on text_ctcss filler 2023-05-04 15:26:33 +02:00
GullCode 7b6f8b271c Fixed so ui glitches, start when empty file and direct click on config. Added yellow coloration when loaded file was truncated (too big). Added/changed some error messages 2023-05-04 15:20:12 +02:00
GullCode 1b18b3ac45 fixing limit so we can detect if a list is the same size as the limit or truncated 2023-05-04 15:19:13 +02:00
gullradriel 68fc2a143f Merge pull request #953 from gullradriel/freqman-limits
fixing freqman limits
2023-05-04 12:11:15 +02:00
GullCode 1deebaff09 fixing freqman limits 2023-05-04 12:09:42 +02:00
gullradriel d6118c9fc4 Merge pull request #951 from kallanreed/fileloadview-fix
Fix nav.pop order on FileLoadView
2023-05-04 07:43:54 +02:00
Kyle Reed 44a62aef21 Fix nav.pop order on FileLoadView 2023-05-03 15:29:01 -07:00
gullradriel 0742fc169d Merge pull request #950 from kallanreed/fileman_ux2
Fileman fit and finish
2023-05-03 22:32:00 +02:00
Kyle Reed 62859f901f Fix indents 2023-05-03 13:23:15 -07:00
Kyle Reed c6316f5aa6 Fileman fit and finish 2023-05-03 13:13:15 -07:00
gullradriel 5f2043d229 Merge pull request #949 from gullradriel/pmem-defaults
Pmem defaults
2023-05-03 19:51:47 +02:00
gullradriel 074658c4bb Merge branch 'eried:next' into pmem-defaults 2023-05-03 19:51:15 +02:00
GullCode d641ae5b47 Fixed size of things 2023-05-03 19:50:12 +02:00
gullradriel bec70b4ee5 Merge pull request #948 from gullradriel/pmem-defaults
Pmem defaults
2023-05-03 19:48:05 +02:00
GullCode c4373d1560 indentation 2023-05-03 19:45:01 +02:00
GullCode 1dae2c0d25 indentation 2023-05-03 19:44:08 +02:00
GullCode 658d0c9b3a Added reset persitent memory 2023-05-03 19:42:57 +02:00
gullradriel 2f343adf21 Merge pull request #941 from kallanreed/fileman_ux
Fileman UI and Perf Fixes
2023-05-03 17:13:05 +02:00
gullradriel f7a5f2c437 Merge pull request #946 from Brumi-2021/noise_Signal_Generator_LFSR_polynomial_of_16_32_bits
Leaving only 1 Noise signal generator GUI option , (the best one , using  LFSR polynomial of 16 bits)
2023-05-03 13:57:06 +02:00
Brumi-2021 5a336d5e71 Compact with unique, best Noise Gererator option. 2023-05-03 13:49:50 +02:00
gullradriel 91675e26cb Merge pull request #945 from bernd-herzog/touchscreen_multiinput_fix
fixed touch handling issue causing multiple inputs
2023-05-03 11:43:34 +02:00
bernd-herzog 078da8ca16 Improved sensitivity for non pointy touches 2023-05-03 11:18:37 +02:00
bernd-herzog 77260bc68a fixed touch handling issue causing multiple inputs 2023-05-03 10:47:43 +02:00
gullradriel ca143f9788 Merge pull request #944 from joyel24/meteomodem-M20-radiosondes-altitude
Add Meteomodem M20 radiosondes altitude
2023-05-03 06:31:47 +02:00
Kyle Reed 3fc23354ce Fix path separator, revert UI 2023-05-02 20:49:41 -07:00
joyel24 d48e25167f fix altitude inaccuracy 2023-05-03 05:37:31 +02:00
joyel24 cfe5a6bfe4 Merge branch 'eried:next' into meteomodem-M20-radiosondes-altitude 2023-05-03 02:09:20 +02:00
Brumi-2021 d77102426a Finally Noise Signal with best option 16 bit LFSR 2023-05-02 21:29:35 +02:00
Kyle Reed 11f4edc892 Modal dialog for partner file action, fix lifetime 2023-05-02 09:38:08 -07:00
Brumi-2021 804fa0d3c4 Minor GUI corrections-Signal Generator 2023-05-02 17:41:00 +02:00
Brumi-2021 d5f20c45b9 Adding 16 bit LFSR , to Noise Signal Generator App 2023-05-02 17:19:23 +02:00
Kyle Reed 2cba96ff36 Support for partner file rename/delete 2023-05-01 09:25:32 -07:00
Joel M 7139abb947 alt divided by 100 2023-05-01 16:54:29 +02:00
Kyle Reed bf4ed416bd Remove expensive path.string() calls, UI changes 2023-04-30 22:42:28 -07:00
gullradriel 06643df6a5 Merge pull request #938 from gullradriel/pmemsettings-create-folder
Added SETTINGS folder creating for PMem files
2023-04-30 18:42:51 +02:00
GullCode 81752c8d78 Added SETTINGS folder creating for PMem files 2023-04-30 18:41:24 +02:00
gullradriel 0cb8c9200a Merge pull request #937 from gullradriel/hackrf-flashing-tool-update
Updating to release 2023.01.1
2023-04-30 18:27:41 +02:00
GullCode 8e64221384 Updating to release 2023.01.1 https://github.com/greatscottgadgets/hackrf/releases/tag/v2023.01.1 2023-04-30 18:26:22 +02:00
gullradriel fe1837ec23 Merge pull request #936 from Brumi-2021/solving_bug_in_noise_option_Signal_Generator_tool
Solving Noise generation in Signal gen App
2023-04-30 17:33:18 +02:00
Brumi-2021 ee53b28e60 Solving Noise generation in Signal gen App 2023-04-30 18:03:40 +02:00
gullradriel 18c986cd76 Merge pull request #931 from kallanreed/cursor_text_input
Add a TextField widget that supports a cursor.
2023-04-30 17:28:42 +02:00
gullradriel a1c3cbcea9 Merge pull request #935 from gullradriel/looking-glass-update
Looking glass update
2023-04-30 15:01:57 +02:00
GullCode 1135a42932 better roundings/per pixel marker 2023-04-30 14:56:17 +02:00
Joel M a74d0e5167 altitude 3 bytes 2023-04-30 13:59:21 +02:00
gullradriel c5579e25fd Merge pull request #932 from joyel24/meteomodem-M20-radiosondes
Identifying meteomodem m20 radiosondes & extract GNSS location
2023-04-30 13:25:42 +02:00
Joel M e8b8f0ca5c Disable inaccurate altitude for the moment 2023-04-30 12:06:37 +02:00
GullCode 98e7116230 Changed to per pixel marker, short freq display, adjusted <24Mhz view to look like SPEC one 2023-04-29 21:46:19 +02:00
Joel M c916eaf43f Detects M20 radiosondes and decode GNSS location 2023-04-29 14:00:28 +02:00
Joel M e3169a3495 add Meteomodem_M20 to packet class in sonde_packet.hpp 2023-04-29 13:49:27 +02:00
Kyle Reed 4b37f1bb2f Add a TestField widget that supports a cursor. 2023-04-28 19:26:53 -07:00
gullradriel cb93f2636e Merge pull request #929 from gullradriel/freq-disp-fix
Freq disp fix
2023-04-28 13:01:12 +02:00
GullCode 596c304b08 Took out unused func declaration 2023-04-28 12:59:51 +02:00
GullCode 63f7be02b6 Used correct to_string_short_freq instead of erroneous calculation 2023-04-28 12:57:00 +02:00
GullCode de99afa19b Took out unused func declaration 2023-04-28 12:55:58 +02:00
gullradriel 5c4e27ea29 Merge pull request #927 from gullradriel/dsp-warning-fix
Dsp warning fix
2023-04-27 16:08:18 +02:00
GullCode 54e4230191 indentation 2023-04-27 16:07:57 +02:00
GullCode f069383c2a Fix unused warnings in ssb_execute 2023-04-27 16:06:47 +02:00
gullradriel d3a356d415 Merge pull request #926 from gullradriel/gitignore-fix
restoring gitignore
2023-04-27 15:51:54 +02:00
GullCode f0e4fdcbcc restoring gitignore, bad move on last commit 2023-04-27 15:50:59 +02:00
ittercho d5f6f42fae Addition of water meters (#892)
Water Meters frequency list
NRK and RMF radio stations frequencies list
Fixed and ordered as much as possible PRESETS.TXT
Co-authored-by: gullradriel
2023-04-27 15:44:32 +02:00
gullradriel 7a89858cc6 Merge pull request #925 from gullradriel/level-mem-workaround
Automatically reduce rssi graph history
2023-04-27 15:42:06 +02:00
gullradriel 15c9a76536 Merge pull request #924 from bernd-herzog/dfu_menu
added frame drop rate for m4 signal processing
2023-04-27 15:41:46 +02:00
GullCode d7359a8cd5 Automatically reduce rssi graph history when hidden, restore size on show. Prevent Memory exhaustion in apps like 'Level' or any app eating a bit too much mem before launching a FrequencyPadView 2023-04-27 15:38:29 +02:00
Bernd Herzog 50e5bc60ee added frame miss rate for m4 signal processing 2023-04-26 22:28:14 +02:00
jLynx 9385be4f1e Merge pull request #920 from zxkmm/ready_to_pr_2_20230426_imp_issue_917
implemented issue#917
2023-04-27 07:01:02 +12:00
zxkmmOnHaseeWSL 9cddab9a5e fix mistakenly remane dir as file -- credit:Gull 2023-04-26 19:09:38 +08:00
zxkmmOnHaseeWSL 6e01a1d0dc change ?: to if else 2023-04-26 16:20:05 +08:00
gullradriel f73cd39d2d Merge pull request #922 from NotherNgineer/next
#910 Brighter color for .C8/.C16 files in fileman
2023-04-26 09:29:57 +02:00
Mark Thompson 0303c658ea Brighter color for .C8/.C16 files in fileman
See https://github.com/eried/portapack-mayhem/issues/910
2023-04-26 02:04:37 -05:00
gullradriel 94ddb63b1d Merge pull request #921 from zxkmm/ready_to_pr_20230426_3_textual_change_for_flash_unity
textual change for  the flash unity
2023-04-26 08:29:51 +02:00
gullradriel b1aa607a7c Merge pull request #907 from NotherNgineer/next
Support for ERT SCM+ meter protocol
2023-04-26 08:28:39 +02:00
Mark Thompson 509f86c1f7 Merge branch 'eried:next' into next 2023-04-26 01:25:46 -05:00
zxkmmOnHaseeWSL b45ca43e27 textual change for the flash unity 2023-04-26 13:29:11 +08:00
zxkmmOnHaseeWSL 47482d1e58 fixed var.clear 2023-04-26 13:22:50 +08:00
zxkmmOnHaseeWSL 59dfe5b50b implemented issue#917 2023-04-26 13:01:51 +08:00
Mark Thompson b1f5023fe1 Removed unneeded space characters 2023-04-24 15:29:51 -05:00
gullradriel a54b94fe53 Merge pull request #915 from gullradriel/recon-update
Recon description flashing on range fix
2023-04-24 21:15:56 +02:00
GullCode 45bdabcef9 Fix for description being updated at each step on a range 2023-04-24 21:14:34 +02:00
Mark Thompson 6cdada1118 Include ERT packet type in ert.txt log file 2023-04-24 09:59:43 -05:00
gullradriel cffc72c516 Merge pull request #913 from gullradriel/looking-glass-zoom
Looking glass zoom update
2023-04-24 13:56:04 +02:00
GullCode e53514aa12 tweaking scan start values and ranges, allowing <24MHz range 2023-04-24 13:51:31 +02:00
Bernd Herzog 775de5ce6f Merge pull request #912 from bernd-herzog/dfu_menu
improved stability of cpu usage calculation
2023-04-24 13:05:36 +02:00
Bernd Herzog 4ff92be23b refactoring 2023-04-24 13:04:59 +02:00
Bernd Herzog 948d8d947e improved stability of cpu usage calculation 2023-04-24 13:00:34 +02:00
jLynx 55c300ac4b Merge pull request #909 from bernd-herzog/dfu_menu
Dfu menu
2023-04-24 10:26:11 +12:00
Bernd Herzog 29b7a5ee56 improved m4 m0 communication 2023-04-23 23:48:20 +02:00
Bernd Herzog 2ef9ebd7bd implemented M4 stats 2023-04-23 21:48:45 +02:00
Bernd Herzog 850a79c9bb added m0 stats to dfu screen 2023-04-23 19:52:38 +02:00
Bernd Herzog 812f0f8211 added overlay to system view 2023-04-23 16:21:33 +02:00
jLynx d00c21adb7 Merge pull request #908 from zxkmm/ready_to_pr_20230423_fix_stealth_in_replay
fix stealth doesn't work
2023-04-23 21:11:45 +12:00
zxkmmOnHaseeWSL 925c1548a8 fix stealth doesn't work 2023-04-23 16:47:06 +08:00
jLynx cd1f1bd388 Merge pull request #906 from zxkmm/fix_fileman_refactor
fix last commit aka fileman refactor exception
2023-04-23 19:12:40 +12:00
zxkmmOnHaseeWSL 474fe00146 formatting fix 2023-04-23 14:53:06 +08:00
Mark Thompson 44b2e5ea61 Support for ERT SCM+ meter protocol 2023-04-23 01:34:56 -05:00
Mark Thompson 48ed7b1b1a Support for ERT SCM+ meter protocol 2023-04-23 01:33:42 -05:00
Mark Thompson 6201be82ea Support for ERT SCM+ meter protocol 2023-04-23 01:31:45 -05:00
Mark Thompson fe1d296b48 Support for ERT SCM+ meter protocol 2023-04-23 01:29:51 -05:00
Mark Thompson 697876d86a Support for ERT SCM+ meter protocol 2023-04-23 01:26:37 -05:00
Brumi-2021 b72c765911 Merge pull request #904 from zxkmm/ready_to_pr_20230421
make the title touchable, and back/return when touch it
2023-04-22 21:39:10 +02:00
zxkmmOnHaseeWSL 2a14888b80 fix last commit aka fileman refactor exception 2023-04-22 22:58:10 +08:00
jLynx 99f1bded4d Merge pull request #905 from zxkmm/ready_to_pr_20230422
add Refactor in fileman app
2023-04-22 21:52:53 +12:00
zxkmmOnHaseeWSL d8e9fad205 fix indentation for pr 20230422-2 2023-04-22 17:51:31 +08:00
zxkmmOnHaseeWSL 0e8dc1567c fix indentation for pr 20230422 2023-04-22 17:50:21 +08:00
zxkmmOnHaseeWSL 4ff71dcfca add Refactor in fileman app 2023-04-22 17:21:51 +08:00
zxkmmOnHaseeWSL ed0f0eb15e touchable title, little width adjust again... sorry 2023-04-22 13:31:27 +08:00
zxkmmOnHaseeWSL 193a80edea smaller touchable title 2023-04-22 13:02:41 +08:00
zxkmmOnHaseeWSL df0c85db8f touchable title 2023-04-21 21:34:18 +08:00
Bernd Herzog c5738c46d5 Merge pull request #899 from bernd-herzog/dfu_menu
Dfu button
2023-04-17 08:17:21 +02:00
Bernd Herzog 0acf7ec2c2 refactoring 2023-04-16 20:33:02 +02:00
Bernd Herzog dc560ba01f improved debug app layout 2023-04-16 20:31:14 +02:00
Bernd Herzog d74fd92451 added dfu button to debug app 2023-04-16 19:51:06 +02:00
Bernd Herzog bcefa774cd added dfu button to debug app 2023-04-16 18:23:54 +02:00
gullradriel 8382eaf45f Merge pull request #896 from gullradriel/looking-fast-slow
Looking fast slow
2023-04-13 11:11:45 +02:00
GullCode 9f700a30c0 Changed text to MAX HOLD to make a difference with existing 'MAX' 2023-04-13 11:02:32 +02:00
GullCode d815e6c952 Merge branch 'next' of github.com:gullradriel/portapack-mayhem into looking-fast-slow 2023-04-13 10:38:13 +02:00
GullCode e60ec953ab move text and button a bit so it's fitting when big 2023-04-13 10:36:15 +02:00
GullCode 72d1e21fc6 added adjust_range, fast scan and slow scan, lock/unlock range, integer division results when possible, default step of 1 2023-04-13 10:18:16 +02:00
jLynx e4d42817ee Merge pull request #895 from JimiHFord/patch-1
fix typo
2023-04-13 16:16:19 +12:00
Jimi Ford 5729bde214 fix typo 2023-04-13 00:11:30 -04:00
gullradriel ec7a77896a Update ui_looking_glass_app.hpp
size of db is uint8_t, adjusting live-v and peak-v array to uint8_t
2023-04-11 20:41:42 +02:00
eried 99c26c3b7b Adding step files of the enclosure 2023-04-11 09:55:21 +02:00
Brumi-2021 aa20bff2b9 Merge pull request #887 from gullradriel/looking-glass-fix
Peak view entry menu and functionnalities
2023-04-10 23:10:19 +02:00
GullCode f5e949047d correct clear size in peak-v and live-v 2023-04-10 21:39:50 +02:00
GullCode afb75af5b1 removed redundant set_dirty 2023-04-09 22:32:35 +02:00
GullCode 7f99b1181e Added MAX:FREQ , RST , JMP on LIVE-V and PEAK-V. Ploter is having a y shift in these modes 2023-04-09 22:07:50 +02:00
GullCode cec0fe3288 Peak view entry menu and functionnalities 2023-04-09 14:45:07 +02:00
80 changed files with 34738 additions and 708 deletions
+1 -1
View File
@@ -1 +1 @@
v1.5.4
v1.6.0
+1 -1
View File
@@ -1 +1 @@
v1.6.0
v1.7.0
+1 -1
View File
@@ -39,7 +39,7 @@ The current **stable release** is on the [![GitHub release (latest by date)](htt
## How can I collaborate
You can write [documentation](https://github.com/eried/portapack-mayhem/wiki), fix bugs and [answer issues](https://github.com/eried/portapack-mayhem/issues) or add new functionality. Please check the following [guide](https://github.com/eried/portapack-mayhem/wiki/How-to-collaborate) with details.
Consider that the hardware and firmware has been created and maintain by a [lot](https://github.com/mossmann/hackrf/graphs/contributors) of [people](https://github.com/eried/portapack-mayhem/graphs/contributors), so always try colaborating your time and effort first. For coding related questions, if something does not fit as an issue, please join our Discord by clicking the chat badge on [top](#portapack-mayhem).
Consider that the hardware and firmware has been created and maintain by a [lot](https://github.com/mossmann/hackrf/graphs/contributors) of [people](https://github.com/eried/portapack-mayhem/graphs/contributors), so always try collaborating your time and effort first. For coding related questions, if something does not fit as an issue, please join our Discord by clicking the chat badge on [top](#portapack-mayhem).
[![Contributors](https://contrib.rocks/image?repo=eried/portapack-mayhem)](https://github.com/eried/portapack-mayhem/graphs/contributors)
+2
View File
@@ -155,6 +155,7 @@ set(CPPSRC
${COMMON}/ui_widget.cpp
${COMMON}/utility.cpp
${COMMON}/wm8731.cpp
${COMMON}/performance_counter.cpp
app_settings.cpp
audio.cpp
baseband_api.cpp
@@ -230,6 +231,7 @@ set(CPPSRC
apps/ui_nrf_rx.cpp
apps/ui_aprs_tx.cpp
apps/ui_bht_tx.cpp
apps/ui_dfu_menu.cpp
apps/ui_coasterp.cpp
apps/ui_debug.cpp
apps/ui_encoders.cpp
+3 -1
View File
@@ -41,6 +41,7 @@ std::string type(Packet::Type value) {
case Packet::Type::Unknown: return "???";
case Packet::Type::IDM: return "IDM";
case Packet::Type::SCM: return "SCM";
case Packet::Type::SCMPLUS: return "SCM+";
}
}
@@ -62,7 +63,8 @@ std::string commodity_type(CommodityType value) {
void ERTLogger::on_packet(const ert::Packet& packet) {
const auto formatted = packet.symbols_formatted();
log_file.write_entry(packet.received_at(), formatted.data + "/" + formatted.errors);
std::string entry = ert::format::type(packet.type()) + " " + formatted.data + "/" + formatted.errors;
log_file.write_entry(packet.received_at(), entry);
}
const ERTRecentEntry::Key ERTRecentEntry::invalid_key { };
+7 -1
View File
@@ -161,10 +161,16 @@ void ReplayAppView::start() {
sample_rate * 8,
baseband_bandwidth,
rf::Direction::Transmit,
rf_amp, // previous code line : "receiver_model.rf_amp()," was passing the same rf_amp of all Receiver Apps
rf_amp, // previous code line : "receiver_model.rf_amp()," was passing the same rf_amp of all Receiver Apps
static_cast<int8_t>(receiver_model.lna()),
static_cast<int8_t>(receiver_model.vga())
});
if (portapack::persistent_memory::stealth_mode()){
DisplaySleepMessage message;
EventDispatcher::send_message(message);
}
}
void ReplayAppView::stop(const bool do_loop) {
+1 -1
View File
@@ -206,7 +206,7 @@ void SoundBoardView::refresh_list() {
file_list[n].string().substr(0, 30),
ui::Color::white(),
nullptr,
[this](){
[this](KeyEvent){
on_select_entry();
}
});
+55 -17
View File
@@ -266,7 +266,9 @@ bool ControlsSwitchesWidget::on_key(const KeyEvent key) {
}
void ControlsSwitchesWidget::paint(Painter& painter) {
const std::array<Rect, 7> button_rects { {
const auto pos = screen_pos();
const std::array<Rect, 8> button_rects { {
{ 64, 32, 16, 16 }, // Right
{ 0, 32, 16, 16 }, // Left
{ 32, 64, 16, 16 }, // Down
@@ -274,27 +276,63 @@ void ControlsSwitchesWidget::paint(Painter& painter) {
{ 32, 32, 16, 16 }, // Select
{ 16, 96, 16, 16 }, // Encoder phase 0
{ 48, 96, 16, 16 }, // Encoder phase 1
{ 96, 0, 16, 16 }, // Dfu
} };
const auto pos = screen_pos();
auto switches_raw = control::debug::switches();
auto switches_debounced = get_switches_state().to_ulong();
auto switches_event = key_event_mask;
for(const auto r : button_rects) {
const auto c =
((switches_event & 1) ?
Color::red() :
((switches_debounced & 1) ?
Color::green() :
((switches_raw & 1) ?
Color::yellow() :
Color::blue()
)
)
);
painter.fill_rectangle(r + pos, c);
painter.fill_rectangle(r + pos, Color::blue());
}
const std::array<Rect, 8> raw_rects { {
{ 64 + 1, 32 + 1, 16 - 2, 16 - 2 }, // Right
{ 0 + 1, 32 + 1, 16 - 2, 16 - 2 }, // Left
{ 32 + 1, 64 + 1, 16 - 2, 16 - 2 }, // Down
{ 32 + 1, 0 + 1, 16 - 2, 16 - 2 }, // Up
{ 32 + 1, 32 + 1, 16 - 2, 16 - 2 }, // Select
{ 16 + 1, 96 + 1, 16 - 2, 16 - 2 }, // Encoder phase 0
{ 48 + 1, 96 + 1, 16 - 2, 16 - 2 }, // Encoder phase 1
{ 96 + 1, 0 + 1, 16 - 2, 16 - 2 }, // Dfu
} };
auto switches_raw = control::debug::switches();
for(const auto r : raw_rects) {
if (switches_raw & 1)
painter.fill_rectangle(r + pos, Color::yellow());
switches_raw >>= 1;
}
const std::array<Rect, 6> debounced_rects { {
{ 64 + 2, 32 + 2, 16 - 4, 16 - 4 }, // Right
{ 0 + 2, 32 + 2, 16 - 4, 16 - 4 }, // Left
{ 32 + 2, 64 + 2, 16 - 4, 16 - 4 }, // Down
{ 32 + 2, 0 + 2, 16 - 4, 16 - 4 }, // Up
{ 32 + 2, 32 + 2, 16 - 4, 16 - 4 }, // Select
{ 96 + 2, 0 + 2, 16 - 4, 16 - 4 }, // Dfu
} };
auto switches_debounced = get_switches_state().to_ulong();
for(const auto r : debounced_rects) {
if (switches_debounced & 1)
painter.fill_rectangle(r + pos, Color::green());
switches_debounced >>= 1;
}
const std::array<Rect, 6> events_rects { {
{ 64 + 3, 32 + 3, 16 - 6, 16 - 6 }, // Right
{ 0 + 3, 32 + 3, 16 - 6, 16 - 6 }, // Left
{ 32 + 3, 64 + 3, 16 - 6, 16 - 6 }, // Down
{ 32 + 3, 0 + 3, 16 - 6, 16 - 6 }, // Up
{ 32 + 3, 32 + 3, 16 - 6, 16 - 6 }, // Select
{ 96 + 3, 0 + 3, 16 - 6, 16 - 6 }, // Dfu
} };
auto switches_event = key_event_mask;
for(const auto r : events_rects) {
if (switches_event & 1)
painter.fill_rectangle(r + pos, Color::red());
switches_event >>= 1;
}
}
+99
View File
@@ -0,0 +1,99 @@
/*
* 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_dfu_menu.hpp"
#include "portapack_shared_memory.hpp"
#include "performance_counter.hpp"
namespace ui {
DfuMenu::DfuMenu(NavigationView& nav) : nav_ (nav) {
add_children({
&text_head,
&labels,
&text_info_line_1,
&text_info_line_2,
&text_info_line_3,
&text_info_line_4,
&text_info_line_5,
&text_info_line_6,
&text_info_line_7,
&text_info_line_8
});
}
void DfuMenu::paint(Painter& painter) {
auto utilisation = get_cpu_utilisation_in_percent();
text_info_line_1.set(to_string_dec_uint(chCoreStatus(), 6));
text_info_line_2.set(to_string_dec_uint((uint32_t)get_free_stack_space(), 6));
text_info_line_3.set(to_string_dec_uint(utilisation, 6));
text_info_line_4.set(to_string_dec_uint(shared_memory.m4_heap_usage, 6));
text_info_line_5.set(to_string_dec_uint(shared_memory.m4_stack_usage, 6));
text_info_line_6.set(to_string_dec_uint(shared_memory.m4_cpu_usage, 6));
text_info_line_7.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
text_info_line_8.set(to_string_dec_uint(chTimeNow()/1000, 6));
constexpr auto margin = 5;
constexpr auto lines = 8 + 2;
painter.fill_rectangle(
{
{6 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin},
{15 * CHARACTER_WIDTH + margin * 2, lines * LINE_HEIGHT + margin * 2}
},
ui::Color::black()
);
painter.fill_rectangle(
{
{5 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin},
{CHARACTER_WIDTH, lines * LINE_HEIGHT + margin * 2}
},
ui::Color::dark_cyan()
);
painter.fill_rectangle(
{
{21 * CHARACTER_WIDTH + margin, 3 * LINE_HEIGHT - margin},
{CHARACTER_WIDTH, lines * LINE_HEIGHT + margin * 2}
},
ui::Color::dark_cyan()
);
painter.fill_rectangle(
{
{5 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin - 8},
{17 * CHARACTER_WIDTH + margin * 2, 8}
},
ui::Color::dark_cyan()
);
painter.fill_rectangle(
{
{5 * CHARACTER_WIDTH - margin, (lines+3) * LINE_HEIGHT + margin},
{17 * CHARACTER_WIDTH + margin * 2, 8}
},
ui::Color::dark_cyan()
);
}
} /* namespace ui */
+73
View File
@@ -0,0 +1,73 @@
/*
* 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_DFU_MENU_H__
#define __UI_DFU_MENU_H__
#include <cstdint>
#include "ui_widget.hpp"
#include "event_m0.hpp"
#include "debug.hpp"
#include "string_format.hpp"
#define LINE_HEIGHT 16
#define CHARACTER_WIDTH 8
namespace ui {
class NavigationView;
class DfuMenu : public View {
public:
DfuMenu(NavigationView& nav);
~DfuMenu() = default;
void paint(Painter& painter) override;
private:
NavigationView& nav_;
Text text_head {{ 6 * CHARACTER_WIDTH, 3 * LINE_HEIGHT, 11 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, "Performance"};
Labels labels {
{ { 6 * CHARACTER_WIDTH, 5 * LINE_HEIGHT }, "M0 heap:", Color::dark_cyan() },
{ { 6 * CHARACTER_WIDTH, 6 * LINE_HEIGHT }, "M0 stack:", Color::dark_cyan() },
{ { 6 * CHARACTER_WIDTH, 7 * LINE_HEIGHT }, "M0 cpu %:", Color::dark_cyan() },
{ { 6 * CHARACTER_WIDTH, 8 * LINE_HEIGHT }, "M4 heap:", Color::dark_cyan() },
{ { 6 * CHARACTER_WIDTH, 9 * LINE_HEIGHT }, "M4 stack:", Color::dark_cyan() },
{ { 6 * CHARACTER_WIDTH,10 * LINE_HEIGHT }, "M4 cpu %:", Color::dark_cyan() },
{ { 6 * CHARACTER_WIDTH,11 * LINE_HEIGHT }, "M4 miss:", Color::dark_cyan() },
{ { 6 * CHARACTER_WIDTH,12 * LINE_HEIGHT }, "uptime:", Color::dark_cyan() }
};
Text text_info_line_1 {{ 15 * CHARACTER_WIDTH, 5 * LINE_HEIGHT, 5 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, ""};
Text text_info_line_2 {{ 15 * CHARACTER_WIDTH, 6 * LINE_HEIGHT, 5 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, ""};
Text text_info_line_3 {{ 15 * CHARACTER_WIDTH, 7 * LINE_HEIGHT, 5 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, ""};
Text text_info_line_4 {{ 15 * CHARACTER_WIDTH, 8 * LINE_HEIGHT, 5 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, ""};
Text text_info_line_5 {{ 15 * CHARACTER_WIDTH, 9 * LINE_HEIGHT, 5 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, ""};
Text text_info_line_6 {{ 15 * CHARACTER_WIDTH,10 * LINE_HEIGHT, 5 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, ""};
Text text_info_line_7 {{ 15 * CHARACTER_WIDTH,11 * LINE_HEIGHT, 5 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, ""};
Text text_info_line_8 {{ 15 * CHARACTER_WIDTH,12 * LINE_HEIGHT, 5 * CHARACTER_WIDTH, 1 * LINE_HEIGHT }, ""};
};
} /* namespace ui */
#endif/*__UI_DFU_MENU_H__*/
+306 -148
View File
@@ -20,72 +20,173 @@
* Boston, MA 02110-1301, USA.
*/
/* TODO:
* - Paging menu items
* - Copy/Move
*/
#include <algorithm>
#include "ui_fileman.hpp"
#include "string_format.hpp"
#include "portapack.hpp"
#include "event_m0.hpp"
using namespace portapack;
namespace fs = std::filesystem;
namespace {
using namespace ui;
bool is_hidden_file(const fs::path& path) {
return !path.empty() && path.native()[0] == u'.';
}
// Gets a truncated name from a path for display.
std::string truncate(const fs::path& path, size_t max_length) {
auto name = path.string();
return name.length() <= max_length ? name : name.substr(0, max_length);
}
// Gets a human readable file size string.
std::string get_pretty_size(uint32_t file_size) {
static const std::string suffix[5] = { "B", "kB", "MB", "GB", "??" };
size_t suffix_index = 0;
while (file_size >= 1024) {
file_size /= 1024;
suffix_index++;
}
if (suffix_index > 4)
suffix_index = 4;
return to_string_dec_uint(file_size) + suffix[suffix_index];
}
// Case insensitive path equality on underlying "native" string.
bool iequal(
const fs::path& lhs,
const fs::path& rhs
) {
const auto& lhs_str = lhs.native();
const auto& rhs_str = rhs.native();
// NB: Not correct for Unicode/locales.
if (lhs_str.length() == rhs_str.length()) {
for (size_t i = 0; i < lhs_str.length(); ++i)
if (towupper(lhs_str[i]) != towupper(rhs_str[i]))
return false;
return true;
}
return false;
}
// Inserts the entry into the entry list sorted directories first then by file name.
void insert_sorted(std::vector<fileman_entry>& entries, fileman_entry&& entry) {
auto it = std::lower_bound(std::begin(entries), std::end(entries), entry,
[](const fileman_entry& lhs, const fileman_entry& rhs) {
if (lhs.is_directory && !rhs.is_directory)
return true;
else if (!lhs.is_directory && rhs.is_directory)
return false;
else
return lhs.path < rhs.path;
});
entries.insert(it, std::move(entry));
}
// Returns the partner file path or an empty path if no partner is found.
fs::path get_partner_file(fs::path path) {
if (fs::is_directory(path))
return { };
const fs::path txt_path{ u".TXT" };
const fs::path c16_path{ u".C16" };
auto ext = path.extension();
if (iequal(ext, txt_path))
ext = c16_path;
else if (iequal(ext, c16_path))
ext = txt_path;
else
return { };
path.replace_extension(ext);
return fs::file_exists(path) && !fs::is_directory(path) ? path : fs::path{ };
}
// Modal prompt to update the partner file if it exists.
// Runs continuation on_partner_action to update the partner file.
// Returns true is a partner is found, otherwise false.
// Path must be the full path to the file.
bool partner_file_prompt(
NavigationView& nav,
const fs::path& path,
std::string action_name,
std::function<void(const fs::path&, bool)> on_partner_action
) {
auto partner = get_partner_file(path);
if (partner.empty())
return false;
nav.push_under_current<ModalMessageView>(
"Partner File",
partner.filename().string() + "\n" + action_name + " this file too?",
YESNO,
[&nav, partner, on_partner_action](bool choice) {
if (on_partner_action)
on_partner_action(partner, choice);
}
);
return true;
}
}
namespace ui {
void FileManBaseView::load_directory_contents(const std::filesystem::path& dir_path) {
/* FileManBaseView ***********************************************************/
void FileManBaseView::load_directory_contents(const fs::path& dir_path) {
current_path = dir_path;
text_current.set(dir_path.string().length()? dir_path.string().substr(0, 30 - 6):"(sd root)");
entry_list.clear();
auto filtering = (bool)extension_filter.size();
// List directories and files, put directories up top
if (dir_path.string().length())
entry_list.push_back({ u"..", 0, true });
auto filtering = !extension_filter.empty();
for (const auto& entry : std::filesystem::directory_iterator(dir_path, u"*")) {
text_current.set(dir_path.empty() ? "(sd root)" : truncate(dir_path, 24));
for (const auto& entry : fs::directory_iterator(dir_path, u"*")) {
// Hide files starting with '.' (hidden / tmp).
if (is_hidden_file(entry.path()))
continue;
// do not display dir / files starting with '.' (hidden / tmp)
if (entry.path().string().length() && entry.path().filename().string()[0] != '.') {
if (std::filesystem::is_regular_file(entry.status())) {
bool matched = true;
if (filtering) {
auto entry_extension = entry.path().extension().string();
for (auto &c: entry_extension)
c = toupper(c);
if (entry_extension != extension_filter)
matched = false;
}
if (matched)
entry_list.push_back({ entry.path(), (uint32_t)entry.size(), false });
} else if (std::filesystem::is_directory(entry.status())) {
entry_list.insert(entry_list.begin(), { entry.path(), 0, true });
}
if (fs::is_regular_file(entry.status())) {
if (!filtering || iequal(entry.path().extension(), extension_filter))
insert_sorted(entry_list, { entry.path(), (uint32_t)entry.size(), false });
} else if (fs::is_directory(entry.status())) {
insert_sorted(entry_list, { entry.path(), 0, true });
}
}
// Add "parent" directory if not at the root.
if (!dir_path.empty())
entry_list.insert(entry_list.begin(), { parent_dir_path, 0, true });
}
std::filesystem::path FileManBaseView::get_selected_path() {
auto selected_path_str = current_path.string();
auto entry_path = entry_list[menu_view.highlighted_index()].entry_path.string();
if (entry_path == "..") {
selected_path_str = get_parent_dir().string();
} else {
if (selected_path_str.back() != '/')
selected_path_str += '/';
selected_path_str += entry_path;
}
return selected_path_str;
fs::path FileManBaseView::get_selected_full_path() const {
if (get_selected_entry().path == parent_dir_path)
return current_path.parent_path();
return current_path / get_selected_entry().path;
}
std::filesystem::path FileManBaseView::get_parent_dir() {
auto current_path_str = current_path.string();
return current_path.string().substr(0, current_path_str.find_last_of('/'));
const fileman_entry& FileManBaseView::get_selected_entry() const {
// TODO: return reference to an "empty" entry on OOB?
return entry_list[menu_view.highlighted_index()];
}
FileManBaseView::FileManBaseView(
@@ -105,20 +206,20 @@ FileManBaseView::FileManBaseView(
};
if (!sdcIsCardInserted(&SDCD1)) {
empty_root=true;
empty_root = true;
text_current.set("NO SD CARD!");
return;
}
load_directory_contents(current_path);
if (!entry_list.size()) {
empty_root = true;
text_current.set("EMPTY SD CARD!");
} else {
load_directory_contents(current_path);
if (!entry_list.size())
{
empty_root = true;
text_current.set("EMPTY SD CARD!");
} else {
menu_view.on_left = [&nav, this]() {
load_directory_contents(get_parent_dir());
refresh_list();
};
}
menu_view.on_left = [this]() {
pop_dir();
};
}
}
@@ -130,67 +231,83 @@ void FileManBaseView::focus() {
}
}
void FileManBaseView::push_dir(const fs::path& path) {
if (path == parent_dir_path) {
pop_dir();
} else {
current_path /= path;
saved_index_stack.push_back(menu_view.highlighted_index());
menu_view.set_highlighted(0);
reload_current();
}
}
void FileManBaseView::pop_dir() {
if (saved_index_stack.empty())
return;
current_path = current_path.parent_path();
reload_current();
menu_view.set_highlighted(saved_index_stack.back());
saved_index_stack.pop_back();
}
void FileManBaseView::refresh_list() {
if (on_refresh_widgets)
on_refresh_widgets(false);
auto prev_highlight = menu_view.highlighted_index();
menu_view.clear();
for (size_t n = 0; n < entry_list.size(); n++) {
auto entry = &entry_list[n];
auto entry_name = entry->entry_path.filename().string().substr(0, 20);
if (entry->is_directory) {
for (const auto& entry : entry_list) {
auto entry_name = truncate(entry.path, 20);
if (entry.is_directory) {
menu_view.add_item({
entry_name,
ui::Color::yellow(),
&bitmap_icon_dir,
[this](){
[this](KeyEvent key) {
if (on_select_entry)
on_select_entry();
on_select_entry(key);
}
});
} else {
auto file_size = entry->size;
size_t suffix_index = 0;
while (file_size >= 1024) {
file_size /= 1024;
suffix_index++;
}
if (suffix_index > 4)
suffix_index = 4;
std::string size_str = to_string_dec_uint(file_size) + suffix[suffix_index];
auto entry_extension = entry->entry_path.extension().string();
for (auto &c: entry_extension)
c = toupper(c);
// Associate extension to icon and color
size_t c;
for (c = 0; c < file_types.size() - 1; c++) {
if (entry_extension == file_types[c].extension)
break;
}
const auto& assoc = get_assoc(entry.path.extension());
auto size_str = get_pretty_size(entry.size);
menu_view.add_item({
entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
file_types[c].color,
file_types[c].icon,
[this](){
assoc.color,
assoc.icon,
[this](KeyEvent key) {
if (on_select_entry)
on_select_entry();
on_select_entry(key);
}
});
}
}
menu_view.set_highlighted(0); // Refresh
menu_view.set_highlighted(prev_highlight);
}
void FileManBaseView::reload_current() {
load_directory_contents(current_path);
refresh_list();
}
const FileManBaseView::file_assoc_t& FileManBaseView::get_assoc(
const fs::path& ext) const
{
size_t index = 0;
for (; index < file_types.size() - 1; ++index)
if (iequal(ext, file_types[index].extension))
return file_types[index];
// Default to last entry in the list.
return file_types[index];
}
/*void FileSaveView::on_save_name() {
@@ -215,8 +332,9 @@ FileSaveView::FileSaveView(
};
}*/
void FileLoadView::refresh_widgets(const bool v) {
(void)v; //avoid unused warning
/* FileLoadView **************************************************************/
void FileLoadView::refresh_widgets(const bool) {
set_dirty();
}
@@ -238,45 +356,92 @@ FileLoadView::FileLoadView(
refresh_list();
on_select_entry = [&nav, this]() {
if (entry_list[menu_view.highlighted_index()].is_directory) {
load_directory_contents(get_selected_path());
refresh_list();
on_select_entry = [this](KeyEvent) {
if (get_selected_entry().is_directory) {
push_dir(get_selected_entry().path);
} else {
nav_.pop();
if (on_changed)
on_changed(current_path.string() + '/' + entry_list[menu_view.highlighted_index()].entry_path.string());
on_changed(get_selected_full_path());
}
};
}
void FileManagerView::on_rename(NavigationView& nav) {
text_prompt(nav, name_buffer, max_filename_length, [this](std::string& buffer) {
std::string destination_path = current_path.string();
if (destination_path.back() != '/')
destination_path += '/';
destination_path = destination_path + buffer;
rename_file(get_selected_path(), destination_path);
load_directory_contents(current_path);
refresh_list();
});
/* FileManagerView ***********************************************************/
void FileManagerView::on_rename() {
auto& entry = get_selected_entry();
name_buffer = entry.path.filename().string();
uint32_t cursor_pos = (uint32_t)name_buffer.length();
if (auto pos = name_buffer.find_last_of(".");
pos != name_buffer.npos && !entry.is_directory)
cursor_pos = pos;
text_prompt(nav_, name_buffer, cursor_pos, max_filename_length,
[this](std::string& renamed) {
auto renamed_path = fs::path{ renamed };
rename_file(get_selected_full_path(), current_path / renamed_path);
auto has_partner = partner_file_prompt(nav_, get_selected_full_path(), "Rename",
[this, renamed_path](const fs::path& partner, bool should_rename) mutable {
if (should_rename) {
auto new_name = renamed_path.replace_extension(partner.extension());
rename_file(current_path / partner, current_path / new_name);
}
reload_current();
}
);
if (!has_partner)
reload_current();
});
}
void FileManagerView::on_delete() {
delete_file(get_selected_path());
load_directory_contents(current_path);
refresh_list();
auto name = get_selected_entry().path.filename().string();
nav_.push<ModalMessageView>("Delete", "Delete " + name + "\nAre you sure?", YESNO,
[this](bool choice) {
if (choice) {
delete_file(get_selected_full_path());
auto has_partner = partner_file_prompt(
nav_, get_selected_full_path(), "Delete",
[this](const fs::path& partner, bool should_delete) {
if (should_delete)
delete_file(current_path / partner);
reload_current();
}
);
if (!has_partner)
reload_current();
}
}
);
}
void FileManagerView::on_new_dir() {
name_buffer = "";
text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& dir_name) {
make_new_directory(current_path / dir_name);
reload_current();
});
}
bool FileManagerView::selected_is_valid() const {
return !entry_list.empty() &&
get_selected_entry().path != parent_dir_path;
}
void FileManagerView::refresh_widgets(const bool v) {
button_rename.hidden(v);
button_new_dir.hidden(v);
button_delete.hidden(v);
button_new_dir.hidden(v);
set_dirty();
}
FileManagerView::~FileManagerView() {
// Flush ?
}
FileManagerView::FileManagerView(
@@ -293,47 +458,40 @@ FileManagerView::FileManagerView(
&labels,
&text_date,
&button_rename,
&button_delete,
&button_new_dir,
&button_delete
});
menu_view.on_highlight = [this]() {
text_date.set(to_string_FAT_timestamp(file_created_date(get_selected_path())));
// TODO: enable/disable buttons.
if (selected_is_valid())
text_date.set(to_string_FAT_timestamp(file_created_date(get_selected_full_path())));
else
text_date.set("");
};
refresh_list();
on_select_entry = [this]() {
if (entry_list[menu_view.highlighted_index()].is_directory) {
load_directory_contents(get_selected_path());
refresh_list();
} else
on_select_entry = [this](KeyEvent key) {
if (key == KeyEvent::Select && get_selected_entry().is_directory) {
push_dir(get_selected_entry().path);
} else {
button_rename.focus();
}
};
button_new_dir.on_select = [this, &nav](Button&) {
name_buffer.clear();
text_prompt(nav, name_buffer, max_filename_length, [this](std::string& buffer) {
make_new_directory(current_path.string() + '/' + buffer);
load_directory_contents(current_path);
refresh_list();
});
button_rename.on_select = [this](Button&) {
if (selected_is_valid())
on_rename();
};
button_rename.on_select = [this, &nav](Button&) {
name_buffer = entry_list[menu_view.highlighted_index()].entry_path.filename().string().substr(0, max_filename_length);
on_rename(nav);
button_delete.on_select = [this](Button&) {
if (selected_is_valid())
on_delete();
};
button_delete.on_select = [this, &nav](Button&) {
// Use display_modal ?
nav.push<ModalMessageView>("Delete", "Delete " + entry_list[menu_view.highlighted_index()].entry_path.filename().string() + "\nAre you sure?", YESNO,
[this](bool choice) {
if (choice)
on_delete();
}
);
button_new_dir.on_select = [this](Button&) {
on_new_dir();
};
}
}
+45 -34
View File
@@ -31,7 +31,7 @@
namespace ui {
struct fileman_entry {
std::filesystem::path entry_path { };
std::filesystem::path path { };
uint32_t size { };
bool is_directory { };
};
@@ -43,50 +43,56 @@ public:
std::string filter
);
void focus() override;
void load_directory_contents(const std::filesystem::path& dir_path);
std::filesystem::path get_selected_path();
void focus() override;
std::string title() const override { return "Fileman"; };
protected:
NavigationView& nav_;
static constexpr size_t max_filename_length = 30 - 2;
const std::string suffix[5] = { "B", "kB", "MB", "GB", "??" };
static constexpr size_t max_filename_length = 50;
struct file_assoc_t {
std::string extension;
std::filesystem::path extension;
const Bitmap* icon;
ui::Color color;
};
const std::vector<file_assoc_t> file_types = {
{ ".TXT", &bitmap_icon_file_text, ui::Color::white() },
{ ".PNG", &bitmap_icon_file_image, ui::Color::green() },
{ ".BMP", &bitmap_icon_file_image, ui::Color::green() },
{ ".C8", &bitmap_icon_file_iq, ui::Color::blue() },
{ ".C16", &bitmap_icon_file_iq, ui::Color::blue() },
{ ".WAV", &bitmap_icon_file_wav, ui::Color::dark_magenta() },
{ "", &bitmap_icon_file, ui::Color::light_grey() }
{ u".TXT", &bitmap_icon_file_text, ui::Color::white() },
{ u".PNG", &bitmap_icon_file_image, ui::Color::green() },
{ u".BMP", &bitmap_icon_file_image, ui::Color::green() },
{ u".C8", &bitmap_icon_file_iq, ui::Color::dark_cyan() },
{ u".C16", &bitmap_icon_file_iq, ui::Color::dark_cyan() },
{ u".WAV", &bitmap_icon_file_wav, ui::Color::dark_magenta() },
{ u"", &bitmap_icon_file, ui::Color::light_grey() } // NB: Must be last.
};
bool empty_root { false };
std::function<void(void)> on_select_entry { nullptr };
std::function<void(bool)> on_refresh_widgets { nullptr };
std::vector<fileman_entry> entry_list { };
std::filesystem::path current_path { u"" };
std::string extension_filter { "" };
void change_category(int32_t category_id);
std::filesystem::path get_parent_dir();
std::filesystem::path get_selected_full_path() const;
const fileman_entry& get_selected_entry() const;
void push_dir(const std::filesystem::path& path);
void pop_dir();
void refresh_list();
void reload_current();
void load_directory_contents(const std::filesystem::path& dir_path);
const file_assoc_t& get_assoc(const std::filesystem::path& ext) const;
NavigationView& nav_;
bool empty_root { false };
std::function<void(KeyEvent)> on_select_entry { nullptr };
std::function<void(bool)> on_refresh_widgets { nullptr };
const std::filesystem::path parent_dir_path { u".." };
std::filesystem::path current_path { u"" };
std::filesystem::path extension_filter { u"" };
std::vector<fileman_entry> entry_list { };
std::vector<uint32_t> saved_index_stack { };
Labels labels {
{ { 0, 0 }, "Path:", Color::light_grey() }
};
Text text_current {
{ 6 * 8, 0 * 8, 24 * 8, 16 },
"",
@@ -142,11 +148,16 @@ public:
~FileManagerView();
private:
// Passed by ref to other views needing lifetime extension.
std::string name_buffer { };
void refresh_widgets(const bool v);
void on_rename(NavigationView& nav);
void on_rename();
void on_delete();
void on_new_dir();
// True if the selected entry is a real file item.
bool selected_is_valid() const;
Labels labels {
{ { 0, 26 * 8 }, "Created ", Color::light_grey() }
@@ -161,16 +172,16 @@ private:
{ 0 * 8, 29 * 8, 14 * 8, 32 },
"Rename"
};
Button button_delete {
{ 16 * 8, 29 * 8, 14 * 8, 32 },
"Delete"
};
Button button_new_dir {
{ 0 * 8, 34 * 8, 14 * 8, 32 },
"New dir"
"New Dir"
};
};
} /* namespace ui */
@@ -44,7 +44,7 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav) : nav_ (nav) {
filename.string().substr(0, max_filename_length),
ui::Color::red(),
&bitmap_icon_temperature,
[this, path]() {
[this, path](KeyEvent) {
this->firmware_selected(path);
}
});
+1 -1
View File
@@ -120,7 +120,7 @@ void FreqManBaseView::refresh_list() {
freqman_item_string(database[n], 30),
ui::Color::white(),
nullptr,
[this](){
[this](KeyEvent){
if (on_select_frequency)
on_select_frequency();
}
-2
View File
@@ -48,8 +48,6 @@ namespace ui {
void focus() override;
void big_display_freq( int64_t f );
const Style style_grey { // level
.font = font::fixed_8x16,
.background = Color::black(),
+374 -158
View File
@@ -26,10 +26,9 @@ using namespace portapack;
namespace ui
{
void GlassView::focus()
{
field_marker.focus();
button_marker.focus();
}
GlassView::~GlassView()
@@ -39,6 +38,24 @@ namespace ui
baseband::shutdown();
}
// Returns the next multiple of num that is a multiple of multiplier
int64_t GlassView::next_mult_of(int64_t num, int64_t multiplier) {
return ((num / multiplier) + 1) * multiplier;
}
void GlassView::adjust_range(int64_t* f_min, int64_t* f_max, int64_t width) {
int64_t span = *f_max - *f_min;
int64_t num_intervals = span / width;
if( span % width != 0 )
{
num_intervals++;
}
int64_t new_span = num_intervals * width;
int64_t delta_span = (new_span - span) / 2;
*f_min -= delta_span;
*f_max += delta_span;
}
void GlassView::on_lna_changed(int32_t v_db)
{
receiver_model.set_lna(v_db);
@@ -49,40 +66,71 @@ namespace ui
receiver_model.set_vga(v_db);
}
void GlassView::add_spectrum_pixel(int16_t color)
void GlassView::reset_live_view( bool clear_screen )
{
spectrum_row[pixel_index] = spectrum_rgb3_lut[color] ;
spectrum_data[pixel_index] = ( live_frequency_integrate * spectrum_data[pixel_index] + color ) / (live_frequency_integrate + 1); // smoothing
max_freq_hold = 0 ;
max_freq_power = -1000 ;
if( clear_screen )
{
// only clear screen in peak mode
if( live_frequency_view == 2 )
{
display.fill_rectangle( { { 0 , 108 + 16 } , { 240 , 320 - (108 + 16) } } , { 0 , 0 , 0 } );
}
}
}
void GlassView::add_spectrum_pixel( uint8_t power )
{
static int64_t last_max_freq = 0 ;
spectrum_row[pixel_index] = spectrum_rgb3_lut[power] ; // row of colors
spectrum_data[pixel_index] = ( live_frequency_integrate * spectrum_data[pixel_index] + power ) / (live_frequency_integrate + 1); // smoothing
pixel_index ++ ;
if (pixel_index == 240) // got an entire waterfall line
{
if( live_frequency_view )
{
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 range_t<int> y_max_range { 0 , 320 - 108 };
if( live_frequency_view > 0 )
{
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> y_max_range { 0 , 320 - ( 108 + 16 ) };
//drawing
//display.fill_rectangle( { { 0 , 108 } , { 240 , 320 - 108 } } , { 0 , 0 , 0 } );
for( uint16_t xpos = 0 ; xpos < 240 ; xpos ++ )
{
int16_t point = y_max_range.clip( ( ( spectrum_data[ xpos ] - raw_min ) * ( 320 - 108 ) ) / raw_delta );
uint8_t color_gradient = (point * 255) / 212 ;
display.fill_rectangle( { { xpos , 108 } , { 1 , 320 - point } } , { 0 , 0 , 0 } );
display.fill_rectangle( { { xpos , 320 - point } , { 1 , point } } , { color_gradient , 0 , uint8_t( 255 - color_gradient ) } );
}
}
else
{
display.draw_pixels({{0, display.scroll(1)}, {240, 1}}, spectrum_row); // new line at top, one less var, speedier
}
//drawing and keeping track of max freq
for( uint16_t xpos = 0 ; xpos < 240 ; xpos ++ )
{
// save max powerwull freq
if( spectrum_data[ xpos ] > max_freq_power )
{
max_freq_power = spectrum_data[ xpos ];
max_freq_hold = f_min + ( (f_max - f_min) * xpos) / 240 ;
}
int16_t point = y_max_range.clip( ( ( spectrum_data[ xpos ] - raw_min ) * ( 320 - ( 108 + 16 ) ) ) / raw_delta );
uint8_t color_gradient = (point * 255) / 212 ;
// clear if not in peak view
if( live_frequency_view != 2 )
{
display.fill_rectangle( { { xpos , 108 + 16 } , { 1 , 320 - point } } , { 0 , 0 , 0 } );
}
display.fill_rectangle( { { xpos , 320 - point } , { 1 , point } } , { color_gradient , 0 , uint8_t( 255 - color_gradient ) } );
}
if( last_max_freq != max_freq_hold )
{
last_max_freq = max_freq_hold ;
freq_stats.set( "MAX HOLD: "+to_string_short_freq( max_freq_hold ) );
}
PlotMarker( marker );
}
else
{
display.draw_pixels({{0, display.scroll(1)}, {240, 1}}, spectrum_row); // new line at top, one less var, speedier
}
pixel_index = 0; // Start New cascade line
}
}
@@ -91,53 +139,123 @@ namespace ui
// Each having the radio signal power for it's corresponding frequency slot
void GlassView::on_channel_spectrum(const ChannelSpectrum &spectrum)
{
// default fast scan offset
uint8_t offset = 2 ;
baseband::spectrum_streaming_stop();
// Convert bins of this spectrum slice into a representative max_power and when enough, into pixels
// Spectrum.db has 256 bins. Center 12 bins are ignored (DC spike is blanked) Leftmost and rightmost 2 bins are ignored
// All things said and done, we actually need 240 of those bins:
for (uint8_t bin = 0; bin < 240; bin++)
if( fast_scan || ( LOOKING_GLASS_SLICE_WIDTH < LOOKING_GLASS_SLICE_WIDTH_MAX ) )
{
if (bin < 120)
// Convert bins of this spectrum slice into a representative max_power and when enough, into pixels
// Spectrum.db has 256 bins.
// All things said and done, we actually need 240 of those bins
for (uint8_t bin = 0; bin < 240; bin++)
{
if (spectrum.db[134 + bin] > max_power) // 134
max_power = spectrum.db[134 + bin];
}
else
{
if (spectrum.db[bin - 118] > max_power) // 118
max_power = spectrum.db[bin - 118];
}
bins_Hz_size += each_bin_size; // add this bin Hz count into the "pixel fulfilled bag of Hz"
if (bins_Hz_size >= marker_pixel_step) // new pixel fullfilled
{
if (min_color_power < max_power)
add_spectrum_pixel(max_power); // Pixel will represent max_power
else
add_spectrum_pixel(0); // Filtered out, show black
max_power = 0;
if (!pixel_index) // Received indication that a waterfall line has been completed
// if the view is done in one pass, show it like in analog_audio_app
if( ( LOOKING_GLASS_SLICE_WIDTH < LOOKING_GLASS_SLICE_WIDTH_MAX ) )
{
bins_Hz_size = 0; // Since this is an entire pixel line, we don't carry "Pixels into next bin"
f_center = f_center_ini; // Start a new sweep
radio::set_tuning_frequency(f_center); // tune rx for this new slice directly, faster than using persistent memory saving
chThdSleepMilliseconds(10);
baseband::spectrum_streaming_start(); // Do the RX
return;
// Center 16 bins are ignored (DC spike is blanked)
if (bin < 120)
{
if (spectrum.db[256 - 120 + bin] > max_power) // 134
max_power = spectrum.db[256 - 120 + bin];
}
else
{
if (spectrum.db[ bin - 120] > max_power) // 118
max_power = spectrum.db[bin - 120];
}
}
else // view is made in multiple pass, use original bin picking
{
// Center 12 bins are ignored (DC spike is blanked) Leftmost and rightmost 2 bins are ignored
if (bin < 120)
{
if (spectrum.db[134 + bin] > max_power) // 134
max_power = spectrum.db[134 + bin];
}
else
{
if (spectrum.db[bin - 118] > max_power) // 118
max_power = spectrum.db[bin - 118];
}
}
if( bin == 120 )
{
bins_Hz_size += 12 * each_bin_size; // add DC bin Hz count into the "pixel fulfilled bag of Hz"
}
else
{
bins_Hz_size += each_bin_size; // add this bin Hz count into the "pixel fulfilled bag of Hz"
}
bins_Hz_size -= marker_pixel_step; // reset bins size, but carrying the eventual excess Hz into next pixel
}
}
f_center += LOOKING_GLASS_SLICE_WIDTH; // Move into the next bandwidth slice NOTE: spectrum.sampling_rate = LOOKING_GLASS_SLICE_WIDTH
if (bins_Hz_size >= marker_pixel_step) // new pixel fullfilled
{
if (min_color_power < max_power)
add_spectrum_pixel(max_power); // Pixel will represent max_power
else
add_spectrum_pixel(0); // Filtered out, show black
max_power = 0;
if (!pixel_index) // Received indication that a waterfall line has been completed
{
bins_Hz_size = 0; // Since this is an entire pixel line, we don't carry "Pixels into next bin"
f_center = f_center_ini - offset * each_bin_size ; // Start a new sweep
radio::set_tuning_frequency(f_center); // tune rx for this new slice directly, faster than using persistent memory saving
chThdSleepMilliseconds(10);
baseband::spectrum_streaming_start(); // Do the RX
return;
}
bins_Hz_size -= marker_pixel_step; // reset bins size, but carrying the eventual excess Hz into next pixel
}
}
f_center += ( 256 - ( 2 * offset ) ) * each_bin_size ; // Move into the next bandwidth slice NOTE: spectrum.sampling_rate = LOOKING_GLASS_SLICE_WIDTH
// lost bins are taken in account so next slice first ignored bins overlap previous kept ones
}
else //slow scan
{
offset = 32 ;
uint8_t bin_length = 80 ;
for (uint8_t bin = offset ; bin < bin_length + offset ; bin++)
{
if (bin < 120)
{
if (spectrum.db[134 + bin] > max_power) // 134
max_power = spectrum.db[134 + bin];
}
else
{
if (spectrum.db[bin - 118] > max_power) // 118
max_power = spectrum.db[bin - 118];
}
bins_Hz_size += each_bin_size; // add this bin Hz count into the "pixel fulfilled bag of Hz"
if (bins_Hz_size >= marker_pixel_step) // new pixel fullfilled
{
if (min_color_power < max_power)
add_spectrum_pixel(max_power); // Pixel will represent max_power
else
add_spectrum_pixel(0); // Filtered out, show black
max_power = 0;
if (!pixel_index) // Received indication that a waterfall line has been completed
{
bins_Hz_size = 0; // Since this is an entire pixel line, we don't carry "Pixels into next bin"
f_center = f_center_ini - offset * each_bin_size ; // Start a new sweep
radio::set_tuning_frequency(f_center); // tune rx for this new slice directly, faster than using persistent memory saving
chThdSleepMilliseconds(10);
baseband::spectrum_streaming_start(); // Do the RX
return;
}
bins_Hz_size -= marker_pixel_step; // reset bins size, but carrying the eventual excess Hz into next pixel
}
}
f_center += bin_length * each_bin_size ;
}
radio::set_tuning_frequency(f_center); // tune rx for this new slice directly, faster than using persistent memory saving
chThdSleepMilliseconds(5);
// receiver_model.set_tuning_frequency(f_center); //tune rx for this slice
baseband::spectrum_streaming_start(); // Do the RX
}
@@ -155,50 +273,71 @@ namespace ui
void GlassView::on_range_changed()
{
reset_live_view( false );
f_min = field_frequency_min.value();
f_max = field_frequency_max.value();
search_span = f_max - f_min;
field_marker.set_range(f_min, f_max); // Move the marker between range
field_marker.set_value(f_min + (search_span / 2)); // Put MARKER AT MIDDLE RANGE
text_range.set(to_string_dec_uint(search_span));
if( locked_range )
{
button_range.set_text(">"+to_string_dec_uint(search_span)+"<");
}
else
{
button_range.set_text(" "+to_string_dec_uint(search_span)+" ");
}
f_min = (f_min)*MHZ_DIV; // Transpose into full frequency realm
f_max = (f_max)*MHZ_DIV;
search_span = search_span * MHZ_DIV;
adjust_range( &f_min , &f_max , 240 );
marker_pixel_step = search_span / 240; // Each pixel value in Hz
text_marker_pm.set(to_string_dec_uint((marker_pixel_step / X2_MHZ_DIV) + 1)); // Give idea of +/- marker precision
marker_pixel_step = (f_max - f_min) / 240; // Each pixel value in Hz
marker = f_min + (f_max - f_min) / 2 ;
button_marker.set_text( to_string_short_freq( marker ) );
PlotMarker( marker ); // Refresh marker on screen
int32_t marker_step = marker_pixel_step / MHZ_DIV;
if (!marker_step)
field_marker.set_step(1); // in case selected range is less than 240 (pixels)
else
field_marker.set_step(marker_step); // step needs to be a pixel wide.
f_center_ini = f_min + (LOOKING_GLASS_SLICE_WIDTH / 2); // Initial center frequency for sweep
PlotMarker(field_marker.value()); // Refresh marker on screen
f_center = f_center_ini; // Reset sweep into first slice
pixel_index = 0; // reset pixel counter
max_power = 0;
bins_Hz_size = 0; // reset amount of Hz filled up by pixels
if( (f_max - f_min) <= LOOKING_GLASS_SLICE_WIDTH_MAX )
{
LOOKING_GLASS_SLICE_WIDTH = (f_max - f_min) ;
receiver_model.set_sampling_rate(LOOKING_GLASS_SLICE_WIDTH);
receiver_model.set_baseband_bandwidth(LOOKING_GLASS_SLICE_WIDTH/2);
}
else if( LOOKING_GLASS_SLICE_WIDTH != LOOKING_GLASS_SLICE_WIDTH_MAX )
{
LOOKING_GLASS_SLICE_WIDTH = LOOKING_GLASS_SLICE_WIDTH_MAX ;
receiver_model.set_sampling_rate(LOOKING_GLASS_SLICE_WIDTH);
receiver_model.set_baseband_bandwidth(LOOKING_GLASS_SLICE_WIDTH);
}
if( next_mult_of( LOOKING_GLASS_SLICE_WIDTH , 256 ) > LOOKING_GLASS_SLICE_WIDTH_MAX )
LOOKING_GLASS_SLICE_WIDTH = LOOKING_GLASS_SLICE_WIDTH_MAX ;
else
LOOKING_GLASS_SLICE_WIDTH = next_mult_of( LOOKING_GLASS_SLICE_WIDTH , 256 );
receiver_model.set_squelch_level(0);
each_bin_size = LOOKING_GLASS_SLICE_WIDTH / 256 ;
f_center_ini = f_min + (LOOKING_GLASS_SLICE_WIDTH / 2) ; // Initial center frequency for sweep
f_center = f_center_ini ; // Reset sweep into first slice
baseband::set_spectrum(LOOKING_GLASS_SLICE_WIDTH, field_trigger.value());
receiver_model.set_tuning_frequency(f_center_ini); // tune rx for this slice
}
void GlassView::PlotMarker(rf::Frequency pos)
{
pos = pos * MHZ_DIV;
pos -= f_min;
pos = pos / marker_pixel_step; // Real pixel
portapack::display.fill_rectangle({0, 100, 240, 8}, Color::black()); // Clear old marker and whole marker rectangle btw
portapack::display.fill_rectangle({(int)pos - 2, 100, 5, 3}, Color::red()); // Red marker top
portapack::display.fill_rectangle({(int)pos - 1, 103, 3, 3}, Color::red()); // Red marker middle
portapack::display.fill_rectangle({(int)pos, 106, 1, 2}, Color::red()); // Red marker bottom
uint8_t shift_y = 0 ;
if( live_frequency_view > 0 ) // plot one line down when in live view
{
shift_y = 16 ;
}
portapack::display.fill_rectangle({0, 100 + shift_y, 240, 8}, Color::black()); // Clear old marker and whole marker rectangle btw
portapack::display.fill_rectangle({(int)pos - 2, 100 + shift_y, 5, 3}, Color::red()); // Red marker top
portapack::display.fill_rectangle({(int)pos - 1, 103 + shift_y, 3, 3}, Color::red()); // Red marker middle
portapack::display.fill_rectangle({(int)pos, 106 + shift_y, 1, 2}, Color::red()); // Red marker bottom
}
GlassView::GlassView(
@@ -211,98 +350,116 @@ namespace ui
&field_frequency_max,
&field_lna,
&field_vga,
&text_range,
&button_range,
&steps_config,
&scan_type,
&view_config,
&level_integration,
&filter_config,
&field_rf_amp,
&range_presets,
&field_marker,
&text_marker_pm,
&field_trigger});
&button_marker,
&field_trigger,
&button_jump,
&button_rst,
&freq_stats});
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)
{
int32_t steps_ = steps ;
if( steps_ < 24 )
steps_ = 24 ;
if( v > 7200 - steps_ )
reset_live_view( true );
int32_t min_size = steps ;
if( locked_range )
min_size = search_span ;
if( min_size < 2 )
min_size = 2 ;
if( v > 7200 - min_size )
{
v = 7200 - steps_ ;
v = 7200 - min_size ;
field_frequency_min.set_value( v );
}
if (v >= (field_frequency_max.value() - steps_ ) )
field_frequency_max.set_value( v + steps_ );
if (v > (field_frequency_max.value() - min_size ) )
field_frequency_max.set_value( v + min_size );
if( locked_range )
field_frequency_max.set_value( v + min_size );
this->on_range_changed();
};
field_frequency_min.set_value(presets_db[0].min); // Defaults to first preset
field_frequency_min.set_step( steps );
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_ ;
int32_t min_size = steps ;
if( locked_range )
min_size = search_span ;
if( min_size < 2 )
min_size = 2 ;
if( freq > (7200 - min_size ) )
freq = 7200 - min_size ;
field_frequency_min.set_value( freq );
if( field_frequency_max.value() < ( freq + steps_ ) )
field_frequency_max.set_value( freq + steps_ );
if( field_frequency_max.value() < ( freq + min_size ) )
field_frequency_max.set_value( freq + min_size );
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)
{
int32_t steps_ = steps ;
if( steps_ < 24 )
steps_ = 24 ;
if( v < steps_ )
reset_live_view( true );
int32_t min_size = steps ;
if( locked_range )
min_size = search_span ;
if( min_size < 2 )
min_size = 2 ;
if( v < min_size )
{
v = steps_ ;
v = min_size ;
field_frequency_max.set_value( v );
}
if (v < (field_frequency_min.value() + steps_) )
field_frequency_min.set_value(v - steps_);
if (v < (field_frequency_min.value() + min_size) )
field_frequency_min.set_value(v - min_size);
if( locked_range )
field_frequency_min.set_value( v - min_size );
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_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 min_size = steps ;
if( locked_range )
min_size = search_span ;
if( min_size < 2 )
min_size = 2 ;
int32_t freq = f / 1000000 ;
if( freq < 24 )
freq = 24 ;
if( freq < min_size )
freq = min_size ;
field_frequency_max.set_value( freq );
if( field_frequency_min.value() > ( freq - steps) )
field_frequency_min.set_value( freq - steps );
if( field_frequency_min.value() > ( freq - min_size) )
field_frequency_min.set_value( freq - min_size );
this->on_range_changed();
};
};
field_lna.set_value(receiver_model.lna());
field_lna.on_change = [this](int32_t v)
{
reset_live_view( true );
this->on_lna_changed(v);
};
field_lna.set_value(receiver_model.lna());
field_vga.set_value(receiver_model.vga());
field_vga.on_change = [this](int32_t v_db)
{
reset_live_view( true );
this->on_vga_changed(v_db);
};
field_vga.set_value(receiver_model.vga());
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;
@@ -310,39 +467,67 @@ namespace ui
field_frequency_max.set_step( v );
steps = v ;
};
steps_config.set_selected_index(0); //default of 1 Mhz steps
scan_type.on_change = [this](size_t n, OptionsField::value_t v)
{
(void)n;
fast_scan = v ;
};
scan_type.set_selected_index(0); // default legacy fast scan
view_config.on_change = [this](size_t n, OptionsField::value_t v)
{
(void)n;
live_frequency_view = v ;
if( v )
{
display.scroll_disable();
level_integration.hidden( false );
}
else
{
level_integration.hidden( true );
set_dirty();
display.scroll_set_area(109, 319); // Restart scroll on the correct coordinates
}
// clear between changes
display.fill_rectangle( { { 0 , 108 } , { 240 , 320 - 108 } } , { 0 , 0 , 0 } );
(void)n;
// clear between changes
reset_live_view( true );
if( v == 0 )
{
live_frequency_view = 0 ;
level_integration.hidden( true );
freq_stats.hidden( true );
button_jump.hidden( true );
button_rst.hidden( true );
display.scroll_set_area(109, 319); // Restart scroll on the correct coordinates
}
else if( v == 1 )
{
display.fill_rectangle( { { 0 , 108 } , { 240 , 24 } } , { 0 , 0 , 0 } );
live_frequency_view = 1 ;
display.scroll_disable();
level_integration.hidden( false );
freq_stats.hidden( false );
button_jump.hidden( false );
button_rst.hidden( false );
}
else if( v == 2 )
{
display.fill_rectangle( { { 0 , 108 } , { 240 , 24 } } , { 0 , 0 , 0 } );
live_frequency_view = 2 ;
display.scroll_disable();
level_integration.hidden( false );
freq_stats.hidden( false );
button_jump.hidden( false );
button_rst.hidden( false );
}
set_dirty();
};
view_config.set_selected_index(0); //default spectrum
level_integration.on_change = [this](size_t n, OptionsField::value_t v)
{
(void)n;
live_frequency_integrate = v ;
(void)n;
reset_live_view( true );
live_frequency_integrate = v ;
};
level_integration.set_selected_index(2); //default integration of ( 3 * old value + new_value ) / 4
level_integration.set_selected_index(3); //default integration of ( 3 * old value + new_value ) / 4
filter_config.set_selected_index(0);
filter_config.on_change = [this](size_t n, OptionsField::value_t v) {
(void)n;
reset_live_view( true );
min_color_power = v;
};
filter_config.set_selected_index(0);
range_presets.on_change = [this](size_t n, OptionsField::value_t v)
{
@@ -352,26 +537,57 @@ namespace ui
this->on_range_changed();
};
field_marker.on_change = [this](int32_t v)
button_marker.on_change = [this]()
{
PlotMarker(v); // Refresh marker on screen
marker = marker + button_marker.get_encoder_delta() * marker_pixel_step ;
if( marker < f_min )
marker = f_min ;
if( marker > f_max )
marker = f_max ;
button_marker.set_text( to_string_short_freq( marker ) );
button_marker.set_encoder_delta( 0 );
PlotMarker( marker ); // Refresh marker on screen
};
field_marker.on_select = [this](NumberField &)
button_marker.on_select = [this](ButtonWithEncoder &)
{
f_center = field_marker.value();
f_center = f_center * MHZ_DIV;
receiver_model.set_tuning_frequency(f_center); // Center tune rx in marker freq.
receiver_model.set_tuning_frequency(marker); // Center tune rx in marker freq.
receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.pop();
nav_.push<AnalogAudioView>(); // Jump into audio view
};
field_trigger.set_value(32); // Defaults to 32, as normal triggering resolution
field_trigger.on_change = [this](int32_t v)
{
baseband::set_spectrum(LOOKING_GLASS_SLICE_WIDTH, v);
};
field_trigger.set_value(32); // Defaults to 32, as normal triggering resolution
button_range.on_select = [this](Button&) {
if( locked_range )
{
locked_range = false ;
button_range.set_style(&style_white);
button_range.set_text(" "+to_string_dec_uint(search_span)+" ");
}
else
{
locked_range = true ;
button_range.set_style(&style_red);
button_range.set_text(">"+to_string_dec_uint(search_span)+"<");
}
};
button_jump.on_select = [this](Button&) {
receiver_model.set_tuning_frequency(max_freq_hold); // Center tune rx in marker freq.
receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.pop();
nav_.push<AnalogAudioView>(); // Jump into audio view
};
button_rst.on_select = [this](Button&) {
reset_live_view( true );
};
display.scroll_set_area(109, 319);
baseband::set_spectrum(LOOKING_GLASS_SLICE_WIDTH, field_trigger.value()); // trigger:
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2020 euquiq
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
*
* This file is part of PortaPack.
*
@@ -36,13 +37,14 @@
namespace ui
{
#define LOOKING_GLASS_SLICE_WIDTH 20000000 // Each slice bandwidth 20 MHz
#define LOOKING_GLASS_SLICE_WIDTH_MAX 20000000
#define MHZ_DIV 1000000
#define X2_MHZ_DIV 2000000
class GlassView : public View
{
public:
GlassView(NavigationView &nav);
GlassView( const GlassView &);
@@ -64,15 +66,37 @@ namespace ui
rf::Frequency max{};
std::string label{};
};
const Style style_white { // free range
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::white(),
};
const Style style_red { // locked range
.font = font::fixed_8x16,
.background = Color::black(),
.foreground = Color::red(),
};
std::vector<preset_entry> presets_db{};
// Each slice bandwidth 20 MHz and a multiple of 256
// since we are using LOOKING_GLASS_SLICE_WIDTH/256 as the each_bin_size
// it should also be a multiple of 2 since we are using LOOKING_GLASS_SLICE_WIDTH / 2 as centering freq
int64_t LOOKING_GLASS_SLICE_WIDTH = 20000000;
// frequency rounding helpers
int64_t next_mult_of(int64_t num, int64_t multiplier);
void adjust_range(int64_t* f_min, int64_t* f_max, int64_t width);
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(int16_t color);
void reset_live_view( bool clear_screen );
void add_spectrum_pixel(uint8_t power);
void PlotMarker(rf::Frequency pos);
void load_Presets();
void txtline_process(std::string& line);
@@ -83,24 +107,29 @@ namespace ui
rf::Frequency search_span { 0 };
rf::Frequency f_center { 0 };
rf::Frequency f_center_ini { 0 };
rf::Frequency marker { 0 };
rf::Frequency marker_pixel_step { 0 };
rf::Frequency each_bin_size { LOOKING_GLASS_SLICE_WIDTH / 240 };
rf::Frequency each_bin_size { LOOKING_GLASS_SLICE_WIDTH / 256 };
rf::Frequency bins_Hz_size { 0 };
uint8_t min_color_power { 0 };
uint32_t pixel_index { 0 };
std::array<Color, 240> spectrum_row = { 0 };
std::array<int16_t, 240> spectrum_data = { 0 };
std::array<uint8_t, 240> spectrum_data = { 0 };
ChannelSpectrumFIFO* fifo { nullptr };
uint8_t max_power = 0;
int32_t steps = 250 ; // default of 250 Mhz steps
bool live_frequency_view = false ;
int32_t steps = 0 ;
uint8_t live_frequency_view = 0 ;
int16_t live_frequency_integrate = 3 ;
int64_t max_freq_hold = 0 ;
int16_t max_freq_power = -1000 ;
bool fast_scan = true ; // default to legacy fast scan
bool locked_range = false ;
Labels labels{
{{0, 0}, "MIN: MAX: LNA VGA ", Color::light_grey()},
{{0, 1 * 16}, " RANGE: FILTER: AMP:", 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, 3 * 16}, "MARKER: MHz", Color::light_grey()},
{{0, 4 * 16}, "RES: STEP:", Color::light_grey()}
};
@@ -128,47 +157,12 @@ namespace ui
{ 27 * 8, 0 * 16 }
};
Text text_range{
Button button_range{
{7 * 8, 1 * 16, 4 * 8, 16},
""};
OptionsField steps_config{
{ 14 * 8, 4 * 16},
4,
{
{"1", 1},
{"50", 50},
{"100", 100},
{"250", 250},
{"500", 500},
}};
OptionsField view_config{
{ 19 * 8, 4 * 16},
7,
{
{"SPCTR-V", false },
{"LEVEL-V", true },
}};
OptionsField level_integration{
{ 27 * 8, 4 * 16},
2,
{
{"x1", 1 },
{"x2", 2 },
{"x3", 3 },
{"x4", 4 },
{"x5", 5 },
{"x6", 6 },
{"x7", 7 },
{"x8", 8 },
{"x9", 9 },
}};
OptionsField filter_config{
{19 * 8, 1 * 16},
{20 * 8, 1 * 16},
4,
{
{"OFF ", 0},
@@ -186,16 +180,10 @@ namespace ui
{" 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},
""};
ButtonWithEncoder button_marker{
{7 * 8, 3 * 16 , 10 * 8 , 16},
" "
};
NumberField field_trigger{
{4 * 8, 4 * 16},
@@ -204,6 +192,68 @@ namespace ui
2,
' '};
OptionsField steps_config{
{ 13 * 8, 4 * 16},
3,
{
{"1", 1},
{"25", 25},
{"50", 50},
{"100", 100},
{"250", 250},
{"500", 500},
}
};
OptionsField scan_type{
{ 17 * 8, 4 * 16},
2,
{
{"F-", true },
{"S-", false },
}
};
OptionsField view_config{
{ 19 * 8, 4 * 16},
7,
{
{"SPCTR-V", 0 },
{"LEVEL-V", 1 },
{"PEAK-V" , 2 },
}
};
OptionsField level_integration{
{ 27 * 8, 4 * 16},
2,
{
{"x0", 0 },
{"x1", 1 },
{"x2", 2 },
{"x3", 3 },
{"x4", 4 },
{"x5", 5 },
{"x6", 6 },
{"x7", 7 },
{"x8", 8 },
{"x9", 9 },
}};
Button button_jump {
{ 240 - 4 * 8 , 5 * 16 , 4 * 8, 16 },
"JMP"
};
Button button_rst {
{ 240 - 9 * 8 , 5 * 16 , 4 * 8, 16 },
"RST"
};
Text freq_stats{
{0 * 8, 5 * 16 , 240 - 10 * 8 , 8 },
""
};
MessageHandlerRegistration message_handler_spectrum_config {
Message::ID::ChannelSpectrumConfig,
+146 -107
View File
@@ -30,10 +30,9 @@
#define MSG_RECON_SET_MODULATION 10000 // for handle_retune to know that recon thread triggered a modulation change. f is the index of the modulation
#define MSG_RECON_SET_BANDWIDTH 20000 // for handle_retune to know that recon thread triggered a bandwidth change. f is the new bandwidth value index for current modulation
#define MSG_RECON_SET_STEP 30000 // for handle_retune to know that recon thread triggered a bandwidth change. f is the new bandwidth value index for current modulation
#define MSG_RECON_SET_RECEIVER_BANDWIDTH 40000 // for handle_retune to know that recon thread triggered a receiver bandwidth change. f is the new bandwidth in hz
#define MSG_RECON_SET_RECEIVER_BANDWIDTH 40000 // for handle_retune to know that recon thread triggered a receiver bandwidth change. f is the new bandwidth in hz
#define MSG_RECON_SET_RECEIVER_SAMPLERATE 50000 // for handle_retune to know that recon thread triggered a receiver samplerate change. f is the new samplerate in hz/s
using namespace portapack;
using portapack::memory::map::backup_ram;
@@ -104,7 +103,7 @@ namespace ui {
void ReconThread::change_recon_direction() {
_fwd = !_fwd;
// chThdSleepMilliseconds(300); //Give some pause after reversing recon direction
//chThdSleepMilliseconds(300); //Give some pause after reversing recon direction
}
bool ReconThread::get_recon_direction() {
@@ -409,15 +408,16 @@ namespace ui {
default:
break;
}
restart_recon = true ;
}
// send a pause message with the right freq
if( has_looped && !_continuous )
{
// signal pause to handle_retune
receiver_model.set_tuning_frequency( freq ); // Retune to actual freq
message.freq = freq ;
message.range = MSG_RECON_PAUSE ;
EventDispatcher::send_message(message);
receiver_model.set_tuning_frequency( freq ); // Retune to actual freq
}
if( _stepper < 0 ) _stepper ++ ;
if( _stepper > 0 ) _stepper -- ;
@@ -443,9 +443,7 @@ namespace ui {
void ReconView::set_display_freq( int64_t freq )
{
int64_t freqMHz = ( freq / 1000000 );
int64_t freqMhzFloatingPart = ( freq - ( 1000000 * freqMHz ) ) / 100 ;
big_display.set( "FREQ: "+to_string_dec_int( freqMHz )+"."+to_string_dec_int( freqMhzFloatingPart )+" MHz" );
big_display.set( "FREQ: "+to_string_short_freq( freq )+" MHz" );
}
void ReconView::handle_retune( int64_t freq , uint32_t index ) {
@@ -477,8 +475,8 @@ namespace ui {
receiver_model.disable();
baseband::shutdown();
change_mode( freq );
if ( !recon_thread->is_recon() ) //for some motive, audio output gets stopped.
audio::output::start(); //So if recon was stopped we resume audio
if ( !recon_thread->is_recon() ) // for some motive, audio output gets stopped.
audio::output::start(); // so if recon was stopped we resume audio
receiver_model.enable();
field_mode.set_selected_index( freq );
return ;
@@ -528,32 +526,32 @@ namespace ui {
}
}
}
}
uint32_t freq_lock = recon_thread->is_freq_lock();
if( freq_lock == 0 ) {
//NO FREQ LOCK, ONGOING STANDARD SCANNING
if( index < 1000 && index < frequency_list.size() )
text_cycle.set_text( to_string_dec_uint( index + 1 , 3 ) );
if(frequency_list[index].description.size() > 0)
{
text_cycle.set_text( to_string_dec_uint( index + 1 , 3 ) );
if(frequency_list[index].description.size() > 0)
switch( frequency_list[current_index].type )
{
switch( frequency_list[current_index].type )
{
case RANGE:
desc_cycle.set( "R: " + frequency_list[current_index].description ); //Show new description
break ;
case HAMRADIO:
desc_cycle.set( "H: " + frequency_list[current_index].description ); //Show new description
break ;
default:
case SINGLE:
desc_cycle.set( "S: " + frequency_list[current_index].description ); //Show new description
break ;
}
case RANGE:
desc_cycle.set( "R: " + frequency_list[current_index].description ); //Show new description
break ;
case HAMRADIO:
desc_cycle.set( "H: " + frequency_list[current_index].description ); //Show new description
break ;
default:
case SINGLE:
desc_cycle.set( "S: " + frequency_list[current_index].description ); //Show new description
break ;
}
}
else
{
desc_cycle.set( "...no description..." ); //Show new description
}
}
uint32_t freq_lock = recon_thread->is_freq_lock();
if( freq_lock == 0 ) {
//NO FREQ LOCK, ONGOING STANDARD SCANNING
big_display.set_style(&style_white);
if( !userpause )
button_pause.set_text("<PAUSE>");
@@ -647,7 +645,7 @@ namespace ui {
static int32_t last_db = 999999 ;
static int32_t last_nb_match = 999999 ;
static int32_t last_timer = -1 ;
if( recon_thread && frequency_list.size() > 0 )
if( recon_thread )
{
int32_t nb_match = recon_thread->is_freq_lock();
if( last_db != db )
@@ -672,15 +670,6 @@ namespace ui {
text_timer.set( "TIMER: " + to_string_dec_int( timer ) );
}
}
else
{
if( refresh_display )
{
text_max.set( to_string_dec_int( db ) + " db" );
freq_stats.set( "RSSI: " +to_string_dec_int( rssi.get_min() )+"/"+to_string_dec_int( rssi.get_avg() )+"/"+to_string_dec_int( rssi.get_max() )+" db" );
text_timer.set( "TIMER: " + to_string_dec_int( timer ) );
}
}
}
ReconView::ReconView( NavigationView& nav) : nav_ { nav } {
@@ -722,15 +711,11 @@ namespace ui {
} );
// Recon directory
if( check_sd_card() ) { // Check to see if SD Card is mounted
if( check_sd_card() ) { // Check to see if SD Card is mounted
make_new_directory( u"/RECON" );
sd_card_mounted = true ;
}
def_step = 0 ;
change_mode(AM_MODULATION); //Start on AM
field_mode.set_by_value(AM_MODULATION); //Reflect the mode into the manual selector
//HELPER: Pre-setting a manual range, based on stored frequency
rf::Frequency stored_freq = persistent_memory::tuned_frequency();
receiver_model.set_tuning_frequency( stored_freq );
@@ -748,14 +733,12 @@ namespace ui {
load_hamradios = persistent_memory::recon_load_hamradios();
update_ranges = persistent_memory::recon_update_ranges_when_recon();
//Loading input and output file from settings
ReconSetupLoadStrings( "RECON/RECON.CFG" , input_file , output_file , recon_lock_duration , recon_lock_nb_match , squelch , recon_match_mode , wait , recon_lock_duration , volume );
field_volume.set_value( volume );
// load auto common app settings
if( sd_card_mounted )
{
//Loading input and output file from settings
ReconSetupLoadStrings( "RECON/RECON.CFG" , input_file , output_file , recon_lock_duration , recon_lock_nb_match , squelch , recon_match_mode , wait , recon_lock_duration , volume );
// load auto common app settings
auto rc = settings.load("recon", &app_settings);
if(rc == SETTINGS_OK) {
field_lna.set_value(app_settings.lna);
@@ -764,12 +747,7 @@ namespace ui {
receiver_model.set_rf_amp(app_settings.rx_amp);
}
}
button_scanner_mode.set_style( &style_blue );
button_scanner_mode.set_text( "RECON" );
file_name.set( "=>" );
field_squelch.set_value( squelch );
button_manual_start.on_select = [this, &nav](ButtonWithEncoder& button) {
auto new_view = nav_.push<FrequencyKeypadView>(frequency_range.min);
new_view->on_changed = [this, &button](rf::Frequency f) {
@@ -1001,21 +979,21 @@ namespace ui {
switch( frequency_list[current_index].type )
{
case RANGE:
desc_cycle.set( "R: " + frequency_list[current_index].description ); //Show new description
desc_cycle.set( "R: " + frequency_list[current_index].description );
break ;
case HAMRADIO:
desc_cycle.set( "H: " + frequency_list[current_index].description ); //Show new description
desc_cycle.set( "H: " + frequency_list[current_index].description );
break ;
default:
case SINGLE:
desc_cycle.set( "S: " + frequency_list[current_index].description ); //Show new description
desc_cycle.set( "S: " + frequency_list[current_index].description );
break ;
}
}
else
{
desc_cycle.set( "no description" ); //Show new description
show_max( true ); //UPDATE new list size on screen
desc_cycle.set( "...no description..." );
show_max( true );
}
text_cycle.set_text( to_string_dec_uint( current_index + 1 , 3 ) );
@@ -1169,7 +1147,6 @@ namespace ui {
def_step = step_mode.selected_index(); // max range val
manual_freq_entry . type = RANGE ;
manual_freq_entry . description =
"R " + to_string_short_freq(frequency_range.min) + ">"
@@ -1190,11 +1167,14 @@ namespace ui {
freq_stats.set( "0/0/0" );
show_max(); /* display step information */
text_cycle.set_text( "MANUAL SEARCH" );
text_cycle.set_text( "1" );
text_max.set( "/1" );
button_scanner_mode.set_style( &style_white );
button_scanner_mode.set_text( "MSEARCH" );
file_name.set_style( &style_white );
file_name.set( "=> MANUAL RANGE" );
file_name.set( "MANUAL RANGE RECON" );
desc_cycle.set_style( &style_white );
desc_cycle.set( "MANUAL RANGE RECON" );
start_recon_thread();
user_resume();
@@ -1232,7 +1212,7 @@ namespace ui {
button_restart.on_select = [this](Button&) {
if( frequency_list.size() > 0 )
{
def_step = step_mode.selected_index(); //Use def_step from manual selector
def_step = step_mode.selected_index(); //Use def_step from manual selector
frequency_file_load( true );
if( recon_thread )
{
@@ -1251,9 +1231,20 @@ namespace ui {
show_max();
user_resume();
}
if( scanner_mode )
{
file_name.set_style( &style_red );
button_scanner_mode.set_style( &style_red );
button_scanner_mode.set_text( "SCANNER" );
}
else
{
file_name.set_style( &style_blue );
button_scanner_mode.set_style( &style_blue );
button_scanner_mode.set_text( "RECON" );
}
};
button_add.on_select = [this](ButtonWithEncoder&) { //frequency_list[current_index]
if( !scanner_mode)
{
@@ -1377,7 +1368,8 @@ namespace ui {
ReconSetupSaveStrings( "RECON/RECON.CFG" , input_file , output_file , recon_lock_duration , recon_lock_nb_match , squelch , recon_match_mode , wait , recon_lock_duration , field_volume.value() );
user_pause();
if( frequency_list.size() != 0 )
user_pause();
auto open_view = nav.push<ReconSetupView>(input_file,output_file,recon_lock_duration,recon_lock_nb_match,recon_match_mode);
open_view -> on_changed = [this](std::vector<std::string> result) {
@@ -1385,7 +1377,7 @@ namespace ui {
output_file = result[1];
recon_lock_duration = strtol( result[2].c_str() , nullptr , 10 );
recon_lock_nb_match = strtol( result[3].c_str() , nullptr , 10 );
recon_match_mode = strtol( result[4].c_str() , nullptr , 10 );
recon_match_mode = strtol( result[4].c_str() , nullptr , 10 );
ReconSetupSaveStrings( "RECON/RECON.CFG" , input_file , output_file , recon_lock_duration , recon_lock_nb_match , squelch , recon_match_mode , wait , recon_lock_duration , field_volume.value() );
@@ -1455,7 +1447,6 @@ namespace ui {
}
};
//PRE-CONFIGURATION:
field_wait.on_change = [this](int32_t v)
{
wait = v ;
@@ -1476,6 +1467,7 @@ namespace ui {
field_wait.set_style( &style_green );
}
};
field_lock_wait.on_change = [this](int32_t v)
{
lock_wait = v ;
@@ -1500,6 +1492,22 @@ namespace ui {
field_lock_wait.set_style(&style_red);
}
};
field_squelch.on_change = [this](int32_t v) {
squelch = v ;
};
field_volume.on_change = [this](int32_t v) {
this->on_headphone_volume_changed(v);
};
//PRE-CONFIGURATION:
change_mode(AM_MODULATION); //Start on AM
field_mode.set_by_value(AM_MODULATION); //Reflect the mode into the manual selector
button_scanner_mode.set_style( &style_blue );
button_scanner_mode.set_text( "RECON" );
file_name.set( "=>" );
field_squelch.set_value( squelch );
field_wait.set_value(wait);
lock_wait = ( 4 * ( recon_lock_duration * recon_lock_nb_match ) );
@@ -1507,16 +1515,13 @@ namespace ui {
if( lock_wait < 400 )
lock_wait = 400 ;
field_lock_wait.set_value(lock_wait);
field_squelch.on_change = [this](int32_t v) {
squelch = v ;
};
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);
//FILL STEP OPTIONS
freqman_set_modulation_option( field_mode );
freqman_set_step_option( step_mode );
receiver_model.set_tuning_frequency( portapack::persistent_memory::tuned_frequency() ); // Retune
if( filedelete )
{
@@ -1524,11 +1529,11 @@ namespace ui {
}
frequency_file_load( false ); /* do not stop all at start */
if( recon_thread && frequency_list.size() > 0 )
if( recon_thread )
{
recon_thread->set_lock_duration( recon_lock_duration );
recon_thread->set_lock_nb_match( recon_lock_nb_match );
if( update_ranges )
if( update_ranges && frequency_list.size() > 0 )
{
button_manual_start.set_text( to_string_short_freq( frequency_list[ current_index ] . frequency_a ) );
frequency_range.min = frequency_list[ current_index ] . frequency_a ;
@@ -1543,7 +1548,6 @@ namespace ui {
frequency_range.max = frequency_list[ current_index ] . frequency_a ;
}
}
if( autostart )
{
timer = 0 ; //Will trigger a recon_resume() on_statistics_update, also advancing to next freq.
@@ -1566,42 +1570,77 @@ namespace ui {
}
audio::output::stop();
if( !scanner_mode)
def_step = step_mode.selected_index(); // use def_step from manual selector
frequency_list.clear(); // clear the existing frequency list (expected behavior)
std::string file_input = input_file ; // default recon mode
if( scanner_mode )
{
def_step = step_mode.selected_index(); //Use def_step from manual selector
frequency_list.clear(); // clear the existing frequency list (expected behavior)
if( !load_freqman_file_ex( input_file , frequency_list, load_freqs, load_ranges, load_hamradios ) )
{
desc_cycle.set(" NO " + input_file + ".TXT FILE ..." );
file_name.set_style( &style_white );
file_name.set( "=> NO DATA" );
}
else
{
file_name.set_style( &style_blue );
file_name.set( "=> "+input_file );
}
step_mode.set_selected_index(def_step); //Impose the default step into the manual step selector
file_input = output_file ;
file_name.set_style( &style_red );
button_scanner_mode.set_style( &style_red );
button_scanner_mode.set_text( "SCANNER" );
}
else
{
def_step = step_mode.selected_index(); //Use def_step from manual selector
frequency_list.clear(); // clear the existing frequency list (expected behavior)
if( !load_freqman_file_ex( output_file , frequency_list, load_freqs, load_ranges, load_hamradios ) )
file_name.set_style( &style_blue );
button_scanner_mode.set_style( &style_blue );
button_scanner_mode.set_text( "RECON" );
}
file_name.set_style( &style_white );
desc_cycle.set_style( &style_white );
if( !load_freqman_file_ex( file_input , frequency_list, load_freqs, load_ranges, load_hamradios ) )
{
file_name.set_style( &style_red );
desc_cycle.set_style( &style_red );
desc_cycle.set(" NO " + file_input + ".TXT FILE ..." );
file_name.set( "=> NO DATA" );
}
else
{
file_name.set( "=> "+file_input );
if( frequency_list.size() == 0 )
{
desc_cycle.set(" NO " + output_file + ".TXT FILE ..." );
file_name.set_style( &style_white );
file_name.set( "=> EMPTY" );
file_name.set_style( &style_red );
desc_cycle.set_style( &style_red );
desc_cycle.set("/0 no entries in list" );
file_name.set( "BadOrEmpty "+file_input );
}
else
{
file_name.set( "=> "+output_file );
file_name.set_style( &style_red );
if( frequency_list.size() > FREQMAN_MAX_PER_FILE )
{
file_name.set_style( &style_yellow );
desc_cycle.set_style( &style_yellow );
}
}
step_mode.set_selected_index(def_step); //Impose the default step into the manual step selector
}
step_mode.set_selected_index(def_step); //Impose the default step into the manual step selector
start_recon_thread();
std::string description = "...no description..." ;
if( frequency_list.size() != 0 )
{
current_index = 0 ;
recon_thread-> set_freq_index( 0 );
switch( frequency_list[current_index].type )
{
case RANGE:
description = "R: " + frequency_list[current_index].description ;
break ;
case HAMRADIO:
description = "H: " + frequency_list[current_index].description ;
break ;
default:
case SINGLE:
description = "S: " + frequency_list[current_index].description ;
break ;
}
text_cycle.set_text( to_string_dec_uint( current_index + 1 , 3 ) );
}
else
{
text_cycle.set_text( " " );
}
desc_cycle.set( description );
}
void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
@@ -1751,12 +1790,12 @@ namespace ui {
void ReconView::recon_resume() {
audio::output::stop();
if( !recon_thread->is_recon() )
recon_thread->set_recon(true); // RESUME!
recon_thread->set_recon(true); // RESUME!
big_display.set_style(&style_white); //Back to grey color
}
void ReconView::user_pause() {
timer = 0 ; // Will trigger a recon_resume() on_statistics_update, also advancing to next freq.
timer = 0 ; // Will trigger a recon_resume() on_statistics_update, also advancing to next freq.
//button_pause.set_text("<RESUME>"); //PAUSED, show resume
userpause=true;
continuous_lock=false;
@@ -1764,9 +1803,9 @@ namespace ui {
}
void ReconView::user_resume() {
timer = 0 ; // Will trigger a recon_resume() on_statistics_update, also advancing to next freq.
timer = 0 ; // Will trigger a recon_resume() on_statistics_update, also advancing to next freq.
//button_pause.set_text("<PAUSE>"); //Show button for pause
userpause=false; // Resume recon
userpause=false; // Resume recon
continuous_lock=false;
recon_resume();
}
+3 -5
View File
@@ -39,6 +39,8 @@
#include "file.hpp"
#include "app_settings.hpp"
// maximum usable freq
#define MAX_UFREQ 7200000000
namespace ui {
@@ -118,8 +120,6 @@ namespace ui {
void focus() override;
void big_display_freq( int64_t f );
const Style style_grey { // recon
.font = font::fixed_8x16,
.background = Color::black(),
@@ -178,7 +178,7 @@ namespace ui {
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...
jammer::jammer_range_t frequency_range { false, 0, MAX_UFREQ }; //perfect for manual recon task too...
int32_t squelch { 0 };
int32_t db { 0 };
int32_t timer { 0 };
@@ -200,8 +200,6 @@ namespace ui {
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 };
-2
View File
@@ -88,8 +88,6 @@ public:
void focus() override;
void big_display_freq(rf::Frequency f);
const Style style_grey { // scanning
.font = font::fixed_8x16,
.background = Color::black(),
+16 -2
View File
@@ -41,7 +41,6 @@ using namespace portapack;
#include "freqman.hpp"
namespace ui {
SetDateTimeView::SetDateTimeView(
NavigationView& nav
) {
@@ -306,7 +305,6 @@ namespace ui {
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());
@@ -405,11 +403,16 @@ namespace ui {
&check_load_mem_at_startup,
&button_save_mem_to_file,
&button_load_mem_from_file,
&button_load_mem_defaults,
&button_return
});
bool load_mem_at_startup = false ;
File pmem_flag_file_handle ;
std::string folder = "SETTINGS";
make_new_directory(folder);
std::string pmem_flag_file = "/SETTINGS/PMEM_FILEFLAG" ;
auto result = pmem_flag_file_handle.open(pmem_flag_file);
if(!result.is_valid())
@@ -479,6 +482,17 @@ namespace ui {
}
};
button_load_mem_defaults.on_select = [&nav, this](Button&) {
nav.push<ModalMessageView>(
"Warning!",
"This will reset the p.mem\nand set the default settings",
YESNO,
[this](bool choice) {
if (choice) {
portapack::persistent_memory::cache::defaults();
}
} );
};
button_return.on_select = [&nav, this](Button&) {
nav.pop();
+9 -4
View File
@@ -314,7 +314,7 @@ private:
25,
"Save app settings"
};
Button button_save {
{ 2 * 8, 16 * 16, 12 * 8, 32 },
"Save"
@@ -464,15 +464,20 @@ private:
};
Button button_save_mem_to_file {
{ 0, 9 * 16, 240, 32 },
{ 0, 8 * 16, 240, 32 },
"save p.mem to sdcard"
};
Button button_load_mem_from_file {
{ 0, 12 * 16, 240, 32 },
{ 0, 10 * 16 + 4 , 240, 32 },
"load p.mem from sdcard"
};
Button button_load_mem_defaults {
{ 0, 12 * 16 + 8 , 240, 32 },
"! reset p.mem, load defaults !"
};
Button button_return {
{ 16 * 8, 16 * 16, 12 * 8, 32 },
"Return",
+13 -13
View File
@@ -49,26 +49,26 @@ private:
void on_tx_progress(const uint32_t progress, const bool done);
const std::string shape_strings[7] = {
"CW",
"Sine",
"Triangle",
"Saw up",
"Saw down",
"Square",
"Noise"
"CW-just carrier",
"Sine signal ",
"Triangle signal",
"Saw up signal ",
"Saw down signal",
"Square signal ",
"Noise signal " // using 16 bits LFSR register, 16 order polynomial feedback.
};
bool auto_update { false };
Labels labels {
{ { 6 * 8, 4 + 10 }, "Shape:", Color::light_grey() },
{ { 7 * 8, 7 * 8 }, "Tone: Hz", Color::light_grey() },
{ { 3 * 8, 4 + 10 }, "Shape:", Color::light_grey() },
{ { 6 * 8, 7 * 8 }, "Tone: Hz", Color::light_grey() },
{ { 22 * 8, 15 * 8 + 4 }, "s.", Color::light_grey() },
{ { 8 * 8, 20 * 8 }, "Modulation: FM", Color::light_grey() }
};
ImageOptionsField options_shape {
{ 13 * 8, 4, 32, 32 },
{ 10 * 8, 4, 32, 32 },
Color::white(),
Color::black(),
{
@@ -83,7 +83,7 @@ private:
};
Text text_shape {
{ 18 * 8, 4 + 10, 8 * 8, 16 },
{ 15 * 8, 4 + 10, 8 * 8, 16 },
""
};
@@ -94,12 +94,12 @@ private:
};
Button button_update {
{ 6 * 8, 10 * 8, 8 * 8, 3 * 8 },
{ 5 * 8, 10 * 8, 8 * 8, 3 * 8 },
"Update"
};
Checkbox checkbox_auto {
{ 16 * 8, 10 * 8 },
{ 15 * 8, 10 * 8 },
4,
"Auto"
};
+9 -1
View File
@@ -43,6 +43,7 @@ using namespace lpc43xx;
#include <array>
#include "ui_font_fixed_8x16.hpp"
#include "ui_navigation.hpp"
extern "C" {
@@ -262,6 +263,8 @@ void EventDispatcher::on_touch_event(ui::TouchEvent event) {
void EventDispatcher::handle_lcd_frame_sync() {
DisplayFrameSyncMessage message;
message_map.send(&message);
static_cast<ui::SystemView *>(top_widget)->paint_overlay();
painter.paint_widget_tree(top_widget);
portapack::backlight()->on();
@@ -304,7 +307,12 @@ void EventDispatcher::handle_switches() {
if( switches_state[i] ) {
const auto event = static_cast<ui::KeyEvent>(i);
if( !event_bubble_key(event) ) {
context.focus_manager().update(top_widget, event);
if (switches_state[(size_t)ui::KeyEvent::Dfu]) {
static_cast<ui::SystemView *>(top_widget)->toggle_overlay();
}
else {
context.focus_manager().update(top_widget, event);
}
}
in_key_event = true;
+44 -1
View File
@@ -250,6 +250,15 @@ std::string filesystem_error::what() const {
}
}
path path::parent_path() const {
const auto index = _s.find_last_of(preferred_separator);
if( index == _s.npos ) {
return { }; // NB: Deviation from STL.
} else {
return _s.substr(0, index);
}
}
path path::extension() const {
const auto t = filename().native();
const auto index = t.find_last_of(u'.');
@@ -296,6 +305,14 @@ path& path::replace_extension(const path& replacement) {
return *this;
}
bool operator==(const path& lhs, const path& rhs) {
return lhs.native() == rhs.native();
}
bool operator!=(const path& lhs, const path& rhs) {
return !(lhs == rhs);
}
bool operator<(const path& lhs, const path& rhs) {
return lhs.native() < rhs.native();
}
@@ -304,6 +321,18 @@ bool operator>(const path& lhs, const path& rhs) {
return lhs.native() > rhs.native();
}
path operator+(const path& lhs, const path& rhs) {
path result = lhs;
result += rhs;
return result;
}
path operator/(const path& lhs, const path& rhs) {
path result = lhs;
result /= rhs;
return result;
}
directory_iterator::directory_iterator(
std::filesystem::path path,
std::filesystem::path wild
@@ -311,7 +340,7 @@ directory_iterator::directory_iterator(
{
impl = std::make_shared<Impl>();
const auto result = f_findfirst(&impl->dir, &impl->filinfo, reinterpret_cast<const TCHAR*>(path.c_str()), reinterpret_cast<const TCHAR*>(pattern.c_str()));
if( result != FR_OK ) {
if( result != FR_OK || impl->filinfo.fname[0] == (TCHAR)'\0') {
impl.reset();
// TODO: Throw exception if/when I enable exceptions...
}
@@ -333,6 +362,20 @@ bool is_regular_file(const file_status s) {
return !(s & AM_DIR);
}
bool file_exists(const path& file_path) {
FILINFO filinfo;
auto fr = f_stat(reinterpret_cast<const TCHAR*>(file_path.c_str()), &filinfo);
return fr == FR_OK;
}
bool is_directory(const path& file_path) {
FILINFO filinfo;
auto fr = f_stat(reinterpret_cast<const TCHAR*>(file_path.c_str()), &filinfo);
return fr == FR_OK && is_directory(static_cast<file_status>(filinfo.fattrib));
}
space_info space(const path& p) {
DWORD free_clusters { 0 };
FATFS* fs;
+16
View File
@@ -123,6 +123,7 @@ struct path {
return *this;
}
path parent_path() const;
path extension() const;
path filename() const;
path stem() const;
@@ -151,14 +152,25 @@ struct path {
return *this;
}
path& operator/=(const path& p) {
if (_s.back() != preferred_separator)
_s += preferred_separator;
_s += p._s;
return *this;
}
path& replace_extension(const path& replacement = path());
private:
string_type _s;
};
bool operator==(const path& lhs, const path& rhs);
bool operator!=(const path& lhs, const path& rhs);
bool operator<(const path& lhs, const path& rhs);
bool operator>(const path& lhs, const path& rhs);
path operator+(const path& lhs, const path& rhs);
path operator/(const path& lhs, const path& rhs);
using file_status = BYTE;
@@ -227,6 +239,8 @@ inline bool operator!=(const directory_iterator& lhs, const directory_iterator&
bool is_directory(const file_status s);
bool is_regular_file(const file_status s);
bool file_exists(const path& file_path);
bool is_directory(const path& file_path);
space_info space(const path& p);
@@ -245,6 +259,8 @@ uint32_t make_new_directory(const std::filesystem::path& dir_path);
std::vector<std::filesystem::path> scan_root_files(const std::filesystem::path& directory, const std::filesystem::path& extension);
std::vector<std::filesystem::path> scan_root_directories(const std::filesystem::path& directory);
/* Gets an auto incrementing filename. */
std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_stem_pattern);
/* Values added to FatFs FRESULT enum, values outside the FRESULT data type */
+1 -1
View File
@@ -229,7 +229,7 @@ bool load_freqman_file_ex(std::string& file_stem, freqman_db& db, bool load_freq
{
db.push_back({ frequency_a, frequency_b, description, type , modulation , bandwidth , step , tone });
n++;
if (n >= FREQMAN_MAX_PER_FILE) return true;
if (n > FREQMAN_MAX_PER_FILE) return true;
}
line_start = line_end + 1;
+4 -3
View File
@@ -31,9 +31,10 @@
#include "string_format.hpp"
#include "ui_widget.hpp"
#define FREQMAN_DESC_MAX_LEN 30
#define FREQMAN_MAX_PER_FILE 500 /* MAX PER FILES */
#define FREQMAN_MAX_PER_FILE_STR "500" /*STRING OF FREQMAN_MAX_PER_FILE */
#define FREQMAN_DESC_MAX_LEN 24 // This is the number of characters that can be drawn in front of "R: TEXT..." before taking a full screen line
#define FREQMAN_MAX_PER_FILE 115 // Maximum of entries we can read. This is a hardware limit
// It was tested and lowered to leave a bit of space to the caller
#define FREQMAN_MAX_PER_FILE_STR "115" // STRING OF FREQMAN_MAX_PER_FILE
using namespace ui;
using namespace std;
+4 -2
View File
@@ -42,7 +42,7 @@ using namespace hackrf::one;
static Thread* thread_controls_event = NULL;
static std::array<Debounce, 7> switch_debounce;
static std::array<Debounce, 8> switch_debounce;
static Encoder encoder;
@@ -193,11 +193,13 @@ void controls_init() {
SwitchesState get_switches_state() {
SwitchesState result;
for(size_t i=0; i<result.size(); i++) {
for(size_t i=0; i<result.size()-1; i++) {
// TODO: Ignore multiple keys at the same time?
result[i] = switch_debounce[i].state();
}
result[result.size()-1] = switch_debounce[switch_debounce.size()-1].state();
return result;
}
+2 -1
View File
@@ -33,9 +33,10 @@ enum class Switch {
Down = 2,
Up = 3,
Sel = 4,
Dfu = 5,
};
using SwitchesState = std::bitset<5>;
using SwitchesState = std::bitset<6>;
using EncoderPosition = uint32_t;
+3 -3
View File
@@ -145,14 +145,14 @@ Continuous (Fox-oring)
rffc507x::RFFC507x first_if;
static void event_loop() {
ui::Context context;
ui::SystemView system_view {
static ui::Context context;
static ui::SystemView system_view {
context,
portapack::display.screen_rect()
};
EventDispatcher event_dispatcher { &system_view, context };
MessageHandlerRegistration message_handler_display_sleep {
static MessageHandlerRegistration message_handler_display_sleep {
Message::ID::DisplaySleep,
[&event_dispatcher](const Message* const) {
event_dispatcher.set_display_sleep(true);
+7 -4
View File
@@ -61,7 +61,7 @@ portapack::IO io {
portapack::gpio_io_stbx,
portapack::gpio_addr,
portapack::gpio_lcd_te,
portapack::gpio_unused,
portapack::gpio_dfu,
};
portapack::BacklightCAT4004 backlight_cat4004;
@@ -489,10 +489,13 @@ bool init() {
chThdSleepMilliseconds(10);
if( !portapack::cpld::update_if_necessary(portapack_cpld_config()) ) {
portapack::cpld::CpldUpdateStatus result = portapack::cpld::update_if_necessary(portapack_cpld_config());
if ( result == portapack::cpld::CpldUpdateStatus::Program_failed ) {
chThdSleepMilliseconds(10);
// If using a "2021/12 QFP100", press and hold the left button while booting. Should only need to do once.
if (load_config() != 3 && load_config() != 4){
// Mode left (R1) and right (R2,H2,H2+) bypass going into hackrf mode after failing CPLD update
// Mode center (autodetect), up (R1) and down (R2,H2,H2+) will go into hackrf mode after failing CPLD update
if (load_config() != 3 /* left */ && load_config() != 4 /* right */){
shutdown_base();
return false;
}
+11 -6
View File
@@ -81,16 +81,21 @@ void Manager::feed(const Frame& frame) {
const auto touch_raw = frame.touch;
//const auto touch_stable = touch_debounce.state();
const auto touch_stable = frame.touch;
bool touch_pressure = false;
bool touch_down_pressure = false;
bool touch_up_pressure = false;
// Only feed coordinate averaging if there's a touch.
// TODO: Separate threshold to gate coordinates for filtering?
if( touch_raw ) {
const auto metrics = calculate_metrics(frame);
// TODO: Add touch pressure hysteresis?
touch_pressure = (metrics.r < r_touch_threshold);
if( touch_pressure ) {
constexpr float r_touch_down_threshold = 3200.0f;
constexpr float r_touch_up_threshold = r_touch_down_threshold * 2.0f;
touch_down_pressure = (metrics.r < r_touch_down_threshold);
touch_up_pressure = (metrics.r < r_touch_up_threshold);
if( touch_down_pressure ) {
filter_x.feed(metrics.x * 1024);
filter_y.feed(metrics.y * 1024);
}
@@ -101,7 +106,7 @@ void Manager::feed(const Frame& frame) {
switch(state) {
case State::NoTouch:
if( touch_stable && touch_pressure && !persistent_memory::disable_touchscreen()) {
if( touch_stable && touch_down_pressure && !persistent_memory::disable_touchscreen()) {
if( point_stable() ) {
state = State::TouchDetected;
touch_started();
@@ -110,7 +115,7 @@ void Manager::feed(const Frame& frame) {
break;
case State::TouchDetected:
if( touch_stable && touch_pressure ) {
if( touch_stable && touch_up_pressure ) {
touch_moved();
} else {
state = State::NoTouch;
-1
View File
@@ -219,7 +219,6 @@ private:
TouchDetected,
};
static constexpr float r_touch_threshold = 640;
static constexpr size_t touch_count_threshold { 3 };
static constexpr uint32_t touch_stable_bound { 8 };
+1 -16
View File
@@ -30,10 +30,6 @@
namespace ui {
void AlphanumView::paint(Painter&) {
draw_cursor();
}
AlphanumView::AlphanumView(
NavigationView& nav,
std::string& str,
@@ -41,7 +37,7 @@ AlphanumView::AlphanumView(
) : TextEntryView(nav, str, max_length)
{
size_t n;
add_children({
&button_mode,
&text_raw,
@@ -77,16 +73,7 @@ AlphanumView::AlphanumView(
field_raw.set_value('0');
field_raw.on_select = [this](NumberField&) {
char_add(field_raw.value());
update_text();
};
button_ok.on_select = [this, &nav](Button&) {
if (on_changed)
on_changed(_str);
nav.pop();
};
update_text();
}
void AlphanumView::set_mode(const uint32_t new_mode) {
@@ -120,8 +107,6 @@ void AlphanumView::on_button(Button& button) {
char_delete();
else
char_add(c);
update_text();
}
bool AlphanumView::on_encoder(const EncoderEvent delta) {
-1
View File
@@ -40,7 +40,6 @@ public:
AlphanumView& operator=(const AlphanumView&) = delete;
AlphanumView& operator=(AlphanumView&&) = delete;
void paint(Painter& painter) override;
bool on_encoder(const EncoderEvent delta) override;
private:
+5 -3
View File
@@ -163,6 +163,8 @@ void MenuView::clear() {
}
menu_items.clear();
highlighted_item = 0;
offset = 0;
}
void MenuView::add_item(MenuItem new_item) {
@@ -209,7 +211,7 @@ MenuItemView* MenuView::item_view(size_t index) const {
bool MenuView::set_highlighted(int32_t new_value) {
int32_t item_count = (int32_t)menu_items.size();
if (new_value < 0)
if (new_value < 0 || item_count == 0)
return false;
if (new_value >= item_count)
@@ -238,7 +240,7 @@ bool MenuView::set_highlighted(int32_t new_value) {
return true;
}
uint32_t MenuView::highlighted_index() {
uint32_t MenuView::highlighted_index() const {
return highlighted_item;
}
@@ -262,7 +264,7 @@ bool MenuView::on_key(const KeyEvent key) {
case KeyEvent::Select:
case KeyEvent::Right:
if( menu_items[highlighted_item].on_select ) {
menu_items[highlighted_item].on_select();
menu_items[highlighted_item].on_select(key);
}
return true;
+2 -2
View File
@@ -39,7 +39,7 @@ struct MenuItem {
std::string text;
ui::Color color;
const Bitmap* bitmap;
std::function<void(void)> on_select;
std::function<void(KeyEvent)> on_select;
// TODO: Prevent default-constructed MenuItems.
// I managed to construct a menu with three extra, unspecified menu items
@@ -87,7 +87,7 @@ public:
MenuItemView* item_view(size_t index) const;
bool set_highlighted(int32_t new_value);
uint32_t highlighted_index();
uint32_t highlighted_index() const;
void set_parent_rect(const Rect new_parent_rect) override;
void on_focus() override;
+17
View File
@@ -434,6 +434,23 @@ namespace ui {
void RSSIGraph::set_nb_columns( int16_t nb )
{
nb_columns = nb ;
while( graph_list.size() > nb_columns )
{
graph_list.erase( graph_list.begin() );
}
}
void RSSIGraph::on_hide() {
nb_columns_before_hide = nb_columns ;
nb_columns = 1 ;
while( graph_list.size() > nb_columns )
{
graph_list.erase( graph_list.begin() );
}
}
void RSSIGraph::on_show() {
nb_columns = nb_columns_before_hide ;
}
void RSSI::on_focus() {
+4
View File
@@ -115,8 +115,12 @@ namespace ui {
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 );
void on_hide() override ;
void on_show() override ;
private:
uint16_t nb_columns_before_hide = 16 ;
uint16_t nb_columns = 16 ;
RSSIGraphList graph_list { } ;
};
+157 -48
View File
@@ -29,9 +29,25 @@ using namespace portapack;
namespace ui {
void text_prompt(NavigationView& nav, std::string& str, const size_t max_length, const std::function<void(std::string&)> on_done) {
void text_prompt(
NavigationView& nav,
std::string& str,
size_t max_length,
std::function<void(std::string&)> on_done
) {
text_prompt(nav, str, str.length(), max_length, on_done);
}
void text_prompt(
NavigationView& nav,
std::string& str,
uint32_t cursor_pos,
size_t max_length,
std::function<void(std::string&)> on_done
) {
//if (persistent_memory::ui_config_textentry() == 0) {
auto te_view = nav.push<AlphanumView>(str, max_length);
te_view->set_cursor(cursor_pos);
te_view->on_changed = [on_done](std::string& value) {
if (on_done)
on_done(value);
@@ -45,76 +61,169 @@ void text_prompt(NavigationView& nav, std::string& str, const size_t max_length,
}*/
}
void TextEntryView::update_text() {
if (cursor_pos < 30)
text_input.set(_str + std::string(_max_length - _str.length(), ' '));
else
text_input.set('<' + _str.substr(cursor_pos - 29, 29));
draw_cursor();
/* TextField ***********************************************************/
TextField::TextField(
std::string& str,
size_t max_length,
Point position,
uint32_t length
) : Widget{ { position, { 8 * static_cast<int>(length), 16 } } },
text_{ str },
max_length_{ std::max<size_t>(max_length, str.length()) },
char_count_{ std::max<uint32_t>(length, 1) },
cursor_pos_{ text_.length() },
insert_mode_{ true }
{
set_focusable(true);
}
const std::string& TextField::value() const {
return text_;
}
void TextField::set_cursor(uint32_t pos) {
cursor_pos_ = std::min<size_t>(pos, text_.length());
set_dirty();
}
void TextField::set_insert_mode() {
insert_mode_ = true;
}
void TextField::set_overwrite_mode() {
insert_mode_ = false;
}
void TextField::char_add(char c) {
// Don't add if inserting and at max_length and
// don't overwrite if past the end of the text.
if ((text_.length() >= max_length_ && insert_mode_) ||
(cursor_pos_ >= text_.length() && !insert_mode_))
return;
if (insert_mode_)
text_.insert(cursor_pos_, 1, c);
else
text_[cursor_pos_] = c;
cursor_pos_++;
set_dirty();
}
void TextField::char_delete() {
if (cursor_pos_ == 0)
return;
cursor_pos_--;
text_.erase(cursor_pos_, 1);
set_dirty();
}
void TextField::paint(Painter& painter) {
constexpr int char_width = 8;
auto rect = screen_rect();
auto text_style = has_focus() ? style().invert() : style();
auto offset = 0;
// Does the string need to be shifted?
if (cursor_pos_ >= char_count_)
offset = cursor_pos_ - char_count_ + 1;
// Clear the control.
painter.fill_rectangle(rect, text_style.background);
// Draw the text starting at the offset.
for (uint32_t i = 0; i < char_count_ && i + offset < text_.length(); i++) {
painter.draw_char(
{ rect.location().x() + (static_cast<int>(i) * char_width), rect.location().y() },
text_style,
text_[i + offset]
);
}
// Determine cursor position on screen (either the cursor position or the last char).
int32_t cursor_x = char_width * (offset > 0 ? char_count_ - 1 : cursor_pos_);
Point cursor_point{ screen_pos().x() + cursor_x, screen_pos().y() };
auto cursor_style = text_style.invert();
// Invert the cursor character when in overwrite mode.
if (!insert_mode_ && (cursor_pos_) < text_.length())
painter.draw_char(cursor_point, cursor_style, text_[cursor_pos_]);
// Draw the cursor.
Rect cursor_box{ cursor_point, { char_width, 16 } };
painter.draw_rectangle(cursor_box, cursor_style.background);
}
bool TextField::on_key(const KeyEvent key) {
if (key == KeyEvent::Left && cursor_pos_ > 0)
cursor_pos_--;
else if (key == KeyEvent::Right && cursor_pos_ < text_.length())
cursor_pos_++;
else if (key == KeyEvent::Select)
insert_mode_ = !insert_mode_;
else
return false;
set_dirty();
return true;
}
bool TextField::on_encoder(const EncoderEvent delta) {
int32_t new_pos = cursor_pos_ + delta;
// Let the encoder wrap around the ends of the text.
if (new_pos < 0)
new_pos = text_.length();
else if (static_cast<size_t>(new_pos) > text_.length())
new_pos = 0;
set_cursor(new_pos);
return true;
}
bool TextField::on_touch(const TouchEvent event) {
if (event.type == TouchEvent::Type::Start)
focus();
set_dirty();
return true;
}
/* TextEntryView ***********************************************************/
void TextEntryView::char_delete() {
if (!cursor_pos) return;
cursor_pos--;
_str.resize(cursor_pos);
text_input.char_delete();
}
void TextEntryView::char_add(const char c) {
if (cursor_pos >= _max_length) return;
_str += c;
cursor_pos++;
text_input.char_add(c);
}
void TextEntryView::draw_cursor() {
Point draw_pos;
draw_pos = { text_input.screen_rect().location().x() + std::min((Coord)cursor_pos, (Coord)28) * 8,
text_input.screen_rect().location().y() + 16 };
// Erase previous
display.fill_rectangle(
{ { text_input.screen_rect().location().x(), draw_pos.y() }, { text_input.screen_rect().size().width(), 4 } },
Color::black()
);
// Draw new
display.fill_rectangle(
{ draw_pos, { 8, 4 } },
Color::white()
);
void TextEntryView::set_cursor(uint32_t pos) {
text_input.set_cursor(pos);
}
void TextEntryView::focus() {
button_ok.focus();
text_input.focus();
}
TextEntryView::TextEntryView(
NavigationView& nav,
std::string& str,
size_t max_length
) : _str(str),
_max_length(max_length)
) : text_input{ str, max_length, { 0, 0 } }
{
// Trim from right
//_str->erase(std::find_if(_str->rbegin(), _str->rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), _str->end());
if (_str.length() > _max_length)
_str.resize(_max_length);
_str.reserve(_max_length);
cursor_pos = _str.length();
add_children({
&text_input,
&button_ok
});
button_ok.on_select = [this, &nav](Button&) {
_str.resize(cursor_pos);
button_ok.on_select = [this, &str, &nav](Button&) {
if (on_changed)
on_changed(_str);
on_changed(str);
nav.pop();
};
}
+65 -11
View File
@@ -28,12 +28,60 @@
namespace ui {
// A TextField is bound to a string reference and allows the string
// to be manipulated. The field itself does not provide the UI for
// setting the value. It provides the UI of rendering the text,
// a cursor, and an API to edit the string content.
class TextField : public Widget {
public:
TextField(std::string& str, Point position, uint32_t length = 30)
: TextField{str, 64, position, length} { }
// Str: the string containing the content to edit.
// Max_length: max length the string is allowed to use.
// Position: the top-left corner of the control.
// Length: the number of characters to display.
// - Characters are 8 pixels wide.
// - The screen can show 30 characters max.
// - The control is 16 pixels tall.
TextField(std::string& str, size_t max_length, Point position, uint32_t length = 30);
TextField(const TextField&) = delete;
TextField(TextField&&) = delete;
TextField& operator=(const TextField&) = delete;
TextField& operator=(TextField&&) = delete;
const std::string& value() const;
void set_cursor(uint32_t pos);
void set_insert_mode();
void set_overwrite_mode();
void char_add(char c);
void char_delete();
void paint(Painter& painter) override;
bool on_key(const KeyEvent key) override;
bool on_encoder(const EncoderEvent delta) override;
bool on_touch(const TouchEvent event) override;
protected:
std::string& text_;
size_t max_length_;
uint32_t char_count_;
uint32_t cursor_pos_;
bool insert_mode_;
};
class TextEntryView : public View {
public:
std::function<void(std::string&)> on_changed { };
void focus() override;
std::string title() const override { return "Text entry"; };
void set_cursor(uint32_t pos);
protected:
TextEntryView(NavigationView& nav, std::string& str, size_t max_length);
@@ -45,24 +93,30 @@ protected:
void char_add(const char c);
void char_delete();
void draw_cursor();
void update_text();
std::string& _str;
size_t _max_length;
uint32_t cursor_pos { 0 };
Text text_input {
{ 0, 0, 240, 16 }
};
TextField text_input;
Button button_ok {
{ 10 * 8, 33 * 8, 9 * 8, 32 },
"OK"
};
};
void text_prompt(NavigationView& nav, std::string& str, size_t max_length, const std::function<void(std::string&)> on_done = nullptr);
// Show the TextEntry view to receive keyboard input.
// NB: This function returns immediately. 'str' is taken
// by reference and its lifetime must be ensured by the
// caller until the TextEntry view is dismissed.
void text_prompt(
NavigationView& nav,
std::string& str,
size_t max_length,
std::function<void(std::string&)> on_done = nullptr);
void text_prompt(
NavigationView& nav,
std::string& str,
uint32_t cursor_pos,
size_t max_length,
std::function<void(std::string&)> on_done = nullptr);
} /* namespace ui */
+31
View File
@@ -29,6 +29,7 @@
#include "bmp_splash.hpp"
#include "bmp_modal_warning.hpp"
#include "portapack_persistent_memory.hpp"
#include "portapack_shared_memory.hpp"
#include "ui_about_simple.hpp"
#include "ui_adsb_rx.hpp"
@@ -748,6 +749,36 @@ Context& SystemView::context() const {
return context_;
}
void SystemView::toggle_overlay() {
if (overlay_active){
this->remove_child(&this->overlay);
this->set_dirty();
shared_memory.request_m4_performance_counter = 0;
}
else{
this->add_child(&this->overlay);
this->set_dirty();
shared_memory.request_m4_performance_counter = 1;
shared_memory.m4_cpu_usage = 0;
shared_memory.m4_heap_usage = 0;
shared_memory.m4_stack_usage = 0;
}
overlay_active = !overlay_active;
}
void SystemView::paint_overlay() {
static bool last_paint_state = false;
if (overlay_active){
// paint background only every other second
if ((((chTimeNow()>>10) & 0x01) == 0x01) == last_paint_state)
return;
last_paint_state = !last_paint_state;
this->overlay.set_dirty();
}
}
/* ***********************************************************************/
void BMPView::focus() {
+16 -1
View File
@@ -33,6 +33,7 @@
#include "ui_channel.hpp"
#include "ui_audio.hpp"
#include "ui_sd_card_status_view.hpp"
#include "ui_dfu_menu.hpp"
#include "bitmap.hpp"
#include "ff.h"
@@ -75,6 +76,15 @@ namespace ui
{
return reinterpret_cast<T *>(push_view(std::unique_ptr<View>(new T(*this, std::forward<Args>(args)...))));
}
// Pushes a new view under the current on the stack so the current view returns into this new one.
template <class T, class... Args>
void push_under_current(Args &&...args)
{
auto new_view = std::unique_ptr<View>(new T(*this, std::forward<Args>(args)...));
view_stack.insert(view_stack.end() - 1, std::move(new_view));
}
template <class T, class... Args>
T *replace(Args &&...args)
{
@@ -125,7 +135,7 @@ namespace ui
Color::dark_grey()};
ImageButton button_back{
{2, 0 * 16, 16, 16},
{0, 0 * 16, 12 * 8, 16},//back button is long enough to cover the title area to make it easier to touch
&bitmap_icon_previous,
Color::white(),
Color::dark_grey()};
@@ -290,10 +300,15 @@ namespace ui
const Rect parent_rect);
Context &context() const override;
void toggle_overlay();
void paint_overlay();
private:
bool overlay_active {false};
SystemStatusView status_view{navigation_view};
InformationView info_view{navigation_view};
DfuMenu overlay{navigation_view};
NavigationView navigation_view{};
Context &context_;
};
+1
View File
@@ -139,6 +139,7 @@ set(CPPSRC
${COMMON}/chibios_cpp.cpp
debug.cpp
${COMMON}/gcc.cpp
${COMMON}/performance_counter.cpp
tone_gen.cpp
)
+9
View File
@@ -20,6 +20,7 @@
*/
#include "baseband_dma.hpp"
#include "portapack_shared_memory.hpp"
#include <cstdint>
#include <cstddef>
@@ -103,8 +104,12 @@ static constexpr auto& gpdma_channel_sgpio = gpdma::channels[portapack::sgpio_gp
static ThreadWait thread_wait;
volatile uint32_t buffer_transfered = 0;
volatile uint32_t buffer_handled = 0;
static void transfer_complete() {
const auto next_lli_index = gpdma_channel_sgpio.next_lli() - &lli_loop[0];
buffer_transfered++;
thread_wait.wake_from_interrupt(next_lli_index);
}
@@ -158,6 +163,10 @@ void disable() {
baseband::buffer_t wait_for_buffer() {
const auto next_index = thread_wait.sleep();
buffer_handled++;
auto buffer_missed = buffer_transfered - buffer_handled;
shared_memory.m4_buffer_missed = buffer_missed;
if( next_index >= 0 ) {
const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask;
+4
View File
@@ -508,6 +508,8 @@
}
#endif
/**
* @brief System tick event hook.
* @details This hook is invoked in the system tick handler immediately
@@ -516,6 +518,8 @@
#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__)
#define SYSTEM_TICK_EVENT_HOOK() { \
/* System tick event code here.*/ \
extern void update_performance_counters(); \
update_performance_counters(); \
}
#endif
+24
View File
@@ -26,6 +26,7 @@
#include <hal.h>
#include "portapack_shared_memory.hpp"
#include "performance_counter.hpp"
void write_m4_panic_msg(const char *panic_message, struct extctx *ctxp) {
if (ctxp == nullptr) {
@@ -116,5 +117,28 @@ CH_IRQ_HANDLER(HardFaultVector) {
#endif
}
void update_performance_counters() {
auto performance_counter_active = shared_memory.request_m4_performance_counter;
if (performance_counter_active == 0x00)
return;
static bool last_paint_state = false;
if ((((chTimeNow()>>10) & 0x01) == 0x01) == last_paint_state)
return;
// Idle thread state is sometimes unuseable
if (chThdGetTicks(chSysGetIdleThread()) > 0x10000000)
return;
last_paint_state = !last_paint_state;
auto utilisation = get_cpu_utilisation_in_percent();
auto free_stack = (uint32_t)get_free_stack_space();
auto free_heap = chCoreStatus();
shared_memory.m4_cpu_usage = utilisation;
shared_memory.m4_stack_usage = free_stack;
shared_memory.m4_heap_usage = free_heap;
}
} /* extern "C" */
+6
View File
@@ -83,6 +83,12 @@ SSB::SSB() : hilbert() {
}
void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer,TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) {
//unused
(void)configured_in ;
(void)new_beep_index ;
(void)new_beep_timer ;
(void)new_txprogress_message ;
// No way to activate correctly the roger beep in this option, Maybe not enough M4 CPU power , Let's block roger beep in SSB selection by now .
int32_t sample = 0;
int8_t re = 0, im = 0;
+2
View File
@@ -20,6 +20,7 @@
*/
#include "event_m4.hpp"
#include "debug.hpp"
#include "portapack_shared_memory.hpp"
@@ -120,3 +121,4 @@ void EventDispatcher::handle_spectrum() {
const UpdateSpectrumMessage message;
baseband_processor->on_message(&message);
}
+8
View File
@@ -87,6 +87,7 @@ void ERTProcessor::consume_symbol(
) {
const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
scm_builder.execute(sliced_symbol);
scmplus_builder.execute(sliced_symbol);
idm_builder.execute(sliced_symbol);
}
@@ -97,6 +98,13 @@ void ERTProcessor::scm_handler(
shared_memory.application_queue.push(message);
}
void ERTProcessor::scmplus_handler(
const baseband::Packet& packet
) {
const ERTPacketMessage message { ert::Packet::Type::SCMPLUS, packet };
shared_memory.application_queue.push(message);
}
void ERTProcessor::idm_handler(
const baseband::Packet& packet
) {
+15 -1
View File
@@ -44,10 +44,14 @@ constexpr uint64_t scm_preamble_and_sync_manchester { 0b101010101001011001100110
constexpr size_t scm_preamble_and_sync_length { 42 - 10 };
constexpr size_t scm_payload_length_max { 150 };
// ''.join(['%d%d' % (c, 1-c) for c in map(int, bin(0x16a3)[2:].zfill(16))])
constexpr uint64_t scmplus_preamble_and_sync_manchester { 0b01010110011010011001100101011010 };
constexpr size_t scmplus_preamble_and_sync_length { 32 - 0 };
constexpr size_t scmplus_payload_length_max { 224 };
// ''.join(['%d%d' % (c, 1-c) for c in map(int, bin(0x555516a3)[2:].zfill(32))])
constexpr uint64_t idm_preamble_and_sync_manchester { 0b0110011001100110011001100110011001010110011010011001100101011010 };
constexpr size_t idm_preamble_and_sync_length { 64 - 16 };
constexpr size_t idm_payload_length_max { 1408 };
class ERTProcessor : public BasebandProcessor {
@@ -80,6 +84,15 @@ private:
}
};
PacketBuilder<BitPattern, NeverMatch, FixedLength> scmplus_builder {
{ scmplus_preamble_and_sync_manchester, scmplus_preamble_and_sync_length, 1 },
{ },
{ scmplus_payload_length_max },
[this](const baseband::Packet& packet) {
this->scmplus_handler(packet);
}
};
PacketBuilder<BitPattern, NeverMatch, FixedLength> idm_builder {
{ idm_preamble_and_sync_manchester, idm_preamble_and_sync_length, 1 },
{ },
@@ -91,6 +104,7 @@ private:
void consume_symbol(const float symbol);
void scm_handler(const baseband::Packet& packet);
void scmplus_handler(const baseband::Packet& packet);
void idm_handler(const baseband::Packet& packet);
float sum_half_period[2];
+29 -12
View File
@@ -49,7 +49,7 @@ void SigGenProcessor::execute(const buffer_c8_t& buffer) {
// Sine
sample = (sine_table_i8[(tone_phase & 0xFF000000) >> 24]);
} else if (tone_shape == 2) {
// Tri
// Triangle
int8_t a = (tone_phase & 0xFF000000) >> 24;
sample = (a & 0x80) ? ((a << 1) ^ 0xFF) - 0x80 : (a << 1) + 0x80;
} else if (tone_shape == 3) {
@@ -61,24 +61,40 @@ void SigGenProcessor::execute(const buffer_c8_t& buffer) {
} else if (tone_shape == 5) {
// Square
sample = (((tone_phase & 0xFF000000) >> 24) & 0x80) ? 127 : -128;
} else if (tone_shape == 6) {
// Noise
sample = (lfsr & 0xFF000000) >> 24;
feedback = ((lfsr >> 31) ^ (lfsr >> 29) ^ (lfsr >> 15) ^ (lfsr >> 11)) & 1;
lfsr = (lfsr << 1) | feedback;
if (!lfsr) lfsr = 0x1337; // Shouldn't do this :(
} else if (tone_shape == 6) {
// Noise generator, pseudo random noise generator, 16 bits linear-feedback shift register (LFSR) algorithm, variant Fibonacci.
// https://en.wikipedia.org/wiki/Linear-feedback_shift_register
// 16 bits LFSR .taps: 16, 15, 13, 4 ;feedback polynomial: x^16 + x^15 + x^13 + x^4 + 1
// Periode 65535= 2^n-1, quite continuous .
if (counter == 0) { // we slow down the shift register, because the pseudo random noise clock freq was too high for modulator.
bit_16 = ((lfsr_16 >> 0) ^ (lfsr_16 >> 1) ^ (lfsr_16 >> 3) ^ (lfsr_16 >> 4) ^ (lfsr_16 >> 12) & 1);
lfsr_16 = (lfsr_16 >> 1) | (bit_16 << 15);
sample = (lfsr_16 & 0x00FF); // main pseudo random noise generator.
}
if (counter == 5) { // after many empiric test, that combination mix of >>4 and >>5, gives a reasonable trade off white noise / good rf power level .
sample = ((lfsr_16 & 0b0000111111110000) >> 4); // just changing the spectrum shape .
}
if (counter == 10) {
sample = ((lfsr_16 & 0b0001111111100000) >> 5); // just changing the spectrum shape .
}
counter++;
if (counter ==15) {
counter=0;
}
}
if (tone_shape < 6) { // we are in periodic signals, we need tone phases update.
tone_phase += tone_delta;
}
tone_phase += tone_delta;
// Do FM
// Do FM modulation
delta = sample * fm_delta;
phase += delta;
sphase = phase + (64 << 24);
re = (sine_table_i8[(sphase & 0xFF000000) >> 24]);
im = (sine_table_i8[(phase & 0xFF000000) >> 24]);
im = (sine_table_i8[( phase & 0xFF000000) >> 24]);
}
buffer.p[i] = {re, im};
@@ -104,7 +120,8 @@ void SigGenProcessor::on_message(const Message* const msg) {
fm_delta = message.bw * (0xFFFFFFULL / 1536000);
tone_shape = message.shape;
lfsr = 0x54DF0119;
// lfsr = seed_value ; // Finally not used , init lfsr 8 bits.
lfsr_16 = seed_value_16; // init lfsr 16 bits.
configured = true;
break;
+10 -6
View File
@@ -38,14 +38,18 @@ private:
BasebandThread baseband_thread { 1536000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
uint32_t tone_delta { 0 }, fm_delta { };
uint32_t lfsr { }, feedback { }, tone_shape { };
uint32_t tone_delta { 0 }, fm_delta { },tone_phase { 0 };
uint8_t tone_shape { };
uint32_t sample_count { 0 };
bool auto_off { };
uint32_t tone_phase { 0 }, phase { 0 }, delta { 0 }, sphase { 0 };
int8_t sample { 0 };
int8_t re { 0 }, im { 0 };
int32_t phase { 0 }, sphase { 0 }, delta { 0 }; // they may have sign in the pseudo random sample generation.
int8_t sample { 0 }, re { 0 }, im { 0 }; // they have sign + and -.
uint16_t seed_value_16 = {0xACE1}; // seed 16 bits lfsr : any nonzero start state will work.
uint16_t lfsr_16 { }, bit_16 { }; // bit must be 16-bit to allow bit<<15 later in the code */
uint8_t counter {0};
// uint8_t seed_value = {0x56}; // Finally not used lfsr of 8 bits , seed 8blfsr : any nonzero start state will work.
// uint8_t lfsr { }, bit { }; // Finally not used lfsr of 8 bits , bit must be 8-bit to allow bit<<7 later in the code */
TXProgressMessage txprogress_message { };
};
@@ -45,3 +45,5 @@ int main() {
return 0;
}
void update_performance_counters() {}
@@ -508,7 +508,7 @@ static const std::array<scu_setup_t, 26> pins_setup_portapack { {
{ 2, 1, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* U0_RXD: PortaPack P2_1/ADDR */
{ 2, 3, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* I2C1_SDA: PortaPack P2_3/LCD_TE */
{ 2, 4, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* I2C1_SCL: PortaPack P2_4/LCD_RDX */
{ 2, 8, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* P2_8: 10K PD, BOOT2, DFU switch, PortaPack P2_8/<unused> */
{ 2, 8, scu_config_normal_drive_t { .mode=1, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=1 } }, /* P2_8: 10K PD, BOOT2, DFU switch, PortaPack P2_8/<unused> */
{ 2, 9, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* P2_9: 10K PD, BOOT3, PortaPack P2_9/LCD_WRX */
{ 2, 13, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* P2_13: PortaPack P2_13/DIR */
{ 7, 0, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* GPIO3_8: PortaPack GPIO3_8(IO) */
+4 -4
View File
@@ -33,7 +33,7 @@
namespace portapack {
namespace cpld {
bool update_if_necessary(
CpldUpdateStatus update_if_necessary(
const Config config
) {
jtag::GPIOTarget target {
@@ -51,7 +51,7 @@ bool update_if_necessary(
/* Run-Test/Idle */
if( !cpld.idcode_ok() ) {
return false;
return CpldUpdateStatus::Idcode_check_failed;
}
cpld.sample();
@@ -62,7 +62,7 @@ bool update_if_necessary(
* in passive state.
*/
if( !cpld.silicon_id_ok() ) {
return false;
return CpldUpdateStatus::Silicon_id_check_failed;
}
/* Verify CPLD contents against current bitstream. */
@@ -86,7 +86,7 @@ bool update_if_necessary(
cpld.disable();
}
return ok;
return ok ? CpldUpdateStatus::Success : CpldUpdateStatus::Program_failed;
}
} /* namespace cpld */
+8 -1
View File
@@ -27,7 +27,14 @@
namespace portapack {
namespace cpld {
bool update_if_necessary(
enum class CpldUpdateStatus {
Success = 0,
Idcode_check_failed = 1,
Silicon_id_check_failed = 2,
Program_failed = 3
};
CpldUpdateStatus update_if_necessary(
const Config config
);
+12 -2
View File
@@ -47,6 +47,9 @@ ID Packet::id() const {
const auto lsb = reader_.read(35, 24);
return (msb << 24) | lsb;
}
if( type() == Type::SCMPLUS ) {
return reader_.read(2 * 8, 32);
}
if( type() == Type::IDM ) {
return reader_.read(5 * 8, 32);
}
@@ -57,6 +60,9 @@ Consumption Packet::consumption() const {
if( type() == Type::SCM ) {
return reader_.read(11, 24);
}
if( type() == Type::SCMPLUS ) {
return reader_.read(6 * 8, 32);
}
if( type() == Type::IDM ) {
return reader_.read(25 * 8, 32);
}
@@ -67,6 +73,9 @@ CommodityType Packet::commodity_type() const {
if( type() == Type::SCM ) {
return reader_.read(5, 4);
}
if( type() == Type::SCMPLUS ) {
return reader_.read(1 * 8 + 4, 4);
}
if( type() == Type::IDM ) {
return reader_.read(4 * 8 + 4, 4);
}
@@ -80,7 +89,8 @@ FormattedSymbols Packet::symbols_formatted() const {
bool Packet::crc_ok() const {
switch(type()) {
case Type::SCM: return crc_ok_scm();
case Type::IDM: return crc_ok_idm();
case Type::SCMPLUS:
case Type::IDM: return crc_ok_ccitt();
default: return false;
}
}
@@ -95,7 +105,7 @@ bool Packet::crc_ok_scm() const {
return ert_bch.checksum() == 0x0000;
}
bool Packet::crc_ok_idm() const {
bool Packet::crc_ok_ccitt() const {
CRC<16> ert_crc_ccitt { 0x1021, 0xffff, 0x1d0f };
for(size_t i=0; i<length(); i+=8) {
ert_crc_ccitt.process_byte(reader_.read(i, 8));
+2 -1
View File
@@ -45,6 +45,7 @@ public:
Unknown = 0,
IDM = 1,
SCM = 2,
SCMPLUS = 3,
};
Packet(
@@ -80,7 +81,7 @@ private:
const Reader reader_;
const Type type_;
bool crc_ok_idm() const;
bool crc_ok_ccitt() const;
bool crc_ok_scm() const;
};
+57
View File
@@ -0,0 +1,57 @@
/*
* 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 "performance_counter.hpp"
#include "ch.h"
uint8_t get_cpu_utilisation_in_percent() {
static systime_t last_time = 0;
static systime_t last_idle_ticks = 0;
auto now = chTimeNow();
auto idle_ticks = chThdGetTicks(chSysGetIdleThread());
if (last_time == 0) {
last_time = now;
last_idle_ticks = idle_ticks;
return 0;
}
int32_t time_elapsed = now - last_time;
int32_t idle_elapsed = idle_ticks - last_idle_ticks;
int32_t working_ticks = time_elapsed - idle_elapsed;
if (working_ticks < 0)
working_ticks = 0;
auto utilisation = working_ticks * 100 / time_elapsed;
last_time = now;
last_idle_ticks = idle_ticks;
if (utilisation > 100) {
return 100;
}
return (uint8_t) utilisation;
}
+29
View File
@@ -0,0 +1,29 @@
/*
* 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 __PERFORMANCE_COUNTER_H__
#define __PERFORMANCE_COUNTER_H__
#include <stdint.h>
uint8_t get_cpu_utilisation_in_percent();
#endif /* __PERFORMANCE_COUNTER_H__ */
+1 -1
View File
@@ -36,7 +36,7 @@ namespace portapack {
constexpr GPIO gpio_io_stbx = gpio[GPIO5_0]; /* P2_0 */
constexpr GPIO gpio_addr = gpio[GPIO5_1]; /* P2_1 */
constexpr GPIO gpio_lcd_te = gpio[GPIO5_3]; /* P2_3 */
constexpr GPIO gpio_unused = gpio[GPIO5_7]; /* P2_8 */
constexpr GPIO gpio_dfu = gpio[GPIO5_7]; /* P2_8 */
constexpr GPIO gpio_lcd_rdx = gpio[GPIO5_4]; /* P2_4 */
constexpr GPIO gpio_lcd_wrx = gpio[GPIO1_10]; /* P2_9 */
constexpr GPIO gpio_dir = gpio[GPIO1_13]; /* P2_13 */
+2 -1
View File
@@ -110,7 +110,8 @@ uint32_t IO::io_update(const TouchPinsConfig write_value) {
}
gpio_addr.write(addr);
return switches_raw;
auto dfu_btn = portapack::io.dfu_read() & 0x01;
return (switches_raw & 0x7f) | (dfu_btn << 7);
}
}
+4
View File
@@ -214,6 +214,10 @@ public:
return gpio_rot_a.read();
}
uint32_t dfu_read() {
return gpio_rot_b.read();
}
private:
const GPIO gpio_dir;
const GPIO gpio_lcd_rdx;
@@ -64,6 +64,12 @@ struct SharedMemory {
JammerChannel jammer_channels[24];
uint8_t data[512];
} bb_data { { { { 0, 0 } }, 0, { 0 } } };
uint8_t volatile request_m4_performance_counter{ 0 };
uint8_t volatile m4_cpu_usage{ 0 };
uint16_t volatile m4_stack_usage{ 0 };
uint16_t volatile m4_heap_usage{ 0 };
uint16_t volatile m4_buffer_missed{ 0 };
};
extern SharedMemory& shared_memory;
+15
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Early 2023 joyel24 added meteomodem M20 support
*
* This file is part of PortaPack.
*
@@ -64,6 +65,8 @@ Packet::Packet(
type_ = Type::Meteomodem_M10;
else if (id_byte == 0x648F)
type_ = Type::Meteomodem_M2K2;
else if (id_byte == 0x4520) //https://raw.githubusercontent.com/projecthorus/radiosonde_auto_rx/master/demod/mod/m20mod.c
type_ = Type::Meteomodem_M20;
}
}
@@ -109,6 +112,12 @@ GPS_data Packet::get_GPS_data() const
result.lat = reader_bi_m.read(14 * 8, 32) / ((1ULL << 32) / 360.0);
result.lon = reader_bi_m.read(18 * 8, 32) / ((1ULL << 32) / 360.0);
}
else if (type_ == Type::Meteomodem_M20)
{
result.alt = reader_bi_m.read(8 * 8, 24) / 100.0 ; // <|
result.lat = reader_bi_m.read(28 * 8, 32) / 1000000.0 ; // <| Inspired by https://raw.githubusercontent.com/projecthorus/radiosonde_auto_rx/master/demod/mod/m20mod.c
result.lon = reader_bi_m.read(32 * 8, 32) / 1000000.0 ; // <|
}
else if (type_ == Type::Vaisala_RS41_SG)
{
@@ -147,6 +156,10 @@ uint32_t Packet::battery_voltage() const
{
if (type_ == Type::Meteomodem_M10)
return (reader_bi_m.read(69 * 8, 8) + (reader_bi_m.read(70 * 8, 8) << 8)) * 1000 / 150;
else if (type_ == Type::Meteomodem_M20)
{
return 0; //NOT SUPPPORTED YET
}
else if (type_ == Type::Meteomodem_M2K2)
return reader_bi_m.read(69 * 8, 8) * 66; // Actually 65.8
else if (type_ == Type::Vaisala_RS41_SG)
@@ -279,6 +292,8 @@ std::string Packet::type_string() const
return "Meteomodem ???";
case Type::Meteomodem_M10:
return "Meteomodem M10";
case Type::Meteomodem_M20:
return "Meteomodem M20";
case Type::Meteomodem_M2K2:
return "Meteomodem M2K2";
case Type::Vaisala_RS41_SG:
+1
View File
@@ -51,6 +51,7 @@ public:
Meteomodem_M10 = 2,
Meteomodem_M2K2 = 3,
Vaisala_RS41_SG = 4,
Meteomodem_M20 = 5,
};
Packet(const baseband::Packet& packet, const Type type);
+2 -1
View File
@@ -325,7 +325,8 @@ enum class KeyEvent {
Down = 2,
Up = 3,
Select = 4,
Back = 5, /* Left and Up together */
Dfu = 5,
Back = 6, /* Left and Up together */
};
using EncoderEvent = int32_t;
+2 -2
View File
@@ -43,7 +43,7 @@ int Painter::draw_char(const Point p, const Style& style, const char c) {
}
int Painter::draw_string(Point p, const Font& font, const Color foreground,
const Color background, const std::string text) {
const Color background, const std::string& text) {
bool escape = false;
size_t width = 0;
@@ -71,7 +71,7 @@ int Painter::draw_string(Point p, const Font& font, const Color foreground,
return width;
}
int Painter::draw_string(Point p, const Style& style, const std::string text) {
int Painter::draw_string(Point p, const Style& style, const std::string& text) {
return draw_string(p, style.font, style.foreground, style.background, text);
}
+2 -2
View File
@@ -49,8 +49,8 @@ public:
int draw_char(const Point p, const Style& style, const char c);
int draw_string(Point p, const Font& font, const Color foreground,
const Color background, const std::string text);
int draw_string(Point p, const Style& style, const std::string text);
const Color background, const std::string& text);
int draw_string(Point p, const Style& style, const std::string& text);
void draw_bitmap(const Point p, const Bitmap& bitmap, const Color background, const Color foreground);
+2
View File
@@ -12,4 +12,6 @@ pause
echo.
hackrf_update.exe portapack-h1_h2-mayhem.bin
echo.
echo If your device never boot after flashing, please refer to https://github.com/eried/portapack-mayhem/wiki/Won't-boot
echo.
pause
Regular → Executable
BIN
View File
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,986 @@
ISO-10303-21;
HEADER;
/* Generated by software containing ST-Developer
* from STEP Tools, Inc. (www.steptools.com)
*/
FILE_DESCRIPTION(
/* description */ (''),
/* implementation_level */ '2;1');
FILE_NAME(
/* name */
'D:\\OneDrive\\Projects\\RepRap\\HackRF\\REVISITED\\revisited_support.
stp',
/* time_stamp */ '2023-04-11T09:54:07+02:00',
/* author */ ('erwin'),
/* organization */ (''),
/* preprocessor_version */ 'ST-DEVELOPER v18.1',
/* originating_system */ 'Autodesk Inventor 2022',
/* authorisation */ '');
FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
ENDSEC;
DATA;
#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#13),#883);
#11=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#890,#12);
#12=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#14),#882);
#13=STYLED_ITEM('',(#899),#14);
#14=MANIFOLD_SOLID_BREP('Solid1',#461);
#15=FACE_BOUND('',#135,.T.);
#16=FACE_BOUND('',#136,.T.);
#17=FACE_BOUND('',#142,.T.);
#18=FACE_BOUND('',#145,.T.);
#19=CONICAL_SURFACE('',#515,1.50402,0.785398163397446);
#20=CONICAL_SURFACE('',#525,1.50402,0.785398163397446);
#21=CONICAL_SURFACE('',#530,1.50402,0.785398163397446);
#22=CONICAL_SURFACE('',#533,1.50402,0.785398163397446);
#23=PLANE('',#491);
#24=PLANE('',#500);
#25=PLANE('',#501);
#26=PLANE('',#510);
#27=PLANE('',#518);
#28=PLANE('',#532);
#29=PLANE('',#535);
#30=LINE('',#735,#56);
#31=LINE('',#738,#57);
#32=LINE('',#740,#58);
#33=LINE('',#787,#59);
#34=LINE('',#792,#60);
#35=LINE('',#796,#61);
#36=LINE('',#799,#62);
#37=LINE('',#802,#63);
#38=LINE('',#806,#64);
#39=LINE('',#807,#65);
#40=LINE('',#810,#66);
#41=LINE('',#812,#67);
#42=LINE('',#813,#68);
#43=LINE('',#818,#69);
#44=LINE('',#821,#70);
#45=LINE('',#826,#71);
#46=LINE('',#829,#72);
#47=LINE('',#833,#73);
#48=LINE('',#834,#74);
#49=LINE('',#843,#75);
#50=LINE('',#855,#76);
#51=LINE('',#859,#77);
#52=LINE('',#865,#78);
#53=LINE('',#870,#79);
#54=LINE('',#875,#80);
#55=LINE('',#878,#81);
#56=VECTOR('',#550,3.00804);
#57=VECTOR('',#553,10.);
#58=VECTOR('',#554,10.);
#59=VECTOR('',#567,10.);
#60=VECTOR('',#572,10.);
#61=VECTOR('',#577,8.02144);
#62=VECTOR('',#580,10.);
#63=VECTOR('',#583,10.0268);
#64=VECTOR('',#588,7.01876);
#65=VECTOR('',#589,10.0268);
#66=VECTOR('',#592,10.);
#67=VECTOR('',#593,10.0268);
#68=VECTOR('',#594,10.);
#69=VECTOR('',#599,3.00804);
#70=VECTOR('',#602,10.);
#71=VECTOR('',#609,10.);
#72=VECTOR('',#612,10.);
#73=VECTOR('',#617,10.);
#74=VECTOR('',#618,10.0268);
#75=VECTOR('',#631,1.50402);
#76=VECTOR('',#646,1.25335);
#77=VECTOR('',#651,1.50402);
#78=VECTOR('',#658,1.25335);
#79=VECTOR('',#665,1.50402);
#80=VECTOR('',#672,1.50402);
#81=VECTOR('',#677,10.);
#82=CYLINDRICAL_SURFACE('',#484,3.00804);
#83=CYLINDRICAL_SURFACE('',#496,8.02144);
#84=CYLINDRICAL_SURFACE('',#498,7.01876);
#85=CYLINDRICAL_SURFACE('',#502,3.00804);
#86=CYLINDRICAL_SURFACE('',#506,8.02144);
#87=CYLINDRICAL_SURFACE('',#508,8.02144);
#88=CYLINDRICAL_SURFACE('',#511,7.01876);
#89=CYLINDRICAL_SURFACE('',#513,7.01876);
#90=CYLINDRICAL_SURFACE('',#522,1.15335);
#91=CYLINDRICAL_SURFACE('',#527,1.15335);
#92=CYLINDRICAL_SURFACE('',#536,7.01876);
#93=CYLINDRICAL_SURFACE('',#537,8.02144);
#94=FACE_OUTER_BOUND('',#119,.T.);
#95=FACE_OUTER_BOUND('',#120,.T.);
#96=FACE_OUTER_BOUND('',#121,.T.);
#97=FACE_OUTER_BOUND('',#122,.T.);
#98=FACE_OUTER_BOUND('',#123,.T.);
#99=FACE_OUTER_BOUND('',#124,.T.);
#100=FACE_OUTER_BOUND('',#125,.T.);
#101=FACE_OUTER_BOUND('',#126,.T.);
#102=FACE_OUTER_BOUND('',#127,.T.);
#103=FACE_OUTER_BOUND('',#128,.T.);
#104=FACE_OUTER_BOUND('',#129,.T.);
#105=FACE_OUTER_BOUND('',#130,.T.);
#106=FACE_OUTER_BOUND('',#131,.T.);
#107=FACE_OUTER_BOUND('',#132,.T.);
#108=FACE_OUTER_BOUND('',#133,.T.);
#109=FACE_OUTER_BOUND('',#134,.T.);
#110=FACE_OUTER_BOUND('',#137,.T.);
#111=FACE_OUTER_BOUND('',#138,.T.);
#112=FACE_OUTER_BOUND('',#139,.T.);
#113=FACE_OUTER_BOUND('',#140,.T.);
#114=FACE_OUTER_BOUND('',#141,.T.);
#115=FACE_OUTER_BOUND('',#143,.T.);
#116=FACE_OUTER_BOUND('',#144,.T.);
#117=FACE_OUTER_BOUND('',#146,.T.);
#118=FACE_OUTER_BOUND('',#147,.T.);
#119=EDGE_LOOP('',(#300,#301,#302,#303,#304,#305,#306));
#120=EDGE_LOOP('',(#307,#308,#309,#310,#311,#312,#313,#314));
#121=EDGE_LOOP('',(#315,#316,#317,#318,#319,#320));
#122=EDGE_LOOP('',(#321,#322,#323,#324,#325,#326,#327,#328));
#123=EDGE_LOOP('',(#329,#330,#331,#332));
#124=EDGE_LOOP('',(#333,#334,#335,#336,#337));
#125=EDGE_LOOP('',(#338,#339,#340,#341));
#126=EDGE_LOOP('',(#342,#343,#344,#345));
#127=EDGE_LOOP('',(#346,#347,#348,#349,#350,#351,#352,#353));
#128=EDGE_LOOP('',(#354,#355,#356,#357));
#129=EDGE_LOOP('',(#358,#359,#360,#361));
#130=EDGE_LOOP('',(#362,#363,#364,#365));
#131=EDGE_LOOP('',(#366,#367,#368,#369,#370));
#132=EDGE_LOOP('',(#371,#372,#373,#374,#375));
#133=EDGE_LOOP('',(#376,#377,#378,#379));
#134=EDGE_LOOP('',(#380,#381,#382,#383,#384,#385,#386,#387,#388,#389,#390,
#391,#392,#393,#394));
#135=EDGE_LOOP('',(#395));
#136=EDGE_LOOP('',(#396));
#137=EDGE_LOOP('',(#397,#398,#399,#400,#401));
#138=EDGE_LOOP('',(#402,#403,#404,#405));
#139=EDGE_LOOP('',(#406,#407,#408,#409,#410));
#140=EDGE_LOOP('',(#411,#412,#413,#414,#415));
#141=EDGE_LOOP('',(#416));
#142=EDGE_LOOP('',(#417));
#143=EDGE_LOOP('',(#418,#419,#420,#421,#422));
#144=EDGE_LOOP('',(#423));
#145=EDGE_LOOP('',(#424));
#146=EDGE_LOOP('',(#425,#426,#427,#428,#429));
#147=EDGE_LOOP('',(#430,#431,#432,#433));
#148=CIRCLE('',#482,7.00804);
#149=CIRCLE('',#483,3.00804);
#150=CIRCLE('',#485,3.00804);
#151=CIRCLE('',#486,3.00804);
#152=CIRCLE('',#487,3.00804);
#153=CIRCLE('',#489,3.00804);
#154=CIRCLE('',#490,7.00804);
#155=CIRCLE('',#492,7.01876);
#156=CIRCLE('',#493,7.01876);
#157=CIRCLE('',#494,7.01876);
#158=CIRCLE('',#495,7.01876);
#159=CIRCLE('',#497,8.02144);
#160=CIRCLE('',#499,7.01876);
#161=CIRCLE('',#503,3.00804);
#162=CIRCLE('',#504,3.00804);
#163=CIRCLE('',#505,3.00804);
#164=CIRCLE('',#507,8.02144);
#165=CIRCLE('',#509,8.02144);
#166=CIRCLE('',#512,7.01876);
#167=CIRCLE('',#514,7.01876);
#168=CIRCLE('',#516,1.75469);
#169=CIRCLE('',#517,1.15335);
#170=CIRCLE('',#519,7.01876);
#171=CIRCLE('',#520,8.02144);
#172=CIRCLE('',#521,1.75469);
#173=CIRCLE('',#523,1.15335);
#174=CIRCLE('',#524,1.15335);
#175=CIRCLE('',#526,1.15335);
#176=CIRCLE('',#528,1.15335);
#177=CIRCLE('',#529,1.15335);
#178=CIRCLE('',#531,1.75469);
#179=CIRCLE('',#534,1.75469);
#180=B_SPLINE_CURVE_WITH_KNOTS('',3,(#684,#685,#686,#687,#688,#689),
.UNSPECIFIED.,.F.,.F.,(4,2,4),(1.84958971453185,1.88077149669059,1.89236508906971),
.UNSPECIFIED.);
#181=B_SPLINE_CURVE_WITH_KNOTS('',3,(#693,#694,#695,#696,#697,#698),
.UNSPECIFIED.,.F.,.F.,(4,2,4),(0.677497757408314,0.788403142650085,0.821392408392587),
.UNSPECIFIED.);
#182=B_SPLINE_CURVE_WITH_KNOTS('',3,(#700,#701,#702,#703,#704,#705),
.UNSPECIFIED.,.F.,.F.,(4,2,4),(0.718120459763341,0.755157597858511,0.76176835105742),
.UNSPECIFIED.);
#183=B_SPLINE_CURVE_WITH_KNOTS('',3,(#707,#708,#709,#710,#711,#712,#713,
#714,#715,#716),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,4),(1.8094458082449,1.88790790479797,
2.05305157993795,2.26943298100183,2.27022614805197),.UNSPECIFIED.);
#184=B_SPLINE_CURVE_WITH_KNOTS('',3,(#719,#720,#721,#722,#723,#724,#725,
#726,#727,#728,#729,#730),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,2,4),(-0.000793167050811743,
0.,0.216381428611185,0.381525135470128,0.509883396641204,0.567800192420913),
.UNSPECIFIED.);
#185=B_SPLINE_CURVE_WITH_KNOTS('',3,(#745,#746,#747,#748,#749,#750,#751,
#752,#753,#754,#755,#756),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,2,4),(1.71827230670034,
1.75955118014646,1.88790953171987,2.05305335488903,2.26943488454831,2.27022805161283),
.UNSPECIFIED.);
#186=B_SPLINE_CURVE_WITH_KNOTS('',3,(#760,#761,#762,#763,#764,#765,#766,
#767),.UNSPECIFIED.,.F.,.F.,(4,2,2,4),(-0.000793167053338841,0.,0.216381446124703,
0.281282906842762),.UNSPECIFIED.);
#187=B_SPLINE_CURVE_WITH_KNOTS('',3,(#769,#770,#771,#772,#773,#774,#775,
#776),.UNSPECIFIED.,.F.,.F.,(4,2,2,4),(4.43658033669356,4.60723589928881,
4.776503081225,4.8535852884345),.UNSPECIFIED.);
#188=B_SPLINE_CURVE_WITH_KNOTS('',3,(#779,#780,#781,#782),.UNSPECIFIED.,
.F.,.F.,(4,4),(0.661852334486626,0.723354146244754),.UNSPECIFIED.);
#189=VERTEX_POINT('',#682);
#190=VERTEX_POINT('',#683);
#191=VERTEX_POINT('',#690);
#192=VERTEX_POINT('',#692);
#193=VERTEX_POINT('',#699);
#194=VERTEX_POINT('',#706);
#195=VERTEX_POINT('',#717);
#196=VERTEX_POINT('',#732);
#197=VERTEX_POINT('',#734);
#198=VERTEX_POINT('',#736);
#199=VERTEX_POINT('',#739);
#200=VERTEX_POINT('',#743);
#201=VERTEX_POINT('',#744);
#202=VERTEX_POINT('',#757);
#203=VERTEX_POINT('',#759);
#204=VERTEX_POINT('',#768);
#205=VERTEX_POINT('',#777);
#206=VERTEX_POINT('',#784);
#207=VERTEX_POINT('',#786);
#208=VERTEX_POINT('',#789);
#209=VERTEX_POINT('',#791);
#210=VERTEX_POINT('',#795);
#211=VERTEX_POINT('',#797);
#212=VERTEX_POINT('',#801);
#213=VERTEX_POINT('',#805);
#214=VERTEX_POINT('',#809);
#215=VERTEX_POINT('',#811);
#216=VERTEX_POINT('',#815);
#217=VERTEX_POINT('',#817);
#218=VERTEX_POINT('',#819);
#219=VERTEX_POINT('',#824);
#220=VERTEX_POINT('',#828);
#221=VERTEX_POINT('',#832);
#222=VERTEX_POINT('',#840);
#223=VERTEX_POINT('',#842);
#224=VERTEX_POINT('',#846);
#225=VERTEX_POINT('',#849);
#226=VERTEX_POINT('',#852);
#227=VERTEX_POINT('',#853);
#228=VERTEX_POINT('',#858);
#229=VERTEX_POINT('',#862);
#230=VERTEX_POINT('',#863);
#231=VERTEX_POINT('',#868);
#232=VERTEX_POINT('',#873);
#233=EDGE_CURVE('',#189,#190,#180,.T.);
#234=EDGE_CURVE('',#190,#191,#148,.T.);
#235=EDGE_CURVE('',#191,#192,#181,.T.);
#236=EDGE_CURVE('',#193,#192,#182,.F.);
#237=EDGE_CURVE('',#194,#193,#183,.F.);
#238=EDGE_CURVE('',#194,#195,#149,.T.);
#239=EDGE_CURVE('',#195,#189,#184,.T.);
#240=EDGE_CURVE('',#196,#196,#150,.T.);
#241=EDGE_CURVE('',#196,#197,#30,.T.);
#242=EDGE_CURVE('',#198,#197,#151,.T.);
#243=EDGE_CURVE('',#198,#195,#31,.T.);
#244=EDGE_CURVE('',#194,#199,#32,.T.);
#245=EDGE_CURVE('',#197,#199,#152,.T.);
#246=EDGE_CURVE('',#200,#201,#185,.F.);
#247=EDGE_CURVE('',#200,#202,#153,.T.);
#248=EDGE_CURVE('',#202,#203,#186,.T.);
#249=EDGE_CURVE('',#204,#203,#187,.F.);
#250=EDGE_CURVE('',#204,#205,#154,.T.);
#251=EDGE_CURVE('',#201,#205,#188,.F.);
#252=EDGE_CURVE('',#206,#190,#155,.F.);
#253=EDGE_CURVE('',#206,#207,#33,.T.);
#254=EDGE_CURVE('',#207,#205,#156,.T.);
#255=EDGE_CURVE('',#208,#204,#157,.F.);
#256=EDGE_CURVE('',#208,#209,#34,.T.);
#257=EDGE_CURVE('',#191,#209,#158,.F.);
#258=EDGE_CURVE('',#201,#210,#35,.T.);
#259=EDGE_CURVE('',#210,#211,#159,.T.);
#260=EDGE_CURVE('',#211,#200,#36,.T.);
#261=EDGE_CURVE('',#207,#212,#37,.T.);
#262=EDGE_CURVE('',#212,#210,#160,.T.);
#263=EDGE_CURVE('',#213,#206,#38,.T.);
#264=EDGE_CURVE('',#213,#212,#39,.T.);
#265=EDGE_CURVE('',#208,#214,#40,.T.);
#266=EDGE_CURVE('',#214,#215,#41,.F.);
#267=EDGE_CURVE('',#215,#209,#42,.F.);
#268=EDGE_CURVE('',#216,#216,#161,.T.);
#269=EDGE_CURVE('',#216,#217,#43,.T.);
#270=EDGE_CURVE('',#217,#218,#162,.T.);
#271=EDGE_CURVE('',#218,#202,#44,.T.);
#272=EDGE_CURVE('',#211,#217,#163,.T.);
#273=EDGE_CURVE('',#198,#219,#164,.T.);
#274=EDGE_CURVE('',#189,#219,#45,.T.);
#275=EDGE_CURVE('',#193,#220,#46,.F.);
#276=EDGE_CURVE('',#220,#199,#165,.T.);
#277=EDGE_CURVE('',#192,#221,#47,.T.);
#278=EDGE_CURVE('',#221,#220,#48,.F.);
#279=EDGE_CURVE('',#215,#221,#166,.T.);
#280=EDGE_CURVE('',#219,#213,#167,.T.);
#281=EDGE_CURVE('',#222,#222,#168,.T.);
#282=EDGE_CURVE('',#222,#223,#49,.T.);
#283=EDGE_CURVE('',#223,#223,#169,.F.);
#284=EDGE_CURVE('',#214,#224,#170,.F.);
#285=EDGE_CURVE('',#218,#224,#171,.T.);
#286=EDGE_CURVE('',#225,#225,#172,.T.);
#287=EDGE_CURVE('',#226,#227,#173,.F.);
#288=EDGE_CURVE('',#226,#223,#50,.T.);
#289=EDGE_CURVE('',#227,#226,#174,.F.);
#290=EDGE_CURVE('',#225,#228,#51,.T.);
#291=EDGE_CURVE('',#228,#228,#175,.F.);
#292=EDGE_CURVE('',#229,#230,#176,.F.);
#293=EDGE_CURVE('',#229,#228,#52,.T.);
#294=EDGE_CURVE('',#230,#229,#177,.F.);
#295=EDGE_CURVE('',#231,#231,#178,.T.);
#296=EDGE_CURVE('',#231,#230,#53,.T.);
#297=EDGE_CURVE('',#232,#232,#179,.T.);
#298=EDGE_CURVE('',#232,#227,#54,.T.);
#299=EDGE_CURVE('',#203,#224,#55,.F.);
#300=ORIENTED_EDGE('',*,*,#233,.T.);
#301=ORIENTED_EDGE('',*,*,#234,.T.);
#302=ORIENTED_EDGE('',*,*,#235,.T.);
#303=ORIENTED_EDGE('',*,*,#236,.F.);
#304=ORIENTED_EDGE('',*,*,#237,.F.);
#305=ORIENTED_EDGE('',*,*,#238,.T.);
#306=ORIENTED_EDGE('',*,*,#239,.T.);
#307=ORIENTED_EDGE('',*,*,#240,.T.);
#308=ORIENTED_EDGE('',*,*,#241,.T.);
#309=ORIENTED_EDGE('',*,*,#242,.F.);
#310=ORIENTED_EDGE('',*,*,#243,.T.);
#311=ORIENTED_EDGE('',*,*,#238,.F.);
#312=ORIENTED_EDGE('',*,*,#244,.T.);
#313=ORIENTED_EDGE('',*,*,#245,.F.);
#314=ORIENTED_EDGE('',*,*,#241,.F.);
#315=ORIENTED_EDGE('',*,*,#246,.F.);
#316=ORIENTED_EDGE('',*,*,#247,.T.);
#317=ORIENTED_EDGE('',*,*,#248,.T.);
#318=ORIENTED_EDGE('',*,*,#249,.F.);
#319=ORIENTED_EDGE('',*,*,#250,.T.);
#320=ORIENTED_EDGE('',*,*,#251,.F.);
#321=ORIENTED_EDGE('',*,*,#234,.F.);
#322=ORIENTED_EDGE('',*,*,#252,.F.);
#323=ORIENTED_EDGE('',*,*,#253,.T.);
#324=ORIENTED_EDGE('',*,*,#254,.T.);
#325=ORIENTED_EDGE('',*,*,#250,.F.);
#326=ORIENTED_EDGE('',*,*,#255,.F.);
#327=ORIENTED_EDGE('',*,*,#256,.T.);
#328=ORIENTED_EDGE('',*,*,#257,.F.);
#329=ORIENTED_EDGE('',*,*,#258,.T.);
#330=ORIENTED_EDGE('',*,*,#259,.T.);
#331=ORIENTED_EDGE('',*,*,#260,.T.);
#332=ORIENTED_EDGE('',*,*,#246,.T.);
#333=ORIENTED_EDGE('',*,*,#254,.F.);
#334=ORIENTED_EDGE('',*,*,#261,.T.);
#335=ORIENTED_EDGE('',*,*,#262,.T.);
#336=ORIENTED_EDGE('',*,*,#258,.F.);
#337=ORIENTED_EDGE('',*,*,#251,.T.);
#338=ORIENTED_EDGE('',*,*,#253,.F.);
#339=ORIENTED_EDGE('',*,*,#263,.F.);
#340=ORIENTED_EDGE('',*,*,#264,.T.);
#341=ORIENTED_EDGE('',*,*,#261,.F.);
#342=ORIENTED_EDGE('',*,*,#256,.F.);
#343=ORIENTED_EDGE('',*,*,#265,.T.);
#344=ORIENTED_EDGE('',*,*,#266,.T.);
#345=ORIENTED_EDGE('',*,*,#267,.T.);
#346=ORIENTED_EDGE('',*,*,#268,.F.);
#347=ORIENTED_EDGE('',*,*,#269,.T.);
#348=ORIENTED_EDGE('',*,*,#270,.T.);
#349=ORIENTED_EDGE('',*,*,#271,.T.);
#350=ORIENTED_EDGE('',*,*,#247,.F.);
#351=ORIENTED_EDGE('',*,*,#260,.F.);
#352=ORIENTED_EDGE('',*,*,#272,.T.);
#353=ORIENTED_EDGE('',*,*,#269,.F.);
#354=ORIENTED_EDGE('',*,*,#243,.F.);
#355=ORIENTED_EDGE('',*,*,#273,.T.);
#356=ORIENTED_EDGE('',*,*,#274,.F.);
#357=ORIENTED_EDGE('',*,*,#239,.F.);
#358=ORIENTED_EDGE('',*,*,#275,.T.);
#359=ORIENTED_EDGE('',*,*,#276,.T.);
#360=ORIENTED_EDGE('',*,*,#244,.F.);
#361=ORIENTED_EDGE('',*,*,#237,.T.);
#362=ORIENTED_EDGE('',*,*,#277,.T.);
#363=ORIENTED_EDGE('',*,*,#278,.T.);
#364=ORIENTED_EDGE('',*,*,#275,.F.);
#365=ORIENTED_EDGE('',*,*,#236,.T.);
#366=ORIENTED_EDGE('',*,*,#257,.T.);
#367=ORIENTED_EDGE('',*,*,#267,.F.);
#368=ORIENTED_EDGE('',*,*,#279,.T.);
#369=ORIENTED_EDGE('',*,*,#277,.F.);
#370=ORIENTED_EDGE('',*,*,#235,.F.);
#371=ORIENTED_EDGE('',*,*,#252,.T.);
#372=ORIENTED_EDGE('',*,*,#233,.F.);
#373=ORIENTED_EDGE('',*,*,#274,.T.);
#374=ORIENTED_EDGE('',*,*,#280,.T.);
#375=ORIENTED_EDGE('',*,*,#263,.T.);
#376=ORIENTED_EDGE('',*,*,#281,.T.);
#377=ORIENTED_EDGE('',*,*,#282,.T.);
#378=ORIENTED_EDGE('',*,*,#283,.T.);
#379=ORIENTED_EDGE('',*,*,#282,.F.);
#380=ORIENTED_EDGE('',*,*,#259,.F.);
#381=ORIENTED_EDGE('',*,*,#262,.F.);
#382=ORIENTED_EDGE('',*,*,#264,.F.);
#383=ORIENTED_EDGE('',*,*,#280,.F.);
#384=ORIENTED_EDGE('',*,*,#273,.F.);
#385=ORIENTED_EDGE('',*,*,#242,.T.);
#386=ORIENTED_EDGE('',*,*,#245,.T.);
#387=ORIENTED_EDGE('',*,*,#276,.F.);
#388=ORIENTED_EDGE('',*,*,#278,.F.);
#389=ORIENTED_EDGE('',*,*,#279,.F.);
#390=ORIENTED_EDGE('',*,*,#266,.F.);
#391=ORIENTED_EDGE('',*,*,#284,.T.);
#392=ORIENTED_EDGE('',*,*,#285,.F.);
#393=ORIENTED_EDGE('',*,*,#270,.F.);
#394=ORIENTED_EDGE('',*,*,#272,.F.);
#395=ORIENTED_EDGE('',*,*,#281,.F.);
#396=ORIENTED_EDGE('',*,*,#286,.F.);
#397=ORIENTED_EDGE('',*,*,#287,.F.);
#398=ORIENTED_EDGE('',*,*,#288,.T.);
#399=ORIENTED_EDGE('',*,*,#283,.F.);
#400=ORIENTED_EDGE('',*,*,#288,.F.);
#401=ORIENTED_EDGE('',*,*,#289,.F.);
#402=ORIENTED_EDGE('',*,*,#286,.T.);
#403=ORIENTED_EDGE('',*,*,#290,.T.);
#404=ORIENTED_EDGE('',*,*,#291,.T.);
#405=ORIENTED_EDGE('',*,*,#290,.F.);
#406=ORIENTED_EDGE('',*,*,#292,.F.);
#407=ORIENTED_EDGE('',*,*,#293,.T.);
#408=ORIENTED_EDGE('',*,*,#291,.F.);
#409=ORIENTED_EDGE('',*,*,#293,.F.);
#410=ORIENTED_EDGE('',*,*,#294,.F.);
#411=ORIENTED_EDGE('',*,*,#295,.T.);
#412=ORIENTED_EDGE('',*,*,#296,.T.);
#413=ORIENTED_EDGE('',*,*,#294,.T.);
#414=ORIENTED_EDGE('',*,*,#292,.T.);
#415=ORIENTED_EDGE('',*,*,#296,.F.);
#416=ORIENTED_EDGE('',*,*,#240,.F.);
#417=ORIENTED_EDGE('',*,*,#295,.F.);
#418=ORIENTED_EDGE('',*,*,#297,.T.);
#419=ORIENTED_EDGE('',*,*,#298,.T.);
#420=ORIENTED_EDGE('',*,*,#289,.T.);
#421=ORIENTED_EDGE('',*,*,#287,.T.);
#422=ORIENTED_EDGE('',*,*,#298,.F.);
#423=ORIENTED_EDGE('',*,*,#268,.T.);
#424=ORIENTED_EDGE('',*,*,#297,.F.);
#425=ORIENTED_EDGE('',*,*,#255,.T.);
#426=ORIENTED_EDGE('',*,*,#249,.T.);
#427=ORIENTED_EDGE('',*,*,#299,.T.);
#428=ORIENTED_EDGE('',*,*,#284,.F.);
#429=ORIENTED_EDGE('',*,*,#265,.F.);
#430=ORIENTED_EDGE('',*,*,#271,.F.);
#431=ORIENTED_EDGE('',*,*,#285,.T.);
#432=ORIENTED_EDGE('',*,*,#299,.F.);
#433=ORIENTED_EDGE('',*,*,#248,.F.);
#434=TOROIDAL_SURFACE('',#481,7.00804000000001,4.);
#435=TOROIDAL_SURFACE('',#488,7.00804,4.);
#436=ADVANCED_FACE('',(#94),#434,.F.);
#437=ADVANCED_FACE('',(#95),#82,.T.);
#438=ADVANCED_FACE('',(#96),#435,.F.);
#439=ADVANCED_FACE('',(#97),#23,.T.);
#440=ADVANCED_FACE('',(#98),#83,.F.);
#441=ADVANCED_FACE('',(#99),#84,.T.);
#442=ADVANCED_FACE('',(#100),#24,.T.);
#443=ADVANCED_FACE('',(#101),#25,.T.);
#444=ADVANCED_FACE('',(#102),#85,.T.);
#445=ADVANCED_FACE('',(#103),#86,.F.);
#446=ADVANCED_FACE('',(#104),#87,.F.);
#447=ADVANCED_FACE('',(#105),#26,.T.);
#448=ADVANCED_FACE('',(#106),#88,.F.);
#449=ADVANCED_FACE('',(#107),#89,.T.);
#450=ADVANCED_FACE('',(#108),#19,.F.);
#451=ADVANCED_FACE('',(#109,#15,#16),#27,.T.);
#452=ADVANCED_FACE('',(#110),#90,.F.);
#453=ADVANCED_FACE('',(#111),#20,.F.);
#454=ADVANCED_FACE('',(#112),#91,.F.);
#455=ADVANCED_FACE('',(#113),#21,.F.);
#456=ADVANCED_FACE('',(#114,#17),#28,.T.);
#457=ADVANCED_FACE('',(#115),#22,.F.);
#458=ADVANCED_FACE('',(#116,#18),#29,.F.);
#459=ADVANCED_FACE('',(#117),#92,.F.);
#460=ADVANCED_FACE('',(#118),#93,.F.);
#461=CLOSED_SHELL('',(#436,#437,#438,#439,#440,#441,#442,#443,#444,#445,
#446,#447,#448,#449,#450,#451,#452,#453,#454,#455,#456,#457,#458,#459,#460));
#462=DERIVED_UNIT_ELEMENT(#464,1.);
#463=DERIVED_UNIT_ELEMENT(#885,-3.);
#464=(
MASS_UNIT()
NAMED_UNIT(*)
SI_UNIT($,.GRAM.)
);
#465=DERIVED_UNIT((#462,#463));
#466=MEASURE_REPRESENTATION_ITEM('density measure',
POSITIVE_RATIO_MEASURE(1.),#465);
#467=PROPERTY_DEFINITION_REPRESENTATION(#472,#469);
#468=PROPERTY_DEFINITION_REPRESENTATION(#473,#470);
#469=REPRESENTATION('material name',(#471),#882);
#470=REPRESENTATION('density',(#466),#882);
#471=DESCRIPTIVE_REPRESENTATION_ITEM('Generic','Generic');
#472=PROPERTY_DEFINITION('material property','material name',#892);
#473=PROPERTY_DEFINITION('material property','density of part',#892);
#474=DATE_TIME_ROLE('creation_date');
#475=APPLIED_DATE_AND_TIME_ASSIGNMENT(#476,#474,(#892));
#476=DATE_AND_TIME(#477,#478);
#477=CALENDAR_DATE(2020,5,10);
#478=LOCAL_TIME(0,0,0.,#479);
#479=COORDINATED_UNIVERSAL_TIME_OFFSET(0,0,.BEHIND.);
#480=AXIS2_PLACEMENT_3D('placement',#680,#538,#539);
#481=AXIS2_PLACEMENT_3D('',#681,#540,#541);
#482=AXIS2_PLACEMENT_3D('',#691,#542,#543);
#483=AXIS2_PLACEMENT_3D('',#718,#544,#545);
#484=AXIS2_PLACEMENT_3D('',#731,#546,#547);
#485=AXIS2_PLACEMENT_3D('',#733,#548,#549);
#486=AXIS2_PLACEMENT_3D('',#737,#551,#552);
#487=AXIS2_PLACEMENT_3D('',#741,#555,#556);
#488=AXIS2_PLACEMENT_3D('',#742,#557,#558);
#489=AXIS2_PLACEMENT_3D('',#758,#559,#560);
#490=AXIS2_PLACEMENT_3D('',#778,#561,#562);
#491=AXIS2_PLACEMENT_3D('',#783,#563,#564);
#492=AXIS2_PLACEMENT_3D('',#785,#565,#566);
#493=AXIS2_PLACEMENT_3D('',#788,#568,#569);
#494=AXIS2_PLACEMENT_3D('',#790,#570,#571);
#495=AXIS2_PLACEMENT_3D('',#793,#573,#574);
#496=AXIS2_PLACEMENT_3D('',#794,#575,#576);
#497=AXIS2_PLACEMENT_3D('',#798,#578,#579);
#498=AXIS2_PLACEMENT_3D('',#800,#581,#582);
#499=AXIS2_PLACEMENT_3D('',#803,#584,#585);
#500=AXIS2_PLACEMENT_3D('',#804,#586,#587);
#501=AXIS2_PLACEMENT_3D('',#808,#590,#591);
#502=AXIS2_PLACEMENT_3D('',#814,#595,#596);
#503=AXIS2_PLACEMENT_3D('',#816,#597,#598);
#504=AXIS2_PLACEMENT_3D('',#820,#600,#601);
#505=AXIS2_PLACEMENT_3D('',#822,#603,#604);
#506=AXIS2_PLACEMENT_3D('',#823,#605,#606);
#507=AXIS2_PLACEMENT_3D('',#825,#607,#608);
#508=AXIS2_PLACEMENT_3D('',#827,#610,#611);
#509=AXIS2_PLACEMENT_3D('',#830,#613,#614);
#510=AXIS2_PLACEMENT_3D('',#831,#615,#616);
#511=AXIS2_PLACEMENT_3D('',#835,#619,#620);
#512=AXIS2_PLACEMENT_3D('',#836,#621,#622);
#513=AXIS2_PLACEMENT_3D('',#837,#623,#624);
#514=AXIS2_PLACEMENT_3D('',#838,#625,#626);
#515=AXIS2_PLACEMENT_3D('',#839,#627,#628);
#516=AXIS2_PLACEMENT_3D('',#841,#629,#630);
#517=AXIS2_PLACEMENT_3D('',#844,#632,#633);
#518=AXIS2_PLACEMENT_3D('',#845,#634,#635);
#519=AXIS2_PLACEMENT_3D('',#847,#636,#637);
#520=AXIS2_PLACEMENT_3D('',#848,#638,#639);
#521=AXIS2_PLACEMENT_3D('',#850,#640,#641);
#522=AXIS2_PLACEMENT_3D('',#851,#642,#643);
#523=AXIS2_PLACEMENT_3D('',#854,#644,#645);
#524=AXIS2_PLACEMENT_3D('',#856,#647,#648);
#525=AXIS2_PLACEMENT_3D('',#857,#649,#650);
#526=AXIS2_PLACEMENT_3D('',#860,#652,#653);
#527=AXIS2_PLACEMENT_3D('',#861,#654,#655);
#528=AXIS2_PLACEMENT_3D('',#864,#656,#657);
#529=AXIS2_PLACEMENT_3D('',#866,#659,#660);
#530=AXIS2_PLACEMENT_3D('',#867,#661,#662);
#531=AXIS2_PLACEMENT_3D('',#869,#663,#664);
#532=AXIS2_PLACEMENT_3D('',#871,#666,#667);
#533=AXIS2_PLACEMENT_3D('',#872,#668,#669);
#534=AXIS2_PLACEMENT_3D('',#874,#670,#671);
#535=AXIS2_PLACEMENT_3D('',#876,#673,#674);
#536=AXIS2_PLACEMENT_3D('',#877,#675,#676);
#537=AXIS2_PLACEMENT_3D('',#879,#678,#679);
#538=DIRECTION('axis',(0.,0.,1.));
#539=DIRECTION('refdir',(1.,0.,0.));
#540=DIRECTION('center_axis',(0.,0.,-1.));
#541=DIRECTION('ref_axis',(-1.,0.,0.));
#542=DIRECTION('center_axis',(0.,0.,1.));
#543=DIRECTION('ref_axis',(-0.914718354155798,0.404091985283683,0.));
#544=DIRECTION('center_axis',(0.,0.,-1.));
#545=DIRECTION('ref_axis',(-0.914718354155798,0.404091985283683,0.));
#546=DIRECTION('center_axis',(0.,0.,-1.));
#547=DIRECTION('ref_axis',(-1.,0.,0.));
#548=DIRECTION('center_axis',(0.,0.,-1.));
#549=DIRECTION('ref_axis',(-1.,0.,0.));
#550=DIRECTION('',(0.,0.,-1.));
#551=DIRECTION('center_axis',(0.,0.,-1.));
#552=DIRECTION('ref_axis',(-1.,0.,0.));
#553=DIRECTION('',(0.,0.,1.));
#554=DIRECTION('',(0.,0.,-1.));
#555=DIRECTION('center_axis',(0.,0.,-1.));
#556=DIRECTION('ref_axis',(-1.,0.,0.));
#557=DIRECTION('center_axis',(0.,0.,1.));
#558=DIRECTION('ref_axis',(1.,0.,0.));
#559=DIRECTION('center_axis',(0.,0.,-1.));
#560=DIRECTION('ref_axis',(0.902489931377324,0.430710951523817,0.));
#561=DIRECTION('center_axis',(0.,0.,1.));
#562=DIRECTION('ref_axis',(0.902489931377324,0.430710951523817,0.));
#563=DIRECTION('center_axis',(0.,0.,1.));
#564=DIRECTION('ref_axis',(1.,0.,0.));
#565=DIRECTION('center_axis',(0.,0.,1.));
#566=DIRECTION('ref_axis',(0.,-1.,0.));
#567=DIRECTION('',(-1.,-1.98254111540207E-16,0.));
#568=DIRECTION('center_axis',(0.,0.,1.));
#569=DIRECTION('ref_axis',(-0.227318181659297,0.973820540082777,0.));
#570=DIRECTION('center_axis',(0.,0.,-1.));
#571=DIRECTION('ref_axis',(0.,-1.,0.));
#572=DIRECTION('',(1.,0.,0.));
#573=DIRECTION('center_axis',(0.,0.,-1.));
#574=DIRECTION('ref_axis',(0.265195148400822,0.964194758990457,0.));
#575=DIRECTION('center_axis',(0.,0.,1.));
#576=DIRECTION('ref_axis',(0.166497708562777,0.986041841426288,0.));
#577=DIRECTION('',(0.,0.,-1.));
#578=DIRECTION('center_axis',(0.,0.,-1.));
#579=DIRECTION('ref_axis',(0.166497708562777,0.986041841426288,0.));
#580=DIRECTION('',(0.,0.,1.));
#581=DIRECTION('center_axis',(0.,0.,1.));
#582=DIRECTION('ref_axis',(-0.227318181659297,0.973820540082777,0.));
#583=DIRECTION('',(0.,0.,-1.));
#584=DIRECTION('center_axis',(0.,0.,1.));
#585=DIRECTION('ref_axis',(-0.227318181659297,0.973820540082777,0.));
#586=DIRECTION('center_axis',(-1.98254111540207E-16,1.,0.));
#587=DIRECTION('ref_axis',(-1.,-1.98254111540207E-16,0.));
#588=DIRECTION('',(0.,0.,1.));
#589=DIRECTION('',(-1.,-1.98254111540207E-16,0.));
#590=DIRECTION('center_axis',(0.,-1.,0.));
#591=DIRECTION('ref_axis',(1.,0.,0.));
#592=DIRECTION('',(0.,0.,-1.));
#593=DIRECTION('',(-1.,0.,0.));
#594=DIRECTION('',(0.,0.,-1.));
#595=DIRECTION('center_axis',(0.,0.,1.));
#596=DIRECTION('ref_axis',(1.,0.,0.));
#597=DIRECTION('center_axis',(0.,0.,1.));
#598=DIRECTION('ref_axis',(1.,0.,0.));
#599=DIRECTION('',(0.,0.,-1.));
#600=DIRECTION('center_axis',(0.,0.,1.));
#601=DIRECTION('ref_axis',(1.,0.,0.));
#602=DIRECTION('',(0.,0.,1.));
#603=DIRECTION('center_axis',(0.,0.,1.));
#604=DIRECTION('ref_axis',(1.,0.,0.));
#605=DIRECTION('center_axis',(0.,0.,1.));
#606=DIRECTION('ref_axis',(-0.17448917007188,-0.984659093050801,0.));
#607=DIRECTION('center_axis',(0.,0.,-1.));
#608=DIRECTION('ref_axis',(-0.17448917007188,-0.984659093050801,0.));
#609=DIRECTION('',(0.,0.,-1.));
#610=DIRECTION('center_axis',(0.,0.,-1.));
#611=DIRECTION('ref_axis',(0.701436943476595,0.712731516299239,0.));
#612=DIRECTION('',(0.,0.,1.));
#613=DIRECTION('center_axis',(0.,0.,-1.));
#614=DIRECTION('ref_axis',(0.701436943476595,0.712731516299239,0.));
#615=DIRECTION('center_axis',(-0.511399544395539,-0.859343066529332,0.));
#616=DIRECTION('ref_axis',(0.859343066529332,-0.511399544395539,0.));
#617=DIRECTION('',(0.,0.,-1.));
#618=DIRECTION('',(-0.859343066529332,0.511399544395539,0.));
#619=DIRECTION('center_axis',(0.,0.,1.));
#620=DIRECTION('ref_axis',(0.265195148400822,0.964194758990457,0.));
#621=DIRECTION('center_axis',(0.,0.,-1.));
#622=DIRECTION('ref_axis',(0.265195148400822,0.964194758990457,0.));
#623=DIRECTION('center_axis',(0.,0.,-1.));
#624=DIRECTION('ref_axis',(0.,-1.,0.));
#625=DIRECTION('center_axis',(0.,0.,1.));
#626=DIRECTION('ref_axis',(0.,-1.,0.));
#627=DIRECTION('center_axis',(0.,0.,-1.));
#628=DIRECTION('ref_axis',(1.,0.,0.));
#629=DIRECTION('center_axis',(0.,0.,-1.));
#630=DIRECTION('ref_axis',(1.,0.,0.));
#631=DIRECTION('',(0.707106781186546,-8.65956056235492E-17,0.707106781186549));
#632=DIRECTION('center_axis',(0.,0.,-1.));
#633=DIRECTION('ref_axis',(1.,0.,0.));
#634=DIRECTION('center_axis',(0.,0.,-1.));
#635=DIRECTION('ref_axis',(-1.,0.,0.));
#636=DIRECTION('center_axis',(0.,0.,-1.));
#637=DIRECTION('ref_axis',(0.,-1.,0.));
#638=DIRECTION('center_axis',(0.,0.,-1.));
#639=DIRECTION('ref_axis',(-0.687645856987837,0.726046262553195,0.));
#640=DIRECTION('center_axis',(0.,0.,-1.));
#641=DIRECTION('ref_axis',(-1.,0.,0.));
#642=DIRECTION('center_axis',(0.,0.,1.));
#643=DIRECTION('ref_axis',(1.,0.,0.));
#644=DIRECTION('center_axis',(0.,0.,1.));
#645=DIRECTION('ref_axis',(1.,0.,0.));
#646=DIRECTION('',(0.,0.,-1.));
#647=DIRECTION('center_axis',(0.,0.,1.));
#648=DIRECTION('ref_axis',(1.,0.,0.));
#649=DIRECTION('center_axis',(0.,0.,-1.));
#650=DIRECTION('ref_axis',(-1.,0.,0.));
#651=DIRECTION('',(-0.707106781186546,8.65956056235492E-17,0.707106781186549));
#652=DIRECTION('center_axis',(0.,0.,-1.));
#653=DIRECTION('ref_axis',(-1.,0.,0.));
#654=DIRECTION('center_axis',(0.,0.,-1.));
#655=DIRECTION('ref_axis',(-1.,0.,0.));
#656=DIRECTION('center_axis',(0.,0.,1.));
#657=DIRECTION('ref_axis',(-1.,0.,0.));
#658=DIRECTION('',(0.,0.,-1.));
#659=DIRECTION('center_axis',(0.,0.,1.));
#660=DIRECTION('ref_axis',(-1.,0.,0.));
#661=DIRECTION('center_axis',(0.,0.,1.));
#662=DIRECTION('ref_axis',(1.,0.,0.));
#663=DIRECTION('center_axis',(0.,0.,1.));
#664=DIRECTION('ref_axis',(1.,0.,0.));
#665=DIRECTION('',(0.707106781186546,8.65956056235491E-17,-0.707106781186549));
#666=DIRECTION('center_axis',(0.,0.,1.));
#667=DIRECTION('ref_axis',(1.,0.,0.));
#668=DIRECTION('center_axis',(0.,0.,1.));
#669=DIRECTION('ref_axis',(-1.,0.,0.));
#670=DIRECTION('center_axis',(0.,0.,1.));
#671=DIRECTION('ref_axis',(-1.,0.,0.));
#672=DIRECTION('',(-0.707106781186546,-8.65956056235491E-17,-0.707106781186549));
#673=DIRECTION('center_axis',(0.,0.,-1.));
#674=DIRECTION('ref_axis',(-1.,0.,0.));
#675=DIRECTION('center_axis',(0.,0.,1.));
#676=DIRECTION('ref_axis',(0.,-1.,0.));
#677=DIRECTION('',(0.,0.,1.));
#678=DIRECTION('center_axis',(0.,0.,1.));
#679=DIRECTION('ref_axis',(-0.687645856987837,0.726046262553195,0.));
#680=CARTESIAN_POINT('',(0.,0.,0.));
#681=CARTESIAN_POINT('Origin',(56.15008,33.58978,9.00804));
#682=CARTESIAN_POINT('',(50.6247958150228,37.2041966558329,5.02865273728351));
#683=CARTESIAN_POINT('',(50.2500667968349,37.371640500346,5.00804));
#684=CARTESIAN_POINT('Ctrl Pts',(50.6247958150228,37.2041966558329,5.02865273728351));
#685=CARTESIAN_POINT('Ctrl Pts',(50.5357227502342,37.2471651591677,5.01865867292698));
#686=CARTESIAN_POINT('Ctrl Pts',(50.4451021174361,37.2885580963717,5.01227776512809));
#687=CARTESIAN_POINT('Ctrl Pts',(50.3188228412002,37.3429786608689,5.00854341432407));
#688=CARTESIAN_POINT('Ctrl Pts',(50.2844922321955,37.3574503025008,5.00804000000001));
#689=CARTESIAN_POINT('Ctrl Pts',(50.2500667968359,37.3716405003456,5.00804));
#690=CARTESIAN_POINT('',(49.3915707992385,35.4432033258548,5.00804));
#691=CARTESIAN_POINT('Origin',(56.15008,33.58978,5.00804));
#692=CARTESIAN_POINT('',(50.5009650642326,34.9087067416334,5.19449159161523));
#693=CARTESIAN_POINT('Ctrl Pts',(49.3915707992386,35.4432033258547,5.00804));
#694=CARTESIAN_POINT('Ctrl Pts',(49.6951751671788,35.328531451996,5.00804000000001));
#695=CARTESIAN_POINT('Ctrl Pts',(49.9860105158439,35.1945427153753,5.04710404861977));
#696=CARTESIAN_POINT('Ctrl Pts',(50.3432741314213,35.0005095939757,5.14244590473823));
#697=CARTESIAN_POINT('Ctrl Pts',(50.4231029442769,34.9550428956352,5.16715902818914));
#698=CARTESIAN_POINT('Ctrl Pts',(50.5009650642326,34.9087067416334,5.19449159161523));
#699=CARTESIAN_POINT('',(50.865434714585,34.6918089502903,5.34623350576054));
#700=CARTESIAN_POINT('Ctrl Pts',(50.5009650642326,34.9087067416334,5.19449159161523));
#701=CARTESIAN_POINT('Ctrl Pts',(50.6092970149861,34.8442378322808,5.2325202237245));
#702=CARTESIAN_POINT('Ctrl Pts',(50.713867355334,34.7820074769152,5.27543332367862));
#703=CARTESIAN_POINT('Ctrl Pts',(50.8300172908763,34.7128860440073,5.32928148605159));
#704=CARTESIAN_POINT('Ctrl Pts',(50.8476922638109,34.702367575356,5.33765072778525));
#705=CARTESIAN_POINT('Ctrl Pts',(50.865434714585,34.6918089502903,5.34623350576053));
#706=CARTESIAN_POINT('',(53.5900419872343,32.0103782098292,9.00804));
#707=CARTESIAN_POINT('Ctrl Pts',(50.865434714585,34.6918089502903,5.34623350576054));
#708=CARTESIAN_POINT('Ctrl Pts',(51.1121207963903,34.5450047753834,5.46556605438542));
#709=CARTESIAN_POINT('Ctrl Pts',(51.3409384813757,34.3909239972629,5.61283853761381));
#710=CARTESIAN_POINT('Ctrl Pts',(51.9985611380572,33.901436736254,6.14034807784202));
#711=CARTESIAN_POINT('Ctrl Pts',(52.36002697223,33.5624215607093,6.59035964936713));
#712=CARTESIAN_POINT('Ctrl Pts',(53.0622110060386,32.7998916705579,7.71732122046303));
#713=CARTESIAN_POINT('Ctrl Pts',(53.3621670790386,32.3792556992102,8.42174702507106));
#714=CARTESIAN_POINT('Ctrl Pts',(53.5883907362628,32.0130538273486,9.00378851990973));
#715=CARTESIAN_POINT('Ctrl Pts',(53.5892165587142,32.0117161394183,9.00591426074358));
#716=CARTESIAN_POINT('Ctrl Pts',(53.5900419872343,32.0103782098292,9.00804));
#717=CARTESIAN_POINT('',(55.5936905952374,36.545915225572,9.00804));
#718=CARTESIAN_POINT('Origin',(56.15008,33.58978,9.00804));
#719=CARTESIAN_POINT('Ctrl Pts',(55.5936905952374,36.545915225572,9.00804));
#720=CARTESIAN_POINT('Ctrl Pts',(55.592145656931,36.5456244447927,9.00591426074139));
#721=CARTESIAN_POINT('Ctrl Pts',(55.5906006319998,36.5453341179705,9.003788519914));
#722=CARTESIAN_POINT('Ctrl Pts',(55.1675385371182,36.4659649486835,8.42174695117465));
#723=CARTESIAN_POINT('Ctrl Pts',(54.6545826862427,36.4044463028556,7.71732117907136));
#724=CARTESIAN_POINT('Ctrl Pts',(53.6180100302521,36.4100409995902,6.59035964936721));
#725=CARTESIAN_POINT('Ctrl Pts',(53.1239713487764,36.4489591152896,6.14034807784204));
#726=CARTESIAN_POINT('Ctrl Pts',(52.1544325475448,36.6375433694353,5.50479228867297));
#727=CARTESIAN_POINT('Ctrl Pts',(51.706839390841,36.7599974653572,5.28734773854807));
#728=CARTESIAN_POINT('Ctrl Pts',(51.0368192247517,37.0161904928946,5.09359272486355));
#729=CARTESIAN_POINT('Ctrl Pts',(50.8294613797647,37.1054667718539,5.05161636663702));
#730=CARTESIAN_POINT('Ctrl Pts',(50.6247958150228,37.2041966558329,5.02865273728351));
#731=CARTESIAN_POINT('Origin',(56.15008,33.58978,8.34898816748364E-16));
#732=CARTESIAN_POINT('',(59.15812,33.58978,11.02948));
#733=CARTESIAN_POINT('Origin',(56.15008,33.58978,11.02948));
#734=CARTESIAN_POINT('',(59.15812,33.58978,8.34898816748364E-16));
#735=CARTESIAN_POINT('',(59.15812,33.58978,8.34898816748364E-16));
#736=CARTESIAN_POINT('',(55.5936905952374,36.545915225572,8.34898816748364E-16));
#737=CARTESIAN_POINT('Origin',(56.15008,33.58978,8.34898816748364E-16));
#738=CARTESIAN_POINT('',(55.5936905952374,36.545915225572,8.34898816748364E-16));
#739=CARTESIAN_POINT('',(53.5900419872343,32.0103782098292,8.34898816748364E-16));
#740=CARTESIAN_POINT('',(53.5900419872343,32.0103782098292,8.34898816748364E-16));
#741=CARTESIAN_POINT('Origin',(56.15008,33.58978,8.34898816748364E-16));
#742=CARTESIAN_POINT('Origin',(-56.15008,33.58978,9.00804));
#743=CARTESIAN_POINT('',(-55.6492482327348,36.5558333006839,9.00804));
#744=CARTESIAN_POINT('',(-50.8690026990792,37.2211675600968,5.05313309133144));
#745=CARTESIAN_POINT('Ctrl Pts',(-50.8690026990792,37.2211675600968,5.05313309133144));
#746=CARTESIAN_POINT('Ctrl Pts',(-51.0145997406747,37.1519340562777,5.07724190703958));
#747=CARTESIAN_POINT('Ctrl Pts',(-51.1614075276573,37.0875150337691,5.11089878051668));
#748=CARTESIAN_POINT('Ctrl Pts',(-51.7670974898426,36.8427986295485,5.28734773854807));
#749=CARTESIAN_POINT('Ctrl Pts',(-52.2123145225646,36.7119688419987,5.50479228867298));
#750=CARTESIAN_POINT('Ctrl Pts',(-53.1781446766363,36.5052283730743,6.14034807784203));
#751=CARTESIAN_POINT('Ctrl Pts',(-53.6713662685796,36.4570485041999,6.59035964936717));
#752=CARTESIAN_POINT('Ctrl Pts',(-54.7076513859303,36.4320077753044,7.71732102739605));
#753=CARTESIAN_POINT('Ctrl Pts',(-55.2216710420583,36.4838920515183,8.42174668038323));
#754=CARTESIAN_POINT('Ctrl Pts',(-55.6461479112677,36.5553102658067,9.00378851994531));
#755=CARTESIAN_POINT('Ctrl Pts',(-55.6476981110072,36.5555715554873,9.00591426070426));
#756=CARTESIAN_POINT('Ctrl Pts',(-55.6492482327348,36.5558333006839,9.00804));
#757=CARTESIAN_POINT('',(-53.5291859784223,32.1135621403131,9.00804));
#758=CARTESIAN_POINT('Origin',(-56.15008,33.58978,9.00804));
#759=CARTESIAN_POINT('',(-52.2816789701062,33.7786037525209,6.52377627814055));
#760=CARTESIAN_POINT('Ctrl Pts',(-53.5291859784223,32.1135621403131,9.00804));
#761=CARTESIAN_POINT('Ctrl Pts',(-53.5284144759865,32.1149318745353,9.00591426073462));
#762=CARTESIAN_POINT('Ctrl Pts',(-53.5276425703196,32.1163013829575,9.00378851991685));
#763=CARTESIAN_POINT('Ctrl Pts',(-53.3161791000315,32.4912203499456,8.421746904257));
#764=CARTESIAN_POINT('Ctrl Pts',(-53.0332091000439,32.923465901452,7.71732115279223));
#765=CARTESIAN_POINT('Ctrl Pts',(-52.5383121465054,33.5058147781869,6.88645852589308));
#766=CARTESIAN_POINT('Ctrl Pts',(-52.4152132167845,33.641733996463,6.70051126035222));
#767=CARTESIAN_POINT('Ctrl Pts',(-52.2816789701062,33.7786037525209,6.52377627814055));
#768=CARTESIAN_POINT('',(-49.4228448227586,35.5536872054672,5.00804));
#769=CARTESIAN_POINT('Ctrl Pts',(-52.2816789701062,33.7786037525209,6.52377627814055));
#770=CARTESIAN_POINT('Ctrl Pts',(-52.0283995813855,34.0382097260861,6.188556442245));
#771=CARTESIAN_POINT('Ctrl Pts',(-51.7254354644008,34.3097161939923,5.87034180686871));
#772=CARTESIAN_POINT('Ctrl Pts',(-50.9861359604753,34.8410968297498,5.35362337513694));
#773=CARTESIAN_POINT('Ctrl Pts',(-50.5662347209846,35.0890773541913,5.16508026972491));
#774=CARTESIAN_POINT('Ctrl Pts',(-49.8740938940358,35.3944054481485,5.02954756629323));
#775=CARTESIAN_POINT('Ctrl Pts',(-49.6508407134816,35.4797540591315,5.00804));
#776=CARTESIAN_POINT('Ctrl Pts',(-49.4228448227586,35.5536872054672,5.00804));
#777=CARTESIAN_POINT('',(-50.3070040221276,37.4590289915242,5.00804));
#778=CARTESIAN_POINT('Origin',(-56.15008,33.58978,5.00804));
#779=CARTESIAN_POINT('Ctrl Pts',(-50.3070040221276,37.4590289915242,5.00804));
#780=CARTESIAN_POINT('Ctrl Pts',(-50.4981604245898,37.3877544004905,5.00804));
#781=CARTESIAN_POINT('Ctrl Pts',(-50.685995630357,37.3081900739412,5.02282970300183));
#782=CARTESIAN_POINT('Ctrl Pts',(-50.8690026990792,37.2211675600968,5.05313309133144));
#783=CARTESIAN_POINT('Origin',(-0.143365748922946,36.1667324932162,5.00804));
#784=CARTESIAN_POINT('',(47.5752549255443,37.901304,5.00804));
#785=CARTESIAN_POINT('Origin',(47.5752549255443,30.882544,5.00804));
#786=CARTESIAN_POINT('',(-47.8548953186122,37.901304,5.00804));
#787=CARTESIAN_POINT('',(24.625115448216,37.901304,5.00804));
#788=CARTESIAN_POINT('Origin',(-47.8548953186122,30.882544,5.00804));
#789=CARTESIAN_POINT('',(-47.2578282212087,35.895944,5.00804));
#790=CARTESIAN_POINT('Origin',(-47.2578282212087,28.877184,5.00804));
#791=CARTESIAN_POINT('',(46.911574398011,35.895944,5.00804));
#792=CARTESIAN_POINT('',(-24.7012950035171,35.895944,5.00804));
#793=CARTESIAN_POINT('Origin',(46.911574398011,28.877184,5.00804));
#794=CARTESIAN_POINT('Origin',(-54.313696853361,44.4653087691744,8.34898816748364E-16));
#795=CARTESIAN_POINT('',(-50.8690027014949,37.2211675589481,8.34898816748364E-16));
#796=CARTESIAN_POINT('',(-50.8690027014949,37.2211675589481,8.34898816748364E-16));
#797=CARTESIAN_POINT('',(-55.6492482327348,36.5558333006839,8.34898816748364E-16));
#798=CARTESIAN_POINT('Origin',(-54.313696853361,44.4653087691744,8.34898816748364E-16));
#799=CARTESIAN_POINT('',(-55.6492482327348,36.5558333006839,8.34898816748364E-16));
#800=CARTESIAN_POINT('Origin',(-47.8548953186122,30.882544,8.34898816748364E-16));
#801=CARTESIAN_POINT('',(-47.8548953186122,37.901304,8.34898816748364E-16));
#802=CARTESIAN_POINT('',(-47.8548953186122,37.901304,8.34898816748364E-16));
#803=CARTESIAN_POINT('Origin',(-47.8548953186122,30.882544,8.34898816748364E-16));
#804=CARTESIAN_POINT('Origin',(49.393596645355,37.901304,8.34898816748364E-16));
#805=CARTESIAN_POINT('',(47.5752549255443,37.901304,8.34898816748364E-16));
#806=CARTESIAN_POINT('',(47.5752549255443,37.901304,8.34898816748364E-16));
#807=CARTESIAN_POINT('',(56.15008,37.901304,8.34898816748364E-16));
#808=CARTESIAN_POINT('Origin',(-49.2592242581112,35.895944,8.34898816748364E-16));
#809=CARTESIAN_POINT('',(-47.2578282212087,35.895944,8.34898816748364E-16));
#810=CARTESIAN_POINT('',(-47.2578282212087,35.895944,8.34898816748364E-16));
#811=CARTESIAN_POINT('',(46.911574398011,35.895944,8.34898816748364E-16));
#812=CARTESIAN_POINT('',(3.44542787094439,35.895944,8.34898816748364E-16));
#813=CARTESIAN_POINT('',(46.911574398011,35.895944,8.34898816748364E-16));
#814=CARTESIAN_POINT('Origin',(-56.15008,33.58978,8.34898816748364E-16));
#815=CARTESIAN_POINT('',(-59.15812,33.58978,11.02948));
#816=CARTESIAN_POINT('Origin',(-56.15008,33.58978,11.02948));
#817=CARTESIAN_POINT('',(-59.15812,33.58978,8.34898816748364E-16));
#818=CARTESIAN_POINT('',(-59.15812,33.58978,8.34898816748364E-16));
#819=CARTESIAN_POINT('',(-53.5291859784223,32.1135621403131,8.34898816748364E-16));
#820=CARTESIAN_POINT('Origin',(-56.15008,33.58978,8.34898816748364E-16));
#821=CARTESIAN_POINT('',(-53.5291859784223,32.1135621403131,8.34898816748364E-16));
#822=CARTESIAN_POINT('Origin',(-56.15008,33.58978,8.34898816748364E-16));
#823=CARTESIAN_POINT('Origin',(54.1099855158704,44.4289424937642,8.34898816748364E-16));
#824=CARTESIAN_POINT('',(50.6247958676965,37.2041966304233,8.34898816748364E-16));
#825=CARTESIAN_POINT('Origin',(54.1099855158704,44.4289424937642,8.34898816748364E-16));
#826=CARTESIAN_POINT('',(50.6247958676965,37.2041966304233,8.34898816748364E-16));
#827=CARTESIAN_POINT('Origin',(46.7632739531924,27.7986401027071,8.34898816748364E-16));
#828=CARTESIAN_POINT('',(50.8654347145886,34.6918089502882,8.34898816748364E-16));
#829=CARTESIAN_POINT('',(50.8654347145886,34.6918089502882,8.34898816748364E-16));
#830=CARTESIAN_POINT('Origin',(46.7632739531924,27.7986401027071,8.34898816748364E-16));
#831=CARTESIAN_POINT('Origin',(48.6050463004756,36.0369778940524,8.34898816748364E-16));
#832=CARTESIAN_POINT('',(50.5009650642326,34.9087067416334,8.34898816748364E-16));
#833=CARTESIAN_POINT('',(50.5009650642326,34.9087067416334,8.34898816748364E-16));
#834=CARTESIAN_POINT('',(51.9286708844819,34.0590715558221,8.34898816748364E-16));
#835=CARTESIAN_POINT('Origin',(46.911574398011,28.877184,8.34898816748364E-16));
#836=CARTESIAN_POINT('Origin',(46.911574398011,28.877184,8.34898816748364E-16));
#837=CARTESIAN_POINT('Origin',(47.5752549255443,30.882544,8.34898816748364E-16));
#838=CARTESIAN_POINT('Origin',(47.5752549255443,30.882544,8.34898816748364E-16));
#839=CARTESIAN_POINT('Origin',(-56.15008,33.58978,0.250670000000001));
#840=CARTESIAN_POINT('',(-57.90477,33.58978,8.34898816748364E-16));
#841=CARTESIAN_POINT('Origin',(-56.15008,33.58978,8.34898816748364E-16));
#842=CARTESIAN_POINT('',(-57.30343,33.58978,0.601340000000002));
#843=CARTESIAN_POINT('',(-57.6541,33.58978,0.250670000000001));
#844=CARTESIAN_POINT('Origin',(-56.15008,33.58978,0.601340000000002));
#845=CARTESIAN_POINT('Origin',(56.15008,33.58978,8.34898816748364E-16));
#846=CARTESIAN_POINT('',(-52.2816789901629,33.7786037319632,8.34898816748364E-16));
#847=CARTESIAN_POINT('Origin',(-47.2578282212087,28.877184,8.34898816748364E-16));
#848=CARTESIAN_POINT('Origin',(-46.5401352542153,28.1769811811481,8.34898816748364E-16));
#849=CARTESIAN_POINT('',(57.90477,33.58978,8.34898816748364E-16));
#850=CARTESIAN_POINT('Origin',(56.15008,33.58978,8.34898816748364E-16));
#851=CARTESIAN_POINT('Origin',(-56.15008,33.58978,-2.83875875713276));
#852=CARTESIAN_POINT('',(-57.30343,33.58978,10.42814));
#853=CARTESIAN_POINT('',(-54.99673,33.58978,10.42814));
#854=CARTESIAN_POINT('Origin',(-56.15008,33.58978,10.42814));
#855=CARTESIAN_POINT('',(-57.30343,33.58978,-2.83875875713276));
#856=CARTESIAN_POINT('Origin',(-56.15008,33.58978,10.42814));
#857=CARTESIAN_POINT('Origin',(56.15008,33.58978,0.250670000000001));
#858=CARTESIAN_POINT('',(57.30343,33.58978,0.601340000000002));
#859=CARTESIAN_POINT('',(57.6541,33.58978,0.250670000000001));
#860=CARTESIAN_POINT('Origin',(56.15008,33.58978,0.601340000000002));
#861=CARTESIAN_POINT('Origin',(56.15008,33.58978,-2.83875875713276));
#862=CARTESIAN_POINT('',(57.30343,33.58978,10.42814));
#863=CARTESIAN_POINT('',(54.99673,33.58978,10.42814));
#864=CARTESIAN_POINT('Origin',(56.15008,33.58978,10.42814));
#865=CARTESIAN_POINT('',(57.30343,33.58978,-2.83875875713276));
#866=CARTESIAN_POINT('Origin',(56.15008,33.58978,10.42814));
#867=CARTESIAN_POINT('Origin',(56.15008,33.58978,10.77881));
#868=CARTESIAN_POINT('',(54.39539,33.58978,11.02948));
#869=CARTESIAN_POINT('Origin',(56.15008,33.58978,11.02948));
#870=CARTESIAN_POINT('',(54.64606,33.58978,10.77881));
#871=CARTESIAN_POINT('Origin',(56.15008,33.58978,11.02948));
#872=CARTESIAN_POINT('Origin',(-56.15008,33.58978,10.77881));
#873=CARTESIAN_POINT('',(-54.39539,33.58978,11.02948));
#874=CARTESIAN_POINT('Origin',(-56.15008,33.58978,11.02948));
#875=CARTESIAN_POINT('',(-54.64606,33.58978,10.77881));
#876=CARTESIAN_POINT('Origin',(-56.15008,33.58978,11.02948));
#877=CARTESIAN_POINT('Origin',(-47.2578282212087,28.877184,8.34898816748364E-16));
#878=CARTESIAN_POINT('',(-52.2816789901629,33.7786037319632,8.34898816748364E-16));
#879=CARTESIAN_POINT('Origin',(-46.5401352542153,28.1769811811481,8.34898816748364E-16));
#880=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#884,
'DISTANCE_ACCURACY_VALUE',
'Maximum model space distance between geometric entities at asserted c
onnectivities');
#881=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#884,
'DISTANCE_ACCURACY_VALUE',
'Maximum model space distance between geometric entities at asserted c
onnectivities');
#882=(
GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#880))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#884,#886,#887))
REPRESENTATION_CONTEXT('','3D')
);
#883=(
GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#881))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#884,#886,#887))
REPRESENTATION_CONTEXT('','3D')
);
#884=(
LENGTH_UNIT()
NAMED_UNIT(*)
SI_UNIT(.MILLI.,.METRE.)
);
#885=(
LENGTH_UNIT()
NAMED_UNIT(*)
SI_UNIT(.CENTI.,.METRE.)
);
#886=(
NAMED_UNIT(*)
PLANE_ANGLE_UNIT()
SI_UNIT($,.RADIAN.)
);
#887=(
NAMED_UNIT(*)
SI_UNIT($,.STERADIAN.)
SOLID_ANGLE_UNIT()
);
#888=SHAPE_DEFINITION_REPRESENTATION(#889,#890);
#889=PRODUCT_DEFINITION_SHAPE('',$,#892);
#890=SHAPE_REPRESENTATION('',(#480),#882);
#891=PRODUCT_DEFINITION_CONTEXT('part definition',#896,'design');
#892=PRODUCT_DEFINITION('revisited_support','revisited_support',#893,#891);
#893=PRODUCT_DEFINITION_FORMATION('',$,#898);
#894=PRODUCT_RELATED_PRODUCT_CATEGORY('revisited_support',
'revisited_support',(#898));
#895=APPLICATION_PROTOCOL_DEFINITION('international standard',
'automotive_design',2009,#896);
#896=APPLICATION_CONTEXT(
'Core Data for Automotive Mechanical Design Process');
#897=PRODUCT_CONTEXT('part definition',#896,'mechanical');
#898=PRODUCT('revisited_support','revisited_support',$,(#897));
#899=PRESENTATION_STYLE_ASSIGNMENT((#900));
#900=SURFACE_STYLE_USAGE(.BOTH.,#903);
#901=SURFACE_STYLE_RENDERING_WITH_PROPERTIES($,#907,(#902));
#902=SURFACE_STYLE_TRANSPARENT(0.);
#903=SURFACE_SIDE_STYLE('',(#904,#901));
#904=SURFACE_STYLE_FILL_AREA(#905);
#905=FILL_AREA_STYLE('',(#906));
#906=FILL_AREA_STYLE_COLOUR('',#907);
#907=COLOUR_RGB('',0.749019607843137,0.749019607843137,0.749019607843137);
ENDSEC;
END-ISO-10303-21;
File diff suppressed because it is too large Load Diff
+62
View File
@@ -0,0 +1,62 @@
f=88200000,m=WFM,bw=200k,d=RMF Polkowice
f=88200000,m=WFM,bw=200k,d=RMF Kielce
f=89200000,m=WFM,bw=200k,d=RMF Bielsko-Biala
f=89300000,m=WFM,bw=200k,d=RMF Lublin
f=89300000,m=WFM,bw=200k,d=RMF Koszalin
f=90600000,m=WFM,bw=200k,d=RMF Warsaw
f=91000000,m=WFM,bw=200k,d=RMF Warsaw
f=91300000,m=WFM,bw=200k,d=RMF Łobez
f=91500000,m=WFM,bw=200k,d=RMF Ostroleka
f=91700000,m=WFM,bw=200k,d=RMF Wagrowiec
f=91900000,m=WFM,bw=200k,d=RMF Siedlce
f=92500000,m=WFM,bw=200k,d=NRK Oslo
f=92600000,m=WFM,bw=200k,d=RMF Elbląg
f=92900000,m=WFM,bw=200k,d=RMF Wroclaw
f=93000000,m=WFM,bw=200k,d=RMF Katowice
f=93300000,m=WFM,bw=200k,d=RMF Bydgoszcz
f=93500000,m=WFM,bw=200k,d=RMF Lodz
f=93600000,m=WFM,bw=200k,d=RMF Ryki
f=93800000,m=WFM,bw=200k,d=RMF Luban
f=94300000,m=WFM,bw=200k,d=RMF Płock
f=94600000,m=WFM,bw=200k,d=RMF Poznan
f=94800000,m=WFM,bw=200k,d=NRK Bergen
f=94800000,m=WFM,bw=200k,d=RMF Zagan
f=95100000,m=WFM,bw=200k,d=RMF Suwałki
f=95300000,m=WFM,bw=200k,d=RMF Olsztyn
f=95400000,m=WFM,bw=200k,d=RMF Tarnow
f=96000000,m=WFM,bw=200k,d=RMF Krakow
f=96100000,m=WFM,bw=200k,d=RMF Legnica
f=96100000,m=WFM,bw=200k,d=RMF Gorzow Wielkopolski
f=96400000,m=WFM,bw=200k,d=RMF Bialogard
f=96600000,m=WFM,bw=200k,d=RMF Walcz
f=97100000,m=WFM,bw=200k,d=RMF Włoszczowa
f=97200000,m=WFM,bw=200k,d=NRK Melhus
f=98000000,m=WFM,bw=200k,d=RMF Kalisz
f=98400000,m=WFM,bw=200k,d=RMF Gdansk
f=98600000,m=WFM,bw=200k,d=NRK Arendal
f=98900000,m=WFM,bw=200k,d=RMF Konin
f=99300000,m=WFM,bw=200k,d=RMF Opole
f=99500000,m=WFM,bw=200k,d=RMF Kluczbork
f=100100000,m=WFM,bw=200k,d=RMF Rzeszow
f=100200000,m=WFM,bw=200k,d=RMF Bialystok
f=100800000,m=WFM,bw=200k,d=RMF Jelenia Gora
f=100900000,m=WFM,bw=200k,d=RMF Slupsk
f=101100000,m=WFM,bw=200k,d=RMF Solina
f=101200000,m=WFM,bw=200k,d=RMF Swinoujscie
f=101600000,m=WFM,bw=200k,d=RMF Klodzko
f=101800000,m=WFM,bw=200k,d=RMF Zakopane
f=101800000,m=WFM,bw=200k,d=RMF Leżajsk
f=102000000,m=WFM,bw=200k,d=RMF Gizycko
f=102900000,m=WFM,bw=200k,d=RMF Walbrzych
f=103200000,m=WFM,bw=200k,d=RMF Szczawnica
f=103400000,m=WFM,bw=200k,d=RMF Przemyśl
f=103400000,m=WFM,bw=200k,d=RMF Lebork
f=104700000,m=WFM,bw=200k,d=RMF Rabka
f=104900000,m=WFM,bw=200k,d=RMF Koszalin
f=105900000,m=WFM,bw=200k,d=RMF Krynica
f=105900000,m=WFM,bw=200k,d=RMF Czestochowa
f=106400000,m=WFM,bw=200k,d=RMF Zielona Gora
f=106500000,m=WFM,bw=200k,d=RMF Elk
f=106700000,m=WFM,bw=200k,d=RMF Szczecin
f=107400000,m=WFM,bw=200k,d=RMF Iława
f=107700000,m=WFM,bw=200k,d=RMF Zamosc
+5
View File
@@ -0,0 +1,5 @@
f=863000000,d=WaterMeter
f=868000000,d=WaterMeter: ETW-ECO, Zenner
f=868600000,d=WaterMeter: Ecomess
f=868950000,d=WaterMeter: Apator/Santech/Techem
f=874400000,d=WaterMeter
+17 -13
View File
@@ -1,18 +1,22 @@
# INI,END,DESCRIPTION
# (Freq range in MHz, min separation 240MHz)
# INI,END,DESCRIPTION
# (Freq range in MHz, min separation 3MHz)
# (Description up to 20 char)
# (fields comma delimiter)
260,500,315/433 MHz KEYFOBS
2320,2560,BL / WIFI 2.4GHz
5160,5900,WIFI 5GHz
10,7250,FULL RANGE
140,380,VHF MICS AND MARINE
260,500,315/433 MHz KEYFOBS
390,420,RADIOSONDES
420,660,UHF MICS
# https://www.fcc.gov/wireless/bureau-divisions/mobility-division/paging
35,36,USA PAGERS 35
43,44,USA PAGERS 44
152,159,USA PAGERS 152
454,460,USA PAGERS 454
929,932,USA PAGERS 930
# WATER METERS
850,900,Water meters
902,928,ISM 900MHz
# PAGERS https://www.fcc.gov/wireless/bureau-divisions/mobility-division/paging
34,36,USA PAGERS 35
43,45,USA PAGERS 44
151,153,USA PAGERS 152
453,454,USA PAGERS 454
929,931,USA PAGERS 930
# WIFI
2320,2560,BL / WIFI 2.4GHz
5160,5900,WIFI 5GHz
# FULL
10,7250,FULL RANGE