Compare commits
370 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 554db24b1f | |||
| 2fa6df596a | |||
| aeefecf5c6 | |||
| 06d4916144 | |||
| 911f0c8881 | |||
| 01cfd360fe | |||
| 13ce56f7bf | |||
| 210ec9dd1b | |||
| 47c5c1e9e5 | |||
| 1207bac215 | |||
| 94fcab19d9 | |||
| 7ca322fed4 | |||
| 3e1d726064 | |||
| 01ba7a57ea | |||
| 699504a703 | |||
| 48ccc1e988 | |||
| 95f7eda9c5 | |||
| 4306ba5d83 | |||
| 530789f963 | |||
| ebe6675a3a | |||
| af3130faa8 | |||
| 3419ece682 | |||
| b22448de75 | |||
| 98ba332cda | |||
| f3503e6844 | |||
| 883a62238d | |||
| 9021e43041 | |||
| e75dfdaf2d | |||
| cafc4fdec4 | |||
| 99af859e13 | |||
| 4f2b306784 | |||
| 25ba2f1391 | |||
| a5a3ba184a | |||
| 17cb092978 | |||
| 1ff027ed01 | |||
| e89b7683ef | |||
| 1029322405 | |||
| d280054093 | |||
| 66a841e079 | |||
| b15b781039 | |||
| 55783a60f5 | |||
| e76ec66023 | |||
| bf068abba3 | |||
| 8949662eee | |||
| 3d9ce8a037 | |||
| 7fd9adf3f2 | |||
| 3aaa4a0ba1 | |||
| 875db13917 | |||
| 1a94f4a1ab | |||
| 4390647e28 | |||
| f95467d71b | |||
| 200c57f990 | |||
| d2c66f4515 | |||
| dbdb0bd379 | |||
| fcdbedca98 | |||
| ccb3937e37 | |||
| c4052064a9 | |||
| dd5e63abd3 | |||
| 8a4e6492d9 | |||
| 668afccc28 | |||
| e466c14c88 | |||
| a2b28c097c | |||
| 7fae33eb49 | |||
| 3425ca8d54 | |||
| dbf8d2e130 | |||
| a445bfa444 | |||
| 13abb620f6 | |||
| 8833b2fce5 | |||
| 94eea961b5 | |||
| 7d6fb56c7e | |||
| 911eb36210 | |||
| af0d9d8b68 | |||
| a09db01821 | |||
| d7568b820d | |||
| 0f88efc44e | |||
| 76f6ab78c2 | |||
| 4197b5c083 | |||
| 888225fb55 | |||
| b41074fbe3 | |||
| 2f54c11fea | |||
| 0852bf89f0 | |||
| f1a2155e87 | |||
| af8382eeb0 | |||
| 0993f36157 | |||
| 629f911b91 | |||
| e76a464f7e | |||
| 9186031e95 | |||
| 1c9ccbc247 | |||
| 4bc360d652 | |||
| 99b8fb9b53 | |||
| a73aaaa433 | |||
| 788bf03104 | |||
| 5d21e1d09c | |||
| b3d34cd3c7 | |||
| 8cb5ddb9ce | |||
| 33f6edc08a | |||
| 3559e37a76 | |||
| c626d83c3b | |||
| b7ae9d575b | |||
| 303d9c8a9d | |||
| d79f3ce028 | |||
| c56d84d037 | |||
| 646b7b564e | |||
| cc2046b607 | |||
| 1fc9a1c6e8 | |||
| 4b02a1c410 | |||
| 5a3da3bd6a | |||
| 40785e8094 | |||
| f519168602 | |||
| ccef06c088 | |||
| 8251cf7dbb | |||
| 004fddf4de | |||
| 7b19c0a35f | |||
| 27a549dac7 | |||
| c7b0fbc359 | |||
| 6eabd9f1bc | |||
| c522d3d8e4 | |||
| f6437adc60 | |||
| 13ba70f6c5 | |||
| bbae5047d1 | |||
| 24d43515cd | |||
| f6ad116eb8 | |||
| ba6c102a1a | |||
| 871be0199a | |||
| c7082455c1 | |||
| fcbb26051b | |||
| 4ce44b84f3 | |||
| 90d2dbb49c | |||
| b300cc258e | |||
| b49ad91d24 | |||
| 6d131ccfd4 | |||
| d50ea3cc50 | |||
| 8edf4da511 | |||
| 72f3eea131 | |||
| 9c9021f63b | |||
| 62821a79e5 | |||
| bb264dcf57 | |||
| 41cecc88a1 | |||
| 17057a5e42 | |||
| bf2a04ab57 | |||
| a982ee029e | |||
| 00a8d22c5b | |||
| e7de39d130 | |||
| 93f752d86f | |||
| 4eb3979ace | |||
| 246e628df8 | |||
| 1b2c68b3c0 | |||
| 7ec7a9e07c | |||
| 6f58c7929a | |||
| ee67f74fa7 | |||
| 03084251c5 | |||
| 5ee1f7acb9 | |||
| 4c256f65dd | |||
| 01101ecef2 | |||
| e8f6e1389e | |||
| 3ec41bc209 | |||
| f32584c553 | |||
| 542879b74b | |||
| 62df30eae3 | |||
| ea574ef61f | |||
| f08949acd7 | |||
| f50b376cbd | |||
| 4fbdeeab42 | |||
| 27f566be8f | |||
| f21e26eaa3 | |||
| c13e9ed299 | |||
| 0b12f68a95 | |||
| 5b449b182f | |||
| 87cc3c89d5 | |||
| 645a781ac2 | |||
| 4675ecff59 | |||
| 6c71574d5d | |||
| 2969a0fec9 | |||
| abb4385859 | |||
| 863bb04091 | |||
| 9a50684c00 | |||
| 0baaeec5f8 | |||
| 8239c0d300 | |||
| bd8e1ea6f9 | |||
| 15ee503c39 | |||
| a6e5fa4841 | |||
| b0880d6eff | |||
| e6c5b3ede5 | |||
| 5677b0faf1 | |||
| 9096532eee | |||
| 728426c5e7 | |||
| 9ee83c5dbb | |||
| ddffc69937 | |||
| d175e33990 | |||
| dfa524eac0 | |||
| a81ab66994 | |||
| 3190eec36a | |||
| 33a9e1e97c | |||
| b640f33710 | |||
| a06bf3991c | |||
| 32b07d9f4d | |||
| 65ab23fd3c | |||
| a1501d0993 | |||
| 8443008dfa | |||
| 85664c27f8 | |||
| 1d339af87d | |||
| 77b56810e8 | |||
| 704c5de249 | |||
| d6f9d4040d | |||
| 7796e44b4f | |||
| 46c076c296 | |||
| 7fba40172f | |||
| 7d5d9054e1 | |||
| 62652fdd8a | |||
| e5992a6be8 | |||
| 69ab6d8d3d | |||
| e713f48e5f | |||
| 73bc0e98d9 | |||
| 9f7ef073b6 | |||
| ed1225b411 | |||
| bb32965ef1 | |||
| 934f4b07c4 | |||
| bf3f9cfe75 | |||
| 3c304b9fe3 | |||
| 2d765f8120 | |||
| e4c9287af3 | |||
| 15c6285639 | |||
| d525f9a9b3 | |||
| 89f953c75e | |||
| 0bda172f5e | |||
| 086f3098c4 | |||
| 7ca0d1eb3d | |||
| c232287023 | |||
| 222e2c8530 | |||
| c406e7b631 | |||
| 7426c7a7a5 | |||
| 4d839ea44e | |||
| 07e9b50abe | |||
| a5721c5444 | |||
| 64bc4d4068 | |||
| 0afc88ea7b | |||
| 4b4aab640a | |||
| cc75ed5eee | |||
| 43870e97bc | |||
| 0e75cfea12 | |||
| 993396a048 | |||
| cb0a4da7e1 | |||
| 81d5ac4923 | |||
| ef0336ac4f | |||
| e3533594de | |||
| db9d80dc0c | |||
| b2286eec7e | |||
| e737d3c678 | |||
| 7fa92868d7 | |||
| 79700fcddd | |||
| bf01462bd6 | |||
| eab4567ae8 | |||
| dfe1ddfa9f | |||
| 38b6f334b2 | |||
| 92d9b677f7 | |||
| 8a6e04fc0b | |||
| 9446e64784 | |||
| 74f76348b3 | |||
| a1a417d94b | |||
| 1c11a25571 | |||
| eb3b7ac585 | |||
| d7f3539cd9 | |||
| 853912733e | |||
| 21b69e1793 | |||
| 4b33d98cf8 | |||
| 2e65ce8f85 | |||
| 2437a510ed | |||
| 4dd73d201b | |||
| 4acaeea698 | |||
| 4e850df0fc | |||
| f58b6b95c0 | |||
| fd55c8e8e7 | |||
| ce29411aa4 | |||
| ae569cbd65 | |||
| 0d5798ac30 | |||
| 2cd2443eb2 | |||
| e8792e446a | |||
| 59b310dff5 | |||
| 52b951f705 | |||
| b6aa8e9b01 | |||
| 29457f0e46 | |||
| 7ef617946b | |||
| b539b17a50 | |||
| 2cdd11d96a | |||
| 0d64da4a23 | |||
| 477635a100 | |||
| 6c7dfbfc89 | |||
| 589611c8bd | |||
| 9a1d6aabe4 | |||
| 25a660138b | |||
| f2886715ce | |||
| 38a392e3ea | |||
| defdd57ea3 | |||
| acbb100d64 | |||
| 9b010686b6 | |||
| 9aa2d17753 | |||
| 1ce4c402e0 | |||
| decce5cc17 | |||
| 125aa75553 | |||
| 687b1187d1 | |||
| a467e74a78 | |||
| e889a54e55 | |||
| f501955dfd | |||
| cfd1fe2b18 | |||
| c80ea840d7 | |||
| 6e590d0764 | |||
| 9f72e62db7 | |||
| f3bf8dbd2f | |||
| 739218116d | |||
| bdeab6428b | |||
| 619fa00967 | |||
| 9f0b8852f6 | |||
| e87a088842 | |||
| 4c60aed563 | |||
| f4ebf4a2d5 | |||
| 14c17bce8f | |||
| 7058c872f3 | |||
| 0ee0ac07dc | |||
| d20dc4c610 | |||
| f1ca56b875 | |||
| 76d59d433a | |||
| b5da065bbd | |||
| 15a6bc17b5 | |||
| b48b0efe5c | |||
| 904339370b | |||
| e6ca2541e1 | |||
| 11ad0e0933 | |||
| cf75bb0db2 | |||
| 190379c626 | |||
| f18d9f6ed1 | |||
| 50b9f3219c | |||
| 4597c61c57 | |||
| ebfcc81894 | |||
| 36fed73c71 | |||
| 7d5b8d642f | |||
| e890e77483 | |||
| 8071760d81 | |||
| f9ec428950 | |||
| e1d80acba8 | |||
| 4aaac8545b | |||
| 3e15baa251 | |||
| 69515d702d | |||
| 89b95eb134 | |||
| ff5db151b4 | |||
| 59088071eb | |||
| c76252b79c | |||
| 176579b868 | |||
| 9e5068180b | |||
| 07d746feb5 | |||
| 3e0be7979c | |||
| 3947a0bfea | |||
| 24f060906e | |||
| b98e87284e | |||
| 6a22fbf7a3 | |||
| f4461c4eda | |||
| 018bbdc190 | |||
| 76de12852e | |||
| 444d4f9ff3 | |||
| 31a04f47de | |||
| 484af68693 | |||
| 855dafb959 | |||
| ca6cf0326f | |||
| 79a87f52ba | |||
| 81b766aefa | |||
| ec29e20d79 | |||
| e2ef291add | |||
| efeb4d190a | |||
| 58ef23c0cd | |||
| 2180d5d0b5 | |||
| b2edc2735b |
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: https://salt.bountysource.com/checkout/amount?team=portapack-mayhem
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Tap on '....'
|
||||
3.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Affected versions**
|
||||
Please write any difference related with the Expected behavior, on the following versions:
|
||||
* Latest Stable Release
|
||||
* Previous one (if any) that did not presented the issue
|
||||
* Old versions available here: https://github.com/eried/Research/tree/master/HackRF/PortaPack/old_legacy_firmware
|
||||
|
||||
**Additional**
|
||||
If the bug is difficult to explain, additionally to the text please include images and videos.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen. Remember that adding stuff is always possible, but time is a limited resource for everyone. Check the wiki for more information how to compile the firmware and try to explore modifying the code yourself.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional**
|
||||
If the suggestion is difficult to explain, additionally to the text please include images and videos.
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Problem upgrading the firmware
|
||||
about: Deal with the firmware upgrade problems
|
||||
title: Problem upgrading the firmware
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**What is happening?**
|
||||
Describe here why you are unable to upgrade the firmware. Before describing your problems, **do the following**:
|
||||
* Read: https://github.com/eried/portapack-havoc/wiki/Update-firmware
|
||||
* Watch carefully: https://www.youtube.com/watch?v=_zx4ZvurgOs
|
||||
* (if you are not in Windows) also check: https://www.youtube.com/watch?v=kjFB58Y1TAo
|
||||
|
||||
**Were you able to update the firmware before?**
|
||||
Things might be confusing the first time, please check the video available on the link above.
|
||||
|
||||
**Can you try the upgrade with a different PC/Portapack/HackRF?**
|
||||
If is possible, swap hardware and try again. Also, try different USB cables, even if the one you are using works fine for other purposes.
|
||||
|
||||
**Additional**
|
||||
Add photos and videos of your procedure.
|
||||
@@ -13,7 +13,6 @@
|
||||
/sdcard/FREQMAN/BHT*
|
||||
/sdcard/FREQMAN/R.TXT
|
||||
/sdcard/FREQMAN/XXX.TXT
|
||||
/sdcard/WAV/*
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
@@ -60,8 +59,11 @@ CMakeFiles/
|
||||
# Editor files
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.vscode
|
||||
|
||||
# Host OS turds
|
||||
# Host OS leftovers
|
||||
.DS_Store
|
||||
/firmware/CMakeCache.txt
|
||||
/sdcard/ADSB/airlines.txt
|
||||
|
||||
# Python env
|
||||
env/
|
||||
@@ -1,3 +1,3 @@
|
||||
[submodule "hackrf"]
|
||||
path = hackrf
|
||||
url = https://github.com/jboone/hackrf.git
|
||||
url = https://github.com/mossmann/hackrf.git
|
||||
|
||||
@@ -17,17 +17,6 @@ env:
|
||||
- ARTEFACT_BASE=$TRAVIS_BUILD_DIR/artefacts/
|
||||
- ARTEFACT_PATH=$ARTEFACT_BASE/$BUILD_NAME
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#portapack"
|
||||
template:
|
||||
- "%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message}"
|
||||
- "Change view : %{compare_url}"
|
||||
- "Build details : %{build_url}"
|
||||
# TODO: The "build_number.1" in this URL is almost certainly wrong, but correct value not available from Travis?
|
||||
- "Firmware download : https://jboone.github.io/portapack-havoc-nightly/"
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa -y
|
||||
- sudo apt-get update -q
|
||||
@@ -65,9 +54,3 @@ addons:
|
||||
- cmake
|
||||
- dfu-util
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
skip-cleanup: true
|
||||
script: bash $TRAVIS_BUILD_DIR/tools/deploy-nightly.sh
|
||||
on:
|
||||
branch: master
|
||||
|
||||
@@ -1,25 +1,65 @@
|
||||
## Fork of the unofficial HAVOC
|
||||
# PortaPack Mayhem
|
||||
|
||||
Keeping the latest release files and all features I found, and possible my own features in the future, around here. Check Releases
|
||||
[](https://travis-ci.com/eried/portapack-mayhem) [](https://app.buddy.works/eried/portapack/pipelines/pipeline/252276) [](https://codescene.io/projects/8381) [](https://github.com/eried/portapack-mayhem/releases) [](https://github.com/eried/portapack-mayhem/releases/latest) [](https://hub.docker.com/r/eried/portapack) [](https://discord.gg/tuwVMv3) [](https://www.bountysource.com/teams/portapack-mayhem/issues)
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CBPQA4HRRPJQ6&source=url)
|
||||
This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmware, which itself was a fork of the [PortaPack](https://github.com/sharebrained/portapack-hackrf) firmware, an add-on for the [HackRF](http://greatscottgadgets.com/hackrf/). A fork is a derivate, in this case one that has extra features and fixes when compared to the older versions.
|
||||
|
||||
I only have this [Portapack H2+HackRF+battery](https://s.click.aliexpress.com/e/_dSMPvNo), so that's the version I'll be using for testing the releases before I post them here. BTW, if you have the same H2 (I know... I know it is a *dirty* clone) you could print my case:
|
||||
[](https://www.thingiverse.com/thing:4260973)
|
||||
[<img src="https://raw.githubusercontent.com/wiki/eried/portapack-mayhem/img/hw_overview_h2_front.png" height="400">](https://github.com/eried/portapack-mayhem/wiki/Hardware-overview) [<img src="https://raw.githubusercontent.com/wiki/eried/portapack-mayhem/img/hw_overview_h2_inside.png" height="400">](https://github.com/eried/portapack-mayhem/wiki/Hardware-overview#portapack-internals)
|
||||
|
||||
<details>
|
||||
<summary>More details about the H2 case</summary>
|
||||
|
||||
[STL files](https://www.thingiverse.com/thing:4260973)
|
||||
*[PortaPack H2+HackRF+battery](https://s.click.aliexpress.com/e/_dZ7lA96) (clone) with a custom [3d printed case](https://github.com/eried/portapack-mayhem/wiki/H2-Enclosure)*
|
||||
|
||||
|
||||
</details>
|
||||
# Quick overview
|
||||
|
||||
<details>
|
||||
<summary>Printed magnetic cover for the H2 case</summary>
|
||||
|
||||
[](https://www.thingiverse.com/thing:4278961)
|
||||
|
||||
[STL files](https://www.thingiverse.com/thing:4278961)
|
||||
|
||||
</details>
|
||||
If you are new to *HackRF+PortaPack+Mayhem*, there is an awesome introductory video by [Tech Minds](https://www.youtube.com/channel/UC9a8Z6Sp6eb2s3O79pX5Zvg) available:
|
||||
|
||||
[](https://www.youtube.com/watch?v=kjFB58Y1TAo)
|
||||
|
||||
# Frequently Asked Questions
|
||||
|
||||
This repository expands upon the previous work by many people and aims to constantly add new features, bugfixes and generate documentation to make further development easier. [Collaboration](https://github.com/eried/portapack-mayhem/wiki/How-to-collaborate) is always welcomed and appreciated.
|
||||
|
||||
## Does it work on H1/H2 PortaPack?
|
||||
|
||||
Yes, both devices are the [same](https://github.com/eried/portapack-mayhem/wiki/First-steps). The one I am using to test all changes is this [PortaPack H2+HackRF+battery](https://s.click.aliexpress.com/e/_dZ7lA96), which is a kit that includes everything you need. Sadly, the people making the H2 never made the updated schematics available, which is not ideal (and goes against the terms of the license). Most members of the community are using a clone of the [PortaPack H1+HackRF+metal case](https://s.click.aliexpress.com/e/_dS6liw4), which does not include any battery functionality, but it is a cheaper alternative.
|
||||
|
||||
To support the people behind the hardware, please buy a genuine [HackRF](https://greatscottgadgets.com/hackrf/) and [PortaPack](https://store.sharebrained.com/products/portapack-for-hackrf-one-kit).
|
||||
|
||||
## Where is the latest firmware?
|
||||
|
||||
The current stable release is on the [](https://github.com/eried/portapack-mayhem/releases/latest) page. Follow the instructions you can find in the release description. There is also [nightly builds](https://github.com/eried/portapack-mayhem/releases/tag/nightly) generated periodically, which include the latest commits, but they may contain incomplete or buggy functionality.
|
||||
|
||||
## Is this the newest firmware for my PortaPack?
|
||||
Most probably: **YES**. *If you find new features somewhere else, please [suggest](https://github.com/eried/portapack-mayhem/issues/new/choose) them*.
|
||||
|
||||
## Which one is actually the newest?
|
||||
There is a lot of confusion of which is the latest version because no old version used any actual "version number". Additionally, since the files were distributed on facebook groups, github issue links and similar temporal sources, then there was no central location for them.
|
||||
|
||||
This fork (**Mayhem**) uses *major.minor.release* [semantic versioning](https://en.wikipedia.org/wiki/Software_versioning), so you can always compare your current version with the latest from [Releases](https://github.com/eried/portapack-mayhem/releases/latest).
|
||||
|
||||
## What about Havoc/GridRF/jamesshao8/jboone's?
|
||||
* jboone's PortaPack: the [vanilla](https://en.wikipedia.org/wiki/Vanilla_software) experience
|
||||
* Havoc: It was the most popular fork of jboone's PortaPack, currrently, it is not being maintained nor updated
|
||||
* jamesshao8: He keeps his own version of the fork, while not attached as a fork to anything
|
||||
* GridRF: They sell PortaPack clones with their own firmware based on a old version, which has no sourcecode available
|
||||
|
||||
## 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).
|
||||
|
||||
As a last option, if you want to send money directly to me for getting more boards, antennas and such:
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CBPQA4HRRPJQ6&source=url)
|
||||
|
||||
## What if I really want to pay for something?
|
||||
You can create a bounty and invite people to your own bounty. This will incentivize coders to work on a new feature, solving a bug or even writting documentation. Start a bounty by [creating](https://github.com/eried/portapack-mayhem/issues/new/choose) or [choosing](https://github.com/eried/portapack-mayhem/issues/) an existing issue. Then, go to [Bountysource](https://www.bountysource.com/) and post a bounty using the link to that specific [issue](https://www.bountysource.com/teams/portapack-mayhem/issues).
|
||||
|
||||
Promote your bounty over our Discord by clicking the chat badge on [top](#portapack-mayhem).
|
||||
|
||||
## What if I need help?
|
||||
First, check the [documentation](https://github.com/eried/portapack-mayhem/wiki). If you find a bug or you think the problem is related to the current repository, please open an [issue](https://github.com/eried/portapack-mayhem/issues/new/choose).
|
||||
|
||||
You can reach the [official community](https://www.facebook.com/groups/177623356165819) in Facebook, and our Discord by clicking the chat badge on [top](#portapack-mayhem).
|
||||
|
||||
## What if I find incongruencies, or grammatical errors in the text?
|
||||
If is on the [Wiki](https://github.com/eried/portapack-mayhem/wiki), you can modify it directly. If is on files of the repository, you can send corrections as [pull requests](https://github.com/eried/portapack-mayhem/wiki/How-to-collaborate#coding-new-stuff-or-fixing-bugs). As a last resource, open an [issue](https://github.com/eried/portapack-mayhem/issues/new/choose).
|
||||
|
||||
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 261 KiB |
|
Before Width: | Height: | Size: 245 B |
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,171 +0,0 @@
|
||||
~ Pretty ugly PortaPack H1 (+HAVOC) UI widget documentation ~
|
||||
by @furrtek - v0.1 - 2017/02/02
|
||||
Not approved at all by @Sharebrained
|
||||
|
||||
The display is 240 x 320 pixels.
|
||||
|
||||
A View is basically a rectangular zone on the screen.
|
||||
Widgets (aka controls, UI elements...) go into Views.
|
||||
|
||||
Views can be pushed to/popped from a stack.
|
||||
The main menu view is at the bottom of the stack and can't be popped.
|
||||
The title bar view is a special case, it (normally) can't be hidden by pushed Views.
|
||||
Since the title bar is 16 pixel high, a regular full-screen view is 240 x 304 pixels.
|
||||
|
||||
If the current View can be popped (removed), an arrow shows on the left of the title bar.
|
||||
|
||||
Kind of widgets:
|
||||
|
||||
==== Rectangle ====
|
||||
|
||||
A simple filled or outlined rectangle. No interactivity.
|
||||
|
||||
Constructors:
|
||||
- Empty
|
||||
- Rectangle(Rect, Color)
|
||||
|
||||
Methods:
|
||||
- set_color(Color)
|
||||
- set_outline(bool): Default is filled, set to true for outline only
|
||||
|
||||
==== Text ====
|
||||
|
||||
A simple text label. No interactivity.
|
||||
|
||||
Constructors:
|
||||
- Empty
|
||||
- Text(Rect)
|
||||
- Text(Rect, std::string)
|
||||
|
||||
Methods:
|
||||
- set(std::string): Updates text
|
||||
|
||||
==== BigFrequency (HAVOC) ====
|
||||
|
||||
Displays a big 7-segment style frequency value in the XXXX.xxxMHz format.
|
||||
If the value is 0, ----.--- is displayed. No leading zeros. No interactivity.
|
||||
|
||||
Constructors:
|
||||
- BigFrequency(Rect, rf::Frequency)
|
||||
|
||||
Methods:
|
||||
- set(rf::Frequency): Updates value
|
||||
|
||||
==== ProgressBar (HAVOC) ====
|
||||
|
||||
Displays progress as an horizontal progress bar with value and maximum value.
|
||||
No interactivity.
|
||||
|
||||
Constructors:
|
||||
- ProgressBar(Rect)
|
||||
|
||||
Methods:
|
||||
- set_max(uint32_t): Updates maximum value
|
||||
- set_value(uint32_t): Updates current value
|
||||
|
||||
The maximum value is set by default to 100.
|
||||
|
||||
==== Console ====
|
||||
|
||||
Displays a scrolling text console. No interactivity.
|
||||
|
||||
Constructors:
|
||||
- Console(Rect)
|
||||
|
||||
Methods:
|
||||
- clear(): Clears text and resets cursor to top-left
|
||||
- write(std::string): Adds text
|
||||
- writeln(std::string): Adds text and CR + LF
|
||||
|
||||
==== Checkbox (HAVOC) ====
|
||||
|
||||
A toggle option shown as a tickable box with a text label.
|
||||
Interactive: select and touch.
|
||||
|
||||
Constructors:
|
||||
- Empty
|
||||
- Checkbox(Point, size_t, std::string)
|
||||
- Checkbox(Point, size_t, std::string, bool)
|
||||
|
||||
(Position, length of text label, text, regular size/small)
|
||||
|
||||
Methods:
|
||||
- bool value(): Returns state
|
||||
- set_text(std::string): Updates text label
|
||||
- set_value(bool): Sets state
|
||||
|
||||
Callbacks:
|
||||
- on_select: Select key press or touch. Returns state
|
||||
|
||||
==== Button ====
|
||||
|
||||
A momentary push-button. Interactive: select and touch.
|
||||
|
||||
Constructors:
|
||||
- Empty
|
||||
- Button(Rect, std::string)
|
||||
|
||||
Methods:
|
||||
- std::string text(): Returns text
|
||||
- set_text(std::string): Updates text
|
||||
|
||||
Callbacks:
|
||||
- on_select: Select key press or touch
|
||||
- on_dir: Direction keys press
|
||||
- on_highlight: Focus get
|
||||
|
||||
==== Image ====
|
||||
|
||||
Shows a 1-bit bitmap. No interactivity.
|
||||
|
||||
Constructors:
|
||||
- Empty
|
||||
- Image(Rect, Bitmap*, Color, Color)
|
||||
|
||||
(Rect, pointer to bitmap (see bitmap.hpp), foreground, background)
|
||||
|
||||
Methods:
|
||||
- set_bitmap(Bitmap*): Updates bitmap
|
||||
- set_foreground(Color): Changes foreground color
|
||||
- set_background(Color): Changes background color
|
||||
- invert_colors(): Flip foreground color with background
|
||||
|
||||
==== ImageButton ====
|
||||
|
||||
Same as the Image widget, except interactive (select and touch). No methods.
|
||||
|
||||
Constructors:
|
||||
- Empty
|
||||
- ImageButton(Rect, Bitmap*, Color, Color)
|
||||
|
||||
(Rect, pointer to bitmap (see bitmap.hpp), foreground, background)
|
||||
|
||||
Callbacks:
|
||||
- on_select: Select key press or touch
|
||||
|
||||
==== ImageOptionsField (HAVOC) ====
|
||||
|
||||
Options list displayed as images.
|
||||
Interactive: change (jog wheel) and focus.
|
||||
|
||||
Constructors:
|
||||
- Empty
|
||||
- ImageOptionsField(Rect, options_t)
|
||||
|
||||
options_t is a std::vector of std::pair of unsigned char pointers to color bitmap data and an int32_t
|
||||
|
||||
Methods:
|
||||
- set_options(options_t)
|
||||
- size_t selected_index()
|
||||
- size_t selected_index_value()
|
||||
- set_selected_index(size_t)
|
||||
- set_by_value(value_t)
|
||||
|
||||
Callbacks:
|
||||
- on_change: Option was changed
|
||||
- on_show_options: Focus get
|
||||
|
||||
==== OptionsField ====
|
||||
==== NumberField ====
|
||||
==== SymField (HAVOC) ====
|
||||
==== Waveform (HAVOC) ====
|
||||
@@ -14,10 +14,20 @@ COPY ./ /havocsrc
|
||||
|
||||
#Fetch dependencies from APT
|
||||
RUN apt-get update && \
|
||||
apt-get install -y tar wget dfu-util cmake python python-pip && \
|
||||
apt-get install -y tar wget dfu-util cmake python bzip2 curl && \
|
||||
apt-get -qy autoremove
|
||||
|
||||
#Install current pip from PyPa
|
||||
RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
|
||||
python get-pip.py
|
||||
|
||||
#Fetch additional dependencies from Python 2.x pip
|
||||
RUN pip install pyyaml
|
||||
RUN ln -s /usr/bin/python3 /usr/bin/python && \
|
||||
ln -s /usr/bin/pip3 /usr/bin/pip
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
ENV LC_ALL C.UTF-8
|
||||
|
||||
#Grab the GNU ARM toolchain from arm.com
|
||||
#Then extract contents to /opt/build/armbin/
|
||||
|
||||
@@ -1,27 +1,41 @@
|
||||
FROM ubuntu:latest
|
||||
|
||||
# Set location to download ARM toolkit from.
|
||||
# This will need to be changed over time or replaced with a static link to the latest release.
|
||||
ENV ARMBINURL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2?revision=108bd959-44bd-4619-9c19-26187abf5225&la=en&hash=E788CE92E5DFD64B2A8C246BBA91A249CB8E2D2D \
|
||||
PATH=$PATH:/opt/build/armbin/bin
|
||||
|
||||
#Create volume /havoc/bin for compiled firmware binaries
|
||||
VOLUME /havoc
|
||||
WORKDIR /havoc/firmware
|
||||
|
||||
# Fetch dependencies from APT
|
||||
RUN apt-get update && \
|
||||
apt-get install -y git tar wget dfu-util cmake python3 python-pip && \
|
||||
apt-get -qy autoremove
|
||||
|
||||
RUN pip install pyyaml
|
||||
|
||||
# Grab the GNU ARM toolchain from arm.com
|
||||
# Then extract contents to /opt/build/armbin/
|
||||
RUN mkdir /opt/build && cd /opt/build && \
|
||||
wget -O gcc-arm-none-eabi $ARMBINURL && \
|
||||
mkdir armbin && \
|
||||
tar --strip=1 -xjvf gcc-arm-none-eabi -C armbin
|
||||
|
||||
CMD cd .. && cd build && \
|
||||
FROM ubuntu:xenial
|
||||
|
||||
# Set location to download ARM toolkit from.
|
||||
# This will need to be changed over time or replaced with a static link to the latest release.
|
||||
ENV ARMBINURL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2?revision=108bd959-44bd-4619-9c19-26187abf5225&la=en&hash=E788CE92E5DFD64B2A8C246BBA91A249CB8E2D2D \
|
||||
PATH=$HOME/bin:$PATH:/opt/build/armbin/bin
|
||||
|
||||
#Create volume /havoc/bin for compiled firmware binaries
|
||||
VOLUME /havoc
|
||||
WORKDIR /havoc/firmware
|
||||
|
||||
# Fetch dependencies from APT
|
||||
RUN apt-get update && \
|
||||
apt-get install -y git tar wget dfu-util cmake python3 ccache bzip2 curl && \
|
||||
apt-get -qy autoremove
|
||||
|
||||
#Install current pip from PyPa
|
||||
RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
|
||||
python3 get-pip.py
|
||||
|
||||
#Fetch additional dependencies from Python 3.x pip
|
||||
RUN pip install pyyaml
|
||||
RUN ln -s /usr/bin/python3 /usr/bin/python && \
|
||||
ln -s /usr/bin/pip3 /usr/bin/pip
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
ENV LC_ALL C.UTF-8
|
||||
|
||||
# Grab the GNU ARM toolchain from arm.com
|
||||
# Then extract contents to /opt/build/armbin/
|
||||
RUN mkdir /opt/build && cd /opt/build && \
|
||||
wget -O gcc-arm-none-eabi $ARMBINURL && \
|
||||
mkdir armbin && \
|
||||
tar --strip=1 -xjvf gcc-arm-none-eabi -C armbin
|
||||
|
||||
# Configure CCACHE
|
||||
RUN mkdir ~/bin && cd ~/bin && \
|
||||
for tool in gcc g++ cpp c++;do ln -s $(which ccache) arm-none-eabi-$tool;done
|
||||
|
||||
CMD cd .. && cd build && \
|
||||
cmake .. && make firmware
|
||||
@@ -0,0 +1 @@
|
||||
portapack.ried.cl
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
@@ -0,0 +1,6 @@
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=https://github.com/eried/portapack-mayhem/" />
|
||||
</head>
|
||||
<body>
|
||||
<p>If you are not redirected, <a href="https://github.com/eried/portapack-mayhem/">click here</a>.</p>
|
||||
</body>
|
||||
@@ -29,7 +29,7 @@ set(EXTRACT_CPLD_DATA ${PROJECT_SOURCE_DIR}/tools/extract_cpld_data.py)
|
||||
set(MAKE_SPI_IMAGE ${PROJECT_SOURCE_DIR}/tools/make_spi_image.py)
|
||||
set(MAKE_IMAGE_CHUNK ${PROJECT_SOURCE_DIR}/tools/make_image_chunk.py)
|
||||
|
||||
set(FIRMWARE_NAME portapack-h1-havoc)
|
||||
set(FIRMWARE_NAME portapack-h1_h2-mayhem)
|
||||
set(FIRMWARE_FILENAME ${FIRMWARE_NAME}.bin)
|
||||
|
||||
add_subdirectory(application)
|
||||
|
||||
@@ -214,7 +214,7 @@ set(CPPSRC
|
||||
ui/ui_tabview.cpp
|
||||
ui/ui_textentry.cpp
|
||||
ui/ui_transmitter.cpp
|
||||
apps/ui_about.cpp
|
||||
apps/ui_about_simple.cpp
|
||||
apps/ui_adsb_rx.cpp
|
||||
apps/ui_adsb_tx.cpp
|
||||
apps/ui_afsk_rx.cpp
|
||||
@@ -231,6 +231,7 @@ set(CPPSRC
|
||||
apps/ui_keyfob.cpp
|
||||
apps/ui_lcr.cpp
|
||||
apps/lge_app.cpp
|
||||
apps/ui_looking_glass_app.cpp
|
||||
apps/ui_mictx.cpp
|
||||
apps/ui_modemsetup.cpp
|
||||
apps/ui_morse.cpp
|
||||
|
||||
@@ -240,7 +240,7 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) {
|
||||
|
||||
void AISRecentEntryDetailView::update_position() {
|
||||
if (send_updates)
|
||||
geomap_view->update_position(ais::format::latlon_float(entry_.last_position.latitude.normalized()), ais::format::latlon_float(entry_.last_position.longitude.normalized()));
|
||||
geomap_view->update_position(ais::format::latlon_float(entry_.last_position.latitude.normalized()), ais::format::latlon_float(entry_.last_position.longitude.normalized()), (float)entry_.last_position.true_heading);
|
||||
}
|
||||
|
||||
void AISRecentEntryDetailView::focus() {
|
||||
|
||||
@@ -83,6 +83,32 @@ NBFMOptionsView::NBFMOptionsView(
|
||||
};
|
||||
}
|
||||
|
||||
/* SPECOptionsView *******************************************************/
|
||||
|
||||
SPECOptionsView::SPECOptionsView(
|
||||
AnalogAudioView* view, const Rect parent_rect, const Style* const style
|
||||
) : View { parent_rect }
|
||||
{
|
||||
set_style(style);
|
||||
|
||||
add_children({
|
||||
&label_config,
|
||||
&options_config,
|
||||
&text_speed,
|
||||
&field_speed
|
||||
});
|
||||
|
||||
options_config.set_selected_index(view->get_spec_bw_index());
|
||||
options_config.on_change = [this, view](size_t n, OptionsField::value_t bw) {
|
||||
view->set_spec_bw(n, bw);
|
||||
};
|
||||
|
||||
field_speed.set_value(view->get_spec_trigger());
|
||||
field_speed.on_change = [this, view](int32_t v) {
|
||||
view->set_spec_trigger(v);
|
||||
};
|
||||
}
|
||||
|
||||
/* AnalogAudioView *******************************************************/
|
||||
|
||||
AnalogAudioView::AnalogAudioView(
|
||||
@@ -154,6 +180,30 @@ AnalogAudioView::AnalogAudioView(
|
||||
audio::output::start();
|
||||
|
||||
update_modulation(static_cast<ReceiverModel::Mode>(modulation));
|
||||
on_modulation_changed(static_cast<ReceiverModel::Mode>(modulation));
|
||||
}
|
||||
|
||||
size_t AnalogAudioView::get_spec_bw_index() {
|
||||
return spec_bw_index;
|
||||
}
|
||||
|
||||
void AnalogAudioView::set_spec_bw(size_t index, uint32_t bw) {
|
||||
spec_bw_index = index;
|
||||
spec_bw = bw;
|
||||
|
||||
baseband::set_spectrum(bw, spec_trigger);
|
||||
receiver_model.set_sampling_rate(bw);
|
||||
receiver_model.set_baseband_bandwidth(bw/2);
|
||||
}
|
||||
|
||||
uint16_t AnalogAudioView::get_spec_trigger() {
|
||||
return spec_trigger;
|
||||
}
|
||||
|
||||
void AnalogAudioView::set_spec_trigger(uint16_t trigger) {
|
||||
spec_trigger = trigger;
|
||||
|
||||
baseband::set_spectrum(spec_bw, spec_trigger);
|
||||
}
|
||||
|
||||
AnalogAudioView::~AnalogAudioView() {
|
||||
@@ -161,6 +211,7 @@ AnalogAudioView::~AnalogAudioView() {
|
||||
// both?
|
||||
audio::output::stop();
|
||||
|
||||
receiver_model.set_sampling_rate(3072000); // Just a hack to avoid hanging other apps if the last modulation was SPEC
|
||||
receiver_model.disable();
|
||||
|
||||
baseband::shutdown();
|
||||
@@ -270,6 +321,7 @@ void AnalogAudioView::on_show_options_modulation() {
|
||||
break;
|
||||
|
||||
case ReceiverModel::Mode::SpectrumAnalysis:
|
||||
widget = std::make_unique<SPECOptionsView>(this, nbfm_view_rect, &style_options_group);
|
||||
waterfall.show_audio_spectrum_view(false);
|
||||
text_ctcss.hidden(true);
|
||||
break;
|
||||
@@ -313,15 +365,17 @@ void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) {
|
||||
}
|
||||
|
||||
baseband::run_image(image_tag);
|
||||
|
||||
|
||||
if (modulation == ReceiverModel::Mode::SpectrumAnalysis) {
|
||||
baseband::set_spectrum(20000000, 127);
|
||||
baseband::set_spectrum(spec_bw, spec_trigger);
|
||||
}
|
||||
|
||||
const auto is_wideband_spectrum_mode = (modulation == ReceiverModel::Mode::SpectrumAnalysis);
|
||||
receiver_model.set_modulation(modulation);
|
||||
receiver_model.set_sampling_rate(is_wideband_spectrum_mode ? 20000000 : 3072000);
|
||||
receiver_model.set_baseband_bandwidth(is_wideband_spectrum_mode ? 12000000 : 1750000);
|
||||
|
||||
receiver_model.set_sampling_rate(is_wideband_spectrum_mode ? spec_bw : 3072000);
|
||||
receiver_model.set_baseband_bandwidth(is_wideband_spectrum_mode ? spec_bw/2 : 1750000);
|
||||
|
||||
receiver_model.enable();
|
||||
|
||||
// TODO: This doesn't belong here! There's a better way.
|
||||
|
||||
@@ -58,6 +58,7 @@ private:
|
||||
{ "DSB ", 0 },
|
||||
{ "USB ", 0 },
|
||||
{ "LSB ", 0 },
|
||||
{ "CW ", 0 },
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -94,6 +95,43 @@ private:
|
||||
};
|
||||
};
|
||||
|
||||
class AnalogAudioView;
|
||||
|
||||
class SPECOptionsView : public View {
|
||||
public:
|
||||
SPECOptionsView(AnalogAudioView* view, const Rect parent_rect, const Style* const style);
|
||||
|
||||
private:
|
||||
Text label_config {
|
||||
{ 0 * 8, 0 * 16, 2 * 8, 1 * 16 },
|
||||
"BW",
|
||||
};
|
||||
OptionsField options_config {
|
||||
{ 3 * 8, 0 * 16 },
|
||||
4,
|
||||
{
|
||||
{ "20m ", 20000000 },
|
||||
{ "10m ", 10000000 },
|
||||
{ " 5m ", 5000000 },
|
||||
{ " 2m ", 2000000 },
|
||||
{ " 1m ", 1000000 },
|
||||
{ "500k", 500000 },
|
||||
}
|
||||
};
|
||||
|
||||
Text text_speed {
|
||||
{ 9 * 8, 0 * 16, 8 * 8, 1 * 16 },
|
||||
"SP /63"
|
||||
};
|
||||
NumberField field_speed {
|
||||
{ 12 * 8, 0 * 16 },
|
||||
2,
|
||||
{ 0, 63 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
};
|
||||
|
||||
class AnalogAudioView : public View {
|
||||
public:
|
||||
AnalogAudioView(NavigationView& nav);
|
||||
@@ -106,13 +144,23 @@ public:
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Analog audio"; };
|
||||
|
||||
|
||||
size_t get_spec_bw_index();
|
||||
void set_spec_bw(size_t index, uint32_t bw);
|
||||
|
||||
uint16_t get_spec_trigger();
|
||||
void set_spec_trigger(uint16_t trigger);
|
||||
|
||||
private:
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
const Rect options_view_rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 };
|
||||
const Rect nbfm_view_rect { 0 * 8, 1 * 16, 18 * 8, 1 * 16 };
|
||||
|
||||
size_t spec_bw_index = 0;
|
||||
uint32_t spec_bw = 20000000;
|
||||
uint16_t spec_trigger = 63;
|
||||
|
||||
NavigationView& nav_;
|
||||
//bool exit_on_squelch { false };
|
||||
|
||||
|
||||
@@ -46,6 +46,12 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
&waterfall,
|
||||
});
|
||||
|
||||
// Hack for initialization
|
||||
// TODO: This should be included in a more global section so apps dont need to do it
|
||||
receiver_model.set_sampling_rate(3072000);
|
||||
receiver_model.set_baseband_bandwidth(1750000);
|
||||
//-------------------
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
@@ -87,6 +93,14 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
}
|
||||
|
||||
CaptureAppView::~CaptureAppView() {
|
||||
|
||||
// Hack for preventing halting other apps
|
||||
// TODO: This should be also part of something global
|
||||
receiver_model.set_sampling_rate(3072000);
|
||||
receiver_model.set_baseband_bandwidth(1750000);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
|
||||
// ----------------------------
|
||||
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ void GpsSimAppView::on_file_changed(std::filesystem::path new_file_path) {
|
||||
auto file_size = data_file.size();
|
||||
auto duration = (file_size * 1000) / (1 * 2 * sample_rate);
|
||||
|
||||
progressbar.set_max(file_size);
|
||||
progressbar.set_max(file_size / 1024);
|
||||
text_filename.set(file_path.filename().string().substr(0, 12));
|
||||
text_duration.set(to_string_time_ms(duration));
|
||||
|
||||
@@ -234,6 +234,8 @@ GpsSimAppView::~GpsSimAppView() {
|
||||
void GpsSimAppView::on_hide() {
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
if( is_active() )
|
||||
stop(false);
|
||||
waterfall.on_hide();
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
|
||||
&field_vga,
|
||||
&field_frequency,
|
||||
&options_bitrate,
|
||||
&options_phase,
|
||||
&check_log,
|
||||
&check_ignore,
|
||||
&sym_ignore,
|
||||
@@ -99,10 +100,13 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
|
||||
};
|
||||
|
||||
options_bitrate.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
on_bitrate_changed(v);
|
||||
on_config_changed(v, options_phase.selected_index_value());
|
||||
};
|
||||
options_bitrate.set_selected_index(1); // 1200bps
|
||||
|
||||
options_phase.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
on_config_changed(options_bitrate.selected_index_value(),v);
|
||||
};
|
||||
check_ignore.set_value(ignore);
|
||||
check_ignore.on_select = [this](Checkbox&, bool v) {
|
||||
ignore = v;
|
||||
@@ -197,8 +201,8 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) {
|
||||
logger->log_raw_data(message->packet, target_frequency());
|
||||
}
|
||||
|
||||
void POCSAGAppView::on_bitrate_changed(const uint32_t new_bitrate) {
|
||||
baseband::set_pocsag(pocsag_bitrates[new_bitrate]);
|
||||
void POCSAGAppView::on_config_changed(const uint32_t new_bitrate, bool new_phase) {
|
||||
baseband::set_pocsag(pocsag_bitrates[new_bitrate], new_phase);
|
||||
}
|
||||
|
||||
void POCSAGAppView::set_target_frequency(const uint32_t new_value) {
|
||||
|
||||
@@ -93,6 +93,14 @@ private:
|
||||
{ "2400bps", 2 }
|
||||
}
|
||||
};
|
||||
OptionsField options_phase {
|
||||
{ 6 * 8, 21 },
|
||||
1,
|
||||
{
|
||||
{ "P", 0 },
|
||||
{ "N", 1 },
|
||||
}
|
||||
};
|
||||
Checkbox check_log {
|
||||
{ 22 * 8, 21 },
|
||||
3,
|
||||
@@ -124,7 +132,7 @@ private:
|
||||
|
||||
void on_packet(const POCSAGPacketMessage * message);
|
||||
|
||||
void on_bitrate_changed(const uint32_t new_bitrate);
|
||||
void on_config_changed(const uint32_t new_bitrate, const bool phase);
|
||||
|
||||
uint32_t target_frequency() const;
|
||||
void set_target_frequency(const uint32_t new_value);
|
||||
|
||||
@@ -231,6 +231,7 @@ ReplayAppView::~ReplayAppView() {
|
||||
}
|
||||
|
||||
void ReplayAppView::on_hide() {
|
||||
stop(false);
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
waterfall.on_hide();
|
||||
|
||||
@@ -48,7 +48,7 @@ void SoundBoardView::stop() {
|
||||
|
||||
void SoundBoardView::handle_replay_thread_done(const uint32_t return_code) {
|
||||
stop();
|
||||
progressbar.set_value(0);
|
||||
//progressbar.set_value(0);
|
||||
|
||||
if (return_code == ReplayThread::END_OF_FILE) {
|
||||
if (check_random.value()) {
|
||||
@@ -90,7 +90,7 @@ void SoundBoardView::start_tx(const uint32_t id) {
|
||||
|
||||
playing_id = id;
|
||||
|
||||
progressbar.set_max(reader->sample_count());
|
||||
//progressbar.set_max(reader->sample_count());
|
||||
|
||||
//button_play.set_bitmap(&bitmap_stop);
|
||||
|
||||
@@ -130,7 +130,7 @@ void SoundBoardView::start_tx(const uint32_t id) {
|
||||
}*/
|
||||
|
||||
void SoundBoardView::on_tx_progress(const uint32_t progress) {
|
||||
progressbar.set_value(progress);
|
||||
//progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void SoundBoardView::on_select_entry() {
|
||||
@@ -141,8 +141,10 @@ void SoundBoardView::refresh_list() {
|
||||
auto reader = std::make_unique<WAVFileReader>();
|
||||
|
||||
file_list.clear();
|
||||
c_page = page;
|
||||
|
||||
// List directories and files, put directories up top
|
||||
uint32_t count = 0;
|
||||
for (const auto& entry : std::filesystem::directory_iterator(u"WAV", u"*")) {
|
||||
if (std::filesystem::is_regular_file(entry.status())) {
|
||||
if (entry.path().string().length()) {
|
||||
@@ -158,21 +160,32 @@ void SoundBoardView::refresh_list() {
|
||||
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8)) {
|
||||
//sounds[c].ms_duration = reader->ms_duration();
|
||||
//sounds[c].path = u"WAV/" + entry.path().native();
|
||||
file_list.push_back(entry.path());
|
||||
if (file_list.size() == 100)
|
||||
break;
|
||||
if (count >= (page - 1) * 100 && count < page * 100){
|
||||
file_list.push_back(entry.path());
|
||||
if (file_list.size() == 100){
|
||||
page++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!file_list.size()) {
|
||||
// Hide widgets, show warning
|
||||
menu_view.hidden(true);
|
||||
text_empty.hidden(false);
|
||||
set_dirty();
|
||||
if (page == 1){
|
||||
menu_view.hidden(true);
|
||||
text_empty.hidden(false);
|
||||
set_dirty();
|
||||
}else{
|
||||
page = 1;
|
||||
refresh_list();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Hide warning, show widgets
|
||||
menu_view.hidden(false);
|
||||
@@ -191,9 +204,14 @@ void SoundBoardView::refresh_list() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
page_info.set("Page: " + to_string_dec_uint(c_page) + " Sounds: " + to_string_dec_uint(file_list.size()));
|
||||
menu_view.set_highlighted(0); // Refresh
|
||||
}
|
||||
|
||||
if (file_list.size() < 100){
|
||||
page = 1;
|
||||
}
|
||||
}
|
||||
|
||||
SoundBoardView::SoundBoardView(
|
||||
@@ -207,17 +225,31 @@ SoundBoardView::SoundBoardView(
|
||||
&menu_view,
|
||||
&text_empty,
|
||||
&options_tone_key,
|
||||
&text_title,
|
||||
&text_duration,
|
||||
&progressbar,
|
||||
//&text_title,
|
||||
//&text_duration,
|
||||
//&progressbar,
|
||||
&page_info,
|
||||
&check_loop,
|
||||
&check_random,
|
||||
&button_prev_page,
|
||||
&button_next_page,
|
||||
&tx_view
|
||||
});
|
||||
|
||||
refresh_list();
|
||||
|
||||
button_next_page.on_select = [this](Button&) {
|
||||
this->refresh_list();
|
||||
};
|
||||
|
||||
button_prev_page.on_select = [this](Button&) {
|
||||
if (c_page == 1) return;
|
||||
if (c_page == 2) page = 1;
|
||||
page = c_page - 1;
|
||||
refresh_list();
|
||||
};
|
||||
|
||||
text_title.set(to_string_dec_uint(file_list.size()));
|
||||
//text_title.set(to_string_dec_uint(file_list.size()));
|
||||
|
||||
tone_keys_populate(options_tone_key);
|
||||
options_tone_key.set_selected_index(0);
|
||||
@@ -243,6 +275,7 @@ SoundBoardView::SoundBoardView(
|
||||
}
|
||||
|
||||
SoundBoardView::~SoundBoardView() {
|
||||
stop();
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ private:
|
||||
tx_modes tx_mode = NORMAL;
|
||||
|
||||
uint32_t playing_id { };
|
||||
uint32_t page = 1;
|
||||
uint32_t c_page = 1;
|
||||
|
||||
std::vector<std::filesystem::path> file_list { };
|
||||
|
||||
@@ -80,12 +82,26 @@ private:
|
||||
void on_select_entry();
|
||||
|
||||
Labels labels {
|
||||
{ { 0, 20 * 8 + 4 }, "Title:", Color::light_grey() },
|
||||
{ { 0, 23 * 8 }, "Key:", Color::light_grey() }
|
||||
//{ { 0, 20 * 8 + 4 }, "Title:", Color::light_grey() },
|
||||
{ { 0, 180 }, "Key:", Color::light_grey() }
|
||||
};
|
||||
|
||||
|
||||
Button button_next_page {
|
||||
{ 30 * 7, 25 * 8, 10 * 3, 2 * 14 },
|
||||
"=>"
|
||||
};
|
||||
|
||||
Button button_prev_page {
|
||||
{ 17 * 10, 25 * 8, 10 * 3, 2 * 14 },
|
||||
"<="
|
||||
};
|
||||
|
||||
Text page_info {
|
||||
{ 0, 30 * 8 - 4, 30 * 8, 16 }
|
||||
};
|
||||
|
||||
MenuView menu_view {
|
||||
{ 0, 2 * 8, 240, 20 * 8 },
|
||||
{ 0, 0, 240, 175 },
|
||||
true
|
||||
};
|
||||
Text text_empty {
|
||||
@@ -93,35 +109,35 @@ private:
|
||||
"Empty directory !",
|
||||
};
|
||||
|
||||
Text text_title {
|
||||
/*Text text_title {
|
||||
{ 6 * 8, 20 * 8 + 4, 15 * 8, 16 }
|
||||
};
|
||||
};*/
|
||||
|
||||
Text text_duration {
|
||||
/*Text text_duration {
|
||||
{ 22 * 8, 20 * 8 + 4, 6 * 8, 16 }
|
||||
};
|
||||
};*/
|
||||
|
||||
OptionsField options_tone_key {
|
||||
{ 4 * 8, 23 * 8 },
|
||||
{ 32 , 180 },
|
||||
18,
|
||||
{ }
|
||||
};
|
||||
|
||||
Checkbox check_loop {
|
||||
{ 8, 25 * 8 + 4 },
|
||||
{ 0, 25 * 8 + 4 },
|
||||
4,
|
||||
"Loop"
|
||||
};
|
||||
|
||||
Checkbox check_random {
|
||||
{ 10 * 8, 25 * 8 + 4 },
|
||||
{ 10 * 7, 25 * 8 + 4 },
|
||||
6,
|
||||
"Random"
|
||||
};
|
||||
|
||||
ProgressBar progressbar {
|
||||
{ 0 * 8, 30 * 8 - 4, 30 * 8, 16 }
|
||||
};
|
||||
//ProgressBar progressbar {
|
||||
// { 0 * 8, 30 * 8 - 4, 30 * 8, 16 }
|
||||
//};
|
||||
|
||||
TransmitterView tx_view {
|
||||
16 * 16,
|
||||
|
||||
@@ -72,10 +72,11 @@ private:
|
||||
int32_t delay;
|
||||
} credits_t;
|
||||
|
||||
// TODO: Make this dinamically centered and parse \n as the delay value so it is easy to maintain
|
||||
const credits_t credits[26] = {
|
||||
// 012345678901234567890123456789
|
||||
{ 60, "PortaPack Mayhem", 0 },
|
||||
{ 60, "PortaPack|HAVOC", 0 },
|
||||
{ 4 * 8, "Version " VERSION_STRING, 16 },
|
||||
{ 11 * 8, "Gurus J. Boone", 0 },
|
||||
{ 18 * 8, "M. Ossmann", 16 },
|
||||
{ 11 * 8, "HAVOC Furrtek", 16 },
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "ui_about_simple.hpp"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
AboutView::AboutView(NavigationView &nav)
|
||||
{
|
||||
add_children({&console, &button_ok});
|
||||
|
||||
button_ok.on_select = [&nav](Button &) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
console.writeln("\x1B\x07List of contributors:\x1B\x10");
|
||||
console.writeln("");
|
||||
}
|
||||
|
||||
void AboutView::update()
|
||||
{
|
||||
if (++timer > 200)
|
||||
{
|
||||
timer = 0;
|
||||
|
||||
switch (++frame)
|
||||
{
|
||||
case 1:
|
||||
// TODO: Generate this automatically from github
|
||||
// https://github.com/eried/portapack-mayhem/graphs/contributors?to=2022-01-01&from=2020-04-12&type=c
|
||||
console.writeln("\x1B\x06Mayhem:\x1B\x10");
|
||||
console.writeln("eried,euquiq,gregoryfenton");
|
||||
console.writeln("johnelder,jwetzell,nnemanjan00");
|
||||
console.writeln("N0vaPixel,klockee,jamesshao8");
|
||||
console.writeln("ITAxReal,rascafr,mcules");
|
||||
console.writeln("dqs105,strijar");
|
||||
console.writeln("");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// https://github.com/eried/portapack-mayhem/graphs/contributors?to=2020-04-12&from=2015-07-31&type=c
|
||||
console.writeln("\x1B\x06Havoc:\x1B\x10");
|
||||
console.writeln("furrtek,mrmookie,notpike");
|
||||
console.writeln("mjwaxios,ImDroided,Giorgiofox");
|
||||
console.writeln("F4GEV,z4ziggy,xmycroftx");
|
||||
console.writeln("troussos,silascutler");
|
||||
console.writeln("nickbouwhuis,msoose,leres");
|
||||
console.writeln("joakar,dhoetger,clem-42");
|
||||
console.writeln("brianlechthaler,ZeroChaos-...");
|
||||
console.writeln("");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// https://github.com/eried/portapack-mayhem/graphs/contributors?from=2014-07-05&to=2015-07-31&type=c
|
||||
console.writeln("\x1B\x06PortaPack:\x1B\x10");
|
||||
console.writeln("jboone,argilo");
|
||||
console.writeln("");
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// https://github.com/mossmann/hackrf/graphs/contributors
|
||||
console.writeln("\x1B\x06HackRF:\x1B\x10");
|
||||
console.writeln("mossmann,dominicgs,bvernoux");
|
||||
console.writeln("bgamari,schneider42,miek");
|
||||
console.writeln("willcode,hessu,Sec42");
|
||||
console.writeln("yhetti,ckuethe,smunaut");
|
||||
console.writeln("wishi,mrbubble62,scateu...");
|
||||
console.writeln("");
|
||||
frame = 0; // Loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AboutView::focus()
|
||||
{
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef __UI_ABOUT_SIMPLE_H__
|
||||
#define __UI_ABOUT_SIMPLE_H__
|
||||
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class AboutView : public View
|
||||
{
|
||||
public:
|
||||
AboutView(NavigationView &nav);
|
||||
void focus() override;
|
||||
std::string title() const override { return "About"; };
|
||||
int32_t timer{180};
|
||||
short frame{0};
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
Console console{
|
||||
{0, 10, 240, 240}};
|
||||
|
||||
Button button_ok{
|
||||
{240/3, 270, 240/3, 24},
|
||||
"OK",
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_update{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message *const) {
|
||||
this->update();
|
||||
}};
|
||||
};
|
||||
} // namespace ui
|
||||
|
||||
#endif /*__UI_ABOUT_SIMPLE_H__*/
|
||||
@@ -92,12 +92,16 @@ void ADSBRxDetailsView::update(const AircraftRecentEntry& entry) {
|
||||
text_last_seen.set(to_string_dec_uint(age / 60) + " minutes ago");
|
||||
|
||||
text_infos.set(entry_copy.info_string);
|
||||
|
||||
if(entry_copy.velo.heading < 360 && entry_copy.velo.speed >=0){ //I don't like this but...
|
||||
text_info2.set("Hdg:" + to_string_dec_uint(entry_copy.velo.heading) + " Spd:" + to_string_dec_int(entry_copy.velo.speed));
|
||||
}else{
|
||||
text_info2.set("");
|
||||
}
|
||||
text_frame_pos_even.set(to_string_hex_array(entry_copy.frame_pos_even.get_raw_data(), 14));
|
||||
text_frame_pos_odd.set(to_string_hex_array(entry_copy.frame_pos_odd.get_raw_data(), 14));
|
||||
|
||||
if (send_updates)
|
||||
geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude);
|
||||
geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude, entry_copy.velo.heading);
|
||||
}
|
||||
|
||||
ADSBRxDetailsView::~ADSBRxDetailsView() {
|
||||
@@ -123,6 +127,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
&text_airline,
|
||||
&text_country,
|
||||
&text_infos,
|
||||
&text_info2,
|
||||
&text_frame_pos_even,
|
||||
&text_frame_pos_odd,
|
||||
&button_see_map
|
||||
@@ -172,7 +177,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
GeoPos::alt_unit::FEET,
|
||||
entry_copy.pos.latitude,
|
||||
entry_copy.pos.longitude,
|
||||
0,
|
||||
entry_copy.velo.heading,
|
||||
[this]() {
|
||||
send_updates = false;
|
||||
});
|
||||
@@ -199,7 +204,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
|
||||
auto frame = message->frame;
|
||||
uint32_t ICAO_address = frame.get_ICAO_address();
|
||||
|
||||
|
||||
if (frame.check_CRC() && frame.get_ICAO_address()) {
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
auto& entry = ::on_packet(recent, ICAO_address);
|
||||
@@ -214,6 +219,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
|
||||
if (frame.get_DF() == DF_ADSB) {
|
||||
uint8_t msg_type = frame.get_msg_type();
|
||||
uint8_t msg_sub = frame.get_msg_sub();
|
||||
uint8_t * raw_data = frame.get_raw_data();
|
||||
|
||||
if ((msg_type >= 1) && (msg_type <= 4)) {
|
||||
@@ -224,10 +230,10 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
entry.set_frame_pos(frame, raw_data[6] & 4);
|
||||
|
||||
if (entry.pos.valid) {
|
||||
str_info = "Alt:" + to_string_dec_uint(entry.pos.altitude) +
|
||||
" Lat" + to_string_dec_int(entry.pos.latitude) +
|
||||
str_info = "Alt:" + to_string_dec_int(entry.pos.altitude) +
|
||||
" Lat:" + to_string_dec_int(entry.pos.latitude) +
|
||||
"." + to_string_dec_int((int)abs(entry.pos.latitude * 1000) % 100, 2, '0') +
|
||||
" Lon" + to_string_dec_int(entry.pos.longitude) +
|
||||
" Lon:" + to_string_dec_int(entry.pos.longitude) +
|
||||
"." + to_string_dec_int((int)abs(entry.pos.longitude * 1000) % 100, 2, '0');
|
||||
|
||||
entry.set_info_string(str_info);
|
||||
@@ -236,6 +242,13 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
if (send_updates)
|
||||
details_view->update(entry);
|
||||
}
|
||||
} else if(msg_type == 19 && msg_sub >= 1 && msg_sub <= 4){
|
||||
entry.set_frame_velo(frame);
|
||||
logentry += "Type:" + to_string_dec_uint(msg_sub) +
|
||||
" Hdg:" + to_string_dec_uint(entry.velo.heading) +
|
||||
" Spd: "+ to_string_dec_int(entry.velo.speed);
|
||||
if (send_updates)
|
||||
details_view->update(entry);
|
||||
}
|
||||
}
|
||||
recent_entries_view.set_dirty();
|
||||
|
||||
@@ -49,7 +49,7 @@ struct AircraftRecentEntry {
|
||||
uint16_t hits { 0 };
|
||||
uint32_t age { 0 };
|
||||
adsb_pos pos { false, 0, 0, 0 };
|
||||
|
||||
adsb_vel velo { false, 0, 999 };
|
||||
ADSBFrame frame_pos_even { };
|
||||
ADSBFrame frame_pos_odd { };
|
||||
|
||||
@@ -86,6 +86,10 @@ struct AircraftRecentEntry {
|
||||
pos = decode_frame_pos(frame_pos_even, frame_pos_odd);
|
||||
}
|
||||
}
|
||||
|
||||
void set_frame_velo(ADSBFrame& frame){
|
||||
velo = decode_frame_velo(frame);
|
||||
}
|
||||
|
||||
void set_info_string(std::string& new_info_string) {
|
||||
info_string = new_info_string;
|
||||
@@ -132,7 +136,7 @@ public:
|
||||
|
||||
void update(const AircraftRecentEntry& entry);
|
||||
|
||||
std::string title() const override { return "Aircraft details"; };
|
||||
std::string title() const override { return "Details"; };
|
||||
|
||||
private:
|
||||
AircraftRecentEntry entry_copy { 0 };
|
||||
@@ -146,8 +150,8 @@ private:
|
||||
{ { 0 * 8, 2 * 16 }, "Last seen:", Color::light_grey() },
|
||||
{ { 0 * 8, 3 * 16 }, "Airline:", Color::light_grey() },
|
||||
{ { 0 * 8, 5 * 16 }, "Country:", Color::light_grey() },
|
||||
{ { 0 * 8, 12 * 16 }, "Even position frame:", Color::light_grey() },
|
||||
{ { 0 * 8, 14 * 16 }, "Odd position frame:", Color::light_grey() }
|
||||
{ { 0 * 8, 13 * 16 }, "Even position frame:", Color::light_grey() },
|
||||
{ { 0 * 8, 15 * 16 }, "Odd position frame:", Color::light_grey() }
|
||||
};
|
||||
|
||||
Text text_callsign {
|
||||
@@ -174,17 +178,23 @@ private:
|
||||
{ 0 * 8, 6 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_info2 {
|
||||
{0*8, 7*16, 30*8, 16},
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_frame_pos_even {
|
||||
{ 0 * 8, 13 * 16, 30 * 8, 16 },
|
||||
{ 0 * 8, 14 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
Text text_frame_pos_odd {
|
||||
{ 0 * 8, 15 * 16, 30 * 8, 16 },
|
||||
{ 0 * 8, 16 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Button button_see_map {
|
||||
{ 8 * 8, 8 * 16, 14 * 8, 3 * 16 },
|
||||
{ 8 * 8, 9 * 16, 14 * 8, 3 * 16 },
|
||||
"See on map"
|
||||
};
|
||||
};
|
||||
|
||||
@@ -82,6 +82,7 @@ private:
|
||||
6,
|
||||
SymField::SYMFIELD_ALPHANUM
|
||||
};
|
||||
|
||||
NumberField num_ssid_dest {
|
||||
{ 19 * 8, 2 * 16 },
|
||||
2,
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Si44xx transmit"; };
|
||||
std::string title() const override { return "Si44xx TX"; };
|
||||
|
||||
private:
|
||||
enum tx_modes {
|
||||
|
||||
@@ -121,7 +121,7 @@ void TemperatureWidget::paint(Painter& painter) {
|
||||
}
|
||||
|
||||
TemperatureWidget::temperature_t TemperatureWidget::temperature(const sample_t sensor_value) const {
|
||||
return -45 + sensor_value * 5;
|
||||
return -35 + sensor_value * 4; //max2837 datasheet temp 25ºC has sensor value: 15
|
||||
}
|
||||
|
||||
std::string TemperatureWidget::temperature_str(const temperature_t temperature) const {
|
||||
@@ -321,37 +321,39 @@ void DebugControlsView::focus() {
|
||||
|
||||
DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) {
|
||||
add_items({
|
||||
{ "RFFC5072", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
{ "RFFC5072", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav](){ nav.push<RegistersView>(
|
||||
"RFFC5072", RegistersWidgetConfig { 31, 16 },
|
||||
[](const size_t register_number) { return radio::debug::first_if::register_read(register_number); }
|
||||
); } },
|
||||
{ "MAX2837", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
{ "MAX2837", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav](){ nav.push<RegistersView>(
|
||||
"MAX2837", RegistersWidgetConfig { 32, 10 },
|
||||
[](const size_t register_number) { return radio::debug::second_if::register_read(register_number); }
|
||||
); } },
|
||||
{ "Si5351C", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
{ "Si5351C", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav](){ nav.push<RegistersView>(
|
||||
"Si5351C", RegistersWidgetConfig { 96, 8 },
|
||||
[](const size_t register_number) { return portapack::clock_generator.read_register(register_number); }
|
||||
); } },
|
||||
{ audio::debug::codec_name(), ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
{ audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav](){ nav.push<RegistersView>(
|
||||
audio::debug::codec_name(), RegistersWidgetConfig { audio::debug::reg_count(), audio::debug::reg_bits() },
|
||||
[](const size_t register_number) { return audio::debug::reg_read(register_number); }
|
||||
); } },
|
||||
});
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
set_max_rows(2); // allow wider buttons
|
||||
}
|
||||
|
||||
/* DebugMenuView *********************************************************/
|
||||
|
||||
DebugMenuView::DebugMenuView(NavigationView& nav) {
|
||||
add_items({
|
||||
{ "Memory", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMemoryView>(); } },
|
||||
{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "SD Card", ui::Color::white(), nullptr, [&nav](){ nav.push<SDCardDebugView>(); } },
|
||||
{ "Peripherals", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugPeripheralsMenuView>(); } },
|
||||
{ "Temperature", ui::Color::white(), nullptr, [&nav](){ nav.push<TemperatureView>(); } },
|
||||
{ "Controls", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugControlsView>(); } }, });
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
//{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } },
|
||||
{ "Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav](){ nav.push<DebugMemoryView>(); } },
|
||||
//{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav](){ nav.push<SDCardDebugView>(); } },
|
||||
{ "Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav](){ nav.push<DebugPeripheralsMenuView>(); } },
|
||||
{ "Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav](){ nav.push<TemperatureView>(); } },
|
||||
{ "Buttons test", ui::Color::dark_cyan(), &bitmap_icon_controls, [&nav](){ nav.push<DebugControlsView>(); } },
|
||||
});
|
||||
set_max_rows(2); // allow wider buttons
|
||||
}
|
||||
|
||||
/*DebugLCRView::DebugLCRView(NavigationView& nav, std::string lcr_string) {
|
||||
|
||||
@@ -101,10 +101,10 @@ private:
|
||||
|
||||
std::string temperature_str(const temperature_t temperature) const;
|
||||
|
||||
static constexpr temperature_t display_temp_min = 0;
|
||||
static constexpr temperature_t display_temp_min = -10; //Accomodate negative values, present in cold startup cases
|
||||
static constexpr temperature_t display_temp_scale = 3;
|
||||
static constexpr int bar_width = 1;
|
||||
static constexpr int temp_len = 3;
|
||||
static constexpr int temp_len = 4; //Now scale shows up to 4 chars ("-10C")
|
||||
};
|
||||
|
||||
class TemperatureView : public View {
|
||||
@@ -287,14 +287,16 @@ private:
|
||||
};
|
||||
};*/
|
||||
|
||||
class DebugPeripheralsMenuView : public MenuView {
|
||||
class DebugPeripheralsMenuView : public BtnGridView {
|
||||
public:
|
||||
DebugPeripheralsMenuView(NavigationView& nav);
|
||||
std::string title() const override { return "Peripherals"; };
|
||||
};
|
||||
|
||||
class DebugMenuView : public MenuView {
|
||||
class DebugMenuView : public BtnGridView {
|
||||
public:
|
||||
DebugMenuView(NavigationView& nav);
|
||||
std::string title() const override { return "Debug"; };
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -55,7 +55,7 @@ private:
|
||||
//uint8_t scan_count;
|
||||
//double scan_progress;
|
||||
//unsigned int scan_index;
|
||||
int16_t waveform_buffer[512];
|
||||
int16_t waveform_buffer[550];
|
||||
const encoder_def_t * encoder_def { };
|
||||
//uint8_t enc_type = 0;
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace ui {
|
||||
void FileManBaseView::load_directory_contents(const std::filesystem::path& dir_path) {
|
||||
current_path = dir_path;
|
||||
|
||||
text_current.set(dir_path.string().substr(0, 30 - 8));
|
||||
|
||||
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();
|
||||
@@ -41,10 +41,12 @@ void FileManBaseView::load_directory_contents(const std::filesystem::path& dir_p
|
||||
// List directories and files, put directories up top
|
||||
if (dir_path.string().length())
|
||||
entry_list.push_back({ u"..", 0, true });
|
||||
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(dir_path, u"*")) {
|
||||
if (std::filesystem::is_regular_file(entry.status())) {
|
||||
if (entry.path().string().length()) {
|
||||
|
||||
// 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();
|
||||
@@ -58,9 +60,9 @@ void FileManBaseView::load_directory_contents(const std::filesystem::path& dir_p
|
||||
|
||||
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 });
|
||||
}
|
||||
} else if (std::filesystem::is_directory(entry.status())) {
|
||||
entry_list.insert(entry_list.begin(), { entry.path(), 0, true });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,31 +94,37 @@ FileManBaseView::FileManBaseView(
|
||||
) : nav_ (nav),
|
||||
extension_filter { filter }
|
||||
{
|
||||
load_directory_contents(current_path);
|
||||
|
||||
if (!entry_list.size())
|
||||
empty_root = true;
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&text_current,
|
||||
&button_exit
|
||||
});
|
||||
|
||||
menu_view.on_left = [&nav, this]() {
|
||||
load_directory_contents(get_parent_dir());
|
||||
refresh_list();
|
||||
};
|
||||
|
||||
button_exit.on_select = [this, &nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
};
|
||||
|
||||
if (!sdcIsCardInserted(&SDCD1)) {
|
||||
empty_root=true;
|
||||
text_current.set("NO 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();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileManBaseView::focus() {
|
||||
if (empty_root) {
|
||||
button_exit.focus();
|
||||
nav_.display_modal("Error", "No files in root.", ABORT, nullptr);
|
||||
} else {
|
||||
menu_view.focus();
|
||||
}
|
||||
@@ -190,7 +198,6 @@ void FileManBaseView::refresh_list() {
|
||||
nav_.pop();
|
||||
});
|
||||
}
|
||||
|
||||
FileSaveView::FileSaveView(
|
||||
NavigationView& nav
|
||||
) : FileManBaseView(nav)
|
||||
@@ -244,7 +251,11 @@ FileLoadView::FileLoadView(
|
||||
|
||||
void FileManagerView::on_rename(NavigationView& nav) {
|
||||
text_prompt(nav, name_buffer, max_filename_length, [this](std::string& buffer) {
|
||||
rename_file(get_selected_path(), 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();
|
||||
});
|
||||
@@ -271,57 +282,59 @@ FileManagerView::FileManagerView(
|
||||
NavigationView& nav
|
||||
) : FileManBaseView(nav, "")
|
||||
{
|
||||
on_refresh_widgets = [this](bool v) {
|
||||
refresh_widgets(v);
|
||||
};
|
||||
|
||||
add_children({
|
||||
&menu_view,
|
||||
&labels,
|
||||
&text_date,
|
||||
&button_rename,
|
||||
&button_new_dir,
|
||||
&button_delete
|
||||
});
|
||||
|
||||
menu_view.on_highlight = [this]() {
|
||||
text_date.set(to_string_FAT_timestamp(file_created_date(get_selected_path())));
|
||||
};
|
||||
|
||||
refresh_list();
|
||||
|
||||
on_select_entry = [this]() {
|
||||
if (entry_list[menu_view.highlighted_index()].is_directory) {
|
||||
load_directory_contents(get_selected_path());
|
||||
refresh_list();
|
||||
} else
|
||||
button_rename.focus();
|
||||
};
|
||||
|
||||
button_new_dir.on_select = [this, &nav](Button&) {
|
||||
name_buffer.clear();
|
||||
if (!empty_root) {
|
||||
on_refresh_widgets = [this](bool v) {
|
||||
refresh_widgets(v);
|
||||
};
|
||||
|
||||
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();
|
||||
add_children({
|
||||
&menu_view,
|
||||
&labels,
|
||||
&text_date,
|
||||
&button_rename,
|
||||
&button_new_dir,
|
||||
&button_delete
|
||||
});
|
||||
};
|
||||
|
||||
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, &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();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
menu_view.on_highlight = [this]() {
|
||||
text_date.set(to_string_FAT_timestamp(file_created_date(get_selected_path())));
|
||||
};
|
||||
|
||||
refresh_list();
|
||||
|
||||
on_select_entry = [this]() {
|
||||
if (entry_list[menu_view.highlighted_index()].is_directory) {
|
||||
load_directory_contents(get_selected_path());
|
||||
refresh_list();
|
||||
} 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, &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, &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();
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,8 +67,9 @@ protected:
|
||||
{ ".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_speaker, ui::Color::dark_magenta() },
|
||||
{ ".WAV", &bitmap_icon_file_wav, ui::Color::dark_magenta() },
|
||||
{ "", &bitmap_icon_file, ui::Color::light_grey() }
|
||||
};
|
||||
|
||||
@@ -84,10 +85,10 @@ protected:
|
||||
void refresh_list();
|
||||
|
||||
Labels labels {
|
||||
{ { 0, 0 }, "Current:", Color::light_grey() }
|
||||
{ { 0, 0 }, "Path:", Color::light_grey() }
|
||||
};
|
||||
Text text_current {
|
||||
{ 8 * 8, 0 * 8, 22 * 8, 16 },
|
||||
{ 6 * 8, 0 * 8, 24 * 8, 16 },
|
||||
"",
|
||||
};
|
||||
|
||||
@@ -97,7 +98,7 @@ protected:
|
||||
};
|
||||
|
||||
Button button_exit {
|
||||
{ 20 * 8, 34 * 8, 10 * 8, 4 * 8 },
|
||||
{ 16 * 8, 34 * 8, 14 * 8, 32 },
|
||||
"Exit"
|
||||
};
|
||||
};
|
||||
@@ -157,11 +158,11 @@ private:
|
||||
};
|
||||
|
||||
Button button_rename {
|
||||
{ 0 * 8, 29 * 8, 12 * 8, 32 },
|
||||
{ 0 * 8, 29 * 8, 14 * 8, 32 },
|
||||
"Rename"
|
||||
};
|
||||
Button button_delete {
|
||||
{ 18 * 8, 29 * 8, 12 * 8, 32 },
|
||||
{ 16 * 8, 29 * 8, 14 * 8, 32 },
|
||||
"Delete"
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2020 euquiq
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_looking_glass_app.hpp"
|
||||
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui
|
||||
{
|
||||
|
||||
void GlassView::focus() {
|
||||
field_marker.focus();
|
||||
}
|
||||
|
||||
GlassView::~GlassView() {
|
||||
receiver_model.set_sampling_rate(3072000); // Just a hack to avoid hanging other apps
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void GlassView::on_lna_changed(int32_t v_db) {
|
||||
receiver_model.set_lna(v_db);
|
||||
}
|
||||
|
||||
void GlassView::on_vga_changed(int32_t v_db) {
|
||||
receiver_model.set_vga(v_db);
|
||||
}
|
||||
|
||||
void GlassView::add_spectrum_pixel(Color color)
|
||||
{
|
||||
spectrum_row[pixel_index++] = color;
|
||||
if (pixel_index == 240) //got an entire waterfall line
|
||||
{
|
||||
const auto draw_y = display.scroll(1); //Scroll 1 pixel down
|
||||
display.draw_pixels( {{0, draw_y}, {240, 1}}, spectrum_row); //new line at top
|
||||
pixel_index = 0; //Start New cascade line
|
||||
}
|
||||
}
|
||||
|
||||
//Apparently, the spectrum object returns an array of 256 bins
|
||||
//Each having the radio signal power for it's corresponding frequency slot
|
||||
void GlassView::on_channel_spectrum(const ChannelSpectrum &spectrum)
|
||||
{
|
||||
baseband::spectrum_streaming_stop();
|
||||
|
||||
// Convert bins of this spectrum slice into a representative max_power and when enough, into pixels
|
||||
// Spectrum.db has 256 bins. Center 12 bins are ignored (DC spike is blanked) Leftmost and rightmost 2 bins are ignored
|
||||
// All things said and done, we actually need 240 of those bins:
|
||||
for(uint8_t bin = 0; bin < 240; bin++)
|
||||
{
|
||||
if (bin < 120) {
|
||||
if (spectrum.db[134 + bin] > max_power)
|
||||
max_power = spectrum.db[134 + bin];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spectrum.db[bin - 118] > max_power)
|
||||
max_power = spectrum.db[bin - 118];
|
||||
}
|
||||
|
||||
bins_Hz_size += each_bin_size; //add this bin Hz count into the "pixel fulfilled bag of Hz"
|
||||
|
||||
if (bins_Hz_size >= marker_pixel_step) //new pixel fullfilled
|
||||
{
|
||||
if (min_color_power < max_power)
|
||||
add_spectrum_pixel(spectrum_rgb3_lut[max_power]); //Pixel will represent max_power
|
||||
else
|
||||
add_spectrum_pixel(0); //Filtered out, show black
|
||||
|
||||
max_power = 0;
|
||||
|
||||
if (!pixel_index) //Received indication that a waterfall line has been completed
|
||||
{
|
||||
bins_Hz_size = 0; //Since this is an entire pixel line, we don't carry "Pixels into next bin"
|
||||
break;
|
||||
} else {
|
||||
bins_Hz_size -= marker_pixel_step; //reset bins size, but carrying the eventual excess Hz into next pixel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pixel_index)
|
||||
f_center += SEARCH_SLICE_WIDTH; //Move into the next bandwidth slice NOTE: spectrum.sampling_rate = SEARCH_SLICE_WIDTH
|
||||
else
|
||||
f_center = f_center_ini; //Start a new sweep
|
||||
|
||||
receiver_model.set_tuning_frequency(f_center); //tune rx for this slice
|
||||
baseband::spectrum_streaming_start(); //Do the RX
|
||||
}
|
||||
|
||||
void GlassView::on_hide()
|
||||
{
|
||||
baseband::spectrum_streaming_stop();
|
||||
display.scroll_disable();
|
||||
}
|
||||
|
||||
void GlassView::on_show()
|
||||
{
|
||||
display.scroll_set_area( 109, 319); //Restart scroll on the correct coordinates
|
||||
baseband::spectrum_streaming_start();
|
||||
}
|
||||
|
||||
void GlassView::on_range_changed()
|
||||
{
|
||||
f_min = field_frequency_min.value();
|
||||
f_max = field_frequency_max.value();
|
||||
search_span = f_max - f_min;
|
||||
|
||||
field_marker.set_range(f_min, f_max); //Move the marker between range
|
||||
field_marker.set_value(f_min + (search_span / 2)); //Put MARKER AT MIDDLE RANGE
|
||||
text_range.set(to_string_dec_uint(search_span));
|
||||
|
||||
f_min = (f_min)*MHZ_DIV; //Transpose into full frequency realm
|
||||
f_max = (f_max)*MHZ_DIV;
|
||||
search_span = search_span * MHZ_DIV;
|
||||
|
||||
marker_pixel_step = search_span / 240; //Each pixel value in Hz
|
||||
text_marker_pm.set(to_string_dec_uint((marker_pixel_step / X2_MHZ_DIV) + 1)); // Give idea of +/- marker precision
|
||||
|
||||
int32_t marker_step = marker_pixel_step / MHZ_DIV;
|
||||
if (!marker_step)
|
||||
field_marker.set_step(1); //in case selected range is less than 240 (pixels)
|
||||
else
|
||||
field_marker.set_step(marker_step); //step needs to be a pixel wide.
|
||||
|
||||
f_center_ini = f_min + (SEARCH_SLICE_WIDTH / 2); //Initial center frequency for sweep
|
||||
f_center_ini += SEARCH_SLICE_WIDTH; //euquiq: Why do I need to move the center ???!!! (shift needed for marker accuracy)
|
||||
|
||||
PlotMarker(field_marker.value()); //Refresh marker on screen
|
||||
|
||||
f_center = f_center_ini; //Reset sweep into first slice
|
||||
pixel_index = 0; //reset pixel counter
|
||||
max_power = 0;
|
||||
bins_Hz_size = 0; //reset amount of Hz filled up by pixels
|
||||
|
||||
baseband::set_spectrum(SEARCH_SLICE_WIDTH, field_trigger.value());
|
||||
receiver_model.set_tuning_frequency(f_center_ini); //tune rx for this slice
|
||||
}
|
||||
|
||||
void GlassView::PlotMarker(rf::Frequency pos)
|
||||
{
|
||||
pos = pos * MHZ_DIV;
|
||||
pos -= f_min;
|
||||
pos = pos / marker_pixel_step; //Real pixel
|
||||
|
||||
portapack::display.fill_rectangle({0, 100, 240, 8}, Color::black()); //Clear old marker and whole marker rectangle btw
|
||||
portapack::display.fill_rectangle({pos - 2, 100, 5, 3}, Color::red()); //Red marker middle
|
||||
portapack::display.fill_rectangle({pos - 1, 103, 3, 3}, Color::red()); //Red marker middle
|
||||
portapack::display.fill_rectangle({pos, 106, 1, 2}, Color::red()); //Red marker middle
|
||||
}
|
||||
|
||||
GlassView::GlassView(
|
||||
NavigationView &nav) : nav_(nav)
|
||||
{
|
||||
baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
|
||||
|
||||
add_children({&labels,
|
||||
&field_frequency_min,
|
||||
&field_frequency_max,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&text_range,
|
||||
&filter_config,
|
||||
&field_rf_amp,
|
||||
&range_presets,
|
||||
&field_marker,
|
||||
&text_marker_pm,
|
||||
&field_trigger
|
||||
});
|
||||
|
||||
load_Presets(); //Load available presets from TXT files (or default)
|
||||
|
||||
field_frequency_min.set_value(presets_db[0].min); //Defaults to first preset
|
||||
field_frequency_min.on_change = [this](int32_t v) {
|
||||
if (v >= field_frequency_max.value())
|
||||
field_frequency_max.set_value(v + 240);
|
||||
this->on_range_changed();
|
||||
};
|
||||
|
||||
field_frequency_max.set_value(presets_db[0].max); //Defaults to first preset
|
||||
field_frequency_max.on_change = [this](int32_t v) {
|
||||
if (v <= field_frequency_min.value())
|
||||
field_frequency_min.set_value(v - 240);
|
||||
this->on_range_changed();
|
||||
};
|
||||
|
||||
field_lna.set_value(receiver_model.lna());
|
||||
field_lna.on_change = [this](int32_t v) {
|
||||
this->on_lna_changed(v);
|
||||
};
|
||||
|
||||
field_vga.set_value(receiver_model.vga());
|
||||
field_vga.on_change = [this](int32_t v_db) {
|
||||
this->on_vga_changed(v_db);
|
||||
};
|
||||
|
||||
filter_config.set_selected_index(0);
|
||||
filter_config.on_change = [this](size_t n, OptionsField::value_t v) {
|
||||
min_color_power = v;
|
||||
};
|
||||
|
||||
range_presets.on_change = [this](size_t n, OptionsField::value_t v) {
|
||||
field_frequency_min.set_value(presets_db[v].min,false);
|
||||
field_frequency_max.set_value(presets_db[v].max,false);
|
||||
this->on_range_changed();
|
||||
};
|
||||
|
||||
field_marker.on_change = [this](int32_t v) {
|
||||
PlotMarker(v); //Refresh marker on screen
|
||||
};
|
||||
|
||||
field_marker.on_select = [this](NumberField&) {
|
||||
f_center = field_marker.value();
|
||||
f_center = f_center * MHZ_DIV;
|
||||
receiver_model.set_tuning_frequency(f_center); //Center tune rx in marker freq.
|
||||
receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO
|
||||
nav_.pop();
|
||||
nav_.push<AnalogAudioView>(); //Jump into audio view
|
||||
};
|
||||
|
||||
field_trigger.set_value(32); //Defaults to 32, as normal triggering resolution
|
||||
field_trigger.on_change = [this](int32_t v) {
|
||||
baseband::set_spectrum(SEARCH_SLICE_WIDTH, v);
|
||||
};
|
||||
|
||||
display.scroll_set_area( 109, 319);
|
||||
baseband::set_spectrum(SEARCH_SLICE_WIDTH, field_trigger.value()); //trigger:
|
||||
// Discord User jteich: WidebandSpectrum::on_message to set the trigger value. In WidebandSpectrum::execute ,
|
||||
// it keeps adding the output of the fft to the buffer until "trigger" number of calls are made,
|
||||
//at which time it pushes the buffer up with channel_spectrum.feed
|
||||
|
||||
on_range_changed();
|
||||
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
|
||||
receiver_model.set_sampling_rate(SEARCH_SLICE_WIDTH); //20mhz
|
||||
receiver_model.set_baseband_bandwidth(SEARCH_SLICE_WIDTH); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz
|
||||
receiver_model.set_squelch_level(0);
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
void GlassView::load_Presets() {
|
||||
File presets_file; //LOAD /WHIPCALC/ANTENNAS.TXT from microSD
|
||||
auto result = presets_file.open("LOOKINGGLASS/PRESETS.TXT");
|
||||
presets_db.clear(); //Start with fresh db
|
||||
if (result.is_valid()) {
|
||||
presets_Default(); //There is no txt, store a default range
|
||||
} else {
|
||||
|
||||
std::string line; //There is a txt file
|
||||
char one_char[1]; //Read it char by char
|
||||
for (size_t pointer=0; pointer < presets_file.size();pointer++) {
|
||||
presets_file.seek(pointer);
|
||||
presets_file.read(one_char, 1);
|
||||
if ((int)one_char[0] > 31) { //ascii space upwards
|
||||
line += one_char[0]; //Add it to the textline
|
||||
}
|
||||
else if (one_char[0] == '\n') { //New Line
|
||||
txtline_process(line); //make sense of this textline
|
||||
line.clear(); //Ready for next textline
|
||||
}
|
||||
}
|
||||
if (line.length() > 0) txtline_process(line); //Last line had no newline at end ?
|
||||
if (!presets_db.size()) presets_Default(); //no antenna on txt, use default
|
||||
}
|
||||
|
||||
populate_Presets();
|
||||
}
|
||||
|
||||
void GlassView::txtline_process(std::string& line)
|
||||
{
|
||||
if (line.find("#") != std::string::npos) return; //Line is just a comment
|
||||
|
||||
size_t comma = line.find(","); //Get first comma position
|
||||
if (comma == std::string::npos) return; //No comma at all
|
||||
|
||||
size_t previous = 0;
|
||||
preset_entry new_preset;
|
||||
|
||||
new_preset.min = std::stoi(line.substr(0,comma));
|
||||
if (!new_preset.min) return; //No frequency!
|
||||
|
||||
previous = comma + 1;
|
||||
comma = line.find(",",previous); //Search for next delimiter
|
||||
if (comma == std::string::npos) return; //No comma at all
|
||||
|
||||
new_preset.max = std::stoi(line.substr(previous,comma - previous));
|
||||
if (!new_preset.max) return; //No frequency!
|
||||
|
||||
new_preset.label = line.substr(comma + 1);
|
||||
if (new_preset.label.size() == 0) return; //No label ?
|
||||
|
||||
presets_db.push_back(new_preset); //Add this preset.
|
||||
}
|
||||
|
||||
void GlassView::populate_Presets()
|
||||
{
|
||||
using option_t = std::pair<std::string, int32_t>;
|
||||
using options_t = std::vector<option_t>;
|
||||
options_t entries;
|
||||
|
||||
for (preset_entry preset : presets_db)
|
||||
{ //go thru all available presets
|
||||
entries.emplace_back(preset.label,entries.size());
|
||||
}
|
||||
range_presets.set_options(entries);
|
||||
}
|
||||
|
||||
void GlassView::presets_Default()
|
||||
{
|
||||
presets_db.clear();
|
||||
presets_db.push_back({2320, 2560, "DEFAULT WIFI 2.4GHz"});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2020 euquiq
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "receiver_model.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "spectrum_color_lut.hpp"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
#define SEARCH_SLICE_WIDTH 20000000 // Each slice bandwidth 20 MHz
|
||||
#define MHZ_DIV 1000000
|
||||
#define X2_MHZ_DIV 2000000
|
||||
|
||||
class GlassView : public View
|
||||
{
|
||||
public:
|
||||
GlassView(NavigationView &nav);
|
||||
~GlassView();
|
||||
std::string title() const override { return "Looking Glass"; };
|
||||
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
struct preset_entry
|
||||
{
|
||||
rf::Frequency min{};
|
||||
rf::Frequency max{};
|
||||
std::string label{};
|
||||
};
|
||||
|
||||
std::vector<preset_entry> presets_db{};
|
||||
|
||||
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
||||
void do_timers();
|
||||
void on_range_changed();
|
||||
void on_lna_changed(int32_t v_db);
|
||||
void on_vga_changed(int32_t v_db);
|
||||
void add_spectrum_pixel(Color color);
|
||||
void PlotMarker(rf::Frequency pos);
|
||||
void load_Presets();
|
||||
void txtline_process(std::string& line);
|
||||
void populate_Presets();
|
||||
void presets_Default();
|
||||
|
||||
rf::Frequency f_min { 0 }, f_max { 0 };
|
||||
rf::Frequency search_span { 0 };
|
||||
rf::Frequency f_center { 0 };
|
||||
rf::Frequency f_center_ini { 0 };
|
||||
rf::Frequency marker_pixel_step { 0 };
|
||||
rf::Frequency each_bin_size { SEARCH_SLICE_WIDTH / 240 };
|
||||
rf::Frequency bins_Hz_size { 0 };
|
||||
uint8_t min_color_power { 0 };
|
||||
uint32_t pixel_index { 0 };
|
||||
std::array<Color, 240> spectrum_row = { 0 };
|
||||
ChannelSpectrumFIFO* fifo { nullptr };
|
||||
uint8_t max_power = 0;
|
||||
|
||||
Labels labels{
|
||||
{{0, 0}, "MIN: MAX: LNA VGA ", Color::light_grey()},
|
||||
{{0, 1 * 16}, " RANGE: FILTER: AMP:", Color::light_grey()},
|
||||
{{0, 2 * 16}, "PRESET:", Color::light_grey()},
|
||||
{{0, 3 * 16}, "MARKER: MHz +/- MHz", Color::light_grey()},
|
||||
{{0, 4 * 16}, "RESOLUTION: (fft trigger)", Color::light_grey()}
|
||||
};
|
||||
|
||||
NumberField field_frequency_min {
|
||||
{ 4 * 8, 0 * 16 },
|
||||
4,
|
||||
{ 0, 6960 },
|
||||
240,
|
||||
' '
|
||||
};
|
||||
|
||||
NumberField field_frequency_max {
|
||||
{ 13 * 8, 0 * 16 },
|
||||
4,
|
||||
{ 240, 7200 },
|
||||
240,
|
||||
' '
|
||||
};
|
||||
|
||||
LNAGainField field_lna {
|
||||
{ 21 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
VGAGainField field_vga {
|
||||
{ 27 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
Text text_range{
|
||||
{7 * 8, 1 * 16, 4 * 8, 16},
|
||||
""};
|
||||
|
||||
OptionsField filter_config{
|
||||
{19 * 8, 1 * 16},
|
||||
4,
|
||||
{
|
||||
{"OFF ", 0},
|
||||
{"MID ", 118}, //85 +25 (110) + a bit more to kill all blue
|
||||
{"HIGH", 202}, //168 + 25 (193)
|
||||
}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{29 * 8, 1 * 16}};
|
||||
|
||||
OptionsField range_presets{
|
||||
{7 * 8, 2 * 16},
|
||||
20,
|
||||
{
|
||||
{" NONE (WIFI 2.4GHz)", 0},
|
||||
}};
|
||||
|
||||
NumberField field_marker{
|
||||
{7 * 8, 3 * 16},
|
||||
4,
|
||||
{0, 7200},
|
||||
25,
|
||||
' '};
|
||||
|
||||
Text text_marker_pm{
|
||||
{20 * 8, 3 * 16, 2 * 8, 16},
|
||||
""};
|
||||
|
||||
NumberField field_trigger{
|
||||
{11 * 8, 4 * 16},
|
||||
3,
|
||||
{2, 128},
|
||||
2,
|
||||
' '};
|
||||
|
||||
|
||||
MessageHandlerRegistration message_handler_spectrum_config {
|
||||
Message::ID::ChannelSpectrumConfig,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const ChannelSpectrumConfigMessage*>(p);
|
||||
this->fifo = message.fifo;
|
||||
}
|
||||
};
|
||||
MessageHandlerRegistration message_handler_frame_sync {
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
if( this->fifo ) {
|
||||
ChannelSpectrum channel_spectrum;
|
||||
while( fifo->out(channel_spectrum) ) {
|
||||
this->on_channel_spectrum(channel_spectrum);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,7 +37,17 @@ using namespace portapack;
|
||||
namespace ui {
|
||||
|
||||
void MicTXView::focus() {
|
||||
field_frequency.focus();
|
||||
switch(focused_ui) {
|
||||
case 0:
|
||||
field_frequency.focus();
|
||||
break;
|
||||
case 1:
|
||||
field_rxfrequency.focus();
|
||||
break;
|
||||
default:
|
||||
field_va.focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MicTXView::update_vumeter() {
|
||||
@@ -61,22 +71,25 @@ void MicTXView::configure_baseband() {
|
||||
|
||||
void MicTXView::set_tx(bool enable) {
|
||||
if (enable) {
|
||||
if (rx_enabled) //If audio RX is enabled
|
||||
rxaudio(false); //Then turn off audio RX
|
||||
transmitting = true;
|
||||
configure_baseband();
|
||||
transmitter_model.set_tuning_frequency(tx_frequency);
|
||||
transmitter_model.set_tx_gain(tx_gain);
|
||||
transmitter_model.set_rf_amp(rf_amp);
|
||||
transmitter_model.enable();
|
||||
portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming
|
||||
//gpio_tx.write(1);
|
||||
//led_tx.on();
|
||||
} else {
|
||||
if (transmitting && rogerbeep_enabled) {
|
||||
baseband::request_beep();
|
||||
transmitting = false;
|
||||
} else {
|
||||
baseband::request_beep(); //Transmit the roger beep
|
||||
transmitting = false; //And flag the end of the transmission so ...
|
||||
} else { // (if roger beep was enabled, this will be executed after the beep ends transmitting.
|
||||
transmitting = false;
|
||||
configure_baseband();
|
||||
transmitter_model.disable();
|
||||
//gpio_tx.write(0);
|
||||
//led_tx.off();
|
||||
if (rx_enabled) //If audio RX is enabled and we've been transmitting
|
||||
rxaudio(true); //Turn back on audio RX
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,13 +126,56 @@ void MicTXView::do_timing() {
|
||||
} else {
|
||||
// Check for PTT release
|
||||
const auto switches_state = get_switches_state();
|
||||
if (!switches_state[0] && transmitting) // Right button
|
||||
if (!switches_state[4] && transmitting && !button_touch) // Select button
|
||||
set_tx(false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Hmmmm. Maybe useless now.
|
||||
void MicTXView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
transmitter_model.set_tuning_frequency(f);
|
||||
//if ( rx_enabled )
|
||||
receiver_model.set_tuning_frequency(f); //Update freq also for RX
|
||||
}
|
||||
*/
|
||||
|
||||
void MicTXView::rxaudio(bool is_on) {
|
||||
if (is_on) {
|
||||
audio::input::stop();
|
||||
baseband::shutdown();
|
||||
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
||||
receiver_model.set_sampling_rate(3072000);
|
||||
receiver_model.set_baseband_bandwidth(1750000);
|
||||
// receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out.
|
||||
receiver_model.set_tuning_frequency(rx_frequency); // Now with seperate controls!
|
||||
receiver_model.set_lna(rx_lna);
|
||||
receiver_model.set_vga(rx_vga);
|
||||
receiver_model.set_rf_amp(rx_amp);
|
||||
receiver_model.enable();
|
||||
audio::output::start();
|
||||
} else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX.
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
baseband::run_image(portapack::spi_flash::image_tag_mic_tx);
|
||||
audio::input::start();
|
||||
// transmitter_model.enable();
|
||||
portapack::pin_i2s0_rx_sda.mode(3);
|
||||
// transmitting = false;
|
||||
configure_baseband();
|
||||
// transmitter_model.disable();
|
||||
}
|
||||
}
|
||||
|
||||
void MicTXView::on_headphone_volume_changed(int32_t v) {
|
||||
//if (rx_enabled) {
|
||||
const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max;
|
||||
receiver_model.set_headphone_volume(new_volume);
|
||||
//}
|
||||
}
|
||||
|
||||
void MicTXView::set_ptt_visibility(bool v) {
|
||||
tx_button.hidden(!v);
|
||||
}
|
||||
|
||||
MicTXView::MicTXView(
|
||||
@@ -134,17 +190,27 @@ MicTXView::MicTXView(
|
||||
&labels,
|
||||
&vumeter,
|
||||
&options_gain,
|
||||
&check_va,
|
||||
// &check_va,
|
||||
&field_va,
|
||||
&field_va_level,
|
||||
&field_va_attack,
|
||||
&field_va_decay,
|
||||
&field_bw,
|
||||
&field_rfgain,
|
||||
&field_rfamp,
|
||||
&field_frequency,
|
||||
&options_tone_key,
|
||||
&check_rogerbeep,
|
||||
&text_ptt
|
||||
&check_rxactive,
|
||||
&field_volume,
|
||||
&field_squelch,
|
||||
&field_rxfrequency,
|
||||
&field_rxlna,
|
||||
&field_rxvga,
|
||||
&field_rxamp,
|
||||
&tx_button
|
||||
});
|
||||
|
||||
|
||||
tone_keys_populate(options_tone_key);
|
||||
options_tone_key.on_change = [this](size_t i, int32_t) {
|
||||
tone_key_index = i;
|
||||
@@ -157,17 +223,24 @@ MicTXView::MicTXView(
|
||||
};
|
||||
options_gain.set_selected_index(1); // x1.0
|
||||
|
||||
tx_frequency = transmitter_model.tuning_frequency();
|
||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
tx_frequency = f;
|
||||
if(!rx_enabled)
|
||||
transmitter_model.set_tuning_frequency(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
focused_ui = 0;
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||
auto new_view = nav.push<FrequencyKeypadView>(tx_frequency);
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
tx_frequency = f;
|
||||
if(!rx_enabled)
|
||||
transmitter_model.set_tuning_frequency(f);
|
||||
this->field_frequency.set_value(f);
|
||||
set_dirty();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -176,18 +249,61 @@ MicTXView::MicTXView(
|
||||
};
|
||||
field_bw.set_value(10);
|
||||
|
||||
tx_gain = transmitter_model.tx_gain();
|
||||
field_rfgain.on_change = [this](int32_t v) {
|
||||
tx_gain = v;
|
||||
|
||||
};
|
||||
field_rfgain.set_value(tx_gain);
|
||||
|
||||
rf_amp = transmitter_model.rf_amp();
|
||||
field_rfamp.on_change = [this](int32_t v) {
|
||||
rf_amp = (bool)v;
|
||||
};
|
||||
field_rfamp.set_value(rf_amp ? 14 : 0);
|
||||
|
||||
/*
|
||||
check_va.on_select = [this](Checkbox&, bool v) {
|
||||
va_enabled = v;
|
||||
text_ptt.hidden(v);
|
||||
text_ptt.hidden(v); //hide / show PTT text
|
||||
check_rxactive.hidden(v); //hide / show the RX AUDIO
|
||||
set_dirty(); //Refresh display
|
||||
};
|
||||
*/
|
||||
field_va.set_selected_index(1);
|
||||
field_va.on_change = [this](size_t, int32_t v) {
|
||||
switch(v) {
|
||||
case 0:
|
||||
va_enabled = 0;
|
||||
this->set_ptt_visibility(0);
|
||||
check_rxactive.hidden(0);
|
||||
ptt_enabled = 0;
|
||||
break;
|
||||
case 1:
|
||||
va_enabled = 0;
|
||||
this->set_ptt_visibility(1);
|
||||
check_rxactive.hidden(0);
|
||||
ptt_enabled = 1;
|
||||
break;
|
||||
case 2:
|
||||
if (!rx_enabled) {
|
||||
va_enabled = 1;
|
||||
this->set_ptt_visibility(0);
|
||||
check_rxactive.hidden(1);
|
||||
ptt_enabled = 0;
|
||||
} else {
|
||||
field_va.set_selected_index(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
set_dirty();
|
||||
};
|
||||
check_va.set_value(false);
|
||||
|
||||
|
||||
check_rogerbeep.on_select = [this](Checkbox&, bool v) {
|
||||
rogerbeep_enabled = v;
|
||||
};
|
||||
check_rogerbeep.set_value(false);
|
||||
|
||||
|
||||
field_va_level.on_change = [this](int32_t v) {
|
||||
va_level = v;
|
||||
vumeter.set_mark(v);
|
||||
@@ -203,7 +319,89 @@ MicTXView::MicTXView(
|
||||
decay_ms = v;
|
||||
};
|
||||
field_va_decay.set_value(1000);
|
||||
|
||||
check_rxactive.on_select = [this](Checkbox&, bool v) {
|
||||
// vumeter.set_value(0); //Start with a clean vumeter
|
||||
rx_enabled = v;
|
||||
// check_va.hidden(v); //Hide or show voice activation
|
||||
rxaudio(v); //Activate-Deactivate audio rx accordingly
|
||||
set_dirty(); //Refresh interface
|
||||
};
|
||||
|
||||
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
|
||||
field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); };
|
||||
|
||||
field_squelch.on_change = [this](int32_t v) {
|
||||
receiver_model.set_squelch_level(100 - v);
|
||||
};
|
||||
field_squelch.set_value(0);
|
||||
receiver_model.set_squelch_level(0);
|
||||
|
||||
rx_frequency = receiver_model.tuning_frequency();
|
||||
field_rxfrequency.set_value(rx_frequency);
|
||||
field_rxfrequency.set_step(receiver_model.frequency_step());
|
||||
field_rxfrequency.on_change = [this](rf::Frequency f) {
|
||||
rx_frequency = f;
|
||||
if(rx_enabled)
|
||||
receiver_model.set_tuning_frequency(f);
|
||||
};
|
||||
field_rxfrequency.on_edit = [this, &nav]() {
|
||||
focused_ui = 1;
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(rx_frequency);
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
rx_frequency = f;
|
||||
if(rx_enabled)
|
||||
receiver_model.set_tuning_frequency(f);
|
||||
this->field_rxfrequency.set_value(f);
|
||||
set_dirty();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
rx_lna = receiver_model.lna();
|
||||
field_rxlna.on_change = [this](int32_t v) {
|
||||
rx_lna = v;
|
||||
if(rx_enabled)
|
||||
receiver_model.set_lna(v);
|
||||
};
|
||||
field_rxlna.set_value(rx_lna);
|
||||
|
||||
rx_vga = receiver_model.vga();
|
||||
field_rxvga.on_change = [this](int32_t v) {
|
||||
rx_vga = v;
|
||||
if(rx_enabled)
|
||||
receiver_model.set_vga(v);
|
||||
};
|
||||
field_rxvga.set_value(rx_vga);
|
||||
|
||||
rx_amp = receiver_model.rf_amp();
|
||||
field_rxamp.on_change = [this](int32_t v) {
|
||||
rx_amp = v;
|
||||
if(rx_enabled)
|
||||
receiver_model.set_rf_amp(rx_amp);
|
||||
};
|
||||
field_rxamp.set_value(rx_amp);
|
||||
|
||||
tx_button.on_select = [this](Button&) {
|
||||
if(ptt_enabled && !transmitting) {
|
||||
set_tx(true);
|
||||
}
|
||||
};
|
||||
|
||||
tx_button.on_touch_release = [this](Button&) {
|
||||
if(button_touch) {
|
||||
button_touch = false;
|
||||
set_tx(false);
|
||||
}
|
||||
};
|
||||
|
||||
tx_button.on_touch_press = [this](Button&) {
|
||||
if(!transmitting) {
|
||||
button_touch = true;
|
||||
}
|
||||
};
|
||||
|
||||
transmitter_model.set_sampling_rate(sampling_rate);
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
|
||||
@@ -215,7 +413,10 @@ MicTXView::MicTXView(
|
||||
|
||||
MicTXView::~MicTXView() {
|
||||
audio::input::stop();
|
||||
transmitter_model.set_tuning_frequency(tx_frequency); // Save Tx frequency instead of Rx. Or maybe we need some "System Wide" changes to seperate Tx and Rx frequency.
|
||||
transmitter_model.disable();
|
||||
if (rx_enabled) //Also turn off audio rx if enabled
|
||||
rxaudio(false);
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "transmitter_model.hpp"
|
||||
#include "tone_key.hpp"
|
||||
#include "message.hpp"
|
||||
#include "receiver_model.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@@ -46,30 +47,40 @@ public:
|
||||
void focus() override;
|
||||
|
||||
// PTT: Enable through KeyEvent (only works with presses), disable by polling :(
|
||||
// This is the old "RIGHT BUTTON" method.
|
||||
/*
|
||||
bool on_key(const KeyEvent key) {
|
||||
if ((key == KeyEvent::Right) && (!va_enabled)) {
|
||||
if ((key == KeyEvent::Right) && (!va_enabled) && ptt_enabled) {
|
||||
set_tx(true);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
};
|
||||
|
||||
std::string title() const override { return "Microphone TX"; };
|
||||
*/
|
||||
|
||||
std::string title() const override { return "Mic TX RX"; };
|
||||
|
||||
private:
|
||||
static constexpr uint32_t sampling_rate = 1536000U;
|
||||
static constexpr uint32_t lcd_frame_duration = (256 * 1000UL) / 60; // 1 frame @ 60fps in ms .8 fixed point
|
||||
static constexpr uint32_t lcd_frame_duration = (256 * 1000UL) / 60; // 1 frame @ 60fps in ms .8 fixed point /60
|
||||
|
||||
void update_vumeter();
|
||||
void do_timing();
|
||||
void set_tx(bool enable);
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
// void on_tuning_frequency_changed(rf::Frequency f);
|
||||
void on_tx_progress(const bool done);
|
||||
void configure_baseband();
|
||||
|
||||
void rxaudio(bool is_on);
|
||||
void on_headphone_volume_changed(int32_t v);
|
||||
|
||||
void set_ptt_visibility(bool v);
|
||||
|
||||
bool transmitting { false };
|
||||
bool va_enabled { };
|
||||
bool rogerbeep_enabled { };
|
||||
bool va_enabled { false };
|
||||
bool ptt_enabled { true };
|
||||
bool rogerbeep_enabled { false };
|
||||
bool rx_enabled { false };
|
||||
uint32_t tone_key_index { };
|
||||
float mic_gain { 1.0 };
|
||||
uint32_t audio_level { 0 };
|
||||
@@ -78,25 +89,45 @@ private:
|
||||
uint32_t decay_ms { };
|
||||
uint32_t attack_timer { 0 };
|
||||
uint32_t decay_timer { 0 };
|
||||
int32_t tx_gain { 47 };
|
||||
bool rf_amp { false };
|
||||
int32_t rx_lna { 32 };
|
||||
int32_t rx_vga { 32 };
|
||||
bool rx_amp { false };
|
||||
rf::Frequency tx_frequency { 0 };
|
||||
rf::Frequency rx_frequency { 0 };
|
||||
int32_t focused_ui { 2 };
|
||||
bool button_touch { false };
|
||||
|
||||
|
||||
Labels labels {
|
||||
{ { 7 * 8, 1 * 8 }, "Mic. gain:", Color::light_grey() },
|
||||
{ { 7 * 8, 4 * 8 }, "Frequency:", Color::light_grey() },
|
||||
{ { 7 * 8, 6 * 8 }, "Bandwidth: kHz", Color::light_grey() },
|
||||
{ { 9 * 8, 13 * 8 }, "Level: /255", Color::light_grey() },
|
||||
{ { 9 * 8, 15 * 8 }, "Attack: ms", Color::light_grey() },
|
||||
{ { 9 * 8, 17 * 8 }, "Decay: ms", Color::light_grey() },
|
||||
{ { 7 * 8, 21 * 8 }, "Tone key:", Color::light_grey() }
|
||||
{ { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() },
|
||||
{ { 3 * 8, 3 * 8 }, "F:", Color::light_grey() },
|
||||
{ { 15 * 8, 3 * 8 }, "BW: kHz", Color::light_grey() },
|
||||
{ { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() },
|
||||
{ {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() },
|
||||
{ { 3 * 8, 8 * 8 }, "TX Activation:", Color::light_grey() },
|
||||
{ { 4 * 8, 10 * 8 }, "LVL:", Color::light_grey() },
|
||||
{ {12 * 8, 10 * 8 }, "ATT:", Color::light_grey() },
|
||||
{ {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() },
|
||||
{ { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() },
|
||||
{ { 9 * 8, 23 * 8 }, "VOL:", Color::light_grey() },
|
||||
{ {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() },
|
||||
{ { 5 * 8, 25 * 8 }, "F:", Color::light_grey() },
|
||||
{ { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()},
|
||||
{ {12 * 8, 27 * 8 }, "VGA:", Color::light_grey()},
|
||||
{ {19 * 8, 27 * 8 }, "AMP:", Color::light_grey()}
|
||||
};
|
||||
|
||||
VuMeter vumeter {
|
||||
{ 1 * 8, 2 * 8, 5 * 8, 32 * 8 },
|
||||
20,
|
||||
false
|
||||
{ 0 * 8, 1 * 8, 2 * 8, 33 * 8 },
|
||||
12,
|
||||
true
|
||||
};
|
||||
|
||||
|
||||
OptionsField options_gain {
|
||||
{ 17 * 8, 1 * 8 },
|
||||
{ 13 * 8, 1 * 8 },
|
||||
4,
|
||||
{
|
||||
{ "x0.5", 5 },
|
||||
@@ -107,39 +138,65 @@ private:
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 17 * 8, 4 * 8 },
|
||||
{ 5 * 8, 3 * 8 },
|
||||
};
|
||||
NumberField field_bw {
|
||||
{ 17 * 8, 6 * 8 },
|
||||
{ 18 * 8, 3 * 8 },
|
||||
3,
|
||||
{ 0, 150 },
|
||||
1,
|
||||
' '
|
||||
};
|
||||
|
||||
NumberField field_rfgain {
|
||||
{ 8 * 8, 5 * 8 },
|
||||
2,
|
||||
{ 0, 47 },
|
||||
1,
|
||||
' '
|
||||
};
|
||||
NumberField field_rfamp {
|
||||
{ 15 * 8, 5 * 8 },
|
||||
2,
|
||||
{ 0, 14 },
|
||||
14,
|
||||
' '
|
||||
};
|
||||
/*
|
||||
Checkbox check_va {
|
||||
{ 7 * 8, 10 * 8 },
|
||||
{ 3 * 8, (10 * 8) - 4 },
|
||||
7,
|
||||
"Voice activation",
|
||||
false
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
OptionsField field_va {
|
||||
{ 17 * 8, 8 * 8 },
|
||||
3,
|
||||
{
|
||||
{" OFF", 0},
|
||||
{" PTT", 1},
|
||||
{"AUTO", 2}
|
||||
}
|
||||
};
|
||||
|
||||
NumberField field_va_level {
|
||||
{ 15 * 8, 13 * 8 },
|
||||
{ 8 * 8, 10 * 8 },
|
||||
3,
|
||||
{ 0, 255 },
|
||||
2,
|
||||
' '
|
||||
};
|
||||
NumberField field_va_attack {
|
||||
{ 16 * 8, 15 * 8 },
|
||||
{ 16 * 8, 10 * 8 },
|
||||
3,
|
||||
{ 0, 999 },
|
||||
20,
|
||||
' '
|
||||
};
|
||||
NumberField field_va_decay {
|
||||
{ 15 * 8, 17 * 8 },
|
||||
{ 24 * 8, 10 * 8 },
|
||||
4,
|
||||
{ 0, 9999 },
|
||||
100,
|
||||
@@ -147,28 +204,81 @@ private:
|
||||
};
|
||||
|
||||
OptionsField options_tone_key {
|
||||
{ 7 * 8, 23 * 8 },
|
||||
{ 10 * 8, ( 15 * 8 ) - 2 },
|
||||
23,
|
||||
{ }
|
||||
};
|
||||
|
||||
Checkbox check_rogerbeep {
|
||||
{ 7 * 8, 26 * 8 },
|
||||
{ 3 * 8, ( 16 * 8 ) + 4 },
|
||||
10,
|
||||
"Roger beep",
|
||||
false
|
||||
};
|
||||
|
||||
Text text_ptt {
|
||||
{ 7 * 8, 17 * 16, 16 * 8, 16 },
|
||||
"PTT: RIGHT BUTTON"
|
||||
|
||||
Checkbox check_rxactive {
|
||||
{ 3 * 8, ( 21 * 8 ) - 4 },
|
||||
8,
|
||||
"RX audio listening",
|
||||
false
|
||||
};
|
||||
|
||||
NumberField field_volume {
|
||||
{ 13 * 8, 23 * 8 },
|
||||
2,
|
||||
{ 0, 99 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_squelch {
|
||||
{ 20 * 8, 25 * 8 },
|
||||
2,
|
||||
{ 0, 99 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
FrequencyField field_rxfrequency {
|
||||
{ 7 * 8, 25 * 8 },
|
||||
};
|
||||
|
||||
NumberField field_rxlna {
|
||||
{ 9 * 8, 27 * 8 },
|
||||
2,
|
||||
{ 0, 40 },
|
||||
8,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_rxvga {
|
||||
{ 16 * 8, 27 * 8 },
|
||||
2,
|
||||
{ 0, 62 },
|
||||
2,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_rxamp {
|
||||
{ 23 * 8, 27 * 8 },
|
||||
1,
|
||||
{ 0, 1 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
Button tx_button {
|
||||
{ 10 * 8, 30 * 8, 10 * 8, 5 * 8 },
|
||||
"TX",
|
||||
true
|
||||
};
|
||||
|
||||
|
||||
MessageHandlerRegistration message_handler_lcd_sync {
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->update_vumeter();
|
||||
this->do_timing();
|
||||
this->update_vumeter();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -69,6 +69,25 @@ static msg_t ookthread_fn(void * arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static msg_t loopthread_fn(void * arg) {
|
||||
MorseView * arg_c = (MorseView*)arg;
|
||||
uint32_t wait = arg_c->loop;
|
||||
|
||||
chRegSetThreadName("loopthread");
|
||||
|
||||
for (uint32_t i = 0; i < wait; i++) {
|
||||
if (chThdShouldTerminate()) break;
|
||||
|
||||
arg_c->on_loop_progress(i, false);
|
||||
chThdSleepMilliseconds(1000);
|
||||
}
|
||||
|
||||
arg_c->on_loop_progress(0, true);
|
||||
chThdExit(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MorseView::on_set_text(NavigationView& nav) {
|
||||
text_prompt(nav, buffer, 28);
|
||||
}
|
||||
@@ -115,9 +134,9 @@ bool MorseView::start_tx() {
|
||||
void MorseView::update_tx_duration() {
|
||||
uint32_t duration_ms;
|
||||
|
||||
time_unit_ms = field_time_unit.value();
|
||||
time_unit_ms = 1200 / field_speed.value();
|
||||
symbol_count = morse_encode(message, time_unit_ms, field_tone.value(), &time_units);
|
||||
|
||||
|
||||
if (symbol_count) {
|
||||
duration_ms = time_units * time_unit_ms;
|
||||
text_tx_duration.set(to_string_dec_uint(duration_ms / 1000) + "." + to_string_dec_uint((duration_ms / 100) % 10, 1) + "s ");
|
||||
@@ -130,7 +149,28 @@ void MorseView::on_tx_progress(const uint32_t progress, const bool done) {
|
||||
if (done) {
|
||||
transmitter_model.disable();
|
||||
progressbar.set_value(0);
|
||||
tx_view.set_transmitting(false);
|
||||
|
||||
if (loop && run) {
|
||||
text_tx_duration.set("wait");
|
||||
progressbar.set_max(loop);
|
||||
progressbar.set_value(0);
|
||||
|
||||
if (loopthread) {
|
||||
chThdRelease(loopthread);
|
||||
loopthread = nullptr;
|
||||
}
|
||||
|
||||
loopthread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO, loopthread_fn, this);
|
||||
} else {
|
||||
tx_view.set_transmitting(false);
|
||||
}
|
||||
} else
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void MorseView::on_loop_progress(const uint32_t progress, const bool done) {
|
||||
if (done) {
|
||||
start_tx();
|
||||
} else
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
@@ -152,9 +192,10 @@ MorseView::MorseView(
|
||||
&labels,
|
||||
&checkbox_foxhunt,
|
||||
&options_foxhunt,
|
||||
&field_time_unit,
|
||||
&field_speed,
|
||||
&field_tone,
|
||||
&options_modulation,
|
||||
&options_loop,
|
||||
&text_tx_duration,
|
||||
&text_message,
|
||||
&button_message,
|
||||
@@ -163,9 +204,10 @@ MorseView::MorseView(
|
||||
});
|
||||
|
||||
// Default settings
|
||||
field_time_unit.set_value(50); // 50ms unit
|
||||
field_speed.set_value(15); // 15wps
|
||||
field_tone.set_value(700); // 700Hz FM tone
|
||||
options_modulation.set_selected_index(0); // CW mode
|
||||
options_loop.set_selected_index(0); // Off
|
||||
|
||||
checkbox_foxhunt.on_select = [this](Checkbox&, bool value) {
|
||||
foxhunt_mode = value;
|
||||
@@ -182,8 +224,12 @@ MorseView::MorseView(
|
||||
options_modulation.on_change = [this](size_t i, int32_t) {
|
||||
modulation = (modulation_t)i;
|
||||
};
|
||||
|
||||
options_loop.on_change = [this](size_t i, uint32_t n) {
|
||||
loop = n;
|
||||
};
|
||||
|
||||
field_time_unit.on_change = [this](int32_t) {
|
||||
field_speed.on_change = [this](int32_t) {
|
||||
update_tx_duration();
|
||||
};
|
||||
|
||||
@@ -199,12 +245,22 @@ MorseView::MorseView(
|
||||
};
|
||||
|
||||
tx_view.on_start = [this]() {
|
||||
if (start_tx())
|
||||
if (start_tx()) {
|
||||
run = true;
|
||||
tx_view.set_transmitting(true);
|
||||
}
|
||||
};
|
||||
|
||||
tx_view.on_stop = [this]() {
|
||||
run = false;
|
||||
if (ookthread) chThdTerminate(ookthread);
|
||||
|
||||
if (loopthread) {
|
||||
chThdTerminate(loopthread);
|
||||
chThdWait(loopthread);
|
||||
loopthread = nullptr;
|
||||
}
|
||||
|
||||
transmitter_model.disable();
|
||||
baseband::kill_tone();
|
||||
tx_view.set_transmitting(false);
|
||||
|
||||
@@ -54,11 +54,13 @@ public:
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
void on_tx_progress(const uint32_t progress, const bool done);
|
||||
void on_loop_progress(const uint32_t progress, const bool done);
|
||||
|
||||
std::string title() const override { return "Morse TX"; };
|
||||
|
||||
uint32_t time_unit_ms { 0 };
|
||||
size_t symbol_count { 0 };
|
||||
uint32_t loop { 0 };
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
std::string buffer { "PORTAPACK" };
|
||||
@@ -77,12 +79,15 @@ private:
|
||||
void set_foxhunt(size_t i);
|
||||
|
||||
Thread * ookthread { nullptr };
|
||||
Thread * loopthread { nullptr };
|
||||
bool foxhunt_mode { false };
|
||||
bool run { false };
|
||||
|
||||
Labels labels {
|
||||
{ { 4 * 8, 6 * 8 }, "Time unit: ms", Color::light_grey() },
|
||||
{ { 4 * 8, 6 * 8 }, "Speed: wps", Color::light_grey() },
|
||||
{ { 4 * 8, 8 * 8 }, "Tone: Hz", Color::light_grey() },
|
||||
{ { 4 * 8, 10 * 8 }, "Modulation:", Color::light_grey() },
|
||||
{ { 4 * 8, 12 * 8 }, "Loop:", Color::light_grey() },
|
||||
{ { 1 * 8, 25 * 8 }, "TX will last", Color::light_grey() }
|
||||
};
|
||||
|
||||
@@ -109,10 +114,10 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
NumberField field_time_unit {
|
||||
{ 14 * 8, 6 * 8 },
|
||||
NumberField field_speed {
|
||||
{ 10 * 8, 6 * 8 },
|
||||
3,
|
||||
{ 10, 999 },
|
||||
{ 10, 45 },
|
||||
1,
|
||||
' '
|
||||
};
|
||||
@@ -133,6 +138,20 @@ private:
|
||||
{ "FM", 1 }
|
||||
}
|
||||
};
|
||||
|
||||
OptionsField options_loop {
|
||||
{ 9 * 8, 12 * 8 },
|
||||
6,
|
||||
{
|
||||
{ "Off", 0 },
|
||||
{ "5 sec", 5 },
|
||||
{ "10 sec", 10 },
|
||||
{ "30 sec", 30 },
|
||||
{ "1 min", 60 },
|
||||
{ "3 min", 180 },
|
||||
{ "5 min", 300 }
|
||||
}
|
||||
};
|
||||
|
||||
Text text_tx_duration {
|
||||
{ 14 * 8, 25 * 8, 4 * 8, 16 },
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Numbers station"; };
|
||||
std::string title() const override { return "Station"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
@@ -71,6 +71,7 @@ bool POCSAGTXView::start_tx() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MessageType phase = (MessageType)options_phase.selected_index_value();
|
||||
|
||||
pocsag_encode(type, BCH_code, options_function.selected_index_value(), message, address, codewords);
|
||||
|
||||
@@ -79,6 +80,9 @@ bool POCSAGTXView::start_tx() {
|
||||
progressbar.set_max(total_frames);
|
||||
|
||||
transmitter_model.set_sampling_rate(2280000);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
transmitter_model.enable();
|
||||
|
||||
@@ -86,7 +90,11 @@ bool POCSAGTXView::start_tx() {
|
||||
|
||||
bi = 0;
|
||||
for (i = 0; i < codewords.size(); i++) {
|
||||
if (phase == 0)
|
||||
codeword = ~(codewords[i]);
|
||||
else
|
||||
codeword = codewords[i];
|
||||
|
||||
data_ptr[bi++] = (codeword >> 24) & 0xFF;
|
||||
data_ptr[bi++] = (codeword >> 16) & 0xFF;
|
||||
data_ptr[bi++] = (codeword >> 8) & 0xFF;
|
||||
@@ -126,6 +134,7 @@ POCSAGTXView::POCSAGTXView(
|
||||
&field_address,
|
||||
&options_type,
|
||||
&options_function,
|
||||
&options_phase,
|
||||
&text_message,
|
||||
&button_message,
|
||||
&progressbar,
|
||||
|
||||
@@ -71,6 +71,7 @@ private:
|
||||
{ { 3 * 8, 6 * 8 }, "Address:", Color::light_grey() },
|
||||
{ { 6 * 8, 8 * 8 }, "Type:", Color::light_grey() },
|
||||
{ { 2 * 8, 10 * 8 }, "Function:", Color::light_grey() },
|
||||
{ { 5 * 8, 12 * 8 }, "Phase:", Color::light_grey() },
|
||||
{ { 0 * 8, 14 * 8 }, "Message:", Color::light_grey() }
|
||||
};
|
||||
|
||||
@@ -110,6 +111,15 @@ private:
|
||||
{ "D", 3 }
|
||||
}
|
||||
};
|
||||
|
||||
OptionsField options_phase {
|
||||
{ 11 * 8, 12 * 8 },
|
||||
1,
|
||||
{
|
||||
{ "P", 0 },
|
||||
{ "N", 1 },
|
||||
}
|
||||
};
|
||||
|
||||
Text text_message {
|
||||
{ 0 * 8, 16 * 8, 16 * 8, 16 },
|
||||
|
||||
@@ -21,10 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "ui_scanner.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
@@ -38,6 +35,10 @@ ScannerThread::ScannerThread(
|
||||
}
|
||||
|
||||
ScannerThread::~ScannerThread() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void ScannerThread::stop() {
|
||||
if( thread ) {
|
||||
chThdTerminate(thread);
|
||||
chThdWait(thread);
|
||||
@@ -49,6 +50,28 @@ void ScannerThread::set_scanning(const bool v) {
|
||||
_scanning = v;
|
||||
}
|
||||
|
||||
bool ScannerThread::is_scanning() {
|
||||
return _scanning;
|
||||
}
|
||||
|
||||
void ScannerThread::set_freq_lock(const uint32_t v) {
|
||||
_freq_lock = v;
|
||||
}
|
||||
|
||||
uint32_t ScannerThread::is_freq_lock() {
|
||||
return _freq_lock;
|
||||
}
|
||||
|
||||
void ScannerThread::set_freq_del(const uint32_t v) {
|
||||
_freq_del = v;
|
||||
}
|
||||
|
||||
void ScannerThread::change_scanning_direction() {
|
||||
_fwd = !_fwd;
|
||||
chThdSleepMilliseconds(300); //Give some pause after reversing scanning direction
|
||||
|
||||
}
|
||||
|
||||
msg_t ScannerThread::static_fn(void* arg) {
|
||||
auto obj = static_cast<ScannerThread*>(arg);
|
||||
obj->run();
|
||||
@@ -56,35 +79,78 @@ msg_t ScannerThread::static_fn(void* arg) {
|
||||
}
|
||||
|
||||
void ScannerThread::run() {
|
||||
RetuneMessage message { };
|
||||
uint32_t frequency_index = 0;
|
||||
|
||||
while( !chThdShouldTerminate() ) {
|
||||
if (_scanning) {
|
||||
// Retune
|
||||
receiver_model.set_tuning_frequency(frequency_list_[frequency_index]);
|
||||
|
||||
message.range = frequency_index;
|
||||
EventDispatcher::send_message(message);
|
||||
|
||||
|
||||
frequency_index++;
|
||||
if (frequency_index >= frequency_list_.size())
|
||||
frequency_index = 0;
|
||||
if (frequency_list_.size()) { //IF THERE IS A FREQUENCY LIST ...
|
||||
RetuneMessage message { };
|
||||
uint32_t frequency_index = frequency_list_.size();
|
||||
bool restart_scan = false; //Flag whenever scanning is restarting after a pause
|
||||
while( !chThdShouldTerminate() ) {
|
||||
if (_scanning) { //Scanning
|
||||
if (_freq_lock == 0) { //normal scanning (not performing freq_lock)
|
||||
if (!restart_scan) { //looping at full speed
|
||||
if (_fwd) { //forward
|
||||
frequency_index++;
|
||||
if (frequency_index >= frequency_list_.size())
|
||||
frequency_index = 0;
|
||||
|
||||
} else { //reverse
|
||||
if (frequency_index < 1)
|
||||
frequency_index = frequency_list_.size();
|
||||
frequency_index--;
|
||||
}
|
||||
receiver_model.set_tuning_frequency(frequency_list_[frequency_index]); // Retune
|
||||
}
|
||||
else
|
||||
restart_scan=false; //Effectively skipping first retuning, giving system time
|
||||
}
|
||||
message.range = frequency_index; //Inform freq (for coloring purposes also!)
|
||||
EventDispatcher::send_message(message);
|
||||
}
|
||||
else { //NOT scanning
|
||||
if (_freq_del != 0) { //There is a frequency to delete
|
||||
for (uint16_t i = 0; i < frequency_list_.size(); i++) { //Search for the freq to delete
|
||||
if (frequency_list_[i] == _freq_del)
|
||||
{ //found: Erase it
|
||||
frequency_list_.erase(frequency_list_.begin() + i);
|
||||
if (i==0) //set scan index one place back to compensate
|
||||
i=frequency_list_.size();
|
||||
else
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_freq_del = 0; //deleted.
|
||||
}
|
||||
else {
|
||||
restart_scan=true; //Flag the need for skipping a cycle when restarting scan
|
||||
}
|
||||
}
|
||||
chThdSleepMilliseconds(50); //Needed to (eventually) stabilize the receiver into new freq
|
||||
}
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
}
|
||||
}
|
||||
|
||||
void ScannerView::handle_retune(uint32_t i) {
|
||||
text_cycle.set( to_string_dec_uint(i) + "/" +
|
||||
to_string_dec_uint(frequency_list.size()) + " : " +
|
||||
to_string_dec_uint(frequency_list[i]) );
|
||||
switch (scan_thread->is_freq_lock())
|
||||
{
|
||||
case 0: //NO FREQ LOCK, ONGOING STANDARD SCANNING
|
||||
text_cycle.set( to_string_dec_uint(i + 1,3) );
|
||||
current_index = i; //since it is an ongoing scan, this is a new index
|
||||
if (description_list[current_index].size() > 0) desc_cycle.set( description_list[current_index] ); //Show new description
|
||||
break;
|
||||
case 1: //STARTING LOCK FREQ
|
||||
big_display.set_style(&style_yellow);
|
||||
break;
|
||||
case MAX_FREQ_LOCK: //FREQ IS STRONG: GREEN and scanner will pause when on_statistics_update()
|
||||
big_display.set_style(&style_green);
|
||||
break;
|
||||
default: //freq lock is checking the signal, do not update display
|
||||
return;
|
||||
}
|
||||
big_display.set(frequency_list[current_index]); //UPDATE the big Freq after 0, 1 or MAX_FREQ_LOCK (at least, for color synching)
|
||||
}
|
||||
|
||||
void ScannerView::focus() {
|
||||
field_lna.focus();
|
||||
field_mode.focus();
|
||||
}
|
||||
|
||||
ScannerView::~ScannerView() {
|
||||
@@ -93,9 +159,20 @@ ScannerView::~ScannerView() {
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void ScannerView::show_max() { //show total number of freqs to scan
|
||||
if (frequency_list.size() == MAX_DB_ENTRY) {
|
||||
text_max.set_style(&style_red);
|
||||
text_max.set( "/ " + to_string_dec_uint(MAX_DB_ENTRY) + " (DB MAX!)");
|
||||
}
|
||||
else {
|
||||
text_max.set_style(&style_grey);
|
||||
text_max.set( "/ " + to_string_dec_uint(frequency_list.size()));
|
||||
}
|
||||
}
|
||||
|
||||
ScannerView::ScannerView(
|
||||
NavigationView&
|
||||
)
|
||||
NavigationView& nav
|
||||
) : nav_ { nav }
|
||||
{
|
||||
add_children({
|
||||
&labels,
|
||||
@@ -106,90 +183,377 @@ ScannerView::ScannerView(
|
||||
&field_bw,
|
||||
&field_squelch,
|
||||
&field_wait,
|
||||
//&record_view,
|
||||
&button_load,
|
||||
&rssi,
|
||||
&text_cycle,
|
||||
//&waterfall,
|
||||
&text_max,
|
||||
&desc_cycle,
|
||||
&big_display,
|
||||
&button_manual_start,
|
||||
&button_manual_end,
|
||||
&field_mode,
|
||||
&step_mode,
|
||||
&button_manual_scan,
|
||||
&button_pause,
|
||||
&button_dir,
|
||||
&button_audio_app,
|
||||
&button_mic_app,
|
||||
&button_add,
|
||||
&button_remove
|
||||
|
||||
});
|
||||
|
||||
std::string scanner_file = "SCANNER";
|
||||
if (load_freqman_file(scanner_file, database)) {
|
||||
for(auto& entry : database) {
|
||||
// FIXME
|
||||
if (entry.type == RANGE) {
|
||||
for (uint32_t i=entry.frequency_a; i < entry.frequency_b; i+= 1000000) {
|
||||
frequency_list.push_back(i);
|
||||
}
|
||||
def_step = change_mode(AM); //Start on AM
|
||||
field_mode.set_by_value(AM); //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();
|
||||
frequency_range.min = stored_freq - 1000000;
|
||||
button_manual_start.set_text(to_string_short_freq(frequency_range.min));
|
||||
frequency_range.max = stored_freq + 1000000;
|
||||
button_manual_end.set_text(to_string_short_freq(frequency_range.max));
|
||||
|
||||
button_load.on_select = [this, &nav](Button&) {
|
||||
// load txt files from the FREQMAN folder
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->on_changed = [this](std::filesystem::path new_file_path) {
|
||||
|
||||
std::string dir_filter = "FREQMAN/";
|
||||
std::string str_file_path = new_file_path.string();
|
||||
|
||||
if (str_file_path.find(dir_filter) != string::npos) { // assert file from the FREQMAN folder
|
||||
scan_pause();
|
||||
// get the filename without txt extension so we can use load_freqman_file fcn
|
||||
std::string str_file_name = new_file_path.stem().string();
|
||||
frequency_file_load(str_file_name, true);
|
||||
} else {
|
||||
frequency_list.push_back(entry.frequency_a);
|
||||
nav_.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
button_manual_start.on_select = [this, &nav](Button& button) {
|
||||
auto new_view = nav_.push<FrequencyKeypadView>(frequency_range.min);
|
||||
new_view->on_changed = [this, &button](rf::Frequency f) {
|
||||
frequency_range.min = f;
|
||||
button_manual_start.set_text(to_string_short_freq(f));
|
||||
};
|
||||
};
|
||||
|
||||
button_manual_end.on_select = [this, &nav](Button& button) {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(frequency_range.max);
|
||||
new_view->on_changed = [this, &button](rf::Frequency f) {
|
||||
frequency_range.max = f;
|
||||
button_manual_end.set_text(to_string_short_freq(f));
|
||||
};
|
||||
};
|
||||
|
||||
button_pause.on_select = [this](Button&) {
|
||||
if ( userpause )
|
||||
user_resume();
|
||||
else {
|
||||
scan_pause();
|
||||
button_pause.set_text("RESUME"); //PAUSED, show resume
|
||||
userpause=true;
|
||||
}
|
||||
} else {
|
||||
// DEBUG
|
||||
frequency_list.push_back(466025000);
|
||||
frequency_list.push_back(466050000);
|
||||
frequency_list.push_back(466075000);
|
||||
frequency_list.push_back(466175000);
|
||||
frequency_list.push_back(466206250);
|
||||
frequency_list.push_back(466231250);
|
||||
};
|
||||
|
||||
button_audio_app.on_select = [this](Button&) {
|
||||
scan_thread->stop();
|
||||
nav_.pop();
|
||||
nav_.push<AnalogAudioView>();
|
||||
};
|
||||
|
||||
button_mic_app.on_select = [this](Button&) {
|
||||
scan_thread->stop();
|
||||
nav_.pop();
|
||||
nav_.push<MicTXView>();
|
||||
};
|
||||
|
||||
button_remove.on_select = [this](Button&) {
|
||||
if (frequency_list.size() > current_index) {
|
||||
if (scan_thread->is_scanning()) //STOP Scanning if necessary
|
||||
scan_thread->set_scanning(false);
|
||||
scan_thread->set_freq_del(frequency_list[current_index]);
|
||||
description_list.erase(description_list.begin() + current_index);
|
||||
frequency_list.erase(frequency_list.begin() + current_index);
|
||||
show_max(); //UPDATE new list size on screen
|
||||
desc_cycle.set(" "); //Clean up description (cosmetic detail)
|
||||
scan_thread->set_freq_lock(0); //Reset the scanner lock
|
||||
if ( userpause ) //If user-paused, resume
|
||||
user_resume();
|
||||
}
|
||||
};
|
||||
|
||||
button_manual_scan.on_select = [this](Button&) {
|
||||
if (!frequency_range.min || !frequency_range.max) {
|
||||
nav_.display_modal("Error", "Both START and END freqs\nneed a value");
|
||||
} else if (frequency_range.min > frequency_range.max) {
|
||||
nav_.display_modal("Error", "END freq\nis lower than START");
|
||||
} else {
|
||||
audio::output::stop();
|
||||
scan_thread->stop(); //STOP SCANNER THREAD
|
||||
frequency_list.clear();
|
||||
description_list.clear();
|
||||
def_step = step_mode.selected_index_value(); //Use def_step from manual selector
|
||||
|
||||
description_list.push_back(
|
||||
"M" + to_string_short_freq(frequency_range.min) + ">"
|
||||
+ to_string_short_freq(frequency_range.max) + "S"
|
||||
+ to_string_short_freq(def_step).erase(0,1) //euquiq: lame kludge to reduce spacing in step freq
|
||||
);
|
||||
|
||||
rf::Frequency frequency = frequency_range.min;
|
||||
while (frequency_list.size() < MAX_DB_ENTRY && frequency <= frequency_range.max) { //add manual range
|
||||
frequency_list.push_back(frequency);
|
||||
description_list.push_back(""); //If empty, will keep showing the last description
|
||||
frequency+=def_step;
|
||||
}
|
||||
show_max();
|
||||
if ( userpause ) //If user-paused, resume
|
||||
user_resume();
|
||||
big_display.set_style(&style_grey); //Back to grey color
|
||||
start_scan_thread(); //RESTART SCANNER THREAD
|
||||
}
|
||||
};
|
||||
|
||||
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
change_mode(v);
|
||||
if ( !scan_thread->is_scanning() ) //for some motive, audio output gets stopped.
|
||||
audio::output::start(); //So if scan was stopped we resume audio
|
||||
receiver_model.enable();
|
||||
};
|
||||
|
||||
button_dir.on_select = [this](Button&) {
|
||||
scan_thread->change_scanning_direction();
|
||||
if ( userpause ) //If user-paused, resume
|
||||
user_resume();
|
||||
big_display.set_style(&style_grey); //Back to grey color
|
||||
};
|
||||
|
||||
button_add.on_select = [this](Button&) { //frequency_list[current_index]
|
||||
File scanner_file;
|
||||
std::string freq_file_path = "FREQMAN/" + loaded_file_name + ".TXT";
|
||||
auto result = scanner_file.open(freq_file_path); //First search if freq is already in txt
|
||||
if (!result.is_valid()) {
|
||||
std::string frequency_to_add = "f="
|
||||
+ to_string_dec_uint(frequency_list[current_index] / 1000)
|
||||
+ to_string_dec_uint(frequency_list[current_index] % 1000UL, 3, '0');
|
||||
char one_char[1]; //Read it char by char
|
||||
std::string line; //and put read line in here
|
||||
bool found=false;
|
||||
for (size_t pointer=0; pointer < scanner_file.size();pointer++) {
|
||||
|
||||
scanner_file.seek(pointer);
|
||||
scanner_file.read(one_char, 1);
|
||||
if ((int)one_char[0] > 31) { //ascii space upwards
|
||||
line += one_char[0]; //Add it to the textline
|
||||
}
|
||||
else if (one_char[0] == '\n') { //New Line
|
||||
if (line.compare(0, frequency_to_add.size(),frequency_to_add) == 0) {
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
line.clear(); //Ready for next textline
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
nav_.display_modal("Error", "Frequency already exists");
|
||||
big_display.set(frequency_list[current_index]); //After showing an error
|
||||
}
|
||||
else {
|
||||
auto result = scanner_file.append(freq_file_path); //Second: append if it is not there
|
||||
scanner_file.write_line(frequency_to_add + ",d=ADD FQ");
|
||||
}
|
||||
} else
|
||||
{
|
||||
nav_.display_modal("Error", "Cannot open " + loaded_file_name + ".TXT\nfor appending freq.");
|
||||
big_display.set(frequency_list[current_index]); //After showing an error
|
||||
}
|
||||
};
|
||||
|
||||
//PRE-CONFIGURATION:
|
||||
field_wait.on_change = [this](int32_t v) { wait = v; }; field_wait.set_value(5);
|
||||
field_squelch.on_change = [this](int32_t v) { squelch = v; }; field_squelch.set_value(-10);
|
||||
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
|
||||
field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); };
|
||||
|
||||
// LEARN FREQUENCIES
|
||||
std::string scanner_txt = "SCANNER";
|
||||
frequency_file_load(scanner_txt);
|
||||
}
|
||||
|
||||
void ScannerView::frequency_file_load(std::string file_name, bool stop_all_before) {
|
||||
|
||||
// stop everything running now if required
|
||||
if (stop_all_before) {
|
||||
scan_thread->stop();
|
||||
frequency_list.clear(); // clear the existing frequency list (expected behavior)
|
||||
description_list.clear();
|
||||
def_step = step_mode.selected_index_value(); //Use def_step from manual selector
|
||||
}
|
||||
|
||||
field_bw.set_selected_index(2);
|
||||
field_bw.on_change = [this](size_t n, OptionsField::value_t) {
|
||||
receiver_model.set_nbfm_configuration(n);
|
||||
};
|
||||
|
||||
field_wait.on_change = [this](int32_t v) {
|
||||
wait = v;
|
||||
};
|
||||
field_wait.set_value(5);
|
||||
|
||||
field_squelch.on_change = [this](int32_t v) {
|
||||
squelch = v;
|
||||
};
|
||||
field_squelch.set_value(30);
|
||||
|
||||
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
|
||||
field_volume.on_change = [this](int32_t v) {
|
||||
this->on_headphone_volume_changed(v);
|
||||
};
|
||||
|
||||
audio::output::start();
|
||||
|
||||
audio::output::mute();
|
||||
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
||||
receiver_model.set_sampling_rate(3072000);
|
||||
receiver_model.set_baseband_bandwidth(1750000);
|
||||
receiver_model.enable();
|
||||
receiver_model.set_squelch_level(0);
|
||||
receiver_model.set_nbfm_configuration(field_bw.selected_index());
|
||||
audio::output::unmute();
|
||||
|
||||
// TODO: Scanning thread here
|
||||
scan_thread = std::make_unique<ScannerThread>(frequency_list);
|
||||
if ( load_freqman_file(file_name, database) ) {
|
||||
loaded_file_name = file_name; // keep loaded filename in memory
|
||||
for(auto& entry : database) { // READ LINE PER LINE
|
||||
if (frequency_list.size() < MAX_DB_ENTRY) { //We got space!
|
||||
if (entry.type == RANGE) { //RANGE
|
||||
switch (entry.step) {
|
||||
case AM_US: def_step = 10000; break ;
|
||||
case AM_EUR:def_step = 9000; break ;
|
||||
case NFM_1: def_step = 12500; break ;
|
||||
case NFM_2: def_step = 6250; break ;
|
||||
case FM_1: def_step = 100000; break ;
|
||||
case FM_2: def_step = 50000; break ;
|
||||
case N_1: def_step = 25000; break ;
|
||||
case N_2: def_step = 250000; break ;
|
||||
case AIRBAND:def_step= 8330; break ;
|
||||
}
|
||||
frequency_list.push_back(entry.frequency_a); //Store starting freq and description
|
||||
description_list.push_back("R" + to_string_short_freq(entry.frequency_a)
|
||||
+ ">" + to_string_short_freq(entry.frequency_b)
|
||||
+ " S" + to_string_short_freq(def_step).erase(0,1) //euquiq: lame kludge to reduce spacing in step freq
|
||||
);
|
||||
while (frequency_list.size() < MAX_DB_ENTRY && entry.frequency_a <= entry.frequency_b) { //add the rest of the range
|
||||
entry.frequency_a+=def_step;
|
||||
frequency_list.push_back(entry.frequency_a);
|
||||
description_list.push_back(""); //Token (keep showing the last description)
|
||||
}
|
||||
} else if ( entry.type == SINGLE) {
|
||||
frequency_list.push_back(entry.frequency_a);
|
||||
description_list.push_back("S: " + entry.description);
|
||||
}
|
||||
show_max();
|
||||
}
|
||||
else
|
||||
{
|
||||
break; //No more space: Stop reading the txt file !
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loaded_file_name = 'SCANNER'; // back to the default frequency file
|
||||
desc_cycle.set(" NO " + file_name + ".TXT FILE ..." );
|
||||
}
|
||||
audio::output::stop();
|
||||
step_mode.set_by_value(def_step); //Impose the default step into the manual step selector
|
||||
start_scan_thread();
|
||||
}
|
||||
|
||||
void ScannerView::on_statistics_update(const ChannelStatistics& statistics) {
|
||||
int32_t max_db = statistics.max_db;
|
||||
|
||||
if (timer <= wait)
|
||||
timer++;
|
||||
|
||||
if (max_db < -squelch) {
|
||||
if (timer == wait) {
|
||||
//audio::output::stop();
|
||||
scan_thread->set_scanning(true);
|
||||
if ( !userpause ) //Scanning not user-paused
|
||||
{
|
||||
if (timer >= (wait * 10) )
|
||||
{
|
||||
timer = 0;
|
||||
scan_resume();
|
||||
}
|
||||
else if (!timer)
|
||||
{
|
||||
if (statistics.max_db > squelch ) { //There is something on the air...(statistics.max_db > -squelch)
|
||||
if (scan_thread->is_freq_lock() >= MAX_FREQ_LOCK) { //checking time reached
|
||||
scan_pause();
|
||||
timer++;
|
||||
} else {
|
||||
scan_thread->set_freq_lock( scan_thread->is_freq_lock() + 1 ); //in lock period, still analyzing the signal
|
||||
}
|
||||
} else { //There is NOTHING on the air
|
||||
if (scan_thread->is_freq_lock() > 0) { //But are we already in freq_lock ?
|
||||
big_display.set_style(&style_grey); //Back to grey color
|
||||
scan_thread->set_freq_lock(0); //Reset the scanner lock, since there is no signal
|
||||
}
|
||||
}
|
||||
}
|
||||
else //Ongoing wait time
|
||||
{
|
||||
timer++;
|
||||
}
|
||||
} else {
|
||||
//audio::output::start();
|
||||
scan_thread->set_scanning(false);
|
||||
timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ScannerView::scan_pause() {
|
||||
if (scan_thread->is_scanning()) {
|
||||
scan_thread->set_freq_lock(0); //Reset the scanner lock (because user paused, or MAX_FREQ_LOCK reached) for next freq scan
|
||||
scan_thread->set_scanning(false); // WE STOP SCANNING
|
||||
audio::output::start();
|
||||
}
|
||||
}
|
||||
|
||||
void ScannerView::scan_resume() {
|
||||
audio::output::stop();
|
||||
big_display.set_style(&style_grey); //Back to grey color
|
||||
if (!scan_thread->is_scanning())
|
||||
scan_thread->set_scanning(true); // RESUME!
|
||||
}
|
||||
|
||||
void ScannerView::user_resume() {
|
||||
timer = wait * 10; //Will trigger a scan_resume() on_statistics_update, also advancing to next freq.
|
||||
button_pause.set_text("PAUSE"); //Show button for pause
|
||||
userpause=false; //Resume scanning
|
||||
}
|
||||
|
||||
void ScannerView::on_headphone_volume_changed(int32_t v) {
|
||||
const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max;
|
||||
receiver_model.set_headphone_volume(new_volume);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
size_t ScannerView::change_mode(uint8_t new_mod) { //Before this, do a scan_thread->stop(); After this do a start_scan_thread()
|
||||
using option_t = std::pair<std::string, int32_t>;
|
||||
using options_t = std::vector<option_t>;
|
||||
options_t bw;
|
||||
field_bw.on_change = [this](size_t n, OptionsField::value_t) { };
|
||||
|
||||
switch (new_mod) {
|
||||
case NFM: //bw 16k (2) default
|
||||
bw.emplace_back("8k5", 0);
|
||||
bw.emplace_back("11k", 0);
|
||||
bw.emplace_back("16k", 0);
|
||||
field_bw.set_options(bw);
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
||||
field_bw.set_selected_index(2);
|
||||
receiver_model.set_nbfm_configuration(field_bw.selected_index());
|
||||
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_nbfm_configuration(n); };
|
||||
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000);
|
||||
break;
|
||||
case AM:
|
||||
bw.emplace_back("DSB", 0);
|
||||
bw.emplace_back("USB", 0);
|
||||
bw.emplace_back("LSB", 0);
|
||||
bw.emplace_back("CW ", 0);
|
||||
field_bw.set_options(bw);
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
|
||||
field_bw.set_selected_index(0);
|
||||
receiver_model.set_am_configuration(field_bw.selected_index());
|
||||
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_am_configuration(n); };
|
||||
receiver_model.set_sampling_rate(2000000);receiver_model.set_baseband_bandwidth(2000000);
|
||||
break;
|
||||
case WFM:
|
||||
bw.emplace_back("16k", 0);
|
||||
field_bw.set_options(bw);
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
|
||||
field_bw.set_selected_index(0);
|
||||
receiver_model.set_wfm_configuration(field_bw.selected_index());
|
||||
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_wfm_configuration(n); };
|
||||
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(2000000);
|
||||
break;
|
||||
}
|
||||
|
||||
return mod_step[new_mod];
|
||||
}
|
||||
|
||||
void ScannerView::start_scan_thread() {
|
||||
receiver_model.enable();
|
||||
receiver_model.set_squelch_level(0);
|
||||
scan_thread = std::make_unique<ScannerThread>(frequency_list);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -20,20 +20,46 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "receiver_model.hpp"
|
||||
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "freqman.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "ui_mictx.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "file.hpp"
|
||||
|
||||
|
||||
#define MAX_DB_ENTRY 500
|
||||
#define MAX_FREQ_LOCK 10 //50ms cycles scanner locks into freq when signal detected, to verify signal is not spureous
|
||||
|
||||
namespace ui {
|
||||
|
||||
enum modulation_type { AM = 0,WFM,NFM };
|
||||
|
||||
string const mod_name[3] = {"AM", "WFM", "NFM"};
|
||||
size_t const mod_step[3] = {9000, 100000, 12500 };
|
||||
|
||||
class ScannerThread {
|
||||
public:
|
||||
ScannerThread(std::vector<rf::Frequency> frequency_list);
|
||||
~ScannerThread();
|
||||
|
||||
|
||||
void set_scanning(const bool v);
|
||||
bool is_scanning();
|
||||
|
||||
void set_freq_lock(const uint32_t v);
|
||||
uint32_t is_freq_lock();
|
||||
|
||||
void set_freq_del(const uint32_t v);
|
||||
|
||||
void change_scanning_direction();
|
||||
|
||||
void stop();
|
||||
|
||||
ScannerThread(const ScannerThread&) = delete;
|
||||
ScannerThread(ScannerThread&&) = delete;
|
||||
@@ -45,36 +71,83 @@ private:
|
||||
Thread* thread { nullptr };
|
||||
|
||||
bool _scanning { true };
|
||||
|
||||
bool _fwd { true };
|
||||
uint32_t _freq_lock { 0 };
|
||||
uint32_t _freq_del { 0 };
|
||||
static msg_t static_fn(void* arg);
|
||||
|
||||
void run();
|
||||
};
|
||||
|
||||
class ScannerView : public View {
|
||||
public:
|
||||
ScannerView(NavigationView&);
|
||||
ScannerView(NavigationView& nav);
|
||||
~ScannerView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
void big_display_freq(rf::Frequency f);
|
||||
|
||||
const Style style_grey { // scanning
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::grey(),
|
||||
};
|
||||
|
||||
std::string title() const override { return "Scanner"; };
|
||||
const Style style_yellow { //Found signal
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::dark_yellow(),
|
||||
};
|
||||
|
||||
const Style style_green { //Found signal
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::green(),
|
||||
};
|
||||
|
||||
const Style style_red { //erasing freq
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = Color::red(),
|
||||
};
|
||||
|
||||
std::string title() const override { return "SCANNER"; };
|
||||
std::vector<rf::Frequency> frequency_list{ };
|
||||
std::vector<string> description_list { };
|
||||
|
||||
//void set_parent_rect(const Rect new_parent_rect) override;
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
void start_scan_thread();
|
||||
size_t change_mode(uint8_t mod_type);
|
||||
void show_max();
|
||||
void scan_pause();
|
||||
void scan_resume();
|
||||
void user_resume();
|
||||
void frequency_file_load(std::string file_name, bool stop_all_before = false);
|
||||
|
||||
void on_statistics_update(const ChannelStatistics& statistics);
|
||||
void on_headphone_volume_changed(int32_t v);
|
||||
void handle_retune(uint32_t i);
|
||||
|
||||
std::vector<rf::Frequency> frequency_list { };
|
||||
|
||||
jammer::jammer_range_t frequency_range { false, 0, 0 }; //perfect for manual scan task too...
|
||||
int32_t squelch { 0 };
|
||||
uint32_t timer { 0 };
|
||||
uint32_t wait { 0 };
|
||||
size_t def_step { 0 };
|
||||
freqman_db database { };
|
||||
std::string loaded_file_name;
|
||||
uint32_t current_index { 0 };
|
||||
bool userpause { false };
|
||||
|
||||
Labels labels {
|
||||
{ { 0 * 8, 0 * 16 }, "LNA: VGA: AMP: VOL:", Color::light_grey() },
|
||||
{ { 0 * 8, 1 * 16 }, "BW: SQUELCH: /99 WAIT:", Color::light_grey() },
|
||||
{ { 0 * 8, 3 * 16 }, "Work in progress...", Color::light_grey() }
|
||||
{ { 0 * 8, 1* 16 }, "BW: SQUELCH: db WAIT:", Color::light_grey() },
|
||||
{ { 3 * 8, 10 * 16 }, "START END MANUAL", Color::light_grey() },
|
||||
{ { 0 * 8, (26 * 8) + 4 }, "MODE:", Color::light_grey() },
|
||||
{ { 11 * 8, (26 * 8) + 4 }, "STEP:", Color::light_grey() },
|
||||
};
|
||||
|
||||
LNAGainField field_lna {
|
||||
@@ -99,18 +172,14 @@ private:
|
||||
|
||||
OptionsField field_bw {
|
||||
{ 3 * 8, 1 * 16 },
|
||||
3,
|
||||
{
|
||||
{ "8k5", 0 },
|
||||
{ "11k", 0 },
|
||||
{ "16k", 0 },
|
||||
}
|
||||
};
|
||||
4,
|
||||
{ }
|
||||
};
|
||||
|
||||
NumberField field_squelch {
|
||||
{ 15 * 8, 1 * 16 },
|
||||
2,
|
||||
{ 0, 99 },
|
||||
3,
|
||||
{ -90, 20 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
@@ -123,9 +192,102 @@ private:
|
||||
' ',
|
||||
};
|
||||
|
||||
RSSI rssi {
|
||||
{ 0 * 16, 2 * 16, 15 * 16, 8 },
|
||||
};
|
||||
|
||||
Text text_cycle {
|
||||
{ 0, 5 * 16, 240, 16 },
|
||||
"--/--"
|
||||
{ 0, 3 * 16, 3 * 8, 16 },
|
||||
};
|
||||
|
||||
Text text_max {
|
||||
{ 4 * 8, 3 * 16, 18 * 8, 16 },
|
||||
};
|
||||
|
||||
Text desc_cycle {
|
||||
{0, 4 * 16, 240, 16 },
|
||||
};
|
||||
|
||||
BigFrequency big_display { //Show frequency in glamour
|
||||
{ 4, 6 * 16, 28 * 8, 52 },
|
||||
0
|
||||
};
|
||||
|
||||
Button button_manual_start {
|
||||
{ 0 * 8, 11 * 16, 11 * 8, 28 },
|
||||
""
|
||||
};
|
||||
|
||||
Button button_manual_end {
|
||||
{ 12 * 8, 11 * 16, 11 * 8, 28 },
|
||||
""
|
||||
};
|
||||
|
||||
Button button_manual_scan {
|
||||
{ 24 * 8, 11 * 16, 6 * 8, 28 },
|
||||
"SCAN"
|
||||
};
|
||||
|
||||
OptionsField field_mode {
|
||||
{ 5 * 8, (26 * 8) + 4 },
|
||||
6,
|
||||
{
|
||||
{ " AM ", 0 },
|
||||
{ " WFM ", 1 },
|
||||
{ " NFM ", 2 },
|
||||
}
|
||||
};
|
||||
|
||||
OptionsField step_mode {
|
||||
{ 17 * 8, (26 * 8) + 4 },
|
||||
12,
|
||||
{
|
||||
{ "5Khz (SA AM)", 5000 },
|
||||
{ "9Khz (EU AM)", 9000 },
|
||||
{ "10Khz(US AM)", 10000 },
|
||||
{ "50Khz (FM1)", 50000 },
|
||||
{ "100Khz(FM2)", 100000 },
|
||||
{ "6.25khz(NFM)", 6250 },
|
||||
{ "12.5khz(NFM)", 12500 },
|
||||
{ "25khz (N1)", 25000 },
|
||||
{ "250khz (N2)", 250000 },
|
||||
{ "8.33khz(AIR)", 8330 }
|
||||
}
|
||||
};
|
||||
|
||||
Button button_pause {
|
||||
{ 0, (15 * 16) - 4, 72, 28 },
|
||||
"PAUSE"
|
||||
};
|
||||
|
||||
Button button_dir {
|
||||
{ 0, (35 * 8) - 4, 72, 28 },
|
||||
"FW><RV"
|
||||
};
|
||||
|
||||
Button button_audio_app {
|
||||
{ 84, (15 * 16) - 4, 72, 28 },
|
||||
"AUDIO"
|
||||
};
|
||||
|
||||
Button button_mic_app {
|
||||
{ 84, (35 * 8) - 4, 72, 28 },
|
||||
"MIC TX"
|
||||
};
|
||||
|
||||
Button button_add {
|
||||
{ 168, (15 * 16) - 4, 72, 28 },
|
||||
"ADD FQ"
|
||||
};
|
||||
|
||||
Button button_load {
|
||||
{ 24 * 8, 3 * 16 - 8, 6 * 8, 22 },
|
||||
"Load"
|
||||
};
|
||||
|
||||
Button button_remove {
|
||||
{ 168, (35 * 8) - 4, 72, 28 },
|
||||
"DEL FQ"
|
||||
};
|
||||
|
||||
std::unique_ptr<ScannerThread> scan_thread { };
|
||||
@@ -146,4 +308,4 @@ private:
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
} /* namespace ui */
|
||||
@@ -94,7 +94,7 @@ ScriptView::ScriptView(
|
||||
};
|
||||
|
||||
button_del.on_select = [this, &nav](Button&) {
|
||||
nav.push<ModalMessageView>("Confirm", "Are you sure ?", YESNO,
|
||||
nav.push<ModalMessageView>("Confirm", "Are you sure?", YESNO,
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
on_delete();
|
||||
|
||||
@@ -45,7 +45,7 @@ void WipeSDView::focus() {
|
||||
dummy.focus();
|
||||
|
||||
if (!confirmed) {
|
||||
nav_.push<ModalMessageView>("Warning !", "Wipe FAT of SD card ?", YESCANCEL, [this](bool choice) {
|
||||
nav_.push<ModalMessageView>("Warning !", "Wipe FAT of SD card?", YESCANCEL, [this](bool choice) {
|
||||
if (choice)
|
||||
confirmed = true;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
using namespace lpc43xx;
|
||||
|
||||
#include "audio.hpp"
|
||||
#include "portapack.hpp"
|
||||
using portapack::receiver_model;
|
||||
using namespace portapack;
|
||||
@@ -143,6 +144,10 @@ SetRadioView::SetRadioView(
|
||||
}
|
||||
|
||||
add_children({
|
||||
&check_clkout,
|
||||
&field_clkout_freq,
|
||||
&labels_clkout_khz,
|
||||
&value_freq_step,
|
||||
&labels_bias,
|
||||
&check_bias,
|
||||
&button_done,
|
||||
@@ -155,6 +160,39 @@ SetRadioView::SetRadioView(
|
||||
|
||||
form_init(model);
|
||||
|
||||
check_clkout.set_value(portapack::persistent_memory::clkout_enabled());
|
||||
check_clkout.on_select = [this](Checkbox&, bool v) {
|
||||
clock_manager.enable_clock_output(v);
|
||||
portapack::persistent_memory::set_clkout_enabled(v);
|
||||
StatusRefreshMessage message { };
|
||||
EventDispatcher::send_message(message);
|
||||
};
|
||||
|
||||
field_clkout_freq.set_value(portapack::persistent_memory::clkout_freq());
|
||||
value_freq_step.set_style(&style_text);
|
||||
|
||||
field_clkout_freq.on_select = [this](NumberField&) {
|
||||
freq_step_khz++;
|
||||
if(freq_step_khz > 3) {
|
||||
freq_step_khz = 0;
|
||||
}
|
||||
switch(freq_step_khz) {
|
||||
case 0:
|
||||
value_freq_step.set(" |");
|
||||
break;
|
||||
case 1:
|
||||
value_freq_step.set(" | ");
|
||||
break;
|
||||
case 2:
|
||||
value_freq_step.set(" | ");
|
||||
break;
|
||||
case 3:
|
||||
value_freq_step.set("| ");
|
||||
break;
|
||||
}
|
||||
field_clkout_freq.set_step(pow(10, freq_step_khz));
|
||||
};
|
||||
|
||||
check_bias.set_value(portapack::get_antenna_bias());
|
||||
check_bias.on_select = [this](Checkbox&, bool v) {
|
||||
portapack::set_antenna_bias(v);
|
||||
@@ -165,6 +203,8 @@ SetRadioView::SetRadioView(
|
||||
button_done.on_select = [this, &nav](Button&){
|
||||
const auto model = this->form_collect();
|
||||
portapack::persistent_memory::set_correction_ppb(model.ppm * 1000);
|
||||
portapack::persistent_memory::set_clkout_freq(model.freq);
|
||||
clock_manager.enable_clock_output(portapack::persistent_memory::clkout_enabled());
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
@@ -180,9 +220,11 @@ void SetRadioView::form_init(const SetFrequencyCorrectionModel& model) {
|
||||
SetFrequencyCorrectionModel SetRadioView::form_collect() {
|
||||
return {
|
||||
.ppm = static_cast<int8_t>(field_ppm.value()),
|
||||
.freq = static_cast<uint32_t>(field_clkout_freq.value()),
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
SetPlayDeadView::SetPlayDeadView(NavigationView& nav) {
|
||||
add_children({
|
||||
&text_sequence,
|
||||
@@ -234,18 +276,21 @@ SetPlayDeadView::SetPlayDeadView(NavigationView& nav) {
|
||||
void SetPlayDeadView::focus() {
|
||||
button_cancel.focus();
|
||||
}
|
||||
*/
|
||||
|
||||
SetUIView::SetUIView(NavigationView& nav) {
|
||||
add_children({
|
||||
&checkbox_login,
|
||||
//&checkbox_login,
|
||||
&checkbox_speaker,
|
||||
&checkbox_bloff,
|
||||
&options_bloff,
|
||||
&checkbox_showsplash,
|
||||
&button_ok
|
||||
});
|
||||
|
||||
checkbox_speaker.set_value(persistent_memory::config_speaker());
|
||||
checkbox_showsplash.set_value(persistent_memory::config_splash());
|
||||
checkbox_login.set_value(persistent_memory::config_login());
|
||||
//checkbox_login.set_value(persistent_memory::config_login());
|
||||
|
||||
uint32_t backlight_timer = persistent_memory::config_backlight_timer();
|
||||
|
||||
@@ -256,6 +301,15 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
options_bloff.set_selected_index(0);
|
||||
}
|
||||
|
||||
checkbox_speaker.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) audio::output::speaker_mute(); //Just mute audio if speaker is disabled
|
||||
|
||||
persistent_memory::set_config_speaker(v); //Store Speaker status
|
||||
|
||||
StatusRefreshMessage message { }; //Refresh status bar with/out speaker
|
||||
EventDispatcher::send_message(message);
|
||||
};
|
||||
|
||||
button_ok.on_select = [&nav, this](Button&) {
|
||||
if (checkbox_bloff.value())
|
||||
persistent_memory::set_config_backlight_timer(options_bloff.selected_index() + 1);
|
||||
@@ -263,13 +317,13 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
persistent_memory::set_config_backlight_timer(0);
|
||||
|
||||
persistent_memory::set_config_splash(checkbox_showsplash.value());
|
||||
persistent_memory::set_config_login(checkbox_login.value());
|
||||
//persistent_memory::set_config_login(checkbox_login.value());
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
void SetUIView::focus() {
|
||||
checkbox_login.focus();
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
SetAudioView::SetAudioView(NavigationView& nav) {
|
||||
@@ -471,14 +525,14 @@ void ModInfoView::focus() {
|
||||
|
||||
SettingsMenuView::SettingsMenuView(NavigationView& nav) {
|
||||
add_items({
|
||||
//{ "..", ui::Color::light_grey(), &bitmap_icon_previous, [&nav](){ nav.pop(); } },
|
||||
{ "Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav](){ nav.push<SetAudioView>(); } },
|
||||
{ "Radio", ui::Color::dark_cyan(), nullptr, [&nav](){ nav.push<SetRadioView>(); } },
|
||||
{ "UI", ui::Color::dark_cyan(), nullptr, [&nav](){ nav.push<SetUIView>(); } },
|
||||
//{ "SD card modules", ui::Color::dark_cyan(), [&nav](){ nav.push<ModInfoView>(); } },
|
||||
{ "Date/Time", ui::Color::dark_cyan(), nullptr, [&nav](){ nav.push<SetDateTimeView>(); } },
|
||||
{ "Touch screen", ui::Color::dark_cyan(), nullptr, [&nav](){ nav.push<TouchCalibrationView>(); } },
|
||||
{ "Play dead", ui::Color::dark_cyan(), &bitmap_icon_playdead, [&nav](){ nav.push<SetPlayDeadView>(); } }
|
||||
//{ "..", ui::Color::light_grey(), &bitmap_icon_previous, [&nav](){ nav.pop(); } },
|
||||
{ "Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav](){ nav.push<SetAudioView>(); } },
|
||||
{ "Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav](){ nav.push<SetRadioView>(); } },
|
||||
{ "Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [&nav](){ nav.push<SetUIView>(); } },
|
||||
//{ "SD card modules", ui::Color::dark_cyan(), [&nav](){ nav.push<ModInfoView>(); } },
|
||||
{ "Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [&nav](){ nav.push<SetDateTimeView>(); } },
|
||||
{ "Touchscreen", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav](){ nav.push<TouchCalibrationView>(); } },
|
||||
//{ "Play dead", ui::Color::dark_cyan(), &bitmap_icon_playdead, [&nav](){ nav.push<SetPlayDeadView>(); } }
|
||||
});
|
||||
set_max_rows(2); // allow wider buttons
|
||||
}
|
||||
|
||||
@@ -101,11 +101,11 @@ private:
|
||||
|
||||
Button button_done {
|
||||
{ 2 * 8, 16 * 16, 12 * 8, 32 },
|
||||
"Done"
|
||||
"Save"
|
||||
};
|
||||
Button button_cancel {
|
||||
{ 16 * 8, 16 * 16, 12 * 8, 32 },
|
||||
"Cancel",
|
||||
"Cancel"
|
||||
};
|
||||
|
||||
void form_init(const SetDateTimeModel& model);
|
||||
@@ -114,6 +114,7 @@ private:
|
||||
|
||||
struct SetFrequencyCorrectionModel {
|
||||
int8_t ppm;
|
||||
uint32_t freq;
|
||||
};
|
||||
|
||||
class SetRadioView : public View {
|
||||
@@ -130,6 +131,7 @@ private:
|
||||
.background = Color::black(),
|
||||
.foreground = Color::light_grey(),
|
||||
};
|
||||
uint8_t freq_step_khz = 3;
|
||||
|
||||
Text label_source {
|
||||
{ 0, 1 * 16, 17 * 8, 16 },
|
||||
@@ -147,8 +149,31 @@ private:
|
||||
};
|
||||
|
||||
Labels labels_correction {
|
||||
{ { 2 * 8, 4 * 16 }, "Frequency correction:", Color::light_grey() },
|
||||
{ { 6 * 8, 5 * 16 }, "PPM", Color::light_grey() },
|
||||
{ { 2 * 8, 3 * 16 }, "Frequency correction:", Color::light_grey() },
|
||||
{ { 6 * 8, 4 * 16 }, "PPM", Color::light_grey() },
|
||||
};
|
||||
|
||||
Checkbox check_clkout {
|
||||
{ 18, (6 * 16 - 4) },
|
||||
13,
|
||||
"Enable CLKOUT"
|
||||
};
|
||||
|
||||
NumberField field_clkout_freq {
|
||||
{ 20 * 8, 6 * 16 },
|
||||
5,
|
||||
{ 10, 60000 },
|
||||
1000,
|
||||
' '
|
||||
};
|
||||
|
||||
Labels labels_clkout_khz {
|
||||
{ { 26 * 8, 6 * 16 }, "kHz", Color::light_grey() }
|
||||
};
|
||||
|
||||
Text value_freq_step {
|
||||
{ 21 * 8, (7 * 16 ), 4 * 8, 16 },
|
||||
"| "
|
||||
};
|
||||
|
||||
Labels labels_bias {
|
||||
@@ -159,7 +184,7 @@ private:
|
||||
};
|
||||
|
||||
NumberField field_ppm {
|
||||
{ 2 * 8, 5 * 16 },
|
||||
{ 2 * 8, 4 * 16 },
|
||||
3,
|
||||
{ -50, 50 },
|
||||
1,
|
||||
@@ -174,7 +199,7 @@ private:
|
||||
|
||||
Button button_done {
|
||||
{ 2 * 8, 16 * 16, 12 * 8, 32 },
|
||||
"Done"
|
||||
"Save"
|
||||
};
|
||||
Button button_cancel {
|
||||
{ 16 * 8, 16 * 16, 12 * 8, 32 },
|
||||
@@ -194,12 +219,17 @@ public:
|
||||
std::string title() const override { return "UI settings"; };
|
||||
|
||||
private:
|
||||
Checkbox checkbox_login {
|
||||
/*Checkbox checkbox_login {
|
||||
{ 3 * 8, 2 * 16 },
|
||||
20,
|
||||
"Login with play dead"
|
||||
};
|
||||
};*/
|
||||
|
||||
Checkbox checkbox_speaker {
|
||||
{ 3 * 8, 2 * 16 },
|
||||
20,
|
||||
"Hide H1 Speaker option"
|
||||
};
|
||||
Checkbox checkbox_bloff {
|
||||
{ 3 * 8, 5 * 16 },
|
||||
20,
|
||||
@@ -212,7 +242,9 @@ private:
|
||||
{
|
||||
{ "5 seconds", 5 },
|
||||
{ "15 seconds", 15 },
|
||||
{ "30 seconds", 30 },
|
||||
{ "1 minute", 60 },
|
||||
{ "3 minutes", 180 },
|
||||
{ "5 minutes", 300 },
|
||||
{ "10 minutes", 600 }
|
||||
}
|
||||
@@ -226,7 +258,7 @@ private:
|
||||
|
||||
Button button_ok {
|
||||
{ 2 * 8, 16 * 16, 12 * 8, 32 },
|
||||
"OK"
|
||||
"Save"
|
||||
};
|
||||
};
|
||||
|
||||
@@ -253,10 +285,11 @@ private:
|
||||
|
||||
Button button_ok {
|
||||
{ 2 * 8, 16 * 16, 12 * 8, 32 },
|
||||
"OK"
|
||||
"Save"
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
class SetPlayDeadView : public View {
|
||||
public:
|
||||
SetPlayDeadView(NavigationView& nav);
|
||||
@@ -284,7 +317,7 @@ private:
|
||||
{ 128, 192, 96, 24 },
|
||||
"Cancel"
|
||||
};
|
||||
};
|
||||
};*/
|
||||
|
||||
/*class ModInfoView : public View {
|
||||
public:
|
||||
|
||||
@@ -43,7 +43,11 @@ SigGenView::~SigGenView() {
|
||||
}
|
||||
|
||||
void SigGenView::update_config() {
|
||||
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), options_shape.selected_index_value(), field_stop.value());
|
||||
if(checkbox_stop.value())
|
||||
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), options_shape.selected_index_value(), field_stop.value());
|
||||
else
|
||||
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), options_shape.selected_index_value(), 0);
|
||||
|
||||
}
|
||||
|
||||
void SigGenView::update_tone() {
|
||||
@@ -52,7 +56,7 @@ void SigGenView::update_tone() {
|
||||
|
||||
void SigGenView::start_tx() {
|
||||
transmitter_model.set_sampling_rate(1536000);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
// transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
transmitter_model.enable();
|
||||
|
||||
@@ -68,8 +72,10 @@ void SigGenView::start_tx() {
|
||||
void SigGenView::on_tx_progress(const uint32_t progress, const bool done) {
|
||||
(void) progress;
|
||||
|
||||
if (done)
|
||||
if (done) {
|
||||
transmitter_model.disable();
|
||||
tx_view.set_transmitting(false);
|
||||
}
|
||||
}
|
||||
|
||||
SigGenView::SigGenView(
|
||||
@@ -98,6 +104,8 @@ SigGenView::SigGenView(
|
||||
options_shape.set_selected_index(0);
|
||||
text_shape.set(shape_strings[0]);
|
||||
|
||||
field_stop.set_value(1);
|
||||
|
||||
symfield_tone.set_sym(1, 1); // Default: 1000 Hz
|
||||
symfield_tone.on_change = [this]() {
|
||||
if (auto_update)
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Signal generator"; };
|
||||
std::string title() const override { return "Generator"; };
|
||||
|
||||
private:
|
||||
void start_tx();
|
||||
|
||||
@@ -24,9 +24,14 @@
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
#include "string_format.hpp"
|
||||
#include "complex.hpp"
|
||||
|
||||
|
||||
void SondeLogger::on_packet(const sonde::Packet& packet) {
|
||||
const auto formatted = packet.symbols_formatted();
|
||||
@@ -46,15 +51,20 @@ SondeView::SondeView(NavigationView& nav) {
|
||||
&field_vga,
|
||||
&rssi,
|
||||
&check_log,
|
||||
&check_crc,
|
||||
&text_signature,
|
||||
&text_serial,
|
||||
&text_timestamp,
|
||||
&text_voltage,
|
||||
&text_frame,
|
||||
&text_temp,
|
||||
&text_humid,
|
||||
&geopos,
|
||||
&button_see_map
|
||||
});
|
||||
|
||||
field_frequency.set_value(target_frequency_);
|
||||
field_frequency.set_step(10000);
|
||||
field_frequency.set_step(500); //euquiq: was 10000, but we are using this for fine-tunning
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
set_target_frequency(f);
|
||||
field_frequency.set_value(f);
|
||||
@@ -73,6 +83,10 @@ SondeView::SondeView(NavigationView& nav) {
|
||||
check_log.on_select = [this](Checkbox&, bool v) {
|
||||
logging = v;
|
||||
};
|
||||
|
||||
check_crc.on_select = [this](Checkbox&, bool v) {
|
||||
use_crc = v;
|
||||
};
|
||||
|
||||
radio::enable({
|
||||
tuning_frequency(),
|
||||
@@ -86,12 +100,12 @@ SondeView::SondeView(NavigationView& nav) {
|
||||
|
||||
button_see_map.on_select = [this, &nav](Button&) {
|
||||
nav.push<GeoMapView>(
|
||||
"",
|
||||
altitude,
|
||||
sonde_id,
|
||||
gps_info.alt,
|
||||
GeoPos::alt_unit::METERS,
|
||||
latitude,
|
||||
longitude,
|
||||
0);
|
||||
gps_info.lat,
|
||||
gps_info.lon,
|
||||
999); //set a dummy heading out of range to draw a cross...probably not ideal?
|
||||
};
|
||||
|
||||
logger = std::make_unique<SondeLogger>();
|
||||
@@ -109,27 +123,46 @@ void SondeView::focus() {
|
||||
field_vga.focus();
|
||||
}
|
||||
|
||||
void SondeView::on_packet(const sonde::Packet& packet) {
|
||||
//const auto hex_formatted = packet.symbols_formatted();
|
||||
|
||||
text_signature.set(packet.type_string());
|
||||
text_serial.set(packet.serial_number());
|
||||
text_voltage.set(unit_auto_scale(packet.battery_voltage(), 2, 3) + "V");
|
||||
|
||||
altitude = packet.GPS_altitude();
|
||||
latitude = packet.GPS_latitude();
|
||||
longitude = packet.GPS_longitude();
|
||||
|
||||
geopos.set_altitude(altitude);
|
||||
geopos.set_lat(latitude);
|
||||
geopos.set_lon(longitude);
|
||||
|
||||
if (logger && logging) {
|
||||
logger->on_packet(packet);
|
||||
void SondeView::on_packet(const sonde::Packet &packet)
|
||||
{
|
||||
if (!use_crc || packet.crc_ok()) //euquiq: Reject bad packet if crc is on
|
||||
{
|
||||
text_signature.set(packet.type_string());
|
||||
|
||||
sonde_id = packet.serial_number(); //used also as tag on the geomap
|
||||
text_serial.set(sonde_id);
|
||||
|
||||
text_timestamp.set(to_string_timestamp(packet.received_at()));
|
||||
|
||||
text_voltage.set(unit_auto_scale(packet.battery_voltage(), 2, 2) + "V");
|
||||
|
||||
text_frame.set(to_string_dec_uint(packet.frame(),0)); //euquiq: integrate frame #, temp & humid.
|
||||
|
||||
temp_humid_info = packet.get_temp_humid();
|
||||
if (temp_humid_info.humid != 0)
|
||||
{
|
||||
double decimals = abs(get_decimals(temp_humid_info.humid, 10, true));
|
||||
//if (decimals < 0)
|
||||
// decimals = -decimals;
|
||||
text_humid.set(to_string_dec_int((int)temp_humid_info.humid) + "." + to_string_dec_uint(decimals, 1) + "%");
|
||||
}
|
||||
|
||||
if (temp_humid_info.temp != 0)
|
||||
{
|
||||
double decimals = abs(get_decimals(temp_humid_info.temp, 10, true));
|
||||
// if (decimals < 0)
|
||||
// decimals = -decimals;
|
||||
text_temp.set(to_string_dec_int((int)temp_humid_info.temp) + "." + to_string_dec_uint(decimals, 1) + "C");
|
||||
}
|
||||
|
||||
gps_info = packet.get_GPS_data();
|
||||
geopos.set_altitude(gps_info.alt);
|
||||
geopos.set_lat(gps_info.lat);
|
||||
geopos.set_lon(gps_info.lon);
|
||||
|
||||
if (logger && logging)
|
||||
logger->on_packet(packet);
|
||||
}
|
||||
|
||||
/*if( packet.crc_ok() ) {
|
||||
}*/
|
||||
}
|
||||
|
||||
void SondeView::set_target_frequency(const uint32_t new_value) {
|
||||
|
||||
@@ -65,21 +65,28 @@ public:
|
||||
|
||||
private:
|
||||
std::unique_ptr<SondeLogger> logger { };
|
||||
uint32_t target_frequency_ { 402000000 };
|
||||
uint32_t target_frequency_ { 402700000 };
|
||||
bool logging { false };
|
||||
int32_t altitude { 0 };
|
||||
float latitude { 0 };
|
||||
float longitude { 0 };
|
||||
bool use_crc { false };
|
||||
sonde::GPS_data gps_info;
|
||||
sonde::temp_humid temp_humid_info;
|
||||
std::string sonde_id;
|
||||
|
||||
Labels labels {
|
||||
{ { 0 * 8, 2 * 16 }, "Signature:", Color::light_grey() },
|
||||
{ { 3 * 8, 3 * 16 }, "Serial:", Color::light_grey() },
|
||||
{ { 4 * 8, 4 * 16 }, "Vbatt:", Color::light_grey() }
|
||||
{ { 4 * 8, 2 * 16 }, "Type:", Color::light_grey() },
|
||||
{ { 6 * 8, 3 * 16 }, "ID:", Color::light_grey() },
|
||||
{ { 0 * 8, 4 * 16 }, "DateTime:", Color::light_grey() },
|
||||
|
||||
{ { 3 * 8, 5 * 16 }, "Vbatt:", Color::light_grey() },
|
||||
{ { 3 * 8, 6 * 16 }, "Frame:", Color::light_grey() },
|
||||
{ { 4 * 8, 7 * 16 }, "Temp:", Color::light_grey() },
|
||||
{ { 0 * 8, 8 * 16 }, "Humidity:", Color::light_grey() }
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 0 * 8, 0 * 8 },
|
||||
};
|
||||
|
||||
RFAmpField field_rf_amp {
|
||||
{ 13 * 8, 0 * 16 }
|
||||
};
|
||||
@@ -97,31 +104,59 @@ private:
|
||||
};
|
||||
|
||||
Checkbox check_log {
|
||||
{ 22 * 8, 3 * 16 },
|
||||
{ 23 * 8, 6 * 16 },
|
||||
3,
|
||||
"Log"
|
||||
};
|
||||
|
||||
Text text_signature {
|
||||
{ 10 * 8, 2 * 16, 10 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
Text text_serial {
|
||||
{ 10 * 8, 3 * 16, 11 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
Text text_voltage {
|
||||
{ 10 * 8, 4 * 16, 10 * 8, 16 },
|
||||
"..."
|
||||
Checkbox check_crc {
|
||||
{ 23 * 8, 8 * 16 },
|
||||
3,
|
||||
"CRC"
|
||||
};
|
||||
|
||||
Text text_signature {
|
||||
{ 9 * 8, 2 * 16, 10 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
|
||||
Text text_serial {
|
||||
{ 9 * 8, 3 * 16, 11 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
|
||||
Text text_timestamp {
|
||||
{ 9 * 8, 4 * 16, 11 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
|
||||
Text text_voltage {
|
||||
{ 9 * 8, 5 * 16, 10 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
|
||||
Text text_frame {
|
||||
{ 9 * 8, 6 * 16, 10 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
|
||||
Text text_temp {
|
||||
{ 9 * 8, 7 * 16, 10 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
|
||||
Text text_humid {
|
||||
{ 9 * 8, 8 * 16, 10 * 8, 16 },
|
||||
"..."
|
||||
};
|
||||
|
||||
GeoPos geopos {
|
||||
{ 0, 6 * 16 },
|
||||
{ 0, 12 * 16 },
|
||||
GeoPos::alt_unit::METERS
|
||||
};
|
||||
|
||||
Button button_see_map {
|
||||
{ 8 * 8, 10 * 16, 14 * 8, 3 * 16 },
|
||||
{ 8 * 8, 16 * 16, 14 * 8, 3 * 16 },
|
||||
"See on map"
|
||||
};
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Touch calibration"; };
|
||||
std::string title() const override { return "Calibration"; };
|
||||
|
||||
private:
|
||||
enum class Phase {
|
||||
|
||||
@@ -81,15 +81,6 @@ void ViewWavView::load_wav(std::filesystem::path file_path) {
|
||||
int16_t sample;
|
||||
uint32_t average;
|
||||
|
||||
if (!wav_reader->open(file_path)) {
|
||||
nav_.display_modal("Error", "Couldn't open file.", INFO, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
|
||||
nav_.display_modal("Error", "Wrong format.\nWav viewer only accepts\n16-bit mono files.", INFO, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
text_filename.set(file_path.filename().string());
|
||||
auto ms_duration = wav_reader->ms_duration();
|
||||
@@ -148,10 +139,18 @@ ViewWavView::ViewWavView(
|
||||
&field_cursor_b,
|
||||
&text_delta
|
||||
});
|
||||
|
||||
reset_controls();
|
||||
button_open.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".WAV");
|
||||
open_view->on_changed = [this](std::filesystem::path file_path) {
|
||||
if (!wav_reader->open(file_path)) {
|
||||
nav_.display_modal("Error", "Couldn't open file.", INFO, nullptr);
|
||||
return;
|
||||
}
|
||||
if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
|
||||
nav_.display_modal("Error", "Wrong format.\nWav viewer only accepts\n16-bit mono files.", INFO, nullptr);
|
||||
return;
|
||||
}
|
||||
load_wav(file_path);
|
||||
field_pos_seconds.focus();
|
||||
};
|
||||
@@ -176,7 +175,6 @@ ViewWavView::ViewWavView(
|
||||
refresh_measurements();
|
||||
};
|
||||
|
||||
reset_controls();
|
||||
}
|
||||
|
||||
void ViewWavView::focus() {
|
||||
|
||||
@@ -30,83 +30,190 @@
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
namespace ui
|
||||
{
|
||||
|
||||
void WhipCalcView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
void WhipCalcView::update_result() {
|
||||
double length, divider;
|
||||
|
||||
divider = ((double)options_type.selected_index_value() / 8.0);
|
||||
|
||||
// Metric
|
||||
length = (speed_of_light_mps / (double)field_frequency.value()) * divider;
|
||||
|
||||
auto m = to_string_dec_int((int)length, 2);
|
||||
auto cm = to_string_dec_int(int(length * 100.0) % 100, 2);
|
||||
auto mm = to_string_dec_int(int(length * 1000.0) % 10, 1);
|
||||
|
||||
text_result_metric.set(m + "m " + cm + "." + mm + "cm");
|
||||
|
||||
// ANT500 elements for crude adjustment
|
||||
length /= 0.14;
|
||||
if (int(length) <= 4) {
|
||||
auto elements = to_string_dec_int((int)length, 1);
|
||||
text_result_ant500.set(elements + " " + frac_str[((int(length * 10.0) % 10) + 1) / 3] + "ANT500 elements");
|
||||
} else {
|
||||
text_result_ant500.set("-");
|
||||
void WhipCalcView::focus()
|
||||
{
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
// Imperial
|
||||
length = (speed_of_light_fps / (double)field_frequency.value()) * divider;
|
||||
|
||||
auto feet = to_string_dec_int((int)length, 3);
|
||||
auto inch = to_string_dec_int(int(length * 10.0) % 12, 2);
|
||||
auto inch_c = to_string_dec_int(int(length * 100.0) % 10, 1);
|
||||
|
||||
text_result_imperial.set(feet + "ft " + inch + "." + inch_c + "in");
|
||||
}
|
||||
void WhipCalcView::update_result()
|
||||
{
|
||||
double length, calclength, divider;
|
||||
console.clear(true);
|
||||
divider = ((double)options_type.selected_index_value() / 8.0);
|
||||
|
||||
WhipCalcView::WhipCalcView(
|
||||
NavigationView& nav
|
||||
) {
|
||||
// Antenna lengths fields
|
||||
if (field_frequency.value() > 0)
|
||||
{
|
||||
// Metric
|
||||
length = (speed_of_light_mps / (double)field_frequency.value()) * divider;
|
||||
auto m = to_string_dec_int((int)length, 0);
|
||||
//auto cm = to_string_dec_int(int(length * 100.0) % 100, 2);
|
||||
//auto mm = to_string_dec_int(int(length * 1000.0) % 10, 1);
|
||||
calclength = get_decimals(length, 100); //cm
|
||||
auto cm = to_string_dec_int(int(calclength), 0);
|
||||
auto mm = to_string_dec_int(int(get_decimals(calclength, 10, true)), 0);
|
||||
text_result_metric.set(m + "m " + cm + "." + mm + "cm");
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&field_frequency,
|
||||
&options_type,
|
||||
&text_result_metric,
|
||||
&text_result_imperial,
|
||||
&text_result_ant500,
|
||||
&button_exit
|
||||
});
|
||||
|
||||
options_type.on_change = [this](size_t, OptionsField::value_t) {
|
||||
this->update_result();
|
||||
};
|
||||
options_type.set_selected_index(2); // Quarter wave
|
||||
|
||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
||||
field_frequency.set_step(500000); // 500kHz step
|
||||
field_frequency.on_change = [this](rf::Frequency) {
|
||||
this->update_result();
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.tuning_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
// Imperial
|
||||
calclength = (speed_of_light_fps / (double)field_frequency.value()) * divider;
|
||||
auto feet = to_string_dec_int(int(calclength), 0);
|
||||
calclength = get_decimals(calclength, 12); //inches
|
||||
auto inch = to_string_dec_int(int(calclength), 0);
|
||||
auto inch_c = to_string_dec_int(int(get_decimals(calclength, 10, true)), 0);
|
||||
text_result_imperial.set(feet + "ft " + inch + "." + inch_c + "in");
|
||||
}
|
||||
else
|
||||
{
|
||||
text_result_metric.set("infinity+");
|
||||
text_result_imperial.set("infinity+");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t ant_count = 9; //Shown antennas counter
|
||||
length *= 1000; //Get length in mm needed to extend the antenna
|
||||
for (antenna_entry antenna : antenna_db)
|
||||
{ //go thru all antennas available
|
||||
uint16_t element, refined_quarter = 0;
|
||||
for (element = 0; element < antenna.elements.size(); element++)
|
||||
{
|
||||
if (length == antenna.elements[element]) //Exact element in length
|
||||
{
|
||||
element++; //Real element is +1 (zero based vector)
|
||||
break; //Done with this ant
|
||||
}
|
||||
else if (length < antenna.elements[element])
|
||||
{
|
||||
double remain, this_element, quarter = 0;
|
||||
remain = length - antenna.elements[element - 1]; //mm needed from this element to reach length
|
||||
this_element = antenna.elements[element] - antenna.elements[element - 1]; //total mm on this element
|
||||
quarter = (remain * 4) / this_element; //havoc & portack ended on this int(quarter) resolution.
|
||||
if (quarter - int(quarter) > 0.5)
|
||||
{ //rounding gave a measure closer to next quarter
|
||||
refined_quarter = int(quarter) + 1;
|
||||
if (refined_quarter == 4)
|
||||
{ //rounding gave a measure closer to next element
|
||||
refined_quarter = 0;
|
||||
element++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
refined_quarter = int(quarter);
|
||||
}
|
||||
break; //Done with this ant
|
||||
}
|
||||
}
|
||||
/*if (!ant_count)
|
||||
{
|
||||
console.write(" and more ...");
|
||||
break;
|
||||
}*/
|
||||
console.write(antenna.label + ": " + to_string_dec_int(element, 1) + frac_str[refined_quarter] + " elements\n");
|
||||
ant_count--; // For now, just showing all.
|
||||
}
|
||||
}
|
||||
|
||||
WhipCalcView::WhipCalcView(NavigationView &nav)
|
||||
{
|
||||
add_children({&labels,
|
||||
//&antennas_on_memory,
|
||||
&field_frequency,
|
||||
&options_type,
|
||||
&text_result_metric,
|
||||
&text_result_imperial,
|
||||
&console,
|
||||
&button_exit});
|
||||
|
||||
File antennas_file;
|
||||
auto error = antennas_file.open("WHIPCALC/ANTENNAS.TXT");
|
||||
|
||||
if (!error.is_valid())
|
||||
{
|
||||
std::string line;
|
||||
char one_char[1];
|
||||
for (size_t pointer = 0; pointer < antennas_file.size(); pointer++)
|
||||
{
|
||||
antennas_file.seek(pointer);
|
||||
antennas_file.read(one_char, 1);
|
||||
if ((int)one_char[0] >= ' ')
|
||||
line += one_char[0]; //Add it to the textline
|
||||
else if (one_char[0] == '\n')
|
||||
{ //New Line
|
||||
txtline_process(line); //make sense of this textline
|
||||
line.clear(); //Ready for next textline
|
||||
}
|
||||
}
|
||||
if (line.length() > 0)
|
||||
txtline_process(line); //Last line had no newline at end ?
|
||||
}
|
||||
|
||||
if (!antenna_db.size())
|
||||
add_default_antenna();
|
||||
//antennas_on_memory.set(to_string_dec_int(antenna_db.size(),0) + " antennas"); //tell user
|
||||
|
||||
options_type.set_selected_index(2); // Quarter wave
|
||||
options_type.on_change = [this](size_t, OptionsField::value_t) {
|
||||
this->update_result();
|
||||
this->field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
|
||||
button_exit.on_select = [this, &nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
update_result();
|
||||
}
|
||||
|
||||
}
|
||||
field_frequency.set_step(1000000); // 1MHz step
|
||||
field_frequency.on_change = [this](rf::Frequency) {
|
||||
this->update_result();
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.tuning_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
this->field_frequency.set_value(f);
|
||||
this->update_result();
|
||||
};
|
||||
};
|
||||
|
||||
button_exit.on_select = [this, &nav](Button &) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
||||
}
|
||||
|
||||
void ui::WhipCalcView::txtline_process(std::string &line)
|
||||
{
|
||||
if (line.find("#") != std::string::npos)
|
||||
return; //Line is just a comment
|
||||
|
||||
char separator = ',';
|
||||
size_t previous = 0;
|
||||
uint16_t value = 0;
|
||||
antenna_entry new_antenna;
|
||||
size_t current = line.find(separator);
|
||||
|
||||
while (current != std::string::npos)
|
||||
{
|
||||
if (!previous)
|
||||
new_antenna.label.assign(line, 0, current); //antenna label
|
||||
else
|
||||
{
|
||||
value = std::stoi(line.substr(previous, current - previous));
|
||||
if (!value) return; //No element length? abort antenna
|
||||
new_antenna.elements.push_back(value); //Store this new element
|
||||
}
|
||||
previous = current + 1;
|
||||
current = line.find(separator, previous); //Search for next space delimiter
|
||||
}
|
||||
|
||||
if (!previous) return; //Not even a label ? drop this antenna!
|
||||
value = std::stoi(line.substr(previous, current - previous)); //Last element
|
||||
|
||||
if (!value) return;
|
||||
new_antenna.elements.push_back(value);
|
||||
antenna_db.push_back(new_antenna); //Add this antenna
|
||||
}
|
||||
|
||||
void ui::WhipCalcView::add_default_antenna()
|
||||
{
|
||||
antenna_db.push_back({"ANT500", {185, 315, 450, 586, 724, 862}}); //store a default ant500
|
||||
}
|
||||
} // namespace ui
|
||||
|
||||
@@ -28,68 +28,70 @@
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace ui {
|
||||
namespace ui
|
||||
{
|
||||
class WhipCalcView : public View
|
||||
{
|
||||
public:
|
||||
WhipCalcView(NavigationView &nav);
|
||||
void focus() override;
|
||||
std::string title() const override { return "Antenna length"; };
|
||||
|
||||
class WhipCalcView : public View {
|
||||
public:
|
||||
WhipCalcView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Whip calculator"; };
|
||||
private:
|
||||
const double speed_of_light_mps = 299792458.0; // m/s
|
||||
const double speed_of_light_fps = 983571087.90472; // feet/s
|
||||
const std::string frac_str[4] = {"", " 1/4", " 1/2", " 3/4"};
|
||||
|
||||
private:
|
||||
const double speed_of_light_mps = 299792458.0; // m/s
|
||||
const double speed_of_light_fps = 983571087.90472; // feet/s
|
||||
|
||||
const std::string frac_str[4] = { "", "1/4 ", "1/2 ", "3/4 " };
|
||||
|
||||
void update_result();
|
||||
|
||||
Labels labels {
|
||||
{ { 2 * 8, 2 * 16 }, "Frequency:", Color::light_grey() },
|
||||
{ { 2 * 8, 3 * 16 }, "Type:", Color::light_grey() }
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 13 * 8, 2 * 16 },
|
||||
};
|
||||
|
||||
OptionsField options_type {
|
||||
{ 8 * 8, 3 * 16 },
|
||||
12,
|
||||
struct antenna_entry
|
||||
{
|
||||
{ "Full wave", 8 },
|
||||
{ "Half wave", 4 },
|
||||
{ "Quarter wave", 2 },
|
||||
{ "3/4 wave", 6 },
|
||||
{ "1/8 wave", 1 },
|
||||
{ "3/8 wave", 3 },
|
||||
{ "5/8 wave", 5 },
|
||||
{ "7/8 wave", 7 }
|
||||
}
|
||||
std::string label{};
|
||||
std::vector<uint16_t> elements{};
|
||||
};
|
||||
|
||||
std::vector<antenna_entry> antenna_db{};
|
||||
void update_result();
|
||||
uint16_t string_to_number(std::string);
|
||||
void txtline_process(std::string &);
|
||||
void add_default_antenna();
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 1 * 16}, "Frequency:", Color::light_grey()},
|
||||
{{7 * 8, 2 * 16}, "Wave:", Color::light_grey()},
|
||||
{{5 * 8, 3 * 16}, "Metric:", Color::light_grey()},
|
||||
{{3 * 8, 4 * 16}, "Imperial:", Color::light_grey()}};
|
||||
|
||||
FrequencyField field_frequency{
|
||||
{13 * 8, 1 * 16},
|
||||
};
|
||||
|
||||
OptionsField options_type{
|
||||
{13 * 8, 2 * 16},
|
||||
7,
|
||||
{{"Full", 8},
|
||||
{"Half", 4},
|
||||
{"Quarter", 2},
|
||||
{"3/4", 6},
|
||||
{"1/8", 1},
|
||||
{"3/8", 3},
|
||||
{"5/8", 5},
|
||||
{"7/8", 7}}};
|
||||
|
||||
Text text_result_metric{
|
||||
{13 * 8, 3 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Text text_result_imperial{
|
||||
{13 * 8, 4 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Console console{
|
||||
{0, 6 * 16, 240, 160}};
|
||||
|
||||
Button button_exit{
|
||||
{72, 17 * 16, 96, 32},
|
||||
"Back"};
|
||||
};
|
||||
|
||||
Text text_result_metric {
|
||||
{ 3 * 8, 5 * 16, 10 * 16, 16 },
|
||||
"-"
|
||||
};
|
||||
Text text_result_imperial {
|
||||
{ 2 * 8, 6 * 16, 10 * 16, 16 },
|
||||
"-"
|
||||
};
|
||||
Text text_result_ant500 {
|
||||
{ 2 * 8, 8 * 16, 26 * 16, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Button button_exit {
|
||||
{ 72, 264, 96, 32 },
|
||||
"Exit"
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__UI_WHIPCALC__*/
|
||||
#endif /*__UI_WHIPCALC__*/
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
using portapack::clock_manager;
|
||||
|
||||
#include "portapack_hal.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
#include "i2s.hpp"
|
||||
using namespace lpc43xx;
|
||||
@@ -153,6 +154,16 @@ void unmute() {
|
||||
audio_codec->headphone_enable();
|
||||
}
|
||||
|
||||
void speaker_mute() {
|
||||
i2s::i2s0::tx_mute();
|
||||
audio_codec->speaker_disable();
|
||||
}
|
||||
|
||||
void speaker_unmute() {
|
||||
i2s::i2s0::tx_unmute();
|
||||
audio_codec->speaker_enable();
|
||||
}
|
||||
|
||||
} /* namespace output */
|
||||
|
||||
namespace input {
|
||||
|
||||
@@ -41,6 +41,9 @@ public:
|
||||
virtual bool reset() = 0;
|
||||
virtual void init() = 0;
|
||||
|
||||
virtual void speaker_enable() = 0;
|
||||
virtual void speaker_disable() = 0;
|
||||
|
||||
virtual void headphone_enable() = 0;
|
||||
virtual void headphone_disable() = 0;
|
||||
virtual volume_range_t headphone_gain_range() const = 0;
|
||||
@@ -62,6 +65,9 @@ void stop();
|
||||
void mute();
|
||||
void unmute();
|
||||
|
||||
void speaker_mute();
|
||||
void speaker_unmute();
|
||||
|
||||
} /* namespace output */
|
||||
|
||||
namespace input {
|
||||
@@ -79,6 +85,14 @@ void set_volume(const volume_t volume);
|
||||
|
||||
} /* namespace headphone */
|
||||
|
||||
namespace speaker {
|
||||
|
||||
volume_range_t volume_range();
|
||||
|
||||
void set_volume(const volume_t volume);
|
||||
|
||||
} /* namespace speaker */
|
||||
|
||||
namespace debug {
|
||||
|
||||
size_t reg_count();
|
||||
|
||||
@@ -39,7 +39,7 @@ static void send_message(const Message* const message) {
|
||||
// If message is only sent by this function via one thread, no need to check if
|
||||
// another message is present before setting new message.
|
||||
shared_memory.baseband_message = message;
|
||||
creg::m0apptxevent::assert();
|
||||
creg::m0apptxevent::assert_event();
|
||||
while(shared_memory.baseband_message);
|
||||
}
|
||||
|
||||
@@ -224,9 +224,10 @@ void set_fsk_data(const uint32_t stream_length, const uint32_t samples_per_bit,
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void set_pocsag(const pocsag::BitRate bitrate) {
|
||||
void set_pocsag(const pocsag::BitRate bitrate, bool phase) {
|
||||
const POCSAGConfigureMessage message {
|
||||
bitrate
|
||||
bitrate,
|
||||
phase
|
||||
};
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ void set_ook_data(const uint32_t stream_length, const uint32_t samples_per_bit,
|
||||
const uint32_t pause_symbols);
|
||||
void set_fsk_data(const uint32_t stream_length, const uint32_t samples_per_bit, const uint32_t shift,
|
||||
const uint32_t progress_notice);
|
||||
void set_pocsag(const pocsag::BitRate bitrate);
|
||||
void set_pocsag(const pocsag::BitRate bitrate, bool phase);
|
||||
void set_adsb();
|
||||
void set_jammer(const bool run, const jammer::JammerType type, const uint32_t speed);
|
||||
void set_rds_data(const uint16_t message_length);
|
||||
|
||||
@@ -1,946 +0,0 @@
|
||||
const unsigned char fox_bmp[] = {
|
||||
0x42, 0x4d, 0xee, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00,
|
||||
0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xa0, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x78, 0x2b,
|
||||
0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x17, 0x2a, 0x3c, 0x00, 0x21, 0x3d,
|
||||
0x70, 0x00, 0x2f, 0x48, 0x59, 0x00, 0x1f, 0x48, 0x62, 0x00, 0x44, 0x63,
|
||||
0x7b, 0x00, 0x33, 0x64, 0x86, 0x00, 0x48, 0x7e, 0xa9, 0x00, 0x62, 0x84,
|
||||
0x9f, 0x00, 0x65, 0xa2, 0xd0, 0x00, 0x87, 0xa9, 0xc2, 0x00, 0x83, 0xc5,
|
||||
0xef, 0x00, 0xa7, 0xca, 0xdc, 0x00, 0xb8, 0xc7, 0xe6, 0x00, 0xbf, 0xe4,
|
||||
0xf8, 0x00, 0xf9, 0xfe, 0xfd, 0x00, 0x00, 0x0c, 0xcc, 0xcc, 0xab, 0xca,
|
||||
0xac, 0xaa, 0x0c, 0xca, 0x00, 0x3a, 0xcd, 0xcd, 0xca, 0xcc, 0xdc, 0xdc,
|
||||
0xcc, 0xda, 0xcc, 0xac, 0xdc, 0xcc, 0xcd, 0xce, 0xdc, 0xed, 0xee, 0xcf,
|
||||
0xce, 0xcc, 0xfc, 0xcc, 0xfc, 0xec, 0xfc, 0xcc, 0xcc, 0xfc, 0xec, 0x00,
|
||||
0x08, 0xcc, 0x00, 0x0e, 0xec, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcd, 0x00,
|
||||
0x08, 0xcc, 0x00, 0x10, 0xcf, 0xcc, 0xcd, 0xce, 0xcd, 0xec, 0xcc, 0xfe,
|
||||
0x06, 0xcf, 0x00, 0x1a, 0xcc, 0xcc, 0xfc, 0xcf, 0xce, 0xce, 0xdc, 0xee,
|
||||
0xcf, 0xce, 0xcc, 0xfc, 0xec, 0x00, 0x06, 0xce, 0x0a, 0xcc, 0x00, 0x08,
|
||||
0xce, 0xcc, 0xcc, 0xcd, 0x08, 0xcc, 0x00, 0x0e, 0xce, 0xcc, 0xec, 0xcc,
|
||||
0xce, 0xcc, 0xec, 0x00, 0x22, 0xcc, 0x00, 0x00, 0x02, 0xcc, 0x0a, 0xac,
|
||||
0x02, 0xaa, 0x06, 0xca, 0x00, 0x8c, 0xcc, 0xcc, 0xdc, 0xcc, 0xcc, 0xcd,
|
||||
0xcc, 0xcc, 0xcd, 0xcc, 0xcd, 0xcc, 0xcc, 0xcd, 0xcc, 0xcc, 0xce, 0xcc,
|
||||
0xcc, 0xdc, 0xcc, 0xdc, 0xec, 0xde, 0xcd, 0xcc, 0xde, 0xcf, 0xcc, 0xce,
|
||||
0xcd, 0xec, 0xec, 0xfc, 0xcc, 0xcc, 0xcf, 0xcc, 0xce, 0xce, 0xcc, 0xfc,
|
||||
0xce, 0xcc, 0xfc, 0xcc, 0xed, 0xec, 0xfc, 0xec, 0xde, 0xcc, 0xcf, 0xcc,
|
||||
0xdc, 0xcc, 0xcd, 0xcc, 0xfc, 0xcc, 0xec, 0xde, 0xcd, 0xce, 0xcd, 0xcc,
|
||||
0xcc, 0xec, 0xce, 0xce, 0x10, 0xcc, 0x02, 0xec, 0x08, 0xcc, 0x00, 0x06,
|
||||
0xdc, 0xcc, 0xcf, 0x00, 0x10, 0xcc, 0x00, 0x08, 0xcd, 0xcc, 0xcc, 0xcd,
|
||||
0x18, 0xcc, 0x00, 0x00, 0x00, 0x4e, 0xca, 0xcc, 0x9c, 0xaa, 0xca, 0xac,
|
||||
0xac, 0xaa, 0xcc, 0xad, 0xca, 0xcc, 0xac, 0xca, 0xcd, 0xcc, 0xcc, 0xcd,
|
||||
0xca, 0xca, 0xcc, 0xac, 0xcd, 0xcc, 0xdc, 0xcf, 0xcd, 0xec, 0xfc, 0xec,
|
||||
0xfc, 0xec, 0xcc, 0xcc, 0xce, 0xcc, 0xec, 0xee, 0xcf, 0x00, 0x08, 0xcc,
|
||||
0x00, 0x32, 0xdc, 0xcf, 0xcc, 0xec, 0xce, 0xcc, 0xcc, 0xce, 0xcc, 0xcc,
|
||||
0xec, 0xec, 0xfd, 0xcc, 0xcc, 0xdc, 0xcc, 0xec, 0xcf, 0xcc, 0xce, 0xcc,
|
||||
0xdc, 0xcc, 0xdc, 0x00, 0x0a, 0xcc, 0x00, 0x08, 0xcd, 0xcc, 0xcc, 0xce,
|
||||
0x0c, 0xcc, 0x02, 0xac, 0x0e, 0xcc, 0x00, 0x18, 0xac, 0xda, 0xcc, 0xdc,
|
||||
0xcc, 0xcc, 0xcd, 0xcc, 0xdc, 0xcc, 0xcc, 0xdc, 0x06, 0xcc, 0x00, 0x1c,
|
||||
0xcd, 0xcc, 0xcc, 0xca, 0xcc, 0xac, 0xac, 0xca, 0xcc, 0xcc, 0xca, 0xcc,
|
||||
0xca, 0xcc, 0x00, 0x00, 0x02, 0xca, 0x02, 0xc9, 0x08, 0xca, 0x00, 0x0e,
|
||||
0xac, 0xac, 0xca, 0xcc, 0xac, 0xcd, 0xcd, 0x00, 0x06, 0xcc, 0x00, 0x38,
|
||||
0xdc, 0xcc, 0xac, 0xdc, 0xda, 0xdc, 0xdc, 0xcc, 0xdc, 0xcd, 0xcc, 0xcc,
|
||||
0xdc, 0xec, 0xde, 0xcd, 0xcf, 0xcc, 0xcc, 0xdc, 0xfc, 0xcd, 0xcc, 0xcc,
|
||||
0xfc, 0xcf, 0xcc, 0xec, 0x18, 0xcc, 0x00, 0x08, 0xec, 0xfc, 0xec, 0xfc,
|
||||
0x06, 0xcc, 0x00, 0x08, 0xfc, 0xcd, 0xcc, 0xcc, 0x06, 0xcd, 0x02, 0xfa,
|
||||
0x0c, 0xcc, 0x02, 0xec, 0x0c, 0xcc, 0x00, 0x06, 0xca, 0xcc, 0xac, 0x00,
|
||||
0x06, 0xcc, 0x00, 0x0e, 0xec, 0xcc, 0xcc, 0xcd, 0xcc, 0xcc, 0xdc, 0x00,
|
||||
0x08, 0xcc, 0x00, 0x08, 0xcd, 0xcc, 0xcc, 0xcd, 0x06, 0xcc, 0x00, 0x18,
|
||||
0xdc, 0xca, 0xca, 0xcc, 0xaa, 0xca, 0xcc, 0xca, 0xcc, 0xcc, 0xac, 0xcc,
|
||||
0x00, 0x00, 0x00, 0x08, 0xac, 0xcc, 0xac, 0xaa, 0x08, 0xca, 0x00, 0x28,
|
||||
0xac, 0xac, 0xdc, 0xca, 0xcc, 0xcc, 0xdc, 0xdc, 0xcc, 0xda, 0xdc, 0xac,
|
||||
0xac, 0xcc, 0xad, 0xcd, 0xcd, 0xcc, 0xcc, 0xfc, 0x0c, 0xcc, 0x00, 0x0e,
|
||||
0xfc, 0xec, 0xed, 0xce, 0xcf, 0xce, 0xdc, 0x00, 0x06, 0xcc, 0x00, 0x30,
|
||||
0xcf, 0xcc, 0xcf, 0xcc, 0xcf, 0xcf, 0xdc, 0xcf, 0xcc, 0xfc, 0xcf, 0xce,
|
||||
0xdc, 0xce, 0xdc, 0xed, 0xcf, 0xec, 0xfc, 0xed, 0xcc, 0xcc, 0xfd, 0xce,
|
||||
0x06, 0xcc, 0x00, 0x06, 0xec, 0xce, 0xcc, 0x00, 0x06, 0xec, 0x1e, 0xcc,
|
||||
0x06, 0xec, 0x00, 0x0c, 0xcc, 0xcc, 0xdc, 0xce, 0xdc, 0xcf, 0x06, 0xcc,
|
||||
0x00, 0x06, 0xce, 0xcc, 0xcd, 0x00, 0x0e, 0xcc, 0x02, 0xca, 0x06, 0xcc,
|
||||
0x02, 0xce, 0x02, 0xcc, 0x00, 0x00, 0x00, 0x0a, 0xcc, 0xaa, 0xac, 0xab,
|
||||
0xaa, 0x00, 0x06, 0xac, 0x08, 0xcc, 0x00, 0x34, 0xdc, 0xcd, 0xcc, 0xac,
|
||||
0xcd, 0xca, 0xdc, 0xcd, 0xcd, 0xac, 0xdc, 0xcd, 0xcd, 0xcc, 0xdc, 0xcd,
|
||||
0xcf, 0xcf, 0xce, 0xdc, 0xfc, 0xcc, 0xcd, 0xcc, 0xcc, 0xec, 0x08, 0xcc,
|
||||
0x00, 0x18, 0xcf, 0xcc, 0xcc, 0xce, 0xcc, 0xcc, 0xfc, 0xcc, 0xec, 0xec,
|
||||
0xcc, 0xce, 0x06, 0xcc, 0x00, 0x1a, 0xcd, 0xcc, 0xec, 0xcc, 0xcd, 0xec,
|
||||
0xdc, 0xec, 0xfc, 0xcc, 0xcc, 0xde, 0xce, 0x00, 0x1e, 0xcc, 0x02, 0xac,
|
||||
0x08, 0xcc, 0x00, 0x24, 0xce, 0xce, 0xcc, 0xce, 0xcc, 0xce, 0xfc, 0xce,
|
||||
0xcc, 0xce, 0xcd, 0xce, 0xcf, 0xcc, 0xec, 0xcc, 0xcc, 0xce, 0x18, 0xcc,
|
||||
0x00, 0x00, 0x00, 0x06, 0xca, 0xbc, 0xcc, 0x00, 0x0a, 0xac, 0x00, 0x0a,
|
||||
0xaa, 0xca, 0xcc, 0xdc, 0xcc, 0x00, 0x06, 0xdc, 0x00, 0x12, 0xda, 0xdc,
|
||||
0xca, 0xda, 0xca, 0xda, 0xca, 0xdc, 0xcc, 0x00, 0x06, 0xdc, 0x00, 0x2e,
|
||||
0xcc, 0xcc, 0xdc, 0xcc, 0xec, 0xcf, 0xcc, 0xcc, 0xfc, 0xcc, 0xcf, 0xcc,
|
||||
0xfc, 0xcf, 0xcc, 0xdc, 0xfc, 0xcc, 0xcf, 0xce, 0xcc, 0xce, 0xdc, 0x00,
|
||||
0x08, 0xcc, 0x00, 0x18, 0xfc, 0xcf, 0xce, 0xed, 0xec, 0xcf, 0xcc, 0xcc,
|
||||
0xce, 0xcd, 0xcc, 0xdc, 0x32, 0xcc, 0x00, 0x0e, 0xce, 0xcc, 0xcc, 0xec,
|
||||
0xcc, 0xec, 0xcf, 0x00, 0x08, 0xce, 0x06, 0xcc, 0x02, 0xfc, 0x0a, 0xcc,
|
||||
0x02, 0xca, 0x0e, 0xcc, 0x00, 0x00, 0x00, 0x06, 0xcc, 0xac, 0xaa, 0x00,
|
||||
0x08, 0xca, 0x00, 0x22, 0xcc, 0xcc, 0xcd, 0xcc, 0xdc, 0xcd, 0xcc, 0xdc,
|
||||
0xac, 0xac, 0xca, 0xda, 0xcc, 0xda, 0xcc, 0xdd, 0xcc, 0x00, 0x08, 0xdc,
|
||||
0x00, 0x14, 0xfc, 0xdf, 0xcc, 0xfc, 0xed, 0xec, 0xcc, 0xfc, 0xcd, 0xcf,
|
||||
0x06, 0xcc, 0x00, 0x34, 0xec, 0xec, 0xcc, 0xcc, 0xcf, 0xcc, 0xec, 0xde,
|
||||
0xcc, 0xcc, 0xcf, 0xcc, 0xfc, 0xcd, 0xce, 0xde, 0xcc, 0xdc, 0xcc, 0xfc,
|
||||
0xde, 0xfc, 0xef, 0xcc, 0xcc, 0xec, 0x16, 0xcc, 0x02, 0xac, 0x06, 0xcc,
|
||||
0x00, 0x06, 0xac, 0xcb, 0xac, 0x00, 0x10, 0xcc, 0x00, 0x1a, 0xce, 0xce,
|
||||
0xcc, 0xec, 0xce, 0xcd, 0xec, 0xcd, 0xec, 0xcc, 0xcc, 0xfc, 0xce, 0x00,
|
||||
0x0a, 0xcc, 0x00, 0x08, 0xac, 0xcc, 0xcc, 0xca, 0x0a, 0xcc, 0x00, 0x00,
|
||||
0x00, 0x0c, 0xac, 0xcc, 0xcc, 0xca, 0xca, 0xac, 0x06, 0xca, 0x00, 0x10,
|
||||
0xcc, 0xdc, 0xcd, 0xcd, 0xdc, 0xca, 0xda, 0xda, 0x0a, 0xad, 0x02, 0xac,
|
||||
0x02, 0xad, 0x08, 0xcd, 0x00, 0x06, 0xcc, 0xdc, 0xdc, 0x00, 0x06, 0xcc,
|
||||
0x00, 0x26, 0xce, 0xcc, 0xec, 0xec, 0xdc, 0xcc, 0xec, 0xed, 0xcc, 0xfc,
|
||||
0xcc, 0xfc, 0xcc, 0xce, 0xcc, 0xcf, 0xcc, 0xce, 0xdc, 0x00, 0x06, 0xcc,
|
||||
0x00, 0x18, 0xce, 0xcf, 0xec, 0xfe, 0xdc, 0xce, 0xed, 0xcc, 0xcf, 0xcd,
|
||||
0xcc, 0xdc, 0x10, 0xcc, 0x00, 0x1a, 0xbc, 0xcc, 0xbc, 0xca, 0xca, 0xcb,
|
||||
0xcc, 0xac, 0xcb, 0xac, 0xab, 0xcc, 0xc9, 0x00, 0x06, 0xcc, 0x00, 0x06,
|
||||
0xce, 0xcc, 0xcc, 0x00, 0x0a, 0xec, 0x00, 0x12, 0xee, 0xcc, 0xcf, 0xce,
|
||||
0xcc, 0xcc, 0xce, 0xcc, 0xfc, 0x00, 0x06, 0xcc, 0x00, 0x08, 0xac, 0xcc,
|
||||
0xcc, 0xca, 0x08, 0xcc, 0x00, 0x00, 0x00, 0x06, 0xcc, 0xca, 0xcc, 0x00,
|
||||
0x0a, 0xac, 0x00, 0x10, 0xcc, 0xcd, 0xca, 0xdc, 0xcd, 0xca, 0xda, 0xdc,
|
||||
0x06, 0xad, 0x00, 0x08, 0xaa, 0xda, 0xad, 0xad, 0x0c, 0xcd, 0x00, 0x10,
|
||||
0xcc, 0xcc, 0xfc, 0xcf, 0xcc, 0xfc, 0xdc, 0xdc, 0x06, 0xcc, 0x02, 0xdc,
|
||||
0x06, 0xcc, 0x00, 0x28, 0xef, 0xcc, 0xee, 0xfc, 0xcc, 0xfc, 0xec, 0xfc,
|
||||
0xcc, 0xcd, 0xcf, 0xce, 0xfc, 0xcc, 0xde, 0xcc, 0xde, 0xfc, 0xcd, 0xef,
|
||||
0x0a, 0xcc, 0x02, 0xdc, 0x0e, 0xcc, 0x06, 0xac, 0x00, 0x10, 0xcc, 0xca,
|
||||
0xca, 0xcc, 0xac, 0xcc, 0xcc, 0xca, 0x0c, 0xcc, 0x00, 0x14, 0xec, 0xcc,
|
||||
0xec, 0xce, 0xcc, 0xec, 0xcc, 0xde, 0xfc, 0xcc, 0x06, 0xec, 0x0e, 0xcc,
|
||||
0x02, 0xac, 0x0a, 0xcc, 0x00, 0x00, 0x00, 0x2e, 0xcc, 0xcc, 0xca, 0xcc,
|
||||
0xba, 0xca, 0xca, 0xcc, 0xaa, 0xca, 0xdc, 0xdc, 0xda, 0xcd, 0xcd, 0xaa,
|
||||
0xda, 0xda, 0xaa, 0xda, 0xaa, 0xda, 0xaa, 0x00, 0x06, 0xda, 0x08, 0xdc,
|
||||
0x00, 0x06, 0xfc, 0xdc, 0xce, 0x00, 0x06, 0xcc, 0x00, 0x1a, 0xec, 0xcd,
|
||||
0xed, 0xcd, 0xcc, 0xdc, 0xcc, 0xce, 0xdc, 0xcc, 0xcc, 0xdc, 0xfc, 0x00,
|
||||
0x06, 0xcc, 0x00, 0x24, 0xdc, 0xfc, 0xec, 0xcc, 0xcc, 0xcf, 0xcc, 0xcf,
|
||||
0xec, 0xec, 0xfc, 0xed, 0xcc, 0xdc, 0xcd, 0xcc, 0xdc, 0xec, 0x08, 0xcc,
|
||||
0x00, 0x18, 0xac, 0xcc, 0xac, 0xcc, 0xcc, 0xcb, 0xab, 0xaa, 0xca, 0xba,
|
||||
0xc9, 0xca, 0x08, 0xac, 0x00, 0x24, 0xcc, 0xbc, 0xcc, 0xce, 0xcc, 0xec,
|
||||
0xec, 0xce, 0xce, 0xcc, 0xfe, 0xce, 0xcc, 0xec, 0xec, 0xcc, 0xcc, 0xce,
|
||||
0x0a, 0xcc, 0x02, 0xac, 0x0c, 0xcc, 0x00, 0x00, 0x00, 0x08, 0xcc, 0xca,
|
||||
0xcc, 0xca, 0x06, 0xac, 0x00, 0x0c, 0xaa, 0xcc, 0xdc, 0xdc, 0xca, 0xcd,
|
||||
0x06, 0xad, 0x08, 0xda, 0x02, 0xad, 0x02, 0xaa, 0x06, 0xda, 0x0a, 0xdc,
|
||||
0x02, 0xcd, 0x0c, 0xcc, 0x00, 0x36, 0xce, 0xcc, 0xcc, 0xce, 0xcc, 0xcc,
|
||||
0xdc, 0xce, 0xcf, 0xcf, 0xcc, 0xec, 0xef, 0xcf, 0xcf, 0xcc, 0xcc, 0xcd,
|
||||
0xef, 0xcc, 0xfc, 0xec, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0x00, 0x08, 0xcc,
|
||||
0x00, 0x0c, 0xce, 0xcc, 0xdc, 0xcc, 0xcc, 0xca, 0x06, 0xcc, 0x02, 0xca,
|
||||
0x02, 0xba, 0x06, 0xca, 0x00, 0x12, 0xba, 0xaa, 0xaa, 0xca, 0xbc, 0xba,
|
||||
0xbc, 0xbc, 0xac, 0x00, 0x0c, 0xcc, 0x00, 0x08, 0xec, 0xce, 0xce, 0xcc,
|
||||
0x06, 0xec, 0x02, 0xcc, 0x06, 0xec, 0x00, 0x18, 0xcc, 0xec, 0xcc, 0xcc,
|
||||
0xac, 0xcc, 0xcd, 0xcc, 0xcc, 0xca, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x0a,
|
||||
0xcc, 0xcb, 0xcc, 0xac, 0xcc, 0x00, 0x06, 0xac, 0x00, 0x0e, 0xca, 0xcd,
|
||||
0xcc, 0xda, 0xda, 0xaa, 0xda, 0x00, 0x12, 0xaa, 0x08, 0xad, 0x02, 0xcc,
|
||||
0x02, 0xdc, 0x0c, 0xcc, 0x02, 0xcd, 0x06, 0xcc, 0x02, 0xec, 0x06, 0xcc,
|
||||
0x06, 0xce, 0x00, 0x5e, 0xde, 0xcf, 0xdc, 0xce, 0xcc, 0xcf, 0xcf, 0xcc,
|
||||
0xed, 0xce, 0xdc, 0xde, 0xce, 0xcf, 0xcc, 0xfc, 0xed, 0xcc, 0xfc, 0xdc,
|
||||
0xcc, 0xcc, 0xdc, 0xec, 0xcc, 0xcc, 0xac, 0xcc, 0xac, 0xab, 0xcc, 0xcc,
|
||||
0xab, 0xca, 0xba, 0xca, 0xba, 0xba, 0xab, 0xaa, 0xaa, 0xca, 0xca, 0xbc,
|
||||
0xca, 0xcc, 0xbc, 0x00, 0x08, 0xcc, 0x02, 0xce, 0x02, 0xcc, 0x0c, 0xec,
|
||||
0x00, 0x06, 0xcc, 0xcc, 0xec, 0x00, 0x0e, 0xcc, 0x02, 0xac, 0x06, 0xcc,
|
||||
0x00, 0x00, 0x02, 0xac, 0x02, 0xaa, 0x06, 0xca, 0x08, 0xac, 0x00, 0x1a,
|
||||
0xca, 0xca, 0xda, 0xaa, 0xda, 0xaa, 0xaa, 0xad, 0xaa, 0xad, 0xaa, 0xaa,
|
||||
0x8d, 0x00, 0x08, 0xaa, 0x00, 0x10, 0xad, 0xac, 0xca, 0xcc, 0xca, 0xcc,
|
||||
0xcc, 0xca, 0x06, 0xcc, 0x00, 0x06, 0xcb, 0xcc, 0xbc, 0x00, 0x08, 0xcc,
|
||||
0x00, 0x18, 0xcd, 0xcd, 0xec, 0xec, 0xed, 0xec, 0xfc, 0xcf, 0xcc, 0xcc,
|
||||
0xcf, 0xcd, 0x06, 0xec, 0x00, 0x16, 0xed, 0xce, 0xce, 0xdc, 0xec, 0xcc,
|
||||
0xdc, 0xcc, 0xcd, 0xfc, 0xce, 0x00, 0x08, 0xcc, 0x00, 0x0a, 0xca, 0xcc,
|
||||
0xac, 0xca, 0xcc, 0x00, 0x06, 0xac, 0x00, 0x1a, 0xab, 0xaa, 0xac, 0xab,
|
||||
0xaa, 0xba, 0xba, 0xab, 0xac, 0xab, 0xcc, 0xcc, 0xca, 0x00, 0x08, 0xcc,
|
||||
0x00, 0x12, 0xce, 0xce, 0xcc, 0xee, 0xcc, 0xec, 0xcc, 0xec, 0xec, 0x00,
|
||||
0x0c, 0xcc, 0x02, 0xca, 0x0a, 0xcc, 0x00, 0x00, 0x00, 0x2e, 0xaa, 0xba,
|
||||
0xca, 0xa9, 0xaa, 0xaa, 0x9a, 0xca, 0xac, 0xac, 0xad, 0xaa, 0xda, 0xaa,
|
||||
0xa8, 0xaa, 0xa8, 0xaa, 0xa8, 0xaa, 0x8a, 0xa8, 0xa8, 0x00, 0x0c, 0xaa,
|
||||
0x00, 0x52, 0xac, 0xac, 0xcc, 0xca, 0xcc, 0xcc, 0xcb, 0xcc, 0xcc, 0xca,
|
||||
0xdd, 0xbc, 0xca, 0xba, 0xca, 0xce, 0xce, 0xcc, 0xed, 0xec, 0xee, 0xce,
|
||||
0xde, 0xcc, 0xcf, 0xce, 0xce, 0xcd, 0xec, 0xec, 0xde, 0xec, 0xcc, 0xec,
|
||||
0xcc, 0xce, 0xcc, 0xcd, 0xce, 0xcc, 0xec, 0x00, 0x08, 0xcc, 0x00, 0x2c,
|
||||
0xac, 0xca, 0xbc, 0xac, 0xca, 0xc9, 0xca, 0xc9, 0xca, 0xc9, 0xca, 0x9a,
|
||||
0xaa, 0x9a, 0xaa, 0x9c, 0xa9, 0xca, 0xbc, 0xac, 0xcc, 0xcb, 0x08, 0xcc,
|
||||
0x00, 0x0c, 0xce, 0xce, 0xcc, 0xce, 0xcc, 0xce, 0x06, 0xcc, 0x02, 0xec,
|
||||
0x06, 0xcc, 0x00, 0x0e, 0xac, 0xcc, 0xcc, 0xcd, 0xca, 0xcc, 0xcc, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0c, 0xa9, 0x8a, 0xa9, 0xa8, 0xaa, 0x9a, 0x0e, 0xaa,
|
||||
0x02, 0x88, 0x02, 0x8a, 0x08, 0x88, 0x02, 0xa8, 0x0a, 0x88, 0x02, 0x8a,
|
||||
0x02, 0x8a, 0x0a, 0xaa, 0x00, 0x3c, 0xca, 0xaa, 0xba, 0xbc, 0xcb, 0x9b,
|
||||
0x9b, 0xbb, 0xba, 0xb9, 0xab, 0xac, 0xcb, 0xcc, 0xeb, 0xce, 0xce, 0xcc,
|
||||
0xde, 0xce, 0xde, 0xde, 0xed, 0xed, 0xec, 0xec, 0xdc, 0xec, 0xcc, 0xec,
|
||||
0x08, 0xcc, 0x0a, 0xec, 0x08, 0xcc, 0x00, 0x2c, 0xac, 0xac, 0xcc, 0xbc,
|
||||
0xbc, 0xca, 0xbc, 0xcc, 0xbc, 0xaa, 0xab, 0xab, 0xa9, 0xa9, 0xaa, 0x9a,
|
||||
0xc9, 0xca, 0xbc, 0xab, 0xca, 0xca, 0x0a, 0xcc, 0x0e, 0xec, 0x0c, 0xcc,
|
||||
0x02, 0xcd, 0x02, 0xca, 0x06, 0xcc, 0x00, 0x00, 0x00, 0x10, 0x88, 0xa8,
|
||||
0x98, 0xa9, 0x87, 0xa8, 0x98, 0x88, 0x08, 0xaa, 0x00, 0x06, 0x8a, 0x8a,
|
||||
0x88, 0x00, 0x06, 0x55, 0x02, 0x58, 0x06, 0x55, 0x06, 0x85, 0x02, 0x58,
|
||||
0x02, 0x58, 0x06, 0x88, 0x00, 0x12, 0xa8, 0xaa, 0xaa, 0x9a, 0x9c, 0xab,
|
||||
0x9b, 0xbb, 0xbb, 0x00, 0x06, 0xb9, 0x00, 0x12, 0x99, 0x9b, 0xab, 0xdb,
|
||||
0xad, 0xcd, 0xcc, 0xde, 0xcb, 0x00, 0x06, 0xce, 0x00, 0x0a, 0xdc, 0xec,
|
||||
0xec, 0xcc, 0xce, 0x00, 0x10, 0xcc, 0x00, 0x0a, 0xec, 0xce, 0xcc, 0xcc,
|
||||
0xce, 0x00, 0x0a, 0xcc, 0x00, 0x18, 0xac, 0xca, 0xca, 0xba, 0xcc, 0xcc,
|
||||
0xac, 0xac, 0xba, 0xaa, 0x9a, 0xaa, 0x06, 0x9a, 0x00, 0x10, 0xab, 0xab,
|
||||
0xac, 0xab, 0xca, 0xcc, 0xac, 0xac, 0x1a, 0xcc, 0x00, 0x08, 0xcd, 0xca,
|
||||
0xcc, 0xcd, 0x06, 0xcc, 0x00, 0x00, 0x00, 0x10, 0x87, 0x87, 0xa7, 0xa7,
|
||||
0x89, 0x87, 0x88, 0x87, 0x0c, 0x88, 0x02, 0x85, 0x08, 0x55, 0x00, 0x26,
|
||||
0x35, 0x53, 0x55, 0x55, 0x54, 0x34, 0x34, 0x43, 0x54, 0x55, 0x58, 0x86,
|
||||
0x88, 0x87, 0xa9, 0xa9, 0xb9, 0xbb, 0x9b, 0x00, 0x0c, 0x99, 0x00, 0x16,
|
||||
0x9b, 0xb9, 0xb9, 0xbb, 0x9b, 0xab, 0xae, 0xde, 0xec, 0xde, 0xce, 0x00,
|
||||
0x06, 0xcc, 0x00, 0x0e, 0xbc, 0xcc, 0xcc, 0xca, 0xbc, 0xab, 0xcb, 0x00,
|
||||
0x1a, 0xcc, 0x02, 0xca, 0x0a, 0xcc, 0x00, 0x24, 0xca, 0xac, 0x9c, 0xaa,
|
||||
0xb9, 0xa9, 0xa9, 0xab, 0xa9, 0xaa, 0xab, 0xaa, 0xca, 0xba, 0xbc, 0xcc,
|
||||
0xcc, 0xac, 0x1a, 0xcc, 0x00, 0x0a, 0xcd, 0xac, 0xcc, 0xac, 0xac, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0a, 0x88, 0x88, 0x78, 0x98, 0x98, 0x00, 0x06, 0x78,
|
||||
0x06, 0x88, 0x00, 0x06, 0x58, 0x88, 0x85, 0x00, 0x06, 0x55, 0x02, 0x45,
|
||||
0x06, 0x33, 0x00, 0x0a, 0x43, 0x34, 0x34, 0x14, 0x14, 0x00, 0x08, 0x44,
|
||||
0x00, 0x14, 0x45, 0x65, 0x79, 0x89, 0x99, 0xba, 0xbb, 0x9b, 0x99, 0xb9,
|
||||
0x10, 0x99, 0x00, 0x18, 0xb9, 0xdb, 0xae, 0xbc, 0xcc, 0xee, 0xce, 0xcc,
|
||||
0xdc, 0xdd, 0xdc, 0xca, 0x06, 0xcc, 0x00, 0x0e, 0xca, 0xaa, 0xab, 0xab,
|
||||
0xac, 0xcb, 0xac, 0x00, 0x08, 0xcc, 0x02, 0xdc, 0x08, 0xcc, 0x00, 0x06,
|
||||
0xbc, 0xcc, 0xec, 0x00, 0x06, 0xcc, 0x00, 0x08, 0xbc, 0xac, 0xab, 0xaa,
|
||||
0x08, 0xa9, 0x00, 0x10, 0xab, 0xa9, 0xaa, 0xba, 0xac, 0xaa, 0xac, 0xac,
|
||||
0x08, 0xcc, 0x02, 0xbc, 0x0e, 0xcc, 0x00, 0x0e, 0xca, 0xcd, 0xcc, 0xcc,
|
||||
0xac, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x02, 0x55, 0x02, 0x65, 0x06, 0x88,
|
||||
0x00, 0x0a, 0x78, 0x78, 0x68, 0x68, 0x85, 0x00, 0x08, 0x55, 0x02, 0x35,
|
||||
0x02, 0x34, 0x0c, 0x33, 0x02, 0x31, 0x08, 0x41, 0x06, 0x44, 0x00, 0x0a,
|
||||
0x43, 0x45, 0x77, 0xa9, 0x9b, 0x00, 0x06, 0xbb, 0x02, 0x9b, 0x08, 0x99,
|
||||
0x02, 0x97, 0x08, 0x99, 0x00, 0x24, 0x9b, 0xbb, 0xbb, 0xde, 0xbd, 0xed,
|
||||
0xec, 0xcd, 0xca, 0x99, 0x99, 0x77, 0x77, 0x79, 0x99, 0x77, 0x78, 0x9a,
|
||||
0x06, 0xaa, 0x00, 0x08, 0xcc, 0xcb, 0xcc, 0xcc, 0x06, 0xce, 0x02, 0xcc,
|
||||
0x02, 0xcb, 0x10, 0xcc, 0x02, 0xcb, 0x02, 0xac, 0x0c, 0xa9, 0x00, 0x10,
|
||||
0xaa, 0x9a, 0xaa, 0xa9, 0xc9, 0xcc, 0xbc, 0xac, 0x1a, 0xcc, 0x00, 0x0a,
|
||||
0xac, 0xac, 0xdc, 0xac, 0xac, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x34, 0x55,
|
||||
0x65, 0x86, 0x66, 0x68, 0x68, 0x00, 0x08, 0x88, 0x02, 0x85, 0x02, 0x55,
|
||||
0x0a, 0x33, 0x00, 0x0e, 0x31, 0x33, 0x33, 0x31, 0x41, 0x11, 0x11, 0x00,
|
||||
0x0a, 0x14, 0x00, 0x44, 0x44, 0x46, 0x88, 0x99, 0x9b, 0xab, 0xbb, 0x9b,
|
||||
0x9b, 0xbb, 0xb9, 0x9b, 0x99, 0x97, 0x77, 0x99, 0x99, 0x9b, 0x99, 0xbb,
|
||||
0x9b, 0xeb, 0xec, 0xee, 0xee, 0xbd, 0xba, 0x99, 0x77, 0x77, 0x66, 0x64,
|
||||
0x64, 0x44, 0x06, 0x66, 0x00, 0x12, 0x77, 0x77, 0xa9, 0xaa, 0xac, 0xcc,
|
||||
0xce, 0xcc, 0xec, 0x00, 0x08, 0xcc, 0x00, 0x14, 0xec, 0xec, 0xce, 0xce,
|
||||
0xcc, 0xcc, 0xca, 0xca, 0xab, 0xaa, 0x06, 0x9a, 0x00, 0x08, 0xba, 0xab,
|
||||
0xa9, 0xab, 0x08, 0xaa, 0x00, 0x06, 0xbc, 0xca, 0xcb, 0x00, 0x08, 0xcc,
|
||||
0x02, 0xac, 0x0a, 0xcc, 0x00, 0x0c, 0xdc, 0xac, 0xdc, 0xca, 0xda, 0xcc,
|
||||
0x00, 0x00, 0x00, 0x08, 0x34, 0x43, 0x56, 0x86, 0x08, 0x55, 0x06, 0x85,
|
||||
0x00, 0x12, 0x55, 0x33, 0x33, 0x31, 0x33, 0x33, 0x31, 0x13, 0x13, 0x00,
|
||||
0x0e, 0x11, 0x00, 0x1a, 0x14, 0x14, 0x41, 0x43, 0x44, 0x77, 0x99, 0x99,
|
||||
0x9b, 0x9b, 0xbb, 0xb9, 0xb9, 0x00, 0x08, 0x99, 0x00, 0x22, 0x97, 0x77,
|
||||
0x99, 0xbb, 0x9b, 0xbb, 0xee, 0xee, 0xeb, 0xde, 0xee, 0xeb, 0xa9, 0x77,
|
||||
0x77, 0x26, 0x22, 0x00, 0x06, 0x42, 0x00, 0x1a, 0x44, 0x46, 0x66, 0x67,
|
||||
0x67, 0x77, 0x78, 0x9a, 0xca, 0xce, 0xee, 0xec, 0xec, 0x00, 0x0a, 0xcc,
|
||||
0x00, 0x0e, 0xec, 0xcc, 0xce, 0xcc, 0xcb, 0xcb, 0xac, 0x00, 0x06, 0xa9,
|
||||
0x00, 0x26, 0xab, 0xa9, 0xa9, 0xaa, 0xaa, 0xa9, 0xaa, 0xab, 0xaa, 0xca,
|
||||
0xcb, 0xcc, 0xca, 0xca, 0xcc, 0xcc, 0xcb, 0xcc, 0xcc, 0x00, 0x08, 0xac,
|
||||
0x00, 0x0a, 0xcd, 0xac, 0xad, 0xac, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x10,
|
||||
0x14, 0x34, 0x58, 0x55, 0x54, 0x43, 0x33, 0x53, 0x06, 0x55, 0x00, 0x06,
|
||||
0x33, 0x33, 0x31, 0x00, 0x0a, 0x11, 0x08, 0x01, 0x0c, 0x11, 0x00, 0x1a,
|
||||
0x14, 0x14, 0x45, 0x68, 0x7a, 0x99, 0xbb, 0xbb, 0xb9, 0xbb, 0x9b, 0xb9,
|
||||
0xb9, 0x00, 0x0a, 0x99, 0x00, 0x38, 0x9b, 0xbb, 0xbb, 0xbe, 0xeb, 0xee,
|
||||
0xef, 0xee, 0xea, 0xb9, 0x77, 0x77, 0x62, 0x22, 0x14, 0x24, 0x44, 0x42,
|
||||
0x42, 0x66, 0x67, 0x77, 0x67, 0x77, 0x78, 0x9b, 0xcc, 0xcc, 0x06, 0xec,
|
||||
0x00, 0x0e, 0xcc, 0xbc, 0xec, 0xce, 0xcc, 0xec, 0xee, 0x00, 0x06, 0xcc,
|
||||
0x06, 0xab, 0x00, 0x28, 0xa9, 0xa9, 0xab, 0xab, 0xaa, 0xc9, 0xca, 0xa9,
|
||||
0xaa, 0xab, 0xaa, 0xca, 0xcb, 0xac, 0xcb, 0xca, 0xba, 0xcc, 0xac, 0xac,
|
||||
0x08, 0xcc, 0x00, 0x0a, 0xac, 0xad, 0xaa, 0xca, 0xca, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0a, 0x34, 0x14, 0x45, 0x65, 0x44, 0x00, 0x0a, 0x33, 0x00, 0x08,
|
||||
0x31, 0x31, 0x11, 0x10, 0x08, 0x11, 0x02, 0x01, 0x08, 0x11, 0x02, 0x01,
|
||||
0x06, 0x10, 0x06, 0x11, 0x00, 0x5e, 0x14, 0x34, 0x57, 0x99, 0x99, 0xab,
|
||||
0x9b, 0x9b, 0xbb, 0x9b, 0x99, 0x99, 0x9b, 0x9b, 0x99, 0x99, 0x77, 0x9e,
|
||||
0xb9, 0xbe, 0xee, 0xee, 0xce, 0xee, 0xed, 0xea, 0xb9, 0x97, 0x72, 0x62,
|
||||
0x22, 0x42, 0x24, 0x21, 0x44, 0x44, 0x62, 0x67, 0x66, 0x67, 0x77, 0x77,
|
||||
0x7a, 0xac, 0xcc, 0xce, 0xce, 0x00, 0x0a, 0xcc, 0x00, 0x2a, 0xce, 0xce,
|
||||
0xcc, 0xce, 0xcc, 0xcc, 0xab, 0xac, 0xaa, 0xab, 0xaa, 0xba, 0xaa, 0xca,
|
||||
0xba, 0xaa, 0x9a, 0xaa, 0x9a, 0xac, 0xbc, 0x00, 0x08, 0xac, 0x00, 0x0a,
|
||||
0xcc, 0xca, 0xcc, 0xbc, 0xca, 0x00, 0x06, 0xac, 0x00, 0x0a, 0xca, 0xca,
|
||||
0xcd, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x08, 0x41, 0x34, 0x55, 0x64,
|
||||
0x0e, 0x33, 0x00, 0x06, 0x30, 0x10, 0x10, 0x00, 0x06, 0x00, 0x00, 0x06,
|
||||
0x10, 0x11, 0x00, 0x00, 0x06, 0x10, 0x00, 0x08, 0x11, 0x00, 0x10, 0x11,
|
||||
0x06, 0x01, 0x00, 0x0a, 0x41, 0x44, 0x66, 0x79, 0x99, 0x00, 0x0a, 0xbb,
|
||||
0x02, 0x9b, 0x02, 0x9b, 0x08, 0x99, 0x00, 0x0a, 0x97, 0x9b, 0xbb, 0xbb,
|
||||
0xbe, 0x00, 0x06, 0xee, 0x00, 0x2a, 0xfe, 0xee, 0xb9, 0x77, 0x72, 0x22,
|
||||
0x22, 0x12, 0x24, 0x41, 0x44, 0x44, 0x46, 0x66, 0x66, 0x67, 0x67, 0x77,
|
||||
0x69, 0xaa, 0xbc, 0x00, 0x12, 0xcc, 0x00, 0x10, 0xec, 0xec, 0xcc, 0xcb,
|
||||
0xcc, 0xca, 0xba, 0xba, 0x08, 0xab, 0x00, 0x0a, 0xca, 0xba, 0xaa, 0x9a,
|
||||
0xaa, 0x00, 0x08, 0xac, 0x00, 0x08, 0xab, 0xac, 0xaa, 0xab, 0x06, 0xac,
|
||||
0x06, 0xca, 0x02, 0xac, 0x02, 0xac, 0x06, 0xaa, 0x00, 0x00, 0x00, 0x10,
|
||||
0x11, 0x44, 0x44, 0x43, 0x33, 0x31, 0x31, 0x33, 0x06, 0x31, 0x00, 0x08,
|
||||
0x10, 0x10, 0x00, 0x00, 0x06, 0x10, 0x02, 0x00, 0x08, 0x01, 0x00, 0x2a,
|
||||
0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x11, 0x11, 0x44, 0x47, 0x99, 0x9b,
|
||||
0x9b, 0xbb, 0xbb, 0xb9, 0xbb, 0x9b, 0x99, 0x99, 0x9b, 0x00, 0x08, 0xbb,
|
||||
0x00, 0x38, 0xeb, 0xeb, 0xbe, 0xee, 0xee, 0xef, 0xee, 0xee, 0xea, 0x97,
|
||||
0x62, 0x22, 0x21, 0x22, 0x41, 0x41, 0x44, 0x44, 0x46, 0x66, 0x77, 0x76,
|
||||
0x77, 0x76, 0x79, 0x99, 0xaa, 0xcb, 0x18, 0xcc, 0x00, 0x28, 0xab, 0xab,
|
||||
0xaa, 0xba, 0xba, 0xca, 0xcc, 0xcc, 0xac, 0xac, 0xab, 0xaa, 0xaa, 0xab,
|
||||
0xac, 0xab, 0xca, 0xba, 0xca, 0x9a, 0x0a, 0xaa, 0x00, 0x06, 0xac, 0xaa,
|
||||
0xca, 0x00, 0x06, 0xaa, 0x02, 0xa8, 0x00, 0x00, 0x00, 0x18, 0x14, 0x14,
|
||||
0x44, 0x33, 0x11, 0x13, 0x13, 0x11, 0x33, 0x33, 0x11, 0x01, 0x18, 0x00,
|
||||
0x02, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x01, 0x11, 0x14, 0x47, 0x77, 0x99,
|
||||
0x08, 0xbb, 0x00, 0x08, 0xb9, 0xbb, 0x9b, 0x9b, 0x08, 0xbb, 0x00, 0x08,
|
||||
0xeb, 0xeb, 0xee, 0xef, 0x06, 0xee, 0x00, 0x62, 0xef, 0xee, 0xec, 0x97,
|
||||
0x76, 0x22, 0x22, 0x21, 0x44, 0x41, 0x44, 0x44, 0x46, 0x66, 0x66, 0x67,
|
||||
0x77, 0x67, 0x77, 0x77, 0x79, 0x9a, 0xc9, 0xcb, 0xca, 0xbc, 0x9c, 0xaa,
|
||||
0x9a, 0xba, 0xcc, 0xcb, 0xcc, 0xca, 0xbc, 0xaa, 0x9a, 0xc9, 0xca, 0xbc,
|
||||
0xbc, 0xab, 0xcc, 0xbc, 0xac, 0xaa, 0xba, 0xbc, 0xab, 0x00, 0x06, 0xca,
|
||||
0x00, 0x0c, 0x9a, 0xaa, 0x89, 0xaa, 0x9a, 0x9a, 0x0c, 0xaa, 0x02, 0xa8,
|
||||
0x02, 0xaa, 0x00, 0x00, 0x00, 0x16, 0x14, 0x14, 0x41, 0x11, 0x11, 0x31,
|
||||
0x13, 0x03, 0x11, 0x11, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, 0x10, 0x00,
|
||||
0x10, 0x11, 0x11, 0x46, 0x79, 0x99, 0x06, 0xbb, 0x00, 0x14, 0xb9, 0xbb,
|
||||
0xbb, 0x99, 0xb9, 0xb9, 0xbb, 0xbb, 0xbe, 0xbe, 0x08, 0xee, 0x00, 0x28,
|
||||
0xde, 0xdd, 0xee, 0xed, 0xee, 0xa7, 0x72, 0x62, 0x22, 0x42, 0x44, 0x14,
|
||||
0x14, 0x44, 0x46, 0x46, 0x66, 0x77, 0x77, 0x67, 0x06, 0x77, 0x02, 0x67,
|
||||
0x0a, 0xaa, 0x00, 0x10, 0x8a, 0xaa, 0xaa, 0xab, 0xac, 0xac, 0xba, 0xca,
|
||||
0x06, 0x9a, 0x02, 0xab, 0x06, 0xcc, 0x00, 0x08, 0xca, 0xca, 0xba, 0xac,
|
||||
0x08, 0xaa, 0x00, 0x10, 0x9a, 0x9a, 0xa8, 0x87, 0x88, 0x88, 0x8a, 0xa8,
|
||||
0x0c, 0xaa, 0x02, 0x8a, 0x02, 0xa8, 0x00, 0x00, 0x02, 0x11, 0x02, 0x14,
|
||||
0x06, 0x11, 0x00, 0x0c, 0x03, 0x01, 0x11, 0x11, 0x01, 0x01, 0x1c, 0x00,
|
||||
0x02, 0x01, 0x06, 0x00, 0x00, 0x0c, 0x10, 0x01, 0x11, 0x46, 0x77, 0x99,
|
||||
0x0e, 0xbb, 0x02, 0xb9, 0x02, 0x9b, 0x06, 0xbb, 0x0a, 0xee, 0x00, 0x10,
|
||||
0xd8, 0x87, 0x59, 0xae, 0xea, 0xa7, 0x67, 0x66, 0x06, 0x44, 0x02, 0x41,
|
||||
0x06, 0x44, 0x00, 0x4c, 0x26, 0x26, 0x66, 0x76, 0x76, 0x77, 0x77, 0x67,
|
||||
0x77, 0x67, 0x77, 0x89, 0x78, 0x77, 0x76, 0x77, 0x8a, 0x9a, 0xaa, 0xba,
|
||||
0xca, 0xa9, 0xa7, 0x7a, 0x99, 0xab, 0xac, 0xca, 0xcb, 0xcc, 0xca, 0xaa,
|
||||
0xa9, 0xaa, 0x98, 0x9a, 0x89, 0x8a, 0x08, 0x88, 0x00, 0x16, 0x87, 0x88,
|
||||
0x78, 0xa7, 0xaa, 0xa8, 0xaa, 0x8a, 0xa8, 0xaa, 0x88, 0x00, 0x00, 0x00,
|
||||
0x06, 0x11, 0x08, 0x01, 0x00, 0x06, 0x00, 0x10, 0x01, 0x00, 0x28, 0x00,
|
||||
0x00, 0x0c, 0x11, 0x11, 0x44, 0x67, 0x99, 0x9b, 0x16, 0xbb, 0x08, 0xee,
|
||||
0x00, 0x12, 0xd9, 0x29, 0x82, 0x22, 0x58, 0xda, 0x97, 0x76, 0x66, 0x00,
|
||||
0x06, 0x44, 0x00, 0x0c, 0x41, 0x44, 0x44, 0x42, 0x62, 0x67, 0x08, 0x66,
|
||||
0x00, 0x06, 0x76, 0x77, 0x66, 0x00, 0x06, 0x77, 0x02, 0x67, 0x06, 0x66,
|
||||
0x00, 0x22, 0x67, 0x88, 0xa9, 0xaa, 0x9a, 0xa9, 0x87, 0x89, 0x8a, 0xaa,
|
||||
0xab, 0xab, 0xcc, 0xac, 0x9a, 0xaa, 0x9a, 0x00, 0x08, 0x88, 0x00, 0x0c,
|
||||
0x86, 0x88, 0x88, 0x68, 0x65, 0x85, 0x06, 0x88, 0x00, 0x0e, 0xaa, 0x7a,
|
||||
0xaa, 0x8a, 0x8a, 0x88, 0x88, 0x00, 0x00, 0x00, 0x02, 0x11, 0x06, 0x01,
|
||||
0x02, 0x10, 0x06, 0x01, 0x02, 0x00, 0x02, 0x10, 0x26, 0x00, 0x00, 0x0c,
|
||||
0x01, 0x00, 0x11, 0x14, 0x77, 0x99, 0x18, 0xbb, 0x00, 0x1e, 0xbe, 0xee,
|
||||
0xee, 0xed, 0x78, 0xad, 0xda, 0xd8, 0x22, 0x89, 0x86, 0x78, 0x66, 0x56,
|
||||
0x64, 0x00, 0x0a, 0x44, 0x00, 0x1c, 0x46, 0x66, 0x66, 0x77, 0x66, 0x66,
|
||||
0x67, 0x76, 0x67, 0x76, 0x67, 0x66, 0x66, 0x26, 0x06, 0x44, 0x00, 0x48,
|
||||
0x66, 0x87, 0x89, 0xaa, 0x98, 0x77, 0x67, 0x77, 0x99, 0xa9, 0xaa, 0xa9,
|
||||
0xaa, 0x8a, 0x98, 0x88, 0x88, 0x65, 0x68, 0x65, 0x68, 0x68, 0x56, 0x85,
|
||||
0x68, 0x66, 0x85, 0x68, 0x89, 0x8a, 0xaa, 0x8a, 0x8a, 0xa8, 0x88, 0x88,
|
||||
0x00, 0x00, 0x00, 0x0c, 0x01, 0x01, 0x10, 0x10, 0x00, 0x10, 0x2e, 0x00,
|
||||
0x00, 0x0c, 0x01, 0x01, 0x11, 0x14, 0x77, 0x99, 0x12, 0xbb, 0x00, 0x0e,
|
||||
0xbe, 0xee, 0xbe, 0xbe, 0xee, 0xee, 0xed, 0x00, 0x06, 0xdd, 0x00, 0x0a,
|
||||
0xd9, 0x22, 0x57, 0x87, 0x86, 0x00, 0x06, 0x66, 0x00, 0x1a, 0x64, 0x64,
|
||||
0x44, 0x46, 0x46, 0x66, 0x46, 0x76, 0x76, 0x66, 0x76, 0x77, 0x66, 0x00,
|
||||
0x06, 0x76, 0x02, 0x66, 0x02, 0x66, 0x08, 0x44, 0x00, 0x24, 0x66, 0x58,
|
||||
0x78, 0xa7, 0xa7, 0x76, 0x77, 0x77, 0x78, 0x78, 0xa7, 0xa8, 0x8a, 0x88,
|
||||
0x58, 0x86, 0x56, 0x55, 0x08, 0x65, 0x00, 0x16, 0x66, 0x65, 0x56, 0x55,
|
||||
0x56, 0x86, 0x88, 0xa7, 0xa7, 0xa8, 0xa8, 0x00, 0x06, 0x88, 0x00, 0x00,
|
||||
0x00, 0x10, 0x10, 0x11, 0x00, 0x10, 0x10, 0x00, 0x10, 0x01, 0x28, 0x00,
|
||||
0x00, 0x0e, 0x01, 0x00, 0x00, 0x01, 0x14, 0x67, 0x99, 0x00, 0x12, 0xbb,
|
||||
0x02, 0xbe, 0x0a, 0xee, 0x02, 0xd8, 0x08, 0xdd, 0x00, 0x18, 0x82, 0x26,
|
||||
0x86, 0x86, 0x66, 0x56, 0x65, 0x65, 0x46, 0x54, 0x64, 0x46, 0x08, 0x66,
|
||||
0x00, 0x36, 0x77, 0x66, 0x76, 0x77, 0x77, 0x66, 0x76, 0x62, 0x64, 0x42,
|
||||
0x41, 0x44, 0x44, 0x46, 0x66, 0x88, 0x78, 0x78, 0x77, 0x76, 0x78, 0x76,
|
||||
0x78, 0x68, 0x88, 0x86, 0x56, 0x00, 0x06, 0x65, 0x06, 0x45, 0x00, 0x0a,
|
||||
0x65, 0x56, 0x58, 0x55, 0x86, 0x00, 0x06, 0x56, 0x00, 0x08, 0x88, 0x7a,
|
||||
0x88, 0xa8, 0x06, 0x88, 0x02, 0x85, 0x00, 0x00, 0x06, 0x00, 0x02, 0x10,
|
||||
0x2e, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x14, 0x67, 0x99,
|
||||
0x10, 0xbb, 0x02, 0xbe, 0x0c, 0xee, 0x00, 0x24, 0xed, 0xdd, 0xdd, 0x8d,
|
||||
0xdd, 0x88, 0x25, 0x68, 0x68, 0x65, 0x66, 0x45, 0x66, 0x65, 0x65, 0x66,
|
||||
0x66, 0x86, 0x0a, 0x66, 0x02, 0x77, 0x0c, 0x66, 0x02, 0x24, 0x06, 0x44,
|
||||
0x00, 0x0c, 0x46, 0x66, 0x67, 0x78, 0x77, 0x76, 0x06, 0x67, 0x00, 0x06,
|
||||
0x66, 0x66, 0x46, 0x00, 0x06, 0x56, 0x00, 0x0a, 0x45, 0x64, 0x34, 0x54,
|
||||
0x54, 0x00, 0x06, 0x56, 0x0a, 0x65, 0x00, 0x10, 0x78, 0x68, 0x78, 0x78,
|
||||
0x88, 0x88, 0x85, 0x55, 0x00, 0x00, 0x06, 0x01, 0x06, 0x00, 0x02, 0x10,
|
||||
0x2e, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x14, 0x67, 0x99, 0x00, 0x10, 0xbb,
|
||||
0x00, 0x20, 0xee, 0xef, 0xee, 0xef, 0xee, 0xef, 0xee, 0xdd, 0xd8, 0xd2,
|
||||
0xd2, 0xdd, 0xd2, 0x54, 0x56, 0x66, 0x0a, 0x65, 0x00, 0x0a, 0x68, 0x58,
|
||||
0x55, 0x86, 0x86, 0x00, 0x06, 0x66, 0x00, 0x08, 0x77, 0x76, 0x66, 0x62,
|
||||
0x06, 0x66, 0x00, 0x52, 0x64, 0x44, 0x44, 0x14, 0x44, 0x44, 0x66, 0x86,
|
||||
0x86, 0x77, 0x67, 0x67, 0x76, 0x76, 0x56, 0x46, 0x54, 0x44, 0x46, 0x64,
|
||||
0x56, 0x54, 0x54, 0x34, 0x45, 0x46, 0x56, 0x56, 0x55, 0x65, 0x55, 0x55,
|
||||
0x68, 0x68, 0x78, 0x68, 0x88, 0x58, 0x85, 0x55, 0x55, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x02, 0x10, 0x2e, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x01, 0x14,
|
||||
0x67, 0x99, 0x0e, 0xbb, 0x02, 0xbe, 0x0c, 0xee, 0x02, 0xef, 0x02, 0xcd,
|
||||
0x06, 0xd8, 0x00, 0x06, 0xdd, 0xd2, 0x82, 0x00, 0x0a, 0x56, 0x00, 0x18,
|
||||
0x66, 0x56, 0x58, 0x58, 0xa8, 0x88, 0x85, 0x78, 0x77, 0x77, 0x76, 0x76,
|
||||
0x08, 0x66, 0x00, 0x06, 0x26, 0x62, 0x42, 0x00, 0x06, 0x44, 0x00, 0x06,
|
||||
0x46, 0x65, 0x76, 0x00, 0x06, 0x87, 0x00, 0x1e, 0x67, 0x66, 0x76, 0x64,
|
||||
0x64, 0x45, 0x45, 0x65, 0x46, 0x56, 0x45, 0x43, 0x45, 0x35, 0x45, 0x00,
|
||||
0x06, 0x56, 0x00, 0x18, 0x55, 0x46, 0x56, 0x86, 0x86, 0x88, 0x88, 0x68,
|
||||
0x68, 0x55, 0x55, 0x53, 0x00, 0x00, 0x02, 0x00, 0x02, 0x01, 0x38, 0x00,
|
||||
0x00, 0x0a, 0x01, 0x01, 0x14, 0x27, 0x99, 0x00, 0x0c, 0xbb, 0x02, 0xbe,
|
||||
0x02, 0xbe, 0x06, 0xee, 0x00, 0x22, 0xef, 0xef, 0xee, 0xef, 0xdd, 0xdd,
|
||||
0x2d, 0x28, 0xdf, 0xd2, 0x84, 0x36, 0x66, 0x56, 0x56, 0x66, 0x85, 0x00,
|
||||
0x06, 0x58, 0x00, 0x14, 0x8a, 0xa8, 0x8a, 0x8a, 0x88, 0x77, 0x86, 0x66,
|
||||
0x62, 0x62, 0x06, 0x66, 0x06, 0x44, 0x00, 0x38, 0x14, 0x44, 0x65, 0x65,
|
||||
0x66, 0x87, 0x77, 0x67, 0x66, 0x68, 0x66, 0x66, 0x54, 0x54, 0x44, 0x46,
|
||||
0x66, 0x46, 0x66, 0x54, 0x43, 0x44, 0x54, 0x45, 0x65, 0x55, 0x55, 0x65,
|
||||
0x06, 0x56, 0x00, 0x0e, 0x86, 0x86, 0x85, 0x55, 0x55, 0x53, 0x33, 0x00,
|
||||
0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x02, 0x10, 0x02, 0x01, 0x2c, 0x00,
|
||||
0x00, 0x0e, 0x10, 0x00, 0x01, 0x01, 0x14, 0x67, 0x79, 0x00, 0x0e, 0xbb,
|
||||
0x02, 0xbe, 0x0e, 0xee, 0x00, 0x20, 0xef, 0xdd, 0xd2, 0xd8, 0xdd, 0x82,
|
||||
0x82, 0x46, 0x55, 0x65, 0x68, 0x58, 0x65, 0x68, 0x55, 0x8a, 0x08, 0xaa,
|
||||
0x00, 0x36, 0xa8, 0x88, 0x79, 0x76, 0x66, 0x66, 0x62, 0x66, 0x62, 0x64,
|
||||
0x24, 0x44, 0x14, 0x44, 0x44, 0x66, 0x66, 0x87, 0x68, 0x77, 0x67, 0x66,
|
||||
0x66, 0x65, 0x46, 0x44, 0x46, 0x00, 0x06, 0x56, 0x06, 0x54, 0x00, 0x1c,
|
||||
0x34, 0x35, 0x55, 0x45, 0x56, 0x56, 0x55, 0x65, 0x65, 0x68, 0x66, 0x85,
|
||||
0x65, 0x55, 0x06, 0x33, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x10, 0x00,
|
||||
0x34, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x14, 0x67, 0x99, 0x0c, 0xbb,
|
||||
0x06, 0xee, 0x00, 0x30, 0xef, 0xef, 0xee, 0xef, 0xee, 0xee, 0xdd, 0xdd,
|
||||
0x28, 0x28, 0xdd, 0x8d, 0x82, 0x35, 0x56, 0x65, 0x66, 0x65, 0x68, 0x55,
|
||||
0x88, 0x88, 0x8a, 0xad, 0x06, 0xaa, 0x00, 0x5c, 0xca, 0xa8, 0x86, 0x66,
|
||||
0x62, 0x64, 0x66, 0x26, 0x44, 0x44, 0x41, 0x44, 0x44, 0x46, 0x45, 0x66,
|
||||
0x78, 0x76, 0x77, 0x66, 0x68, 0x66, 0x56, 0x66, 0x45, 0x45, 0x56, 0x66,
|
||||
0x56, 0x65, 0x65, 0x54, 0x34, 0x54, 0x44, 0x55, 0x45, 0x45, 0x56, 0x55,
|
||||
0x65, 0x55, 0x68, 0x56, 0x55, 0x55, 0x06, 0x33, 0x00, 0x00, 0x00, 0x08,
|
||||
0x01, 0x00, 0x00, 0x01, 0x2e, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x08,
|
||||
0x10, 0x44, 0x67, 0x79, 0x08, 0xbb, 0x0e, 0xee, 0x00, 0x36, 0xef, 0xfe,
|
||||
0xee, 0xec, 0xdf, 0xd2, 0x8d, 0xd8, 0xd2, 0xd8, 0x28, 0x23, 0x56, 0x56,
|
||||
0x65, 0x86, 0x86, 0x88, 0x58, 0x8a, 0xad, 0xaa, 0xac, 0xcd, 0xaa, 0xaa,
|
||||
0xa8, 0x00, 0x06, 0x66, 0x00, 0x26, 0x62, 0x62, 0x26, 0x42, 0x44, 0x41,
|
||||
0x41, 0x44, 0x44, 0x65, 0x66, 0x68, 0x67, 0x76, 0x68, 0x66, 0x56, 0x56,
|
||||
0x54, 0x00, 0x06, 0x56, 0x00, 0x24, 0x68, 0x66, 0x68, 0x65, 0x65, 0x56,
|
||||
0x54, 0x55, 0x56, 0x55, 0x55, 0x65, 0x65, 0x56, 0x56, 0x85, 0x55, 0x55,
|
||||
0x06, 0x33, 0x02, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x10, 0x30, 0x00,
|
||||
0x00, 0x0a, 0x01, 0x12, 0x67, 0x9b, 0x9b, 0x00, 0x08, 0xbb, 0x0c, 0xee,
|
||||
0x06, 0xfe, 0x00, 0x08, 0xed, 0xdd, 0x8d, 0x8d, 0x06, 0xdd, 0x00, 0x26,
|
||||
0xd2, 0x31, 0x58, 0x54, 0x66, 0x68, 0x86, 0x85, 0x88, 0x88, 0x8a, 0xac,
|
||||
0xad, 0xaa, 0xcc, 0xaa, 0x86, 0x66, 0x76, 0x00, 0x08, 0x66, 0x00, 0x18,
|
||||
0x24, 0x44, 0x41, 0x41, 0x44, 0x44, 0x46, 0x56, 0x67, 0x67, 0x66, 0x86,
|
||||
0x0a, 0x65, 0x00, 0x20, 0x66, 0x58, 0x66, 0x86, 0x85, 0x68, 0x56, 0x65,
|
||||
0x55, 0x56, 0x54, 0x54, 0x56, 0x54, 0x55, 0x56, 0x06, 0x55, 0x00, 0x0a,
|
||||
0x53, 0x33, 0x33, 0x13, 0x11, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
|
||||
0x01, 0x00, 0x2e, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x0c, 0x10, 0x10,
|
||||
0x14, 0x67, 0x99, 0x9b, 0x06, 0xbb, 0x02, 0xbe, 0x02, 0xee, 0x06, 0xfe,
|
||||
0x06, 0xef, 0x00, 0x38, 0xfe, 0xfe, 0xef, 0xfd, 0xdd, 0xdd, 0x8d, 0xdd,
|
||||
0xd8, 0x82, 0x33, 0x58, 0x32, 0x65, 0x56, 0x58, 0x58, 0x88, 0x8a, 0xad,
|
||||
0xaa, 0xaa, 0xac, 0xaa, 0xaa, 0x88, 0x87, 0x87, 0x06, 0x66, 0x00, 0x18,
|
||||
0x64, 0x64, 0x44, 0x14, 0x14, 0x44, 0x44, 0x64, 0x66, 0x68, 0x67, 0x87,
|
||||
0x06, 0x66, 0x06, 0x56, 0x00, 0x1e, 0x58, 0x66, 0x68, 0x68, 0x67, 0x68,
|
||||
0x65, 0x85, 0x56, 0x55, 0x54, 0x55, 0x65, 0x55, 0x54, 0x00, 0x08, 0x55,
|
||||
0x00, 0x0a, 0x33, 0x33, 0x13, 0x11, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00,
|
||||
0x02, 0x10, 0x2e, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x11, 0x27, 0x79,
|
||||
0x08, 0xbb, 0x02, 0xbe, 0x06, 0xee, 0x00, 0x10, 0xfe, 0xee, 0xee, 0xef,
|
||||
0xef, 0xfe, 0xfd, 0xd8, 0x08, 0xdd, 0x00, 0x18, 0xd8, 0xd8, 0x21, 0x38,
|
||||
0x84, 0x56, 0x56, 0x55, 0x58, 0x58, 0x88, 0x8a, 0x06, 0xaa, 0x00, 0x0c,
|
||||
0xac, 0xaa, 0x8a, 0x88, 0x86, 0x86, 0x06, 0x66, 0x00, 0x0e, 0x44, 0x44,
|
||||
0x41, 0x44, 0x14, 0x44, 0x44, 0x00, 0x0a, 0x66, 0x00, 0x06, 0x56, 0x55,
|
||||
0x45, 0x00, 0x06, 0x56, 0x00, 0x06, 0x65, 0x86, 0x87, 0x00, 0x06, 0x68,
|
||||
0x00, 0x06, 0x66, 0x65, 0x55, 0x00, 0x06, 0x45, 0x00, 0x10, 0x53, 0x65,
|
||||
0x54, 0x55, 0x55, 0x33, 0x33, 0x31, 0x06, 0x11, 0x00, 0x00, 0x3c, 0x00,
|
||||
0x06, 0x01, 0x00, 0x06, 0x47, 0x79, 0x9b, 0x00, 0x08, 0xbb, 0x00, 0x06,
|
||||
0xee, 0xee, 0xff, 0x00, 0x08, 0xee, 0x00, 0x3c, 0xff, 0xfe, 0xfd, 0xa8,
|
||||
0xdd, 0xdd, 0x2d, 0xdd, 0xdd, 0x2d, 0x23, 0x38, 0x85, 0x56, 0x55, 0x45,
|
||||
0x55, 0x85, 0x88, 0x88, 0xaa, 0xad, 0xaa, 0xca, 0xaa, 0xa8, 0x78, 0x87,
|
||||
0x66, 0x76, 0x06, 0x66, 0x00, 0x26, 0x44, 0x41, 0x41, 0x44, 0x44, 0x46,
|
||||
0x66, 0x68, 0x78, 0x68, 0x65, 0x65, 0x64, 0x64, 0x56, 0x55, 0x66, 0x56,
|
||||
0x86, 0x00, 0x06, 0x68, 0x00, 0x24, 0x58, 0x68, 0x55, 0x54, 0x53, 0x55,
|
||||
0x54, 0x55, 0x53, 0x43, 0x53, 0x43, 0x33, 0x31, 0x11, 0x11, 0x10, 0x10,
|
||||
0x00, 0x00, 0x3a, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x11, 0x27, 0x79,
|
||||
0x06, 0xbb, 0x06, 0xbe, 0x00, 0x46, 0xee, 0xee, 0xef, 0xee, 0xef, 0xee,
|
||||
0xfe, 0xff, 0xdd, 0x8d, 0xdd, 0xd8, 0xd8, 0xdd, 0xdd, 0x82, 0x82, 0x35,
|
||||
0x88, 0x62, 0x54, 0x53, 0x55, 0x55, 0x88, 0xad, 0xaa, 0xaa, 0xca, 0xaa,
|
||||
0xaa, 0x88, 0x88, 0x67, 0x86, 0x00, 0x06, 0x66, 0x00, 0x0e, 0x64, 0x44,
|
||||
0x44, 0x41, 0x41, 0x44, 0x44, 0x00, 0x08, 0x66, 0x02, 0x65, 0x02, 0x64,
|
||||
0x06, 0x55, 0x00, 0x0a, 0x56, 0x55, 0x56, 0x56, 0x85, 0x00, 0x06, 0x86,
|
||||
0x00, 0x18, 0x85, 0x64, 0x55, 0x55, 0x44, 0x35, 0x55, 0x45, 0x53, 0x43,
|
||||
0x33, 0x33, 0x06, 0x11, 0x02, 0x01, 0x02, 0x10, 0x00, 0x00, 0x36, 0x00,
|
||||
0x00, 0x12, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x46, 0x79, 0x9b, 0x00,
|
||||
0x06, 0xbb, 0x02, 0xbe, 0x06, 0xee, 0x00, 0x30, 0xfe, 0xee, 0xfe, 0xff,
|
||||
0xef, 0xef, 0xdd, 0x88, 0xdd, 0xdd, 0xd8, 0xdd, 0xd2, 0xd8, 0x88, 0x23,
|
||||
0x88, 0x54, 0x54, 0x45, 0x58, 0x58, 0xad, 0xad, 0x06, 0xaa, 0x00, 0x1a,
|
||||
0xad, 0xaa, 0x8a, 0x87, 0x88, 0x67, 0x86, 0x66, 0x66, 0x44, 0x44, 0x41,
|
||||
0x41, 0x00, 0x06, 0x44, 0x00, 0x0c, 0x66, 0x66, 0x86, 0x66, 0x56, 0x55,
|
||||
0x08, 0x54, 0x00, 0x30, 0x56, 0x55, 0x65, 0x56, 0x68, 0x68, 0x56, 0x56,
|
||||
0x55, 0x65, 0x44, 0x53, 0x54, 0x34, 0x53, 0x43, 0x33, 0x31, 0x31, 0x11,
|
||||
0x11, 0x10, 0x10, 0x00, 0x00, 0x00, 0x32, 0x00, 0x02, 0x01, 0x08, 0x00,
|
||||
0x00, 0x0c, 0x10, 0x00, 0x11, 0x42, 0x79, 0x9b, 0x06, 0xbb, 0x00, 0x48,
|
||||
0xbe, 0xee, 0xee, 0xfe, 0xfe, 0xff, 0xfe, 0xef, 0xef, 0xfe, 0xd8, 0xd8,
|
||||
0xdd, 0x2d, 0x8d, 0xdd, 0xdd, 0xd8, 0x2d, 0x33, 0x5a, 0x56, 0x45, 0x65,
|
||||
0x55, 0x58, 0xaa, 0xda, 0xaa, 0xca, 0xaa, 0xaa, 0x8a, 0x8a, 0xa8, 0x86,
|
||||
0x0a, 0x66, 0x06, 0x44, 0x00, 0x06, 0x41, 0x44, 0x46, 0x00, 0x06, 0x66,
|
||||
0x00, 0x14, 0x65, 0x64, 0x34, 0x54, 0x55, 0x55, 0x35, 0x54, 0x56, 0x55,
|
||||
0x06, 0x65, 0x00, 0x0e, 0x66, 0x55, 0x45, 0x53, 0x53, 0x54, 0x34, 0x00,
|
||||
0x06, 0x33, 0x02, 0x13, 0x06, 0x11, 0x06, 0x10, 0x02, 0x00, 0x00, 0x00,
|
||||
0x3e, 0x00, 0x00, 0x0a, 0x01, 0x11, 0x46, 0x79, 0x9b, 0x00, 0x06, 0xbb,
|
||||
0x00, 0x18, 0xee, 0xee, 0xef, 0xee, 0xef, 0xfe, 0xef, 0xef, 0xff, 0xee,
|
||||
0xda, 0x8d, 0x0c, 0xdd, 0x00, 0x1a, 0x2d, 0x82, 0x3a, 0x54, 0x26, 0x55,
|
||||
0x85, 0x88, 0xda, 0xcc, 0xcd, 0xaa, 0xad, 0x00, 0x06, 0xaa, 0x00, 0x06,
|
||||
0x88, 0x78, 0x78, 0x00, 0x08, 0x66, 0x00, 0x0e, 0x64, 0x44, 0x41, 0x41,
|
||||
0x44, 0x44, 0x66, 0x00, 0x06, 0x86, 0x00, 0x32, 0x54, 0x45, 0x43, 0x54,
|
||||
0x33, 0x54, 0x55, 0x55, 0x54, 0x53, 0x55, 0x56, 0x55, 0x56, 0x55, 0x54,
|
||||
0x54, 0x53, 0x43, 0x43, 0x41, 0x41, 0x31, 0x11, 0x11, 0x00, 0x06, 0x10,
|
||||
0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x0e, 0x10, 0x01,
|
||||
0x00, 0x10, 0x14, 0x46, 0x99, 0x00, 0x08, 0xbb, 0x02, 0xee, 0x02, 0xee,
|
||||
0x08, 0xef, 0x00, 0x10, 0xff, 0xfe, 0xef, 0xfd, 0xad, 0xdd, 0xdd, 0xd8,
|
||||
0x08, 0xdd, 0x00, 0x30, 0x82, 0xd3, 0x38, 0x85, 0x65, 0x65, 0x55, 0x88,
|
||||
0xad, 0xcf, 0xdc, 0xdc, 0xac, 0xda, 0xda, 0xaa, 0xa8, 0x88, 0x78, 0x78,
|
||||
0x77, 0x66, 0x66, 0x44, 0x06, 0x41, 0x02, 0x44, 0x02, 0x44, 0x08, 0x66,
|
||||
0x00, 0x14, 0x54, 0x53, 0x45, 0x43, 0x53, 0x33, 0x34, 0x33, 0x43, 0x34,
|
||||
0x08, 0x43, 0x00, 0x0e, 0x44, 0x43, 0x54, 0x53, 0x43, 0x41, 0x31, 0x00,
|
||||
0x06, 0x11, 0x00, 0x06, 0x10, 0x11, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x36, 0x00, 0x02, 0x10, 0x06, 0x00, 0x00, 0x08, 0x10, 0x14, 0x67, 0x99,
|
||||
0x08, 0xbb, 0x00, 0x06, 0xee, 0xee, 0xff, 0x00, 0x0c, 0xef, 0x00, 0x06,
|
||||
0xee, 0xd8, 0x8d, 0x00, 0x06, 0xdd, 0x00, 0x2c, 0xd8, 0xdd, 0xdd, 0x28,
|
||||
0xd8, 0x25, 0xa8, 0x62, 0x65, 0x58, 0x8a, 0xcc, 0xdc, 0xdc, 0xfc, 0xfc,
|
||||
0xdc, 0xda, 0xa8, 0x88, 0x78, 0x76, 0x08, 0x66, 0x06, 0x44, 0x00, 0x10,
|
||||
0x14, 0x44, 0x44, 0x66, 0x68, 0x68, 0x66, 0x54, 0x06, 0x53, 0x00, 0x0c,
|
||||
0x35, 0x34, 0x33, 0x34, 0x33, 0x43, 0x08, 0x34, 0x02, 0x33, 0x02, 0x34,
|
||||
0x06, 0x33, 0x06, 0x11, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3a, 0x00,
|
||||
0x00, 0x0c, 0x10, 0x10, 0x00, 0x14, 0x67, 0x9b, 0x08, 0xbb, 0x02, 0xee,
|
||||
0x0c, 0xef, 0x00, 0x0c, 0xfe, 0xfe, 0xed, 0xd8, 0xdd, 0xd8, 0x0a, 0xdd,
|
||||
0x00, 0x28, 0xd2, 0x8d, 0x33, 0x88, 0x45, 0x65, 0x58, 0xac, 0xdd, 0xcc,
|
||||
0xfc, 0xcd, 0xcc, 0xdc, 0xca, 0xaa, 0xa8, 0x88, 0x68, 0x76, 0x06, 0x66,
|
||||
0x00, 0x0c, 0x44, 0x44, 0x41, 0x44, 0x14, 0x44, 0x06, 0x66, 0x02, 0x65,
|
||||
0x02, 0x55, 0x08, 0x53, 0x00, 0x0a, 0x33, 0x34, 0x33, 0x34, 0x33, 0x00,
|
||||
0x12, 0x34, 0x00, 0x0c, 0x11, 0x11, 0x01, 0x11, 0x01, 0x01, 0x0a, 0x00,
|
||||
0x00, 0x00, 0x32, 0x00, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x08, 0x01, 0x14,
|
||||
0x47, 0x9b, 0x06, 0xbb, 0x00, 0x08, 0xbe, 0xee, 0xef, 0xef, 0x08, 0xff,
|
||||
0x00, 0x3e, 0xef, 0xee, 0xed, 0xa8, 0xdd, 0xd8, 0xdd, 0xdd, 0xd8, 0xdd,
|
||||
0xdd, 0xd2, 0x2d, 0x82, 0x88, 0x56, 0x65, 0x58, 0xac, 0xdc, 0xcf, 0xdc,
|
||||
0xfc, 0xdf, 0xcf, 0xcd, 0xca, 0xaa, 0xaa, 0xa7, 0x88, 0x00, 0x06, 0x66,
|
||||
0x02, 0x44, 0x02, 0x44, 0x06, 0x14, 0x00, 0x18, 0x44, 0x46, 0x56, 0x86,
|
||||
0x85, 0x65, 0x33, 0x53, 0x53, 0x33, 0x34, 0x33, 0x08, 0x43, 0x00, 0x0c,
|
||||
0x14, 0x14, 0x34, 0x14, 0x44, 0x14, 0x0a, 0x11, 0x02, 0x01, 0x02, 0x01,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x10, 0x06, 0x00, 0x00, 0x0e,
|
||||
0x10, 0x00, 0x00, 0x10, 0x04, 0x47, 0x9b, 0x00, 0x06, 0xbb, 0x06, 0xee,
|
||||
0x0a, 0xef, 0x00, 0x0c, 0xff, 0xff, 0xdd, 0xad, 0xdd, 0xd2, 0x0a, 0xdd,
|
||||
0x00, 0x5e, 0xd8, 0x28, 0xd2, 0x58, 0x62, 0x65, 0x88, 0xac, 0xfc, 0xcf,
|
||||
0xcc, 0xdc, 0xcc, 0xdd, 0xcd, 0xdc, 0xaa, 0xaa, 0x88, 0x86, 0x76, 0x66,
|
||||
0x46, 0x44, 0x44, 0x41, 0x44, 0x41, 0x44, 0x66, 0x86, 0x65, 0x86, 0x55,
|
||||
0x55, 0x53, 0x53, 0x43, 0x43, 0x34, 0x35, 0x35, 0x33, 0x33, 0x43, 0x34,
|
||||
0x43, 0x00, 0x08, 0x41, 0x06, 0x11, 0x02, 0x01, 0x02, 0x01, 0x0e, 0x00,
|
||||
0x00, 0x00, 0x3a, 0x00, 0x00, 0x12, 0x01, 0x00, 0x10, 0x14, 0x46, 0x9b,
|
||||
0xbb, 0xbb, 0xbe, 0x00, 0x06, 0xee, 0x0a, 0xff, 0x00, 0x08, 0xfe, 0xff,
|
||||
0xed, 0xad, 0x0c, 0xdd, 0x00, 0x16, 0x8d, 0xdd, 0x2d, 0xd2, 0x38, 0x84,
|
||||
0x66, 0x58, 0xac, 0xcf, 0xef, 0x00, 0x06, 0xcf, 0x00, 0x0e, 0xcc, 0xcd,
|
||||
0xac, 0xad, 0xa8, 0xa8, 0x77, 0x00, 0x06, 0x66, 0x00, 0x20, 0x44, 0x44,
|
||||
0x41, 0x41, 0x44, 0x44, 0x46, 0x66, 0x86, 0x86, 0x55, 0x53, 0x43, 0x34,
|
||||
0x34, 0x33, 0x06, 0x43, 0x00, 0x0e, 0x33, 0x34, 0x33, 0x43, 0x31, 0x41,
|
||||
0x41, 0x00, 0x06, 0x11, 0x00, 0x06, 0x10, 0x11, 0x01, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x36, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x18, 0x10, 0x14,
|
||||
0x67, 0x9b, 0xbb, 0xbb, 0xbe, 0xee, 0xee, 0xfe, 0xee, 0xfe, 0x06, 0xff,
|
||||
0x00, 0x0c, 0xef, 0xff, 0xda, 0xdd, 0xdd, 0x88, 0x06, 0xdd, 0x00, 0x34,
|
||||
0x8d, 0xdd, 0xdd, 0x28, 0xd8, 0x55, 0x86, 0x56, 0x88, 0xac, 0xfc, 0xdf,
|
||||
0xcf, 0xdc, 0xcc, 0xcf, 0xdd, 0xcd, 0xaa, 0x8a, 0x87, 0x88, 0x86, 0x66,
|
||||
0x66, 0x44, 0x08, 0x41, 0x00, 0x28, 0x34, 0x56, 0x86, 0x68, 0x68, 0x55,
|
||||
0x55, 0x53, 0x34, 0x13, 0x33, 0x43, 0x33, 0x43, 0x34, 0x34, 0x14, 0x41,
|
||||
0x44, 0x14, 0x0a, 0x11, 0x02, 0x10, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00,
|
||||
0x34, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x14, 0x67,
|
||||
0x9b, 0xbb, 0xbb, 0xeb, 0xee, 0xef, 0xef, 0x00, 0x06, 0xff, 0x00, 0x10,
|
||||
0xfe, 0xff, 0xff, 0xef, 0xea, 0xad, 0xdd, 0xad, 0x06, 0xdd, 0x00, 0x34,
|
||||
0x8d, 0x8d, 0xd7, 0x25, 0xdd, 0x25, 0x85, 0x66, 0x88, 0xcf, 0xcc, 0xfc,
|
||||
0xcd, 0xac, 0xcd, 0xfc, 0xcd, 0xcc, 0xaa, 0xaa, 0xa8, 0xa8, 0x76, 0x76,
|
||||
0x66, 0x44, 0x06, 0x41, 0x00, 0x28, 0x44, 0x44, 0x46, 0x56, 0x88, 0x58,
|
||||
0x65, 0x55, 0x34, 0x33, 0x43, 0x34, 0x33, 0x43, 0x33, 0x41, 0x41, 0x14,
|
||||
0x14, 0x41, 0x06, 0x11, 0x02, 0x01, 0x02, 0x01, 0x06, 0x10, 0x10, 0x00,
|
||||
0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x01, 0x67, 0x9b, 0xbb, 0xbb, 0xbe,
|
||||
0xee, 0xee, 0x06, 0xfe, 0x00, 0x10, 0xfd, 0xff, 0xff, 0xef, 0xfe, 0xdd,
|
||||
0xdd, 0xed, 0x0c, 0xdd, 0x00, 0x10, 0xda, 0x82, 0x28, 0x83, 0x86, 0x66,
|
||||
0x5a, 0xcd, 0x06, 0xcf, 0x02, 0xdc, 0x06, 0xcf, 0x00, 0x4e, 0xcd, 0xdc,
|
||||
0xca, 0xaa, 0x88, 0x77, 0x66, 0x66, 0x44, 0x44, 0x41, 0x44, 0x44, 0x34,
|
||||
0x45, 0x65, 0x85, 0x88, 0x55, 0x54, 0x54, 0x34, 0x33, 0x33, 0x34, 0x43,
|
||||
0x44, 0x44, 0x14, 0x11, 0x41, 0x11, 0x11, 0x01, 0x10, 0x11, 0x11, 0x01,
|
||||
0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x14, 0x10, 0x00,
|
||||
0x00, 0x10, 0x11, 0x44, 0x79, 0xbb, 0xbe, 0xbe, 0x06, 0xee, 0x0a, 0xff,
|
||||
0x00, 0x0c, 0xef, 0xef, 0xda, 0xdd, 0xdd, 0x8d, 0x06, 0xdd, 0x00, 0x36,
|
||||
0xd2, 0xd8, 0xfd, 0x92, 0x2d, 0x82, 0x58, 0x56, 0x88, 0xcc, 0xcc, 0xcf,
|
||||
0xcd, 0xcc, 0xfc, 0xdf, 0xcd, 0xcd, 0xca, 0xaa, 0x8a, 0xa7, 0x78, 0x76,
|
||||
0x64, 0x44, 0x44, 0x00, 0x06, 0x14, 0x00, 0x18, 0x44, 0x45, 0x65, 0x88,
|
||||
0x68, 0x55, 0x54, 0x33, 0x43, 0x34, 0x43, 0x44, 0x06, 0x41, 0x02, 0x14,
|
||||
0x0a, 0x11, 0x06, 0x10, 0x02, 0x01, 0x14, 0x00, 0x00, 0x00, 0x32, 0x00,
|
||||
0x02, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x10, 0x00, 0x01, 0x46, 0x7b, 0x00,
|
||||
0x06, 0xbb, 0x02, 0xee, 0x02, 0xee, 0x06, 0xef, 0x08, 0xff, 0x00, 0x06,
|
||||
0xfd, 0xaa, 0xdf, 0x00, 0x0c, 0xdd, 0x00, 0x36, 0xd8, 0xfd, 0xd2, 0x22,
|
||||
0xd5, 0x58, 0x86, 0x88, 0xcc, 0xcf, 0xfd, 0xcd, 0xcf, 0xdc, 0xfc, 0xdc,
|
||||
0xdc, 0xca, 0xaa, 0xaa, 0x78, 0x78, 0x66, 0x66, 0x44, 0x41, 0x41, 0x00,
|
||||
0x06, 0x44, 0x00, 0x14, 0x45, 0x56, 0x58, 0x58, 0x55, 0x45, 0x35, 0x43,
|
||||
0x43, 0x14, 0x0a, 0x41, 0x08, 0x11, 0x0a, 0x01, 0x14, 0x00, 0x00, 0x00,
|
||||
0x36, 0x00, 0x02, 0x10, 0x06, 0x00, 0x00, 0x0e, 0x01, 0x10, 0x14, 0x79,
|
||||
0x9b, 0xbb, 0xbb, 0x00, 0x06, 0xee, 0x0a, 0xff, 0x00, 0x0a, 0xef, 0xee,
|
||||
0xdd, 0xdd, 0xed, 0x00, 0x08, 0xdd, 0x00, 0x48, 0xd8, 0xd2, 0xfd, 0xa7,
|
||||
0x2d, 0x85, 0x28, 0x86, 0x7a, 0xcc, 0xed, 0xcd, 0xcd, 0xca, 0xdc, 0xfc,
|
||||
0xfc, 0xdc, 0xda, 0xaa, 0x8a, 0x78, 0x78, 0x66, 0x64, 0x44, 0x41, 0x44,
|
||||
0x14, 0x44, 0x34, 0x55, 0x55, 0x85, 0x86, 0x55, 0x08, 0x34, 0x00, 0x0e,
|
||||
0x44, 0x41, 0x41, 0x14, 0x11, 0x11, 0x01, 0x00, 0x06, 0x10, 0x00, 0x08,
|
||||
0x01, 0x00, 0x10, 0x10, 0x16, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x0a,
|
||||
0x10, 0x00, 0x01, 0x36, 0x69, 0x00, 0x06, 0xbb, 0x00, 0x1a, 0xeb, 0xee,
|
||||
0xef, 0xef, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xdd, 0x88, 0xdf, 0xfd, 0x00,
|
||||
0x0a, 0xdd, 0x00, 0x4e, 0xd8, 0xdf, 0xdd, 0x8d, 0x88, 0x28, 0x85, 0x8a,
|
||||
0xce, 0xcf, 0xdc, 0xad, 0xcd, 0xfc, 0xdf, 0xcf, 0xcd, 0xca, 0xaa, 0xaa,
|
||||
0xa8, 0x86, 0x66, 0x44, 0x44, 0x14, 0x13, 0x41, 0x34, 0x34, 0x45, 0x65,
|
||||
0x55, 0x85, 0x55, 0x43, 0x54, 0x34, 0x44, 0x00, 0x06, 0x14, 0x08, 0x11,
|
||||
0x02, 0x10, 0x02, 0x10, 0x06, 0x01, 0x1a, 0x00, 0x00, 0x00, 0x3e, 0x00,
|
||||
0x00, 0x14, 0x01, 0x01, 0x44, 0x79, 0x9b, 0xbb, 0xbb, 0xbe, 0xee, 0xee,
|
||||
0x06, 0xff, 0x00, 0x2a, 0xfe, 0xee, 0xee, 0xed, 0xa8, 0xdd, 0xfd, 0xdd,
|
||||
0xdd, 0xfd, 0xdd, 0xd8, 0xd2, 0xff, 0xfd, 0x2d, 0x2d, 0x25, 0x86, 0x7a,
|
||||
0xcc, 0x00, 0x06, 0xcd, 0x00, 0x38, 0xcc, 0xcc, 0xdc, 0xcd, 0xcd, 0xaa,
|
||||
0xaa, 0xa8, 0x88, 0x76, 0x66, 0x64, 0x44, 0x14, 0x44, 0x14, 0x44, 0x43,
|
||||
0x55, 0x55, 0x58, 0x55, 0x55, 0x35, 0x43, 0x34, 0x31, 0x44, 0x08, 0x11,
|
||||
0x00, 0x0a, 0x01, 0x11, 0x00, 0x10, 0x10, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x42, 0x00, 0x02, 0x14, 0x02, 0x89, 0x08, 0xbb, 0x00, 0x18, 0xee, 0xee,
|
||||
0xff, 0xff, 0xfe, 0xff, 0xfe, 0xee, 0xd8, 0xdd, 0x8d, 0xfd, 0x0c, 0xdd,
|
||||
0x00, 0x16, 0x8f, 0xfd, 0x2d, 0xd8, 0x54, 0x87, 0x88, 0xac, 0xac, 0xcc,
|
||||
0xdc, 0x00, 0x06, 0xcd, 0x00, 0x14, 0xfc, 0xdc, 0xcc, 0xaa, 0x8a, 0x86,
|
||||
0x66, 0x66, 0x44, 0x44, 0x06, 0x14, 0x00, 0x06, 0x44, 0x53, 0x45, 0x00,
|
||||
0x08, 0x55, 0x00, 0x0c, 0x44, 0x53, 0x44, 0x44, 0x11, 0x41, 0x08, 0x11,
|
||||
0x00, 0x06, 0x01, 0x01, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3a, 0x00,
|
||||
0x00, 0x2e, 0x01, 0x00, 0x10, 0x01, 0x46, 0x8b, 0xbb, 0xeb, 0xbb, 0xbe,
|
||||
0xee, 0xee, 0xef, 0xff, 0xff, 0xef, 0xee, 0xee, 0xd8, 0x88, 0x8f, 0xfd,
|
||||
0x2d, 0x00, 0x08, 0xdd, 0x00, 0x36, 0xd8, 0x8d, 0xfa, 0x2d, 0x28, 0x22,
|
||||
0xa8, 0x88, 0xcc, 0xec, 0xcc, 0xdc, 0xdd, 0xcd, 0xdc, 0xcc, 0xdc, 0xac,
|
||||
0xaa, 0xaa, 0x88, 0x66, 0x64, 0x44, 0x44, 0x14, 0x41, 0x00, 0x06, 0x43,
|
||||
0x06, 0x55, 0x00, 0x1a, 0x45, 0x54, 0x53, 0x34, 0x34, 0x14, 0x14, 0x11,
|
||||
0x11, 0x10, 0x11, 0x01, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, 0x40, 0x00,
|
||||
0x00, 0x06, 0x01, 0x14, 0x89, 0x00, 0x08, 0xbb, 0x00, 0x1a, 0xbe, 0xee,
|
||||
0xef, 0xff, 0xff, 0xee, 0xee, 0xed, 0xd8, 0x82, 0x2f, 0xfd, 0x8d, 0x00,
|
||||
0x0a, 0xdd, 0x00, 0x28, 0x8d, 0xff, 0x28, 0x82, 0x82, 0x8a, 0x79, 0xac,
|
||||
0xcc, 0xca, 0xca, 0xac, 0xda, 0xca, 0xaa, 0xac, 0xca, 0xaa, 0xa8, 0x76,
|
||||
0x06, 0x66, 0x00, 0x06, 0x44, 0x44, 0x14, 0x00, 0x06, 0x43, 0x00, 0x12,
|
||||
0x34, 0x55, 0x45, 0x55, 0x55, 0x35, 0x54, 0x41, 0x41, 0x00, 0x08, 0x11,
|
||||
0x02, 0x10, 0x02, 0x11, 0x26, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08,
|
||||
0x01, 0x13, 0x68, 0x9b, 0x06, 0xbb, 0x00, 0x1a, 0xbe, 0xee, 0xef, 0xff,
|
||||
0xfe, 0xee, 0xee, 0xed, 0x88, 0x82, 0x8f, 0xfd, 0x2d, 0x00, 0x08, 0xdd,
|
||||
0x00, 0x1a, 0xd2, 0xdd, 0xfd, 0x82, 0x82, 0xd2, 0x8a, 0xa8, 0xaa, 0xc8,
|
||||
0xaa, 0xcc, 0xca, 0x00, 0x06, 0xaa, 0x00, 0x20, 0xac, 0xac, 0xaa, 0x87,
|
||||
0x66, 0x67, 0x66, 0x66, 0x45, 0x44, 0x44, 0x14, 0x34, 0x34, 0x35, 0x53,
|
||||
0x06, 0x55, 0x00, 0x16, 0x35, 0x34, 0x14, 0x14, 0x11, 0x11, 0x10, 0x11,
|
||||
0x01, 0x00, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x0a,
|
||||
0x10, 0x01, 0x01, 0x47, 0x9b, 0x00, 0x08, 0xbb, 0x00, 0x18, 0xbe, 0xef,
|
||||
0xff, 0xfe, 0xee, 0xee, 0xdd, 0xd8, 0x22, 0x5d, 0xf8, 0x2d, 0x0a, 0xdd,
|
||||
0x00, 0x1a, 0x8d, 0xfd, 0xd2, 0x8a, 0x22, 0x8a, 0x9a, 0xaa, 0x9a, 0xaa,
|
||||
0xcc, 0xca, 0xad, 0x00, 0x06, 0xaa, 0x00, 0x08, 0xca, 0xa9, 0x77, 0x67,
|
||||
0x06, 0x66, 0x00, 0x10, 0x64, 0x44, 0x34, 0x34, 0x43, 0x43, 0x34, 0x45,
|
||||
0x08, 0x55, 0x02, 0x34, 0x02, 0x41, 0x08, 0x11, 0x00, 0x06, 0x10, 0x10,
|
||||
0x01, 0x00, 0x26, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x06, 0x01, 0x36,
|
||||
0x89, 0x00, 0x08, 0xbb, 0x0a, 0xee, 0x00, 0x0e, 0xed, 0xd8, 0x22, 0x32,
|
||||
0xdd, 0xf8, 0x28, 0x00, 0x0a, 0xdd, 0x00, 0x18, 0x2d, 0xfd, 0x82, 0x28,
|
||||
0x25, 0x2a, 0xa8, 0xaa, 0x88, 0xac, 0xcc, 0xca, 0x08, 0xaa, 0x00, 0x10,
|
||||
0xa9, 0x77, 0x77, 0x76, 0x66, 0x66, 0x64, 0x46, 0x06, 0x44, 0x00, 0x06,
|
||||
0x34, 0x43, 0x43, 0x00, 0x08, 0x55, 0x00, 0x14, 0x54, 0x44, 0x11, 0x11,
|
||||
0x01, 0x11, 0x01, 0x01, 0x00, 0x10, 0x26, 0x00, 0x00, 0x00, 0x40, 0x00,
|
||||
0x00, 0x08, 0x10, 0x01, 0x14, 0x79, 0x08, 0xbb, 0x00, 0x18, 0xbe, 0xbe,
|
||||
0xee, 0xee, 0xeb, 0xed, 0xd5, 0x21, 0x25, 0x2f, 0xd2, 0x2d, 0x0a, 0xdd,
|
||||
0x00, 0x20, 0x2d, 0xdd, 0x82, 0x28, 0x22, 0x27, 0xaa, 0x87, 0x77, 0xaa,
|
||||
0xcc, 0xca, 0xaa, 0x8a, 0xa8, 0x98, 0x06, 0x77, 0x00, 0x20, 0x67, 0x66,
|
||||
0x66, 0x64, 0x64, 0x44, 0x34, 0x33, 0x34, 0x43, 0x43, 0x55, 0x56, 0x58,
|
||||
0x55, 0x44, 0x08, 0x11, 0x08, 0x01, 0x28, 0x00, 0x00, 0x00, 0x3c, 0x00,
|
||||
0x00, 0x0e, 0x10, 0x00, 0x00, 0x01, 0x16, 0x6a, 0x9b, 0x00, 0x06, 0xbb,
|
||||
0x00, 0x18, 0xbe, 0xee, 0xee, 0xde, 0xbb, 0xdd, 0x82, 0x21, 0x25, 0x2d,
|
||||
0x52, 0x1d, 0x0a, 0xdd, 0x00, 0x30, 0x2d, 0xfd, 0x22, 0x12, 0x82, 0x15,
|
||||
0xa8, 0x76, 0x67, 0xaa, 0xaa, 0x88, 0x88, 0x86, 0x66, 0x66, 0x67, 0x77,
|
||||
0x77, 0x66, 0x26, 0x46, 0x44, 0x45, 0x06, 0x44, 0x00, 0x1e, 0x43, 0x34,
|
||||
0x36, 0x56, 0x58, 0x85, 0x55, 0x11, 0x11, 0x10, 0x11, 0x01, 0x01, 0x00,
|
||||
0x10, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x08, 0x01, 0x46,
|
||||
0x79, 0x9b, 0x08, 0xbb, 0x00, 0x16, 0xbe, 0xee, 0xbb, 0xbd, 0xd8, 0xd8,
|
||||
0x32, 0x55, 0x25, 0x21, 0x22, 0x00, 0x0a, 0xdd, 0x00, 0x06, 0xd2, 0x8d,
|
||||
0x52, 0x00, 0x06, 0x22, 0x00, 0x0c, 0x77, 0x76, 0x67, 0x8a, 0x87, 0x85,
|
||||
0x08, 0x66, 0x02, 0x67, 0x0a, 0x66, 0x00, 0x26, 0x46, 0x44, 0x46, 0x54,
|
||||
0x43, 0x35, 0x45, 0x65, 0x85, 0x88, 0x55, 0x54, 0x41, 0x11, 0x11, 0x10,
|
||||
0x10, 0x11, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x28,
|
||||
0x10, 0x10, 0x44, 0x79, 0xbb, 0xdb, 0xbb, 0x9b, 0xee, 0xec, 0xbe, 0x99,
|
||||
0xda, 0x82, 0x23, 0x22, 0x82, 0x21, 0x21, 0x11, 0x08, 0xdd, 0x00, 0x20,
|
||||
0xd8, 0xd2, 0x58, 0x82, 0x12, 0x82, 0x11, 0x66, 0x66, 0x67, 0x77, 0x88,
|
||||
0x66, 0x64, 0x64, 0x66, 0x06, 0x26, 0x02, 0x66, 0x02, 0x62, 0x06, 0x64,
|
||||
0x00, 0x1a, 0x45, 0x64, 0x44, 0x34, 0x55, 0x45, 0x58, 0x68, 0x85, 0x85,
|
||||
0x44, 0x10, 0x11, 0x00, 0x06, 0x01, 0x30, 0x00, 0x00, 0x00, 0x44, 0x00,
|
||||
0x00, 0x32, 0x16, 0x89, 0xab, 0xbb, 0xbb, 0xbe, 0xbb, 0xee, 0xbd, 0x99,
|
||||
0xa8, 0x53, 0x32, 0xdd, 0x52, 0x22, 0x11, 0x11, 0x18, 0xd8, 0x8d, 0xdd,
|
||||
0xdd, 0x83, 0x25, 0x00, 0x06, 0x22, 0x00, 0x16, 0x21, 0x26, 0x26, 0x77,
|
||||
0x89, 0x86, 0x66, 0x66, 0x26, 0x62, 0x64, 0x00, 0x06, 0x26, 0x06, 0x66,
|
||||
0x00, 0x1a, 0x64, 0x66, 0x65, 0x65, 0x44, 0x56, 0x68, 0x67, 0x88, 0x85,
|
||||
0x54, 0x11, 0x11, 0x00, 0x06, 0x10, 0x02, 0x01, 0x30, 0x00, 0x00, 0x00,
|
||||
0x3e, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x01, 0x13, 0x67, 0x9b, 0x06, 0xbb,
|
||||
0x00, 0x12, 0xbe, 0xbc, 0xb9, 0x99, 0x85, 0x22, 0x22, 0x52, 0x22, 0x00,
|
||||
0x06, 0x11, 0x00, 0x28, 0x01, 0x21, 0x11, 0x12, 0x12, 0x11, 0x23, 0x22,
|
||||
0x11, 0x21, 0x11, 0x12, 0x67, 0x67, 0x98, 0x78, 0x76, 0x62, 0x64, 0x22,
|
||||
0x06, 0x42, 0x00, 0x06, 0x66, 0x62, 0x76, 0x00, 0x06, 0x66, 0x00, 0x1c,
|
||||
0x56, 0x86, 0x56, 0x58, 0x87, 0x88, 0x85, 0x54, 0x44, 0x11, 0x10, 0x10,
|
||||
0x11, 0x01, 0x32, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x02, 0x10, 0x06, 0x00,
|
||||
0x00, 0x08, 0x12, 0x67, 0x9b, 0xbe, 0x06, 0xbb, 0x00, 0x3e, 0xed, 0xb9,
|
||||
0xd8, 0x52, 0x11, 0x12, 0x22, 0x12, 0x21, 0x11, 0x10, 0x12, 0x01, 0x01,
|
||||
0x11, 0x10, 0x11, 0x22, 0x22, 0x12, 0x12, 0x11, 0x24, 0x62, 0x67, 0x78,
|
||||
0x97, 0x76, 0x66, 0x62, 0x64, 0x00, 0x06, 0x42, 0x02, 0x62, 0x06, 0x66,
|
||||
0x02, 0x76, 0x06, 0x66, 0x00, 0x14, 0x68, 0x67, 0x86, 0x86, 0x55, 0x44,
|
||||
0x11, 0x11, 0x10, 0x10, 0x36, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x7a,
|
||||
0x01, 0x14, 0x66, 0x79, 0xbb, 0xbb, 0xbe, 0xbb, 0xdb, 0xbd, 0x95, 0x23,
|
||||
0x21, 0x22, 0x22, 0x12, 0x11, 0x12, 0x12, 0x11, 0x02, 0x01, 0x10, 0x11,
|
||||
0x10, 0x22, 0x11, 0x11, 0x01, 0x11, 0x42, 0x26, 0x67, 0x77, 0x88, 0x76,
|
||||
0x26, 0x26, 0x22, 0x24, 0x22, 0x24, 0x26, 0x66, 0x66, 0x67, 0x68, 0x68,
|
||||
0x78, 0x77, 0x87, 0x88, 0x88, 0x65, 0x44, 0x41, 0x11, 0x10, 0x10, 0x01,
|
||||
0x01, 0x00, 0x34, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x08, 0x10, 0x11,
|
||||
0x47, 0x9b, 0x06, 0xbb, 0x00, 0x20, 0xbe, 0xbb, 0xbd, 0x88, 0x11, 0x32,
|
||||
0x22, 0x21, 0x21, 0x11, 0x10, 0x11, 0x21, 0x21, 0x12, 0x12, 0x08, 0x11,
|
||||
0x00, 0x18, 0x01, 0x11, 0x11, 0x12, 0x66, 0x66, 0x67, 0x77, 0x77, 0x66,
|
||||
0x62, 0x44, 0x06, 0x24, 0x00, 0x24, 0x62, 0x66, 0x66, 0x67, 0x87, 0x66,
|
||||
0x68, 0x98, 0xa7, 0x87, 0x86, 0x54, 0x41, 0x11, 0x11, 0x01, 0x00, 0x01,
|
||||
0x36, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x0a, 0x14, 0x27, 0x99, 0xbb,
|
||||
0xbb, 0x00, 0x06, 0xeb, 0x00, 0x14, 0xaa, 0x28, 0x12, 0x32, 0x22, 0x21,
|
||||
0x21, 0x01, 0x01, 0x22, 0x06, 0x12, 0x00, 0x06, 0x11, 0x11, 0x10, 0x00,
|
||||
0x06, 0x11, 0x00, 0x22, 0x02, 0x11, 0x25, 0x66, 0x66, 0x76, 0x77, 0x77,
|
||||
0x66, 0x62, 0x62, 0x24, 0x24, 0x22, 0x26, 0x26, 0x67, 0x00, 0x0c, 0x78,
|
||||
0x00, 0x08, 0x88, 0x65, 0x43, 0x11, 0x0a, 0x10, 0x36, 0x00, 0x00, 0x00,
|
||||
0x42, 0x00, 0x00, 0x08, 0x10, 0x14, 0x67, 0x79, 0x06, 0xbb, 0x00, 0x18,
|
||||
0xbe, 0xbd, 0xba, 0x52, 0x33, 0x22, 0x22, 0x12, 0x12, 0x11, 0x01, 0x12,
|
||||
0x08, 0x22, 0x00, 0x46, 0x21, 0x00, 0x11, 0x11, 0x01, 0x11, 0x11, 0x46,
|
||||
0x76, 0x66, 0x66, 0x67, 0x77, 0x77, 0x66, 0x42, 0x44, 0x22, 0x42, 0x62,
|
||||
0x67, 0x77, 0x67, 0x76, 0x78, 0x68, 0x88, 0x88, 0x64, 0x43, 0x31, 0x01,
|
||||
0x01, 0x00, 0x10, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
|
||||
0x10, 0x00, 0x15, 0x67, 0x99, 0x9b, 0xbb, 0xbe, 0xbe, 0xbc, 0x9a, 0x25,
|
||||
0x12, 0x22, 0x12, 0x22, 0x21, 0x01, 0x11, 0x22, 0x22, 0x52, 0x22, 0x21,
|
||||
0x20, 0x11, 0x11, 0x01, 0x11, 0x21, 0x12, 0x46, 0x06, 0x66, 0x00, 0x2e,
|
||||
0x77, 0x66, 0x26, 0x66, 0x26, 0x22, 0x44, 0x26, 0x26, 0x66, 0x76, 0x78,
|
||||
0x88, 0x87, 0x77, 0x66, 0x64, 0x41, 0x11, 0x10, 0x11, 0x01, 0x01, 0x00,
|
||||
0x3c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x26, 0x01, 0x13, 0x27, 0x79,
|
||||
0xbb, 0xbe, 0xbb, 0xeb, 0xeb, 0xa8, 0x32, 0x12, 0x32, 0x22, 0x12, 0x11,
|
||||
0x11, 0x00, 0x13, 0x00, 0x08, 0x22, 0x02, 0x01, 0x02, 0x10, 0x08, 0x11,
|
||||
0x00, 0x2c, 0x14, 0x57, 0x88, 0x76, 0x77, 0x77, 0x67, 0x67, 0x62, 0x64,
|
||||
0x24, 0x22, 0x22, 0x66, 0x76, 0x77, 0x78, 0x77, 0x77, 0x66, 0x44, 0x41,
|
||||
0x06, 0x11, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x56, 0x14, 0x66,
|
||||
0x79, 0x9b, 0xbb, 0xeb, 0xee, 0xeb, 0xa8, 0x22, 0x32, 0x32, 0x22, 0x12,
|
||||
0x11, 0x10, 0x11, 0x21, 0x22, 0x52, 0x22, 0x11, 0x11, 0x10, 0x20, 0x11,
|
||||
0x12, 0x11, 0x15, 0x78, 0x77, 0x67, 0x68, 0x87, 0x86, 0x66, 0x76, 0x62,
|
||||
0x42, 0x42, 0x46, 0x62, 0x66, 0x00, 0x06, 0x77, 0x00, 0x10, 0x66, 0x64,
|
||||
0x11, 0x11, 0x01, 0x01, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00,
|
||||
0x00, 0x26, 0x01, 0x14, 0x66, 0x79, 0xbb, 0xeb, 0xbb, 0xee, 0xee, 0xda,
|
||||
0x32, 0x21, 0x22, 0x21, 0x11, 0x11, 0x01, 0x11, 0x01, 0x00, 0x06, 0x22,
|
||||
0x02, 0x11, 0x02, 0x10, 0x06, 0x11, 0x00, 0x08, 0x21, 0x11, 0x26, 0xa8,
|
||||
0x06, 0x87, 0x00, 0x20, 0x77, 0x77, 0x76, 0x66, 0x62, 0x42, 0x42, 0x26,
|
||||
0x26, 0x77, 0x66, 0x67, 0x64, 0x64, 0x44, 0x11, 0x06, 0x10, 0x02, 0x01,
|
||||
0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x24, 0x10, 0x01, 0x00, 0x00,
|
||||
0x11, 0x67, 0x99, 0x9b, 0xbb, 0xbe, 0xee, 0xfe, 0xca, 0x21, 0x21, 0x58,
|
||||
0xa2, 0x11, 0x06, 0x10, 0x06, 0x12, 0x08, 0x11, 0x00, 0x14, 0x12, 0x12,
|
||||
0x11, 0x12, 0x68, 0x88, 0x98, 0x78, 0x78, 0x77, 0x06, 0x66, 0x00, 0x0a,
|
||||
0x64, 0x24, 0x42, 0x46, 0x26, 0x00, 0x06, 0x66, 0x00, 0x08, 0x44, 0x41,
|
||||
0x11, 0x01, 0x4a, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x0a, 0x13, 0x26,
|
||||
0x79, 0xbb, 0xeb, 0x00, 0x06, 0xee, 0x00, 0x10, 0xca, 0x32, 0x21, 0xaf,
|
||||
0xd5, 0x21, 0x11, 0x10, 0x06, 0x11, 0x00, 0x44, 0x12, 0x12, 0x53, 0x32,
|
||||
0x11, 0x12, 0x12, 0x11, 0x32, 0x65, 0x77, 0x78, 0xa8, 0x77, 0x67, 0x67,
|
||||
0x77, 0x72, 0x24, 0x26, 0x22, 0x22, 0x76, 0x76, 0x66, 0x44, 0x41, 0x11,
|
||||
0x01, 0x01, 0x00, 0x01, 0x00, 0x10, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00,
|
||||
0x00, 0x2e, 0x11, 0x45, 0x79, 0xbe, 0xbb, 0xeb, 0xee, 0xee, 0xea, 0x32,
|
||||
0x55, 0xfd, 0xd5, 0x55, 0x51, 0x11, 0x18, 0x31, 0x02, 0x11, 0x13, 0x85,
|
||||
0x85, 0x00, 0x06, 0x21, 0x00, 0x28, 0x11, 0x24, 0x56, 0xaa, 0xca, 0x98,
|
||||
0x87, 0x87, 0x98, 0x97, 0x66, 0x64, 0x24, 0x24, 0x26, 0x62, 0x66, 0x26,
|
||||
0x44, 0x41, 0x06, 0x10, 0x02, 0x00, 0x02, 0x10, 0x46, 0x00, 0x00, 0x00,
|
||||
0x44, 0x00, 0x00, 0x68, 0x11, 0x27, 0x79, 0xbb, 0xbe, 0xbb, 0xee, 0xfe,
|
||||
0xea, 0x21, 0xd8, 0xcf, 0xd5, 0x25, 0x22, 0x12, 0x1d, 0x81, 0x21, 0x11,
|
||||
0x25, 0x58, 0x52, 0x11, 0x22, 0x11, 0x14, 0x25, 0x58, 0xaa, 0xcc, 0xca,
|
||||
0x88, 0x87, 0x89, 0x77, 0x77, 0x64, 0x24, 0x22, 0x22, 0x77, 0x76, 0x64,
|
||||
0x41, 0x01, 0x01, 0x00, 0x00, 0x10, 0x00, 0x10, 0x44, 0x00, 0x00, 0x00,
|
||||
0x44, 0x00, 0x00, 0x5c, 0x11, 0x46, 0x99, 0xbe, 0xdb, 0xbb, 0xee, 0xef,
|
||||
0xc8, 0x35, 0xfd, 0xdd, 0xd8, 0x12, 0x11, 0x11, 0x1d, 0xa1, 0x32, 0x82,
|
||||
0x32, 0x55, 0x21, 0x11, 0x11, 0x01, 0x22, 0x55, 0x58, 0x8a, 0xac, 0xac,
|
||||
0x99, 0xa9, 0xa9, 0x87, 0x76, 0x42, 0x22, 0x22, 0x67, 0x66, 0x26, 0x44,
|
||||
0x11, 0x01, 0x50, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x2c, 0x01, 0x12,
|
||||
0x68, 0x9b, 0xbb, 0xbe, 0xbe, 0xee, 0xda, 0x53, 0xfa, 0x8f, 0xd2, 0x12,
|
||||
0x11, 0x11, 0x1d, 0xd2, 0x55, 0x32, 0x22, 0x22, 0x06, 0x11, 0x00, 0x34,
|
||||
0x12, 0x55, 0x55, 0x58, 0xaa, 0xcc, 0xc9, 0xa8, 0x87, 0x77, 0x77, 0x66,
|
||||
0x66, 0x26, 0x26, 0x67, 0x26, 0x64, 0x24, 0x10, 0x10, 0x00, 0x01, 0x01,
|
||||
0x00, 0x10, 0x46, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x2e, 0x01, 0x11,
|
||||
0x46, 0x67, 0x9b, 0xeb, 0xeb, 0xbb, 0xee, 0xca, 0x55, 0xfa, 0x8d, 0xa5,
|
||||
0x21, 0x11, 0x11, 0x1f, 0xd3, 0x22, 0x12, 0x21, 0x01, 0x00, 0x06, 0x11,
|
||||
0x02, 0x25, 0x06, 0x55, 0x00, 0x20, 0x8a, 0xac, 0x9a, 0x77, 0x76, 0x77,
|
||||
0x77, 0x66, 0x76, 0x26, 0x27, 0x62, 0x66, 0x62, 0x44, 0x10, 0x52, 0x00,
|
||||
0x00, 0x00, 0x44, 0x00, 0x00, 0x26, 0x01, 0x34, 0x89, 0xa9, 0xbb, 0xbb,
|
||||
0xb9, 0xcf, 0xca, 0x53, 0xfd, 0x5d, 0x81, 0x21, 0x11, 0x11, 0x3d, 0xd3,
|
||||
0x22, 0x00, 0x0a, 0x11, 0x00, 0x2a, 0x35, 0x58, 0x55, 0x54, 0x26, 0x78,
|
||||
0x7a, 0x9a, 0x9a, 0xa9, 0x77, 0x77, 0x76, 0x42, 0x22, 0x62, 0x67, 0x66,
|
||||
0x24, 0x21, 0x11, 0x00, 0x52, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x28,
|
||||
0x01, 0x11, 0x44, 0x57, 0x9b, 0xbb, 0xbb, 0x9b, 0xbd, 0xed, 0xa5, 0xfd,
|
||||
0x38, 0x51, 0x11, 0x01, 0x11, 0x2d, 0xd1, 0x21, 0x08, 0x11, 0x02, 0x35,
|
||||
0x06, 0x55, 0x00, 0x22, 0x62, 0x66, 0x66, 0x77, 0x79, 0xa9, 0x99, 0x97,
|
||||
0x77, 0x24, 0x22, 0x66, 0x77, 0x67, 0x26, 0x64, 0x11, 0x00, 0x54, 0x00,
|
||||
0x00, 0x00, 0x44, 0x00, 0x00, 0x2e, 0x01, 0x14, 0x67, 0xa9, 0xbb, 0xbb,
|
||||
0x99, 0xcf, 0xcd, 0xa5, 0xff, 0xdd, 0x88, 0x1d, 0x3d, 0x31, 0x38, 0x82,
|
||||
0x22, 0x32, 0x32, 0x23, 0x25, 0x00, 0x06, 0x55, 0x02, 0x54, 0x06, 0x62,
|
||||
0x00, 0x1c, 0x22, 0x67, 0x79, 0x97, 0x77, 0x66, 0x42, 0x26, 0x78, 0x76,
|
||||
0x67, 0x64, 0x22, 0x11, 0x54, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x2e,
|
||||
0x10, 0x01, 0x01, 0x46, 0x7b, 0xcb, 0x99, 0x99, 0xcd, 0xcd, 0x88, 0xdd,
|
||||
0xfd, 0xdf, 0xdd, 0xad, 0x51, 0x23, 0x25, 0x55, 0x25, 0x25, 0x35, 0x00,
|
||||
0x08, 0x55, 0x00, 0x0c, 0x56, 0x27, 0x62, 0x62, 0x66, 0x67, 0x06, 0x77,
|
||||
0x00, 0x12, 0x62, 0x24, 0x66, 0x66, 0x76, 0x76, 0x64, 0x41, 0x10, 0x00,
|
||||
0x54, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x56, 0x11, 0x16, 0x99, 0xbb,
|
||||
0x99, 0x99, 0x9f, 0xcd, 0xa8, 0x8d, 0xdd, 0xdd, 0x8d, 0x8d, 0x31, 0x35,
|
||||
0x35, 0x55, 0x58, 0x55, 0x25, 0x55, 0x35, 0x55, 0x55, 0x42, 0x62, 0x66,
|
||||
0x66, 0x62, 0x26, 0x66, 0x77, 0x76, 0x24, 0x26, 0x66, 0x76, 0x66, 0x76,
|
||||
0x64, 0x21, 0x10, 0x00, 0x54, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x2a,
|
||||
0x01, 0x00, 0x00, 0x11, 0x46, 0x89, 0xcb, 0xb9, 0x99, 0xae, 0xda, 0xaa,
|
||||
0x83, 0x23, 0x58, 0x15, 0x85, 0x55, 0x85, 0x85, 0x58, 0x00, 0x06, 0x55,
|
||||
0x00, 0x2a, 0x33, 0x55, 0x55, 0x32, 0x22, 0x27, 0x67, 0x62, 0x22, 0x62,
|
||||
0x67, 0x77, 0x24, 0x24, 0x26, 0x67, 0x87, 0x87, 0x66, 0x42, 0x11, 0x00,
|
||||
0x56, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x56,
|
||||
0x01, 0x11, 0x13, 0x69, 0xbb, 0xb9, 0x99, 0xcc, 0xfd, 0xdd, 0xd8, 0x13,
|
||||
0x23, 0x38, 0xd8, 0x85, 0x55, 0x83, 0x85, 0xa8, 0x88, 0x55, 0x35, 0x53,
|
||||
0x33, 0x44, 0x27, 0x77, 0x77, 0x76, 0x77, 0x26, 0x27, 0x76, 0x62, 0x62,
|
||||
0x64, 0x66, 0x77, 0x77, 0x66, 0x21, 0x11, 0x00, 0x56, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x00, 0x5a, 0x10, 0x10, 0x11, 0x01, 0x14, 0x68, 0x9c, 0xb9,
|
||||
0x99, 0xdf, 0xec, 0xda, 0x88, 0x11, 0x21, 0x8d, 0x8a, 0x8a, 0x88, 0xa8,
|
||||
0xaa, 0xd8, 0xa5, 0x35, 0x33, 0x33, 0x22, 0x22, 0x27, 0x77, 0x77, 0x27,
|
||||
0x26, 0x26, 0x67, 0x62, 0x62, 0x24, 0x26, 0x67, 0x87, 0x66, 0x65, 0x41,
|
||||
0x10, 0x00, 0x56, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x42, 0x11, 0x34,
|
||||
0x57, 0x9b, 0xbb, 0x99, 0xef, 0xfd, 0xdd, 0x53, 0x11, 0x11, 0x33, 0x88,
|
||||
0x88, 0xa8, 0x5a, 0x8a, 0xd8, 0xaa, 0x83, 0x32, 0x12, 0x11, 0x22, 0x72,
|
||||
0x72, 0x77, 0x77, 0x66, 0x26, 0x26, 0x42, 0x00, 0x08, 0x66, 0x00, 0x08,
|
||||
0x77, 0x66, 0x54, 0x11, 0x58, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x16,
|
||||
0x01, 0x11, 0x11, 0x44, 0x78, 0x99, 0x77, 0xdf, 0xdd, 0xd5, 0x31, 0x00,
|
||||
0x06, 0x11, 0x00, 0x38, 0x8d, 0xda, 0xda, 0xad, 0xda, 0xda, 0xa8, 0x33,
|
||||
0x21, 0x31, 0x12, 0x27, 0x77, 0x77, 0x76, 0x72, 0x76, 0x22, 0x22, 0x26,
|
||||
0x24, 0x64, 0x66, 0x67, 0x88, 0x68, 0x64, 0x11, 0x08, 0x00, 0x02, 0xf0,
|
||||
0x4e, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1a, 0x11, 0x12, 0x77, 0xb9,
|
||||
0x97, 0xdf, 0xff, 0xd1, 0x11, 0x12, 0x10, 0x10, 0x33, 0x00, 0x06, 0xad,
|
||||
0x00, 0x30, 0xcf, 0xdd, 0xd8, 0x83, 0x11, 0x13, 0x22, 0x77, 0x27, 0x72,
|
||||
0x77, 0x77, 0x62, 0x42, 0x22, 0x67, 0x76, 0x64, 0x66, 0x77, 0x87, 0x76,
|
||||
0x64, 0x11, 0x08, 0x00, 0x02, 0xff, 0x4e, 0x00, 0x00, 0x00, 0x44, 0x00,
|
||||
0x00, 0x22, 0x11, 0x01, 0x01, 0x14, 0x46, 0x89, 0x97, 0xdf, 0xfd, 0x33,
|
||||
0x11, 0x12, 0x01, 0x11, 0x10, 0x5d, 0xdc, 0x00, 0x06, 0xdd, 0x00, 0x0e,
|
||||
0xaa, 0x33, 0x11, 0x12, 0x22, 0x77, 0x77, 0x00, 0x08, 0x72, 0x00, 0x16,
|
||||
0x22, 0x26, 0x76, 0x66, 0x62, 0x66, 0x77, 0x77, 0x76, 0x41, 0x10, 0x00,
|
||||
0x08, 0x00, 0x02, 0xff, 0x02, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00,
|
||||
0x00, 0x50, 0x01, 0x11, 0x34, 0x67, 0x99, 0x7d, 0xff, 0xd1, 0x11, 0x13,
|
||||
0x10, 0x10, 0x11, 0x03, 0xfd, 0xfc, 0xfd, 0x8a, 0x88, 0x52, 0x11, 0x22,
|
||||
0x77, 0x77, 0x72, 0x77, 0x72, 0x77, 0x22, 0x22, 0x66, 0x76, 0x76, 0x66,
|
||||
0x67, 0x77, 0x87, 0x65, 0x41, 0x11, 0x08, 0x00, 0x02, 0x1f, 0x02, 0xf0,
|
||||
0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x2e, 0x10, 0x11, 0x46, 0x9a,
|
||||
0xb9, 0x77, 0xff, 0x51, 0x11, 0x33, 0x10, 0x11, 0x10, 0x01, 0xdd, 0xff,
|
||||
0xfd, 0xcd, 0x85, 0x35, 0x32, 0x67, 0x97, 0x00, 0x08, 0x77, 0x00, 0x0a,
|
||||
0x72, 0x72, 0x62, 0x77, 0x76, 0x00, 0x0a, 0x66, 0x02, 0x54, 0x02, 0x31,
|
||||
0x0a, 0x00, 0x02, 0x0f, 0x02, 0xf1, 0x4c, 0x00, 0x00, 0x00, 0x4a, 0x00,
|
||||
0x00, 0x4e, 0x11, 0x56, 0x8b, 0xdb, 0x77, 0x9d, 0x51, 0x13, 0x35, 0x30,
|
||||
0x11, 0x11, 0x05, 0xcd, 0xed, 0xff, 0xda, 0x55, 0x24, 0x26, 0x67, 0x77,
|
||||
0x77, 0x72, 0x77, 0x27, 0x77, 0x22, 0x26, 0x77, 0x76, 0x76, 0x66, 0x66,
|
||||
0x78, 0x88, 0x53, 0x01, 0x10, 0x00, 0x08, 0x00, 0x02, 0x0f, 0x02, 0xff,
|
||||
0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x4e, 0x01, 0x33, 0x5a, 0xbc,
|
||||
0xbb, 0x99, 0x77, 0x25, 0x3d, 0xdd, 0x50, 0x11, 0x11, 0x1a, 0xa8, 0x88,
|
||||
0xaa, 0x88, 0x42, 0x62, 0x22, 0x27, 0x22, 0x62, 0x72, 0x72, 0x77, 0x22,
|
||||
0x26, 0x77, 0x77, 0x86, 0x66, 0x77, 0x77, 0x78, 0x8a, 0x85, 0x31, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x06, 0x08, 0xff, 0xd0, 0x00, 0x4a, 0x00, 0x00, 0x00,
|
||||
0x4a, 0x00, 0x00, 0x22, 0x38, 0xac, 0xce, 0xcc, 0x97, 0x77, 0x75, 0x33,
|
||||
0x33, 0x53, 0x11, 0x05, 0xaa, 0xd8, 0x85, 0x66, 0x27, 0x00, 0x06, 0x26,
|
||||
0x00, 0x0a, 0x22, 0x62, 0x22, 0x22, 0x72, 0x00, 0x06, 0x22, 0x0c, 0x77,
|
||||
0x00, 0x0c, 0x7a, 0x88, 0xaa, 0x88, 0x33, 0x10, 0x06, 0x00, 0x00, 0x06,
|
||||
0x01, 0xff, 0xf1, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x32,
|
||||
0x03, 0x5a, 0xcc, 0xec, 0xbc, 0xb9, 0x97, 0x97, 0x23, 0x11, 0x11, 0x13,
|
||||
0x59, 0xda, 0x97, 0x66, 0x77, 0x27, 0x27, 0x77, 0x27, 0x22, 0x72, 0x22,
|
||||
0x27, 0x00, 0x06, 0x72, 0x02, 0x26, 0x06, 0x77, 0x00, 0x14, 0x78, 0x77,
|
||||
0x77, 0x88, 0xa8, 0xa8, 0x85, 0x53, 0x30, 0x01, 0x06, 0x00, 0x02, 0xff,
|
||||
0x02, 0xff, 0x4a, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x52, 0x01, 0x38,
|
||||
0xac, 0xcc, 0xec, 0xe9, 0x99, 0x99, 0x77, 0x27, 0x27, 0x77, 0x77, 0x79,
|
||||
0x97, 0x77, 0x72, 0x72, 0x27, 0x72, 0x77, 0x72, 0x26, 0x26, 0x27, 0x77,
|
||||
0x72, 0x62, 0x77, 0x78, 0x77, 0x77, 0x87, 0x77, 0x78, 0x8a, 0x8a, 0x88,
|
||||
0x8a, 0xa8, 0x33, 0x00, 0x08, 0x00, 0x00, 0x06, 0xff, 0xff, 0x80, 0x00,
|
||||
0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x24, 0x03, 0x5a, 0xac, 0xee,
|
||||
0xee, 0x9b, 0xb9, 0xd9, 0x97, 0x79, 0x77, 0x77, 0x79, 0x79, 0x77, 0x97,
|
||||
0x77, 0x72, 0x06, 0x77, 0x00, 0x0e, 0x27, 0x26, 0x27, 0x22, 0x77, 0x27,
|
||||
0x72, 0x00, 0x06, 0x77, 0x00, 0x14, 0x78, 0x98, 0x77, 0xa7, 0x8a, 0x8a,
|
||||
0x88, 0x85, 0x55, 0x53, 0x08, 0x00, 0x00, 0x06, 0xaf, 0xff, 0xf0, 0x00,
|
||||
0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x54, 0x01, 0x5a, 0xce, 0xfe,
|
||||
0xee, 0xee, 0xbb, 0xb9, 0x99, 0x99, 0x97, 0x77, 0x77, 0x97, 0x79, 0x77,
|
||||
0x77, 0x27, 0x22, 0x77, 0x79, 0x77, 0x77, 0x72, 0x76, 0x22, 0x62, 0x77,
|
||||
0x77, 0x79, 0x97, 0x98, 0x99, 0xa7, 0x87, 0xa8, 0x88, 0xa8, 0x58, 0x85,
|
||||
0x53, 0x10, 0x06, 0x00, 0x00, 0x06, 0x1f, 0xff, 0xff, 0x00, 0x48, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x16, 0x13, 0x8c, 0xce, 0xce, 0xee, 0xbb,
|
||||
0xbe, 0xbb, 0xd9, 0x99, 0x79, 0x00, 0x06, 0x77, 0x02, 0x97, 0x06, 0x77,
|
||||
0x00, 0x30, 0x27, 0x77, 0x79, 0x99, 0x89, 0x87, 0x76, 0x27, 0x77, 0x77,
|
||||
0x79, 0x99, 0xa9, 0xab, 0xaa, 0x9a, 0x7a, 0x88, 0x8a, 0x85, 0x53, 0x55,
|
||||
0x83, 0x30, 0x06, 0x00, 0x00, 0x08, 0x0f, 0xff, 0xff, 0x50, 0x46, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x20, 0x03, 0x8c, 0xcf, 0xee, 0xee, 0xeb,
|
||||
0xeb, 0xbe, 0xb9, 0x97, 0x99, 0x77, 0x79, 0x99, 0x77, 0x97, 0x08, 0x77,
|
||||
0x00, 0x08, 0x99, 0x97, 0x77, 0x79, 0x06, 0x77, 0x00, 0x2c, 0x97, 0x99,
|
||||
0x9a, 0x9b, 0xcb, 0xcb, 0xaa, 0x98, 0x8a, 0x88, 0x8a, 0x58, 0x55, 0x55,
|
||||
0x31, 0x01, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x46, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x00, 0x18, 0x08, 0xcc, 0xfe, 0xee, 0xee, 0xbe, 0xee, 0xee,
|
||||
0xbb, 0xa9, 0x99, 0x79, 0x06, 0x97, 0x00, 0x0e, 0x77, 0x79, 0x79, 0x77,
|
||||
0x97, 0x99, 0x97, 0x00, 0x08, 0x77, 0x00, 0x20, 0x79, 0x79, 0x99, 0x99,
|
||||
0xba, 0xbe, 0xbe, 0xbb, 0x89, 0xaa, 0x8a, 0x8a, 0x88, 0x58, 0x55, 0x33,
|
||||
0x06, 0x00, 0x00, 0x08, 0x08, 0xff, 0xff, 0xfd, 0x46, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x00, 0x2a, 0x38, 0xac, 0xce, 0xee, 0xee, 0xbe, 0xbe, 0xeb,
|
||||
0xd9, 0x99, 0x79, 0x99, 0x79, 0x77, 0x97, 0x97, 0x79, 0x77, 0x77, 0x79,
|
||||
0x79, 0x00, 0x0a, 0x77, 0x00, 0x20, 0x79, 0x97, 0x99, 0x9a, 0xbb, 0xeb,
|
||||
0xee, 0xcc, 0xba, 0xaa, 0xa8, 0xa8, 0x88, 0x88, 0x53, 0x31, 0x06, 0x00,
|
||||
0x02, 0x03, 0x06, 0xff, 0x02, 0x30, 0x44, 0x00, 0x00, 0x00, 0x46, 0x00,
|
||||
0x00, 0x08, 0x01, 0x35, 0xaa, 0xce, 0x0a, 0xee, 0x02, 0xba, 0x08, 0x99,
|
||||
0x00, 0x10, 0x77, 0x79, 0x77, 0x97, 0x77, 0x97, 0x79, 0x97, 0x0c, 0x77,
|
||||
0x06, 0x79, 0x00, 0x1a, 0x9b, 0xee, 0xee, 0xbe, 0xca, 0x9c, 0xaa, 0xa8,
|
||||
0x85, 0x85, 0x33, 0x00, 0x10, 0x00, 0x06, 0x00, 0x06, 0xff, 0x02, 0xf0,
|
||||
0x44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x18, 0x03, 0x8c, 0xee, 0xee,
|
||||
0xeb, 0xeb, 0xee, 0xbe, 0x99, 0x99, 0x97, 0x97, 0x06, 0x77, 0x00, 0x06,
|
||||
0x99, 0x77, 0x97, 0x00, 0x08, 0x77, 0x00, 0x0a, 0x27, 0x77, 0x72, 0x77,
|
||||
0x77, 0x00, 0x06, 0x79, 0x00, 0x18, 0x9a, 0xbb, 0xbe, 0xee, 0xbb, 0xca,
|
||||
0xca, 0xaa, 0xa8, 0x55, 0x31, 0x10, 0x08, 0x00, 0x06, 0xff, 0x02, 0xfd,
|
||||
0x44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x18, 0x03, 0xac, 0xce, 0xee,
|
||||
0xbe, 0xee, 0xee, 0xba, 0x9b, 0x99, 0x77, 0x72, 0x12, 0x77, 0x00, 0x06,
|
||||
0x26, 0x26, 0x72, 0x00, 0x0c, 0x77, 0x00, 0x16, 0x99, 0xbd, 0xee, 0xee,
|
||||
0xec, 0xc9, 0xaa, 0xaa, 0x88, 0x35, 0x31, 0x00, 0x0a, 0x00, 0x02, 0xdf,
|
||||
0x06, 0xff, 0x02, 0x10, 0x42, 0x00, 0x00, 0x00, 0x48, 0x00, 0x02, 0x03,
|
||||
0x02, 0x8c, 0x08, 0xee, 0x00, 0x28, 0xbc, 0xbb, 0xbb, 0x99, 0x77, 0x77,
|
||||
0x72, 0x62, 0x62, 0x26, 0x66, 0x67, 0x77, 0x76, 0x62, 0x21, 0x22, 0x66,
|
||||
0x67, 0x26, 0x06, 0x22, 0x00, 0x1c, 0x79, 0x99, 0x9b, 0xbe, 0xee, 0xeb,
|
||||
0xcb, 0xca, 0xaa, 0xaa, 0x85, 0x53, 0x00, 0x01, 0x06, 0x00, 0x02, 0x3f,
|
||||
0x06, 0xff, 0x02, 0xf0, 0x42, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1a,
|
||||
0x03, 0xac, 0xee, 0xee, 0xbe, 0xeb, 0xbe, 0xbd, 0xbb, 0x99, 0x77, 0x76,
|
||||
0x25, 0x00, 0x10, 0x22, 0x02, 0x11, 0x02, 0x12, 0x0a, 0x22, 0x00, 0x1e,
|
||||
0x25, 0x77, 0x99, 0x9b, 0xdb, 0xee, 0xee, 0xcc, 0xca, 0xaa, 0xaa, 0x55,
|
||||
0x30, 0x00, 0x10, 0x00, 0x06, 0x00, 0x02, 0x0f, 0x06, 0xff, 0x02, 0xfd,
|
||||
0x42, 0x00, 0x00, 0x00, 0x48, 0x00, 0x02, 0x03, 0x02, 0xce, 0x06, 0xee,
|
||||
0x00, 0x12, 0xba, 0x9a, 0xbb, 0xbb, 0x99, 0x77, 0x68, 0x22, 0x21, 0x00,
|
||||
0x0a, 0x11, 0x00, 0x2e, 0x21, 0x10, 0x10, 0x01, 0x12, 0x22, 0x11, 0x21,
|
||||
0x11, 0x11, 0x27, 0x89, 0x99, 0xbb, 0xee, 0xee, 0xec, 0xcc, 0xca, 0xad,
|
||||
0x88, 0x31, 0x10, 0x00, 0x08, 0x00, 0x02, 0x0f, 0x08, 0xff, 0x42, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x26, 0x18, 0xae, 0xee, 0xee, 0xeb, 0xc9,
|
||||
0x9b, 0xb9, 0x99, 0x98, 0x88, 0x23, 0x33, 0x11, 0x11, 0x10, 0x10, 0x01,
|
||||
0x01, 0x00, 0x08, 0x00, 0x02, 0x10, 0x08, 0x11, 0x00, 0x0c, 0x10, 0x35,
|
||||
0x88, 0x8a, 0xaa, 0xcc, 0x06, 0xec, 0x00, 0x08, 0xca, 0xaa, 0x85, 0x33,
|
||||
0x0a, 0x00, 0x02, 0x0d, 0x08, 0xff, 0x02, 0xf0, 0x40, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x00, 0x1a, 0x05, 0xae, 0xee, 0xee, 0xbc, 0x98, 0xa9, 0xaa,
|
||||
0x88, 0x85, 0x53, 0x33, 0x11, 0x00, 0x06, 0x10, 0x0e, 0x00, 0x00, 0x26,
|
||||
0x01, 0x11, 0x00, 0x10, 0x00, 0x10, 0x01, 0x35, 0x88, 0xaa, 0x8a, 0xac,
|
||||
0xce, 0xec, 0xcc, 0xaa, 0xaa, 0x53, 0x10, 0x00, 0x08, 0x00, 0x02, 0x03,
|
||||
0x08, 0xff, 0x02, 0xf8, 0x40, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1a,
|
||||
0x15, 0xce, 0xee, 0xee, 0xc7, 0x88, 0xa8, 0xa8, 0x85, 0x33, 0x33, 0x11,
|
||||
0x10, 0x00, 0x20, 0x00, 0x00, 0x1c, 0x01, 0x13, 0x35, 0x85, 0x88, 0xaa,
|
||||
0xdc, 0xce, 0xcc, 0xca, 0x88, 0x51, 0x00, 0x01, 0x08, 0x00, 0x0a, 0xff,
|
||||
0x40, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x18, 0x05, 0xce, 0xee, 0xec,
|
||||
0x88, 0x85, 0x88, 0x53, 0x53, 0x31, 0x33, 0x30, 0x24, 0x00, 0x00, 0x22,
|
||||
0x01, 0x03, 0x35, 0x35, 0x85, 0x88, 0xac, 0xfe, 0xca, 0xa8, 0x53, 0x10,
|
||||
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0a, 0xff, 0x02, 0xf0, 0x3e, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x0a, 0x18, 0xcf, 0xee, 0xea, 0x58, 0x00,
|
||||
0x08, 0x33, 0x02, 0x31, 0x02, 0x31, 0x28, 0x00, 0x00, 0x1a, 0x11, 0x13,
|
||||
0x33, 0x35, 0x85, 0x8d, 0xdc, 0xec, 0xa8, 0x30, 0x00, 0x00, 0x01, 0x00,
|
||||
0x06, 0x00, 0x02, 0xdf, 0x08, 0xff, 0x02, 0xf3, 0x3e, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x00, 0x0a, 0x08, 0xce, 0xee, 0xc8, 0x85, 0x00, 0x06, 0x33,
|
||||
0x00, 0x06, 0x30, 0x33, 0x10, 0x00, 0x2a, 0x00, 0x00, 0x16, 0x01, 0x13,
|
||||
0x33, 0x35, 0x38, 0x5a, 0xcc, 0xaa, 0x31, 0x00, 0x10, 0x00, 0x08, 0x00,
|
||||
0x02, 0x3f, 0x0a, 0xff, 0x3e, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x14,
|
||||
0x08, 0xcf, 0xee, 0xa5, 0x53, 0x31, 0x30, 0x30, 0x33, 0x11, 0x2e, 0x00,
|
||||
0x00, 0x10, 0x11, 0x13, 0x33, 0x35, 0x38, 0xdc, 0xaa, 0x30, 0x0c, 0x00,
|
||||
0x02, 0x0f, 0x0a, 0xff, 0x02, 0xd0, 0x3c, 0x00, 0x00, 0x00, 0x48, 0x00,
|
||||
0x00, 0x0a, 0x05, 0xee, 0xff, 0x88, 0x53, 0x00, 0x06, 0x33, 0x02, 0x11,
|
||||
0x32, 0x00, 0x02, 0x10, 0x06, 0x33, 0x00, 0x14, 0x8c, 0xca, 0x31, 0x00,
|
||||
0x10, 0x00, 0x10, 0x00, 0x00, 0x0f, 0x0a, 0xff, 0x02, 0xf3, 0x3c, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x12, 0x1a, 0xfe, 0xea, 0x55, 0x33, 0x33,
|
||||
0x13, 0x11, 0x01, 0x00, 0x32, 0x00, 0x02, 0x10, 0x06, 0x33, 0x00, 0x06,
|
||||
0xad, 0xc8, 0x30, 0x00, 0x0c, 0x00, 0x02, 0x0f, 0x0c, 0xff, 0x3c, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x10, 0x0a, 0xef, 0xfa, 0x85, 0x33, 0x31,
|
||||
0x33, 0x10, 0x36, 0x00, 0x00, 0x12, 0x10, 0x33, 0x33, 0x5c, 0xcc, 0x51,
|
||||
0x01, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x03, 0x0c, 0xff, 0x02, 0xd0,
|
||||
0x3a, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x0e, 0x3c, 0xfe, 0xc5, 0x33,
|
||||
0x33, 0x31, 0x30, 0x00, 0x36, 0x00, 0x00, 0x0e, 0x10, 0x11, 0x13, 0x33,
|
||||
0x3d, 0xcc, 0x50, 0x00, 0x0e, 0x00, 0x0c, 0xff, 0x02, 0xf1, 0x3a, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x0c, 0x1a, 0xef, 0xc5, 0x53, 0x33, 0x31,
|
||||
0x3c, 0x00, 0x00, 0x10, 0x10, 0x33, 0x38, 0xac, 0x83, 0x01, 0x00, 0x10,
|
||||
0x08, 0x00, 0x0e, 0xff, 0x3a, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x0c,
|
||||
0x1c, 0xfe, 0xa3, 0x33, 0x03, 0x10, 0x38, 0x00, 0x06, 0x01, 0x00, 0x08,
|
||||
0x33, 0x3d, 0xaa, 0x80, 0x0e, 0x00, 0x0e, 0xff, 0x02, 0xa0, 0x38, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x0a, 0x3d, 0xef, 0x83, 0x33, 0x33, 0x00,
|
||||
0x3e, 0x00, 0x00, 0x0a, 0x10, 0x03, 0x35, 0x8a, 0xa3, 0x00, 0x0e, 0x00,
|
||||
0x02, 0x8f, 0x0c, 0xff, 0x02, 0xf0, 0x38, 0x00, 0x00, 0x00, 0x48, 0x00,
|
||||
0x00, 0x0a, 0x3c, 0xec, 0x53, 0x31, 0x10, 0x00, 0x3c, 0x00, 0x00, 0x10,
|
||||
0x01, 0x00, 0x11, 0x33, 0xaa, 0x50, 0x00, 0x10, 0x0a, 0x00, 0x02, 0x0f,
|
||||
0x0e, 0xff, 0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x08, 0x1c, 0xfd,
|
||||
0x53, 0x11, 0x40, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x01, 0x5a, 0x81, 0x00,
|
||||
0x0e, 0x00, 0x02, 0x0f, 0x0e, 0xff, 0x02, 0x80, 0x36, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x00, 0x08, 0x1c, 0xca, 0x33, 0x01, 0x42, 0x00, 0x00, 0x06,
|
||||
0x01, 0x00, 0x11, 0x00, 0x10, 0x00, 0x02, 0x0f, 0x0e, 0xff, 0x02, 0xf0,
|
||||
0x36, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x06, 0x08, 0xf8, 0x31, 0x00,
|
||||
0x5a, 0x00, 0x02, 0x0a, 0x10, 0xff, 0x36, 0x00, 0x00, 0x00, 0x48, 0x00,
|
||||
0x00, 0x06, 0x05, 0xa3, 0x10, 0x00, 0x5a, 0x00, 0x02, 0x01, 0x10, 0xff,
|
||||
0x02, 0x30, 0x34, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x02, 0x10, 0x5e, 0x00,
|
||||
0x10, 0xff, 0x02, 0xf0, 0x34, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x10, 0xff,
|
||||
0x02, 0xfd, 0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x8f, 0xe8, 0xff,
|
||||
0x02, 0xd0, 0x02, 0x00, 0x00, 0x00, 0x02, 0x3f, 0xec, 0xff, 0x02, 0x30,
|
||||
0x00, 0x00, 0xee, 0xff, 0x02, 0xf0, 0x00, 0x00, 0xee, 0xff, 0x02, 0xf8,
|
||||
0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff,
|
||||
0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff,
|
||||
0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff,
|
||||
0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff,
|
||||
0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x01
|
||||
};
|
||||
unsigned int fox_bmp_len = 11314;
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "clock_manager.hpp"
|
||||
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "portapack_io.hpp"
|
||||
|
||||
#include "hackrf_hal.hpp"
|
||||
@@ -463,3 +464,21 @@ void ClockManager::stop_audio_pll() {
|
||||
cgu::pll0audio::power_down();
|
||||
while( cgu::pll0audio::is_locked() );
|
||||
}
|
||||
|
||||
void ClockManager::enable_clock_output(bool enable) {
|
||||
if(enable) {
|
||||
clock_generator.enable_output(clock_generator_output_clkout);
|
||||
if(portapack::persistent_memory::clkout_freq() < 1000) {
|
||||
clock_generator.set_ms_frequency(clock_generator_output_clkout, portapack::persistent_memory::clkout_freq() * 128000, si5351_vco_f, 7);
|
||||
} else {
|
||||
clock_generator.set_ms_frequency(clock_generator_output_clkout, portapack::persistent_memory::clkout_freq() * 1000, si5351_vco_f, 0);
|
||||
}
|
||||
} else {
|
||||
clock_generator.disable_output(clock_generator_output_clkout);
|
||||
}
|
||||
|
||||
if(enable)
|
||||
clock_generator.set_clock_control(clock_generator_output_clkout, si5351_clock_control_common[clock_generator_output_clkout].ms_src(get_reference_clock_generator_pll(reference.source)).clk_pdn(ClockControl::ClockPowerDown::Power_On));
|
||||
else
|
||||
clock_generator.set_clock_control(clock_generator_output_clkout, ClockControl::power_off());
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ public:
|
||||
|
||||
Reference get_reference() const;
|
||||
|
||||
void enable_clock_output(bool enable);
|
||||
|
||||
private:
|
||||
I2C& i2c0;
|
||||
si5351::Si5351& clock_generator;
|
||||
|
||||
@@ -343,6 +343,8 @@ void EventDispatcher::handle_encoder() {
|
||||
}
|
||||
|
||||
void EventDispatcher::handle_touch() {
|
||||
portapack::bl_tick_counter = 0;
|
||||
|
||||
touch_manager.feed(get_touch_frame());
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,11 @@ std::vector<std::string> get_freqman_files() {
|
||||
auto files = scan_root_files(u"FREQMAN", u"*.TXT");
|
||||
|
||||
for (auto file : files) {
|
||||
file_list.emplace_back(file.stem().string());
|
||||
std::string file_name = file.stem().string();
|
||||
// don't propose tmp / hidden files in freqman's list
|
||||
if (file_name.length() && file_name[0] != '.') {
|
||||
file_list.emplace_back(file_name);
|
||||
}
|
||||
}
|
||||
|
||||
return file_list;
|
||||
|
||||
@@ -48,11 +48,28 @@ enum freqman_entry_type {
|
||||
RANGE
|
||||
};
|
||||
|
||||
//Entry step placed for AlainD freqman version (or any other enhanced version)
|
||||
enum freqman_entry_step {
|
||||
STEP_DEF = 0, // default
|
||||
AM_US, // 10 Khz AM/CB
|
||||
AM_EUR, // 9 Khz LW/MW
|
||||
NFM_1, // 12,5 Khz (Analogic PMR 446)
|
||||
NFM_2, // 6,25 Khz (Digital PMR 446)
|
||||
FM_1, // 100 Khz
|
||||
FM_2, // 50 Khz
|
||||
N_1, // 25 Khz
|
||||
N_2, // 250 Khz
|
||||
AIRBAND, // AIRBAND 8,33 Khz
|
||||
ERROR_STEP
|
||||
};
|
||||
|
||||
// freqman_entry_step step added, as above, to provide compatibility / future enhancement.
|
||||
struct freqman_entry {
|
||||
rf::Frequency frequency_a { 0 };
|
||||
rf::Frequency frequency_b { 0 };
|
||||
std::string description { };
|
||||
freqman_entry_type type { };
|
||||
freqman_entry_step step { };
|
||||
};
|
||||
|
||||
using freqman_db = std::vector<freqman_entry>;
|
||||
|
||||
@@ -93,6 +93,15 @@ bool get_antenna_bias() {
|
||||
return antenna_bias;
|
||||
}
|
||||
|
||||
bool speaker_mode { false };
|
||||
void set_speaker_mode(const bool v) {
|
||||
speaker_mode = v;
|
||||
if (speaker_mode)
|
||||
audio::output::speaker_unmute();
|
||||
else
|
||||
audio::output::speaker_mute();
|
||||
}
|
||||
|
||||
static constexpr uint32_t systick_count(const uint32_t clock_source_f) {
|
||||
return clock_source_f / CH_FREQUENCY;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@ extern ClockManager clock_manager;
|
||||
extern ReceiverModel receiver_model;
|
||||
extern TransmitterModel transmitter_model;
|
||||
|
||||
extern bool speaker_mode;
|
||||
void set_speaker_mode(const bool v);
|
||||
|
||||
extern uint8_t bl_tick_counter;
|
||||
extern bool antenna_bias;
|
||||
|
||||
|
||||
@@ -38,9 +38,13 @@ void make_aprs_frame(const char * src_address, const uint32_t src_ssid,
|
||||
char address[14] = { 0 };
|
||||
|
||||
memcpy(&address[0], dest_address, 6);
|
||||
address[6] = (dest_ssid & 15) << 1;
|
||||
memcpy(&address[7], src_address, 6);
|
||||
address[13] = (src_ssid & 15) << 1;
|
||||
//euquiq: According to ax.25 doc section 2.2.13.x.x and 2.4.1.2
|
||||
// SSID need bits 5.6 set, so later when shifted it will end up being 011xxxx0 (xxxx = SSID number)
|
||||
// Notice that if need to signal usage of AX.25 V2.0, (dest_ssid | 112); (MSb will need to be set at the end)
|
||||
address[6] = (dest_ssid | 48);
|
||||
address[13] = (src_ssid | 48);
|
||||
|
||||
|
||||
frame.make_ui_frame(address, 0x03, protocol_id_t::NO_LAYER3, payload);
|
||||
}
|
||||
|
||||
@@ -51,32 +51,37 @@ void AX25Frame::NRZI_add_bit(const uint32_t bit) {
|
||||
}
|
||||
}
|
||||
|
||||
void AX25Frame::add_byte(uint8_t byte, bool is_flag, bool is_data) {
|
||||
uint32_t bit;
|
||||
|
||||
void AX25Frame::add_byte(uint8_t byte, bool is_flag, bool is_data)
|
||||
{
|
||||
bool bit;
|
||||
|
||||
if (is_data)
|
||||
crc_ccitt.process_byte(byte);
|
||||
|
||||
for (uint32_t i = 0; i < 8; i++) {
|
||||
|
||||
for (uint32_t i = 0; i < 8; i++)
|
||||
{
|
||||
bit = (byte >> i) & 1;
|
||||
|
||||
|
||||
NRZI_add_bit(bit);
|
||||
|
||||
if (bit)
|
||||
{
|
||||
ones_counter++;
|
||||
if ((ones_counter == 5) && (!is_flag))
|
||||
{
|
||||
NRZI_add_bit(0);
|
||||
ones_counter = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
ones_counter = 0;
|
||||
|
||||
if ((ones_counter == 6) && (!is_flag)) {
|
||||
NRZI_add_bit(0);
|
||||
ones_counter = 0;
|
||||
}
|
||||
|
||||
NRZI_add_bit(bit);
|
||||
}
|
||||
}
|
||||
|
||||
void AX25Frame::flush() {
|
||||
void AX25Frame::flush()
|
||||
{
|
||||
if (bit_counter)
|
||||
*bb_data_ptr = current_byte << (7 - bit_counter);
|
||||
*bb_data_ptr = current_byte << (8 - bit_counter); //euquiq: This was 7 but there are 8 bits
|
||||
};
|
||||
|
||||
void AX25Frame::add_flag() {
|
||||
|
||||
@@ -38,10 +38,11 @@ using namespace portapack;
|
||||
|
||||
namespace {
|
||||
|
||||
static constexpr std::array<baseband::AMConfig, 3> am_configs { {
|
||||
static constexpr std::array<baseband::AMConfig, 4> am_configs { {
|
||||
{ taps_6k0_dsb_channel, AMConfigureMessage::Modulation::DSB },
|
||||
{ taps_2k8_usb_channel, AMConfigureMessage::Modulation::SSB },
|
||||
{ taps_2k8_lsb_channel, AMConfigureMessage::Modulation::SSB },
|
||||
{ taps_0k7_usb_channel, AMConfigureMessage::Modulation::SSB },
|
||||
} };
|
||||
|
||||
static constexpr std::array<baseband::NBFMConfig, 3> nbfm_configs { {
|
||||
|
||||
@@ -113,7 +113,7 @@ std::string to_string_dec_int(
|
||||
}
|
||||
|
||||
std::string to_string_short_freq(const uint64_t f) {
|
||||
auto final_str = to_string_dec_int(f / 1000000, 4) + "." + to_string_dec_int((f / 100) % 10000, 4, '0');
|
||||
auto final_str = to_string_dec_int(f / 1000000,4) + "." + to_string_dec_int((f / 100) % 10000, 4, '0');
|
||||
return final_str;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format) {
|
||||
}
|
||||
|
||||
string += to_string_dec_uint(value.hour(), 2, '0') + ":" +
|
||||
string += to_string_dec_uint(value.minute(), 2, '0');
|
||||
to_string_dec_uint(value.minute(), 2, '0');
|
||||
|
||||
if ((format == YMDHMS) || (format == HMS))
|
||||
string += ":" + to_string_dec_uint(value.second(), 2, '0');
|
||||
@@ -223,3 +223,13 @@ std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precisi
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
double get_decimals(double num, int16_t mult, bool round) {
|
||||
num -= int(num); //keep decimals only
|
||||
num *= mult; //Shift decimals into integers
|
||||
if (!round) return num;
|
||||
int16_t intnum = int(num); //Round it up if necessary
|
||||
num -= intnum; //Get decimal part
|
||||
if (num > .5) intnum++; //Round up
|
||||
return intnum;
|
||||
}
|
||||
|
||||
@@ -54,5 +54,5 @@ std::string to_string_timestamp(const rtc::RTC& value);
|
||||
std::string to_string_FAT_timestamp(const FATTimestamp& timestamp);
|
||||
|
||||
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision);
|
||||
|
||||
double get_decimals(double num, int16_t mult, bool round = false); //euquiq added
|
||||
#endif/*__STRING_FORMAT_H__*/
|
||||
|
||||
@@ -95,6 +95,15 @@ void BtnGridView::set_parent_rect(const Rect new_parent_rect) {
|
||||
update_items();
|
||||
}
|
||||
|
||||
void BtnGridView::set_arrow_enabled(bool new_value) {
|
||||
if(new_value){
|
||||
add_child(&arrow_more);
|
||||
}
|
||||
else{
|
||||
remove_child(&arrow_more);
|
||||
}
|
||||
};
|
||||
|
||||
void BtnGridView::on_tick_second() {
|
||||
if (more && blink)
|
||||
arrow_more.set_foreground(Color::white());
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
uint32_t highlighted_index();
|
||||
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
void set_arrow_enabled(bool new_value);
|
||||
void on_focus() override;
|
||||
void on_blur() override;
|
||||
bool on_key(const KeyEvent event) override;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
using namespace portapack;
|
||||
|
||||
#include "string_format.hpp"
|
||||
#include "complex.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@@ -58,7 +59,7 @@ GeoPos::GeoPos(
|
||||
set_altitude(0);
|
||||
set_lat(0);
|
||||
set_lon(0);
|
||||
|
||||
|
||||
const auto changed_fn = [this](int32_t) {
|
||||
float lat_value = lat();
|
||||
float lon_value = lon();
|
||||
@@ -147,7 +148,7 @@ GeoMap::GeoMap(
|
||||
}
|
||||
|
||||
void GeoMap::paint(Painter& painter) {
|
||||
Coord line;
|
||||
u_int16_t line;
|
||||
std::array<ui::Color, 240> map_line_buffer;
|
||||
const auto r = screen_rect();
|
||||
|
||||
@@ -162,14 +163,22 @@ void GeoMap::paint(Painter& painter) {
|
||||
prev_x_pos = x_pos;
|
||||
prev_y_pos = y_pos;
|
||||
}
|
||||
|
||||
//center tag above point
|
||||
if(tag_.find_first_not_of(' ') != tag_.npos){ //only draw tag if we have something other than spaces
|
||||
painter.draw_string(r.center() - Point(((int)tag_.length() * 8 / 2), 2 * 16), style(), tag_);
|
||||
}
|
||||
if (mode_ == PROMPT) {
|
||||
// Cross
|
||||
display.fill_rectangle({ r.center() - Point(16, 1), { 32, 2 } }, Color::red());
|
||||
display.fill_rectangle({ r.center() - Point(1, 16), { 2, 32 } }, Color::red());
|
||||
} else {
|
||||
draw_bearing({ 120, 32 + 144 }, angle_, 16, Color::red());
|
||||
painter.draw_string({ 120 - ((int)tag_.length() * 8 / 2), 32 + 144 - 32 }, style(), tag_);
|
||||
} else if (angle_ < 360){
|
||||
//if we have a valid angle draw bearing
|
||||
draw_bearing(r.center(), angle_, 10, Color::red());
|
||||
}
|
||||
else {
|
||||
//draw a small cross
|
||||
display.fill_rectangle({ r.center() - Point(8, 1), { 16, 2 } }, Color::red());
|
||||
display.fill_rectangle({ r.center() - Point(1, 8), { 2, 16 } }, Color::red());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,10 +200,16 @@ void GeoMap::move(const float lon, const float lat) {
|
||||
|
||||
Rect map_rect = screen_rect();
|
||||
|
||||
// Map is in Equidistant "Plate Carrée" projection
|
||||
x_pos = map_center_x - (map_rect.width() / 2) + (lon_ / lon_ratio);
|
||||
y_pos = map_center_y - (map_rect.height() / 2) + (lat_ / lat_ratio) + 16;
|
||||
|
||||
// Using WGS 84/Pseudo-Mercator projection
|
||||
x_pos = map_width * (lon_+180)/360 - (map_rect.width() / 2);
|
||||
|
||||
// Latitude calculation based on https://stackoverflow.com/a/10401734/2278659
|
||||
double map_bottom = sin(-85.05 * pi / 180); // Map bitmap only goes from about -85 to 85 lat
|
||||
double lat_rad = sin(lat * pi / 180);
|
||||
double map_world_lon = map_width / (2 * pi);
|
||||
double map_offset = (map_world_lon / 2 * log((1 + map_bottom) / (1 - map_bottom)));
|
||||
y_pos = map_height - ((map_world_lon / 2 * log((1 + lat_rad) / (1 - lat_rad))) - map_offset) - 128; // Offset added for the GUI
|
||||
|
||||
// Cap position
|
||||
if (x_pos > (map_width - map_rect.width()))
|
||||
x_pos = map_width - map_rect.width();
|
||||
@@ -223,13 +238,13 @@ void GeoMap::set_mode(GeoMapMode mode) {
|
||||
mode_ = mode;
|
||||
}
|
||||
|
||||
void GeoMap::draw_bearing(const Point origin, const uint32_t angle, uint32_t size, const Color color) {
|
||||
void GeoMap::draw_bearing(const Point origin, const uint16_t angle, uint32_t size, const Color color) {
|
||||
Point arrow_a, arrow_b, arrow_c;
|
||||
|
||||
for (size_t thickness = 0; thickness < 3; thickness++) {
|
||||
arrow_a = polar_to_point(angle, size) + origin;
|
||||
arrow_b = polar_to_point(angle + 180 - 30, size) + origin;
|
||||
arrow_c = polar_to_point(angle + 180 + 30, size) + origin;
|
||||
arrow_b = polar_to_point(angle + 180 - 35, size) + origin;
|
||||
arrow_c = polar_to_point(angle + 180 + 35, size) + origin;
|
||||
|
||||
display.draw_line(arrow_a, arrow_b, color);
|
||||
display.draw_line(arrow_b, arrow_c, color);
|
||||
@@ -246,11 +261,12 @@ void GeoMapView::focus() {
|
||||
nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT, nullptr);
|
||||
}
|
||||
|
||||
void GeoMapView::update_position(float lat, float lon) {
|
||||
void GeoMapView::update_position(float lat, float lon, uint16_t angle) {
|
||||
lat_ = lat;
|
||||
lon_ = lon;
|
||||
geopos.set_lat(lat_);
|
||||
geopos.set_lon(lon_);
|
||||
geomap.set_angle(angle);
|
||||
geomap.move(lon_, lat_);
|
||||
geomap.set_dirty();
|
||||
}
|
||||
@@ -261,7 +277,7 @@ void GeoMapView::setup() {
|
||||
geopos.set_altitude(altitude_);
|
||||
geopos.set_lat(lat_);
|
||||
geopos.set_lon(lon_);
|
||||
|
||||
|
||||
geopos.on_change = [this](int32_t altitude, float lat, float lon) {
|
||||
altitude_ = altitude;
|
||||
lat_ = lat;
|
||||
@@ -299,7 +315,7 @@ GeoMapView::GeoMapView(
|
||||
GeoPos::alt_unit altitude_unit,
|
||||
float lat,
|
||||
float lon,
|
||||
float angle,
|
||||
uint16_t angle,
|
||||
const std::function<void(void)> on_close
|
||||
) : nav_ (nav),
|
||||
altitude_ (altitude),
|
||||
@@ -320,6 +336,7 @@ GeoMapView::GeoMapView(
|
||||
|
||||
geomap.set_mode(mode_);
|
||||
geomap.set_tag(tag);
|
||||
geomap.set_angle(angle);
|
||||
geomap.move(lon_, lat_);
|
||||
|
||||
geopos.set_read_only(true);
|
||||
|
||||
@@ -129,8 +129,12 @@ public:
|
||||
tag_ = new_tag;
|
||||
}
|
||||
|
||||
void set_angle(uint16_t new_angle){
|
||||
angle_ = new_angle;
|
||||
}
|
||||
|
||||
private:
|
||||
void draw_bearing(const Point origin, const uint32_t angle, uint32_t size, const Color color);
|
||||
void draw_bearing(const Point origin, const uint16_t angle, uint32_t size, const Color color);
|
||||
|
||||
GeoMapMode mode_ { };
|
||||
File map_file { };
|
||||
@@ -141,7 +145,7 @@ private:
|
||||
int32_t prev_x_pos { 0xFFFF }, prev_y_pos { 0xFFFF };
|
||||
float lat_ { };
|
||||
float lon_ { };
|
||||
float angle_ { };
|
||||
uint16_t angle_ { };
|
||||
std::string tag_ { };
|
||||
};
|
||||
|
||||
@@ -154,7 +158,7 @@ public:
|
||||
GeoPos::alt_unit altitude_unit,
|
||||
float lat,
|
||||
float lon,
|
||||
float angle,
|
||||
uint16_t angle,
|
||||
const std::function<void(void)> on_close = nullptr
|
||||
);
|
||||
GeoMapView(NavigationView& nav,
|
||||
@@ -173,7 +177,7 @@ public:
|
||||
|
||||
void focus() override;
|
||||
|
||||
void update_position(float lat, float lon);
|
||||
void update_position(float lat, float lon, uint16_t angle);
|
||||
|
||||
std::string title() const override { return "Map view"; };
|
||||
|
||||
@@ -190,7 +194,7 @@ private:
|
||||
GeoPos::alt_unit altitude_unit_ { };
|
||||
float lat_ { };
|
||||
float lon_ { };
|
||||
float angle_ { };
|
||||
uint16_t angle_ { };
|
||||
std::function<void(void)> on_close_ { nullptr };
|
||||
|
||||
bool map_opened { };
|
||||
|
||||
@@ -120,8 +120,8 @@ void FrequencyScale::paint(Painter& painter) {
|
||||
|
||||
if (_blink) {
|
||||
const Rect r_cursor {
|
||||
120 + cursor_position, r.bottom() - filter_band_height,
|
||||
2, filter_band_height
|
||||
118 + cursor_position, r.bottom() - filter_band_height,
|
||||
5, filter_band_height
|
||||
};
|
||||
painter.fill_rectangle(
|
||||
r_cursor,
|
||||
|
||||