mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-07-26 10:38:52 +00:00
Compare commits
303 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 55783a60f5 | |||
| e76ec66023 | |||
| bf068abba3 | |||
| 8949662eee | |||
| 3d9ce8a037 | |||
| 7fd9adf3f2 | |||
| 3aaa4a0ba1 | |||
| 875db13917 | |||
| 1a94f4a1ab | |||
| 4390647e28 | |||
| 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 |
@@ -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.
|
||||
+3
-4
@@ -13,7 +13,6 @@
|
||||
/sdcard/FREQMAN/BHT*
|
||||
/sdcard/FREQMAN/R.TXT
|
||||
/sdcard/FREQMAN/XXX.TXT
|
||||
/sdcard/WAV/*
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
@@ -60,8 +59,8 @@ CMakeFiles/
|
||||
# Editor files
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.vscode
|
||||
|
||||
# Host OS turds
|
||||
# Host OS leftovers
|
||||
.DS_Store
|
||||
/firmware/CMakeCache.txt
|
||||
/sdcard/ADSB/airlines.txt
|
||||
/firmware/CMakeCache.txt
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "hackrf"]
|
||||
path = hackrf
|
||||
url = https://github.com/jboone/hackrf.git
|
||||
url = https://github.com/mossmann/hackrf.git
|
||||
|
||||
@@ -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).
|
||||
|
||||
+11
-1
@@ -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/
|
||||
|
||||
+11
-1
@@ -11,10 +11,20 @@ WORKDIR /havoc/firmware
|
||||
|
||||
# Fetch dependencies from APT
|
||||
RUN apt-get update && \
|
||||
apt-get install -y git tar wget dfu-util cmake python3 python-pip ccache && \
|
||||
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/
|
||||
|
||||
+6
-4
@@ -1,4 +1,6 @@
|
||||
<h1>Portapack Havoc</h1>
|
||||
<h2>Nightly builds</h2>
|
||||
<p><a href="/fake.bin">fake.bin</a></p>
|
||||
<p><a href="/fake.bin">fake.bin</a></p>
|
||||
<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
|
||||
|
||||
@@ -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"
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
|
||||
#include "ui_scanner.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "audio.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
@@ -38,6 +34,10 @@ ScannerThread::ScannerThread(
|
||||
}
|
||||
|
||||
ScannerThread::~ScannerThread() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void ScannerThread::stop() {
|
||||
if( thread ) {
|
||||
chThdTerminate(thread);
|
||||
chThdWait(thread);
|
||||
@@ -49,6 +49,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 +78,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 +158,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 +182,340 @@ ScannerView::ScannerView(
|
||||
&field_bw,
|
||||
&field_squelch,
|
||||
&field_wait,
|
||||
//&record_view,
|
||||
&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);
|
||||
}
|
||||
} else {
|
||||
frequency_list.push_back(entry.frequency_a);
|
||||
}
|
||||
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_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);
|
||||
}
|
||||
|
||||
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;
|
||||
button_audio_app.on_select = [this](Button&) {
|
||||
scan_thread->stop();
|
||||
nav_.pop();
|
||||
nav_.push<AnalogAudioView>();
|
||||
};
|
||||
field_wait.set_value(5);
|
||||
|
||||
field_squelch.on_change = [this](int32_t v) {
|
||||
squelch = v;
|
||||
button_mic_app.on_select = [this](Button&) {
|
||||
scan_thread->stop();
|
||||
nav_.pop();
|
||||
nav_.push<MicTXView>();
|
||||
};
|
||||
field_squelch.set_value(30);
|
||||
|
||||
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;
|
||||
auto result = scanner_file.open("FREQMAN/SCANNER.TXT"); //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("FREQMAN/SCANNER.TXT"); //Second: append if it is not there
|
||||
scanner_file.write_line(frequency_to_add + ",d=ADD FQ");
|
||||
}
|
||||
} else
|
||||
{
|
||||
nav_.display_modal("Error", "Cannot open SCANNER.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);
|
||||
};
|
||||
|
||||
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);
|
||||
field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); };
|
||||
// LEARN FREQUENCIES
|
||||
std::string scanner_txt = "SCANNER";
|
||||
if ( load_freqman_file(scanner_txt, database) ) {
|
||||
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
|
||||
{
|
||||
desc_cycle.set(" NO SCANNER.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,81 @@ 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 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 { };
|
||||
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 +170,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 +190,97 @@ 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_remove {
|
||||
{ 168, (35 * 8) - 4, 72, 28 },
|
||||
"DEL FQ"
|
||||
};
|
||||
|
||||
std::unique_ptr<ScannerThread> scan_thread { };
|
||||
@@ -146,4 +301,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;
|
||||
@@ -183,6 +184,7 @@ SetFrequencyCorrectionModel SetRadioView::form_collect() {
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
SetPlayDeadView::SetPlayDeadView(NavigationView& nav) {
|
||||
add_children({
|
||||
&text_sequence,
|
||||
@@ -234,18 +236,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 +261,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 +277,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 +485,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);
|
||||
@@ -174,7 +174,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 +194,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 +217,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 +233,7 @@ private:
|
||||
|
||||
Button button_ok {
|
||||
{ 2 * 8, 16 * 16, 12 * 8, 32 },
|
||||
"OK"
|
||||
"Save"
|
||||
};
|
||||
};
|
||||
|
||||
@@ -253,10 +260,11 @@ private:
|
||||
|
||||
Button button_ok {
|
||||
{ 2 * 8, 16 * 16, 12 * 8, 32 },
|
||||
"OK"
|
||||
"Save"
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
class SetPlayDeadView : public View {
|
||||
public:
|
||||
SetPlayDeadView(NavigationView& nav);
|
||||
@@ -284,7 +292,7 @@ private:
|
||||
{ 128, 192, 96, 24 },
|
||||
"Cancel"
|
||||
};
|
||||
};
|
||||
};*/
|
||||
|
||||
/*class ModInfoView : public View {
|
||||
public:
|
||||
|
||||
@@ -52,7 +52,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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+2005
-1499
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
@@ -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_, 10, 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +202,13 @@ void GeoMap::move(const float lon, const float lat) {
|
||||
|
||||
// Using WGS 84/Pseudo-Mercator projection
|
||||
x_pos = map_width * (lon_+180)/360 - (map_rect.width() / 2);
|
||||
y_pos = (0.5-lat_/(340.1206913+-4.21807e-5*pow((double)abs(lat_),3.4198394))) * map_height -(map_rect.height() / 1) + 32;
|
||||
|
||||
// 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()))
|
||||
@@ -223,7 +238,7 @@ 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++) {
|
||||
@@ -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,
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "bmp_modal_warning.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
#include "ui_about.hpp"
|
||||
#include "ui_about_simple.hpp"
|
||||
#include "ui_adsb_rx.hpp"
|
||||
#include "ui_adsb_tx.hpp"
|
||||
#include "ui_afsk_rx.hpp"
|
||||
@@ -50,7 +50,7 @@
|
||||
#include "ui_morse.hpp"
|
||||
//#include "ui_numbers.hpp"
|
||||
//#include "ui_nuoptix.hpp"
|
||||
#include "ui_playdead.hpp"
|
||||
//#include "ui_playdead.hpp"
|
||||
#include "ui_pocsag_tx.hpp"
|
||||
#include "ui_rds.hpp"
|
||||
#include "ui_remote.hpp"
|
||||
@@ -106,6 +106,8 @@ SystemStatusView::SystemStatusView(
|
||||
&backdrop,
|
||||
&button_back,
|
||||
&title,
|
||||
&button_title,
|
||||
&button_speaker,
|
||||
&button_stealth,
|
||||
//&button_textentry,
|
||||
&button_camera,
|
||||
@@ -115,6 +117,11 @@ SystemStatusView::SystemStatusView(
|
||||
&sd_card_status_view,
|
||||
});
|
||||
|
||||
if (portapack::persistent_memory::config_speaker())
|
||||
button_speaker.hidden(false);
|
||||
else
|
||||
button_speaker.hidden(true);
|
||||
|
||||
button_back.id = -1; // Special ID used by FocusManager
|
||||
title.set_style(&style_systemstatus);
|
||||
|
||||
@@ -132,6 +139,14 @@ SystemStatusView::SystemStatusView(
|
||||
if (this->on_back)
|
||||
this->on_back();
|
||||
};
|
||||
|
||||
button_title.on_select = [this](ImageButton&) {
|
||||
this->on_title();
|
||||
};
|
||||
|
||||
button_speaker.on_select = [this](ImageButton&) {
|
||||
this->on_speaker();
|
||||
};
|
||||
|
||||
button_stealth.on_select = [this](ImageButton&) {
|
||||
this->on_stealth();
|
||||
@@ -156,6 +171,14 @@ SystemStatusView::SystemStatusView(
|
||||
}
|
||||
|
||||
void SystemStatusView::refresh() {
|
||||
if (!portapack::persistent_memory::config_speaker()) {
|
||||
button_speaker.set_foreground(Color::light_grey());
|
||||
button_speaker.set_bitmap(&bitmap_icon_speaker_mute);
|
||||
button_speaker.hidden(false);
|
||||
}
|
||||
else {
|
||||
button_speaker.hidden(true);
|
||||
}
|
||||
if (portapack::get_antenna_bias()) {
|
||||
button_bias_tee.set_bitmap(&bitmap_icon_biast_on);
|
||||
button_bias_tee.set_foreground(ui::Color::yellow());
|
||||
@@ -176,8 +199,23 @@ void SystemStatusView::refresh() {
|
||||
}
|
||||
|
||||
void SystemStatusView::set_back_enabled(bool new_value) {
|
||||
button_back.set_foreground(new_value ? Color::white() : Color::dark_grey());
|
||||
button_back.set_focusable(new_value);
|
||||
|
||||
if(new_value){
|
||||
add_child(&button_back);
|
||||
}
|
||||
else{
|
||||
remove_child(&button_back);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemStatusView::set_title_image_enabled(bool new_value) {
|
||||
|
||||
if(new_value){
|
||||
add_child(&button_title);
|
||||
}
|
||||
else{
|
||||
remove_child(&button_title);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemStatusView::set_title(const std::string new_value) {
|
||||
@@ -188,6 +226,23 @@ void SystemStatusView::set_title(const std::string new_value) {
|
||||
}
|
||||
}
|
||||
|
||||
void SystemStatusView::on_speaker() {
|
||||
if (!portapack::speaker_mode)
|
||||
{
|
||||
portapack::set_speaker_mode(true);
|
||||
button_speaker.set_foreground(Color::green());
|
||||
button_speaker.set_bitmap(&bitmap_icon_speaker);
|
||||
}
|
||||
else
|
||||
{
|
||||
portapack::set_speaker_mode(false);
|
||||
button_speaker.set_foreground(Color::light_grey());
|
||||
button_speaker.set_bitmap(&bitmap_icon_speaker_mute);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SystemStatusView::on_stealth() {
|
||||
bool mode = not portapack::persistent_memory::stealth_mode();
|
||||
|
||||
@@ -198,7 +253,7 @@ void SystemStatusView::on_stealth() {
|
||||
|
||||
void SystemStatusView::on_bias_tee() {
|
||||
if (!portapack::antenna_bias) {
|
||||
nav_.display_modal("Bias voltage", "Enable DC voltage on\nantenna connector ?", YESNO, [this](bool v) {
|
||||
nav_.display_modal("Bias voltage", "Enable DC voltage on\nantenna connector?", YESNO, [this](bool v) {
|
||||
if (v) {
|
||||
portapack::set_antenna_bias(true);
|
||||
//radio::set_antenna_bias(true);
|
||||
@@ -247,6 +302,39 @@ void SystemStatusView::on_camera() {
|
||||
}
|
||||
}
|
||||
|
||||
void SystemStatusView::on_title() {
|
||||
if(nav_.is_top())
|
||||
nav_.push<AboutView>();
|
||||
else
|
||||
nav_.pop();
|
||||
}
|
||||
|
||||
/* Information View *****************************************************/
|
||||
|
||||
InformationView::InformationView(
|
||||
NavigationView& nav
|
||||
) : nav_ (nav)
|
||||
{
|
||||
static constexpr Style style_infobar {
|
||||
.font = font::fixed_8x16,
|
||||
.background = {33, 33, 33},
|
||||
.foreground = Color::white(),
|
||||
};
|
||||
|
||||
add_children({
|
||||
&backdrop,
|
||||
&version,
|
||||
<ime
|
||||
});
|
||||
|
||||
version.set_style(&style_infobar);
|
||||
ltime.set_style(&style_infobar);
|
||||
ltime.set_seconds_enabled(true);
|
||||
ltime.set_date_enabled(false);
|
||||
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
/* Navigation ************************************************************/
|
||||
|
||||
bool NavigationView::is_top() const {
|
||||
@@ -348,26 +436,26 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
||||
add_items({
|
||||
//{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } },
|
||||
{ "ADS-B", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBRxView>(); }, },
|
||||
{ "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ACARSAppView>(); }, },
|
||||
//{ "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ACARSAppView>(); }, },
|
||||
{ "AIS Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
|
||||
{ "AFSK", ui::Color::yellow(), &bitmap_icon_receivers, [&nav](){ nav.push<AFSKRxView>(); } },
|
||||
{ "AFSK", ui::Color::yellow(), &bitmap_icon_modem, [&nav](){ nav.push<AFSKRxView>(); } },
|
||||
{ "BTLE", ui::Color::yellow(), &bitmap_icon_btle, [&nav](){ nav.push<BTLERxView>(); } },
|
||||
{ "NRF", ui::Color::yellow(), &bitmap_icon_nrf, [&nav](){ nav.push<NRFRxView>(); } },
|
||||
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push<AnalogAudioView>(); } },
|
||||
{ "Analog TV", ui::Color::yellow(), &bitmap_icon_sstv, [&nav](){ nav.push<AnalogTvView>(); } },
|
||||
{ "Analog TV", ui::Color::yellow(), &bitmap_icon_sstv, [&nav](){ nav.push<AnalogTvView>(); } },
|
||||
{ "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
|
||||
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
|
||||
{ "Radiosnde", ui::Color::yellow(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
|
||||
{ "Radiosnde", ui::Color::green(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
|
||||
{ "TPMS Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
|
||||
{ "APRS", ui::Color::dark_grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
/*{ "APRS", ui::Color::dark_grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "DMR", ui::Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "SIGFOX", ui::Color::dark_grey(), &bitmap_icon_fox, [&nav](){ nav.push<NotImplementedView>(); } }, // SIGFRXView
|
||||
{ "LoRa", ui::Color::dark_grey(), &bitmap_icon_lora, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "SSTV", ui::Color::dark_grey(), &bitmap_icon_sstv, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "TETRA", ui::Color::dark_grey(), &bitmap_icon_tetra, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "TETRA", ui::Color::dark_grey(), &bitmap_icon_tetra, [&nav](){ nav.push<NotImplementedView>(); } },*/
|
||||
});
|
||||
|
||||
set_highlighted(4); // Default selection is "Audio"
|
||||
//set_highlighted(4); // Default selection is "Audio"
|
||||
}
|
||||
|
||||
/* TransmittersMenuView **************************************************/
|
||||
@@ -376,24 +464,23 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
|
||||
add_items({
|
||||
//{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } },
|
||||
{ "ADS-B [S]", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBTxView>(); } },
|
||||
{ "APRS", ui::Color::orange(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
|
||||
{ "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push<BHTView>(); } },
|
||||
{ "GPS Sim", ui::Color::yellow(), &bitmap_gps_sim, [&nav](){ nav.push<GpsSimAppView>(); } },
|
||||
{ "Jammer", ui::Color::yellow(), &bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
|
||||
{ "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); } },
|
||||
{ "LGE tool", ui::Color::yellow(), &bitmap_icon_lge, [&nav](){ nav.push<LGEView>(); } },
|
||||
{ "Mic", ui::Color::green(), &bitmap_icon_microphone,[&nav](){ nav.push<MicTXView>(); } },
|
||||
{ "APRS", ui::Color::orange(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
|
||||
{ "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push<BHTView>(); } },
|
||||
{ "GPS Sim", ui::Color::yellow(), &bitmap_icon_gps_sim, [&nav](){ nav.push<GpsSimAppView>(); } },
|
||||
{ "Jammer", ui::Color::yellow(), &bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
|
||||
{ "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); } },
|
||||
{ "LGE tool", ui::Color::yellow(), &bitmap_icon_lge, [&nav](){ nav.push<LGEView>(); } },
|
||||
{ "Morse", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push<MorseView>(); } },
|
||||
{ "BurgerPgr", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push<CoasterPagerView>(); } },
|
||||
//{ "Nuoptix DTMF", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push<NuoptixView>(); } },
|
||||
{ "OOK", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<EncodersView>(); } },
|
||||
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGTXView>(); } },
|
||||
{ "RDS", ui::Color::green(), &bitmap_icon_rds, [&nav](){ nav.push<RDSView>(); } },
|
||||
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGTXView>(); } },
|
||||
{ "RDS", ui::Color::green(), &bitmap_icon_rds, [&nav](){ nav.push<RDSView>(); } },
|
||||
{ "Soundbrd", ui::Color::green(), &bitmap_icon_soundboard,[&nav](){ nav.push<SoundBoardView>(); } },
|
||||
{ "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } },
|
||||
{ "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } },
|
||||
{ "TEDI/LCR", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push<LCRView>(); } },
|
||||
{ "TouchTune", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push<TouchTunesView>(); } },
|
||||
{ "Remote", ui::Color::dark_grey(), &bitmap_icon_remote, [&nav](){ nav.push<RemoteView>(); } },
|
||||
//{ "Remote", ui::Color::dark_grey(), &bitmap_icon_remote, [&nav](){ nav.push<RemoteView>(); } },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -402,15 +489,15 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
|
||||
UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
|
||||
add_items({
|
||||
//{ "Test app", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<TestView>(); } },
|
||||
//{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } },
|
||||
{ "Freq manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push<FrequencyManagerView>(); } },
|
||||
{ "File manager", ui::Color::yellow(), &bitmap_icon_file, [&nav](){ nav.push<FileManagerView>(); } },
|
||||
{ "Notepad", ui::Color::dark_grey(), &bitmap_icon_notepad, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "Signal gen", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push<SigGenView>(); } },
|
||||
//{ "Tone search", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<ToneSearchView>(); } },
|
||||
{ "Wave viewer", ui::Color::blue(), nullptr, [&nav](){ nav.push<ViewWavView>(); } },
|
||||
{ "Antenna length", ui::Color::yellow(), nullptr, [&nav](){ nav.push<WhipCalcView>(); } },
|
||||
{ "Wipe SD card", ui::Color::red(), nullptr, [&nav](){ nav.push<WipeSDView>(); } },
|
||||
//{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } },
|
||||
{ "Freq manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push<FrequencyManagerView>(); } },
|
||||
{ "File manager", ui::Color::yellow(), &bitmap_icon_dir, [&nav](){ nav.push<FileManagerView>(); } },
|
||||
//{ "Notepad", ui::Color::dark_grey(), &bitmap_icon_notepad, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "Signal gen", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push<SigGenView>(); } },
|
||||
//{ "Tone search", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push<ToneSearchView>(); } },
|
||||
{ "Wave viewer", ui::Color::yellow(), &bitmap_icon_soundboard, [&nav](){ nav.push<ViewWavView>(); } },
|
||||
{ "Antenna length", ui::Color::green(), &bitmap_icon_tools_antenna, [&nav](){ nav.push<WhipCalcView>(); } },
|
||||
{ "Wipe SD card", ui::Color::red(), &bitmap_icon_tools_wipesd, [&nav](){ nav.push<WipeSDView>(); } },
|
||||
});
|
||||
set_max_rows(2); // allow wider buttons
|
||||
}
|
||||
@@ -418,7 +505,7 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
|
||||
/* SystemMenuView ********************************************************/
|
||||
|
||||
void SystemMenuView::hackrf_mode(NavigationView& nav) {
|
||||
nav.push<ModalMessageView>("Confirm", "Switch to HackRF mode ?", YESNO,
|
||||
nav.push<ModalMessageView>("HackRF mode", " This mode enables HackRF\n functionality. To return,\n press the reset button.\n\n Switch to HackRF mode?", YESNO,
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
EventDispatcher::request_stop();
|
||||
@@ -429,21 +516,23 @@ void SystemMenuView::hackrf_mode(NavigationView& nav) {
|
||||
|
||||
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||
add_items({
|
||||
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
|
||||
{ "Receivers", ui::Color::dark_cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiversMenuView>(); } },
|
||||
{ "Transmit", ui::Color::green(), &bitmap_icon_transmit, [&nav](){ nav.push<TransmittersMenuView>(); } },
|
||||
{ "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
|
||||
{ "Replay", ui::Color::purple(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } },
|
||||
{ "Calls", ui::Color::yellow(), &bitmap_icon_closecall, [&nav](){ nav.push<SearchView>(); } },
|
||||
{ "Scanner", ui::Color::orange(), &bitmap_icon_scanner, [&nav](){ nav.push<ScannerView>(); } },
|
||||
{ "Utilities", ui::Color::light_grey(), &bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesMenuView>(); } },
|
||||
{ "Settings", ui::Color::cyan(), &bitmap_icon_setup, [&nav](){ nav.push<SettingsMenuView>(); } },
|
||||
{ "Debug", ui::Color::cyan(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } },
|
||||
//{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
|
||||
{ "Receive", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiversMenuView>(); } },
|
||||
{ "Transmit", ui::Color::cyan(), &bitmap_icon_transmit, [&nav](){ nav.push<TransmittersMenuView>(); } },
|
||||
{ "Capture", ui::Color::red(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
|
||||
{ "Replay", ui::Color::green(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } },
|
||||
{ "Calls", ui::Color::yellow(), &bitmap_icon_search, [&nav](){ nav.push<SearchView>(); } },
|
||||
{ "Scanner", ui::Color::green(), &bitmap_icon_scanner, [&nav](){ nav.push<ScannerView>(); } },
|
||||
{ "Microphone", ui::Color::yellow(), &bitmap_icon_microphone,[&nav](){ nav.push<MicTXView>(); } },
|
||||
{ "Tools", ui::Color::cyan(), &bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesMenuView>(); } },
|
||||
{ "Options", ui::Color::cyan(), &bitmap_icon_setup, [&nav](){ nav.push<SettingsMenuView>(); } },
|
||||
{ "Debug", ui::Color::light_grey(), &bitmap_icon_debug, [&nav](){ nav.push<DebugMenuView>(); } },
|
||||
{ "HackRF", ui::Color::cyan(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } },
|
||||
{ "About", ui::Color::cyan(), nullptr, [&nav](){ nav.push<AboutView>(); } }
|
||||
//{ "About", ui::Color::cyan(), nullptr, [&nav](){ nav.push<AboutView>(); } }
|
||||
});
|
||||
|
||||
set_highlighted(1); // Startup selection is "Receivers"
|
||||
set_max_rows(2); // allow wider buttons
|
||||
set_arrow_enabled(false);
|
||||
//set_highlighted(1); // Startup selection
|
||||
}
|
||||
|
||||
/* SystemView ************************************************************/
|
||||
@@ -463,6 +552,7 @@ SystemView::SystemView(
|
||||
set_style(&style_default);
|
||||
|
||||
constexpr ui::Dim status_view_height = 16;
|
||||
constexpr ui::Dim info_view_height = 16;
|
||||
|
||||
add_child(&status_view);
|
||||
status_view.set_parent_rect({
|
||||
@@ -478,11 +568,30 @@ SystemView::SystemView(
|
||||
{ 0, status_view_height },
|
||||
{ parent_rect.width(), static_cast<ui::Dim>(parent_rect.height() - status_view_height) }
|
||||
});
|
||||
|
||||
add_child(&info_view);
|
||||
info_view.set_parent_rect({
|
||||
{0, 19 * 16},
|
||||
{ parent_rect.width(), info_view_height }
|
||||
});
|
||||
|
||||
navigation_view.on_view_changed = [this](const View& new_view) {
|
||||
|
||||
if(!this->navigation_view.is_top()){
|
||||
remove_child(&info_view);
|
||||
}
|
||||
else{
|
||||
add_child(&info_view);
|
||||
}
|
||||
|
||||
this->status_view.set_back_enabled(!this->navigation_view.is_top());
|
||||
this->status_view.set_title_image_enabled(this->navigation_view.is_top());
|
||||
this->status_view.set_title(new_view.title());
|
||||
this->status_view.set_dirty();
|
||||
|
||||
};
|
||||
|
||||
|
||||
// portapack::persistent_memory::set_playdead_sequence(0x8D1);
|
||||
|
||||
// Initial view
|
||||
@@ -495,6 +604,9 @@ SystemView::SystemView(
|
||||
|
||||
if (portapack::persistent_memory::config_splash())
|
||||
navigation_view.push<BMPView>();
|
||||
status_view.set_back_enabled(false);
|
||||
status_view.set_title_image_enabled(true);
|
||||
status_view.set_dirty();
|
||||
//else
|
||||
// navigation_view.push<SystemMenuView>();
|
||||
|
||||
@@ -513,7 +625,6 @@ void BMPView::focus() {
|
||||
|
||||
BMPView::BMPView(NavigationView& nav) {
|
||||
add_children({
|
||||
&text_info,
|
||||
&button_done
|
||||
});
|
||||
|
||||
@@ -523,12 +634,12 @@ BMPView::BMPView(NavigationView& nav) {
|
||||
}
|
||||
|
||||
void BMPView::paint(Painter&) {
|
||||
portapack::display.drawBMP({(240 - 185) / 2, 0}, splash_bmp, false);
|
||||
portapack::display.drawBMP({(240 - 230) / 2, (320 - 50) / 2 - 10}, splash_bmp, false);
|
||||
}
|
||||
|
||||
/* NotImplementedView ****************************************************/
|
||||
|
||||
NotImplementedView::NotImplementedView(NavigationView& nav) {
|
||||
/*NotImplementedView::NotImplementedView(NavigationView& nav) {
|
||||
button_done.on_select = [&nav](Button&){
|
||||
nav.pop();
|
||||
};
|
||||
@@ -541,7 +652,7 @@ NotImplementedView::NotImplementedView(NavigationView& nav) {
|
||||
|
||||
void NotImplementedView::focus() {
|
||||
button_done.focus();
|
||||
}
|
||||
}*/
|
||||
|
||||
/* ModalMessageView ******************************************************/
|
||||
|
||||
|
||||
@@ -106,10 +106,11 @@ public:
|
||||
SystemStatusView(NavigationView& nav);
|
||||
|
||||
void set_back_enabled(bool new_value);
|
||||
void set_title_image_enabled(bool new_value);
|
||||
void set_title(const std::string new_value);
|
||||
|
||||
private:
|
||||
static constexpr auto default_title = "PortaPack|Havoc";
|
||||
static constexpr auto default_title = "";
|
||||
|
||||
NavigationView& nav_;
|
||||
|
||||
@@ -126,9 +127,23 @@ private:
|
||||
};
|
||||
|
||||
Text title {
|
||||
{ 20, 0, 16 * 8, 1 * 16 },
|
||||
{ 20, 0, 14 * 8, 1 * 16 },
|
||||
default_title,
|
||||
};
|
||||
|
||||
ImageButton button_title {
|
||||
{2, 0, 80, 16},
|
||||
&bitmap_titlebar_image,
|
||||
Color::white(),
|
||||
Color::dark_grey()
|
||||
};
|
||||
|
||||
ImageButton button_speaker {
|
||||
{ 17 * 8, 0, 2 * 8, 1 * 16 },
|
||||
&bitmap_icon_speaker_mute,
|
||||
Color::light_grey(),
|
||||
Color::dark_grey()
|
||||
};
|
||||
|
||||
ImageButton button_stealth {
|
||||
{ 19 * 8, 0, 2 * 8, 1 * 16 },
|
||||
@@ -176,10 +191,12 @@ private:
|
||||
{ 28 * 8, 0 * 16, 2 * 8, 1 * 16 }
|
||||
};
|
||||
|
||||
void on_speaker();
|
||||
void on_stealth();
|
||||
void on_bias_tee();
|
||||
//void on_textentry();
|
||||
void on_camera();
|
||||
void on_title();
|
||||
void refresh();
|
||||
|
||||
MessageHandlerRegistration message_handler_refresh {
|
||||
@@ -191,6 +208,29 @@ private:
|
||||
};
|
||||
};
|
||||
|
||||
class InformationView : public View {
|
||||
public:
|
||||
InformationView(NavigationView& nav);
|
||||
|
||||
private:
|
||||
static constexpr auto version_string = "v1.2.1";
|
||||
NavigationView& nav_;
|
||||
|
||||
Rectangle backdrop {
|
||||
{ 0, 0 * 16, 240, 16 },
|
||||
{33, 33, 33}
|
||||
};
|
||||
|
||||
Text version {
|
||||
{2, 0, 11 * 8, 16},
|
||||
version_string
|
||||
};
|
||||
|
||||
LiveDateTime ltime {
|
||||
{174, 0, 8 * 8, 16}
|
||||
};
|
||||
};
|
||||
|
||||
class BMPView : public View {
|
||||
public:
|
||||
BMPView(NavigationView& nav);
|
||||
@@ -245,11 +285,12 @@ public:
|
||||
|
||||
private:
|
||||
SystemStatusView status_view { navigation_view };
|
||||
InformationView info_view { navigation_view };
|
||||
NavigationView navigation_view { };
|
||||
Context& context_;
|
||||
};
|
||||
|
||||
class NotImplementedView : public View {
|
||||
/*class NotImplementedView : public View {
|
||||
public:
|
||||
NotImplementedView(NavigationView& nav);
|
||||
|
||||
@@ -265,7 +306,7 @@ private:
|
||||
{ 10 * 8, 13 * 16, 10 * 8, 24 },
|
||||
"Bummer",
|
||||
};
|
||||
};
|
||||
};*/
|
||||
|
||||
class ModalMessageView : public View {
|
||||
public:
|
||||
|
||||
@@ -201,6 +201,11 @@ void RecordView::start() {
|
||||
update_status_display();
|
||||
}
|
||||
|
||||
void RecordView::on_hide() {
|
||||
stop(); // Stop current recording
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
void RecordView::stop() {
|
||||
if( is_active() ) {
|
||||
capture_thread.reset();
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
void on_hide() override;
|
||||
|
||||
bool is_active() const;
|
||||
|
||||
|
||||
@@ -46,6 +46,18 @@ public:
|
||||
Incomplete = 0,
|
||||
OK = 1,
|
||||
};
|
||||
std::string ResultStr[10] = {
|
||||
"Compare",
|
||||
"Read incomplete",
|
||||
"Write incomplete",
|
||||
"Abort",
|
||||
"File Open Read",
|
||||
"File Open Write",
|
||||
"Heap",
|
||||
"Thread",
|
||||
"Incomplete",
|
||||
"OK",
|
||||
};
|
||||
|
||||
struct Stats {
|
||||
halrtcnt_t write_duration_min { 0 };
|
||||
@@ -423,7 +435,7 @@ void SDCardDebugView::on_test() {
|
||||
format_bytes_per_ticks_as_mib(stats.read_bytes, stats.read_test_duration)
|
||||
);
|
||||
} else {
|
||||
text_test_write_time_value.set("Fail: " + to_string_dec_int(toUType(thread.result()), 4));
|
||||
text_test_write_time_value.set("Fail: " + thread.ResultStr[thread.result() + 8]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,14 @@ void NarrowbandAMAudio::execute(const buffer_c8_t& buffer) {
|
||||
|
||||
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
|
||||
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
|
||||
|
||||
channel_spectrum.feed(decim_1_out, channel_filter_pass_f, channel_filter_stop_f);
|
||||
|
||||
const auto decim_2_out = decim_2.execute(decim_1_out, dst_buffer);
|
||||
const auto channel_out = channel_filter.execute(decim_2_out, dst_buffer);
|
||||
|
||||
// TODO: Feed channel_stats post-decimation data?
|
||||
feed_channel_stats(channel_out);
|
||||
channel_spectrum.feed(channel_out, channel_filter_pass_f, channel_filter_stop_f);
|
||||
|
||||
auto audio = demodulate(channel_out);
|
||||
audio_compressor.execute_in_place(audio);
|
||||
@@ -93,7 +95,7 @@ void NarrowbandAMAudio::configure(const AMConfigureMessage& message) {
|
||||
channel_filter.configure(message.channel_filter.taps, channel_filter_decimation_factor);
|
||||
channel_filter_pass_f = message.channel_filter.pass_frequency_normalized * channel_filter_input_fs;
|
||||
channel_filter_stop_f = message.channel_filter.stop_frequency_normalized * channel_filter_input_fs;
|
||||
channel_spectrum.set_decimation_factor(std::floor(channel_filter_output_fs / (channel_filter_pass_f + channel_filter_stop_f)));
|
||||
channel_spectrum.set_decimation_factor(1.0f);
|
||||
modulation_ssb = (message.modulation == AMConfigureMessage::Modulation::SSB);
|
||||
audio_output.configure(message.audio_hpf_config);
|
||||
|
||||
|
||||
@@ -58,34 +58,18 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) {
|
||||
}
|
||||
|
||||
// Fill and "stretch"
|
||||
for (size_t i = 0; i < buffer.count; i++) {
|
||||
/*if (i & 3) {
|
||||
buffer.p[i] = buffer.p[i - 1];
|
||||
} else {
|
||||
auto re_out = iq_buffer.p[i >> 3].real() ;
|
||||
auto im_out = iq_buffer.p[i >> 3].imag() ;
|
||||
buffer.p[i] = { (int8_t)re_out, (int8_t)im_out };
|
||||
}*/
|
||||
/*
|
||||
if (i % 8 != 0) {
|
||||
buffer.p[i] = buffer.p[i - 1];
|
||||
} else {
|
||||
auto re_out = iq_buffer.p[i/8].real() ;
|
||||
auto im_out = iq_buffer.p[i/8].imag() ;
|
||||
buffer.p[i] = { (int8_t)re_out, (int8_t)im_out };
|
||||
}*/
|
||||
|
||||
auto re_out = iq_buffer.p[i].real() ;
|
||||
auto im_out = iq_buffer.p[i].imag() ;
|
||||
for (size_t i = 0; i < buffer.count; i++) {
|
||||
auto re_out = iq_buffer.p[i].real() ;
|
||||
auto im_out = iq_buffer.p[i].imag() ;
|
||||
buffer.p[i] = { (int8_t)re_out, (int8_t)im_out };
|
||||
}
|
||||
|
||||
spectrum_samples += buffer.count;
|
||||
if( spectrum_samples >= spectrum_interval_samples ) {
|
||||
spectrum_samples -= spectrum_interval_samples;
|
||||
//channel_spectrum.feed(iq_buffer, channel_filter_pass_f, channel_filter_stop_f);
|
||||
|
||||
txprogress_message.progress = bytes_read; // Inform UI about progress
|
||||
|
||||
txprogress_message.progress = bytes_read / 1024; // Inform UI about progress
|
||||
|
||||
txprogress_message.done = false;
|
||||
shared_memory.application_queue.push(txprogress_message);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ private:
|
||||
ToneGen tone_gen { };
|
||||
ToneGen beep_gen { };
|
||||
|
||||
uint32_t divider { }, audio_gain { };
|
||||
uint32_t divider { };
|
||||
float audio_gain { };
|
||||
uint64_t power_acc { 0 };
|
||||
uint32_t power_acc_count { 0 };
|
||||
bool play_beep { false };
|
||||
|
||||
@@ -38,10 +38,12 @@ void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) {
|
||||
|
||||
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
|
||||
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
|
||||
|
||||
channel_spectrum.feed(decim_1_out, channel_filter_pass_f, channel_filter_stop_f);
|
||||
|
||||
const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer);
|
||||
|
||||
feed_channel_stats(channel_out);
|
||||
channel_spectrum.feed(channel_out, channel_filter_pass_f, channel_filter_stop_f);
|
||||
|
||||
if (!pitch_rssi_enabled) {
|
||||
// Normal mode, output demodulated audio
|
||||
@@ -145,7 +147,7 @@ void NarrowbandFMAudio::configure(const NBFMConfigureMessage& message) {
|
||||
demod.configure(demod_input_fs, message.deviation);
|
||||
channel_filter_pass_f = message.channel_filter.pass_frequency_normalized * channel_filter_input_fs;
|
||||
channel_filter_stop_f = message.channel_filter.stop_frequency_normalized * channel_filter_input_fs;
|
||||
channel_spectrum.set_decimation_factor(std::floor(channel_filter_output_fs / (channel_filter_pass_f + channel_filter_stop_f)));
|
||||
channel_spectrum.set_decimation_factor(1.0f);
|
||||
audio_output.configure(message.audio_hpf_config, message.audio_deemph_config, (float)message.squelch_level / 100.0);
|
||||
|
||||
hpf.configure(audio_24k_hpf_30hz_config);
|
||||
|
||||
@@ -47,8 +47,11 @@ void POCSAGProcessor::execute(const buffer_c8_t& buffer) {
|
||||
const int32_t audio_sample = __SSAT(sample_int, 16);
|
||||
|
||||
slicer_sr <<= 1;
|
||||
slicer_sr |= (audio_sample < 0); // Do we need hysteresis ?
|
||||
|
||||
if (phase == 0)
|
||||
slicer_sr |= (audio_sample < 0); // Do we need hysteresis ?
|
||||
else
|
||||
slicer_sr |= !(audio_sample < 0);
|
||||
|
||||
// Detect transitions to adjust clock
|
||||
if ((slicer_sr ^ (slicer_sr >> 1)) & 1) {
|
||||
if (sphase < (0x8000u - sphase_delta_half))
|
||||
@@ -162,6 +165,7 @@ void POCSAGProcessor::configure(const POCSAGConfigureMessage& message) {
|
||||
//audio_output.configure(false);
|
||||
|
||||
bitrate = message.bitrate;
|
||||
phase = message.phase;
|
||||
sphase_delta = 0x10000u * bitrate / POCSAG_AUDIO_RATE;
|
||||
sphase_delta_half = sphase_delta / 2; // Just for speed
|
||||
sphase_delta_eighth = sphase_delta / 8;
|
||||
|
||||
@@ -95,6 +95,7 @@ private:
|
||||
bool configured = false;
|
||||
rx_states rx_state { WAITING };
|
||||
pocsag::BitRate bitrate { pocsag::BitRate::FSK1200 };
|
||||
bool phase;
|
||||
uint32_t codeword_count { 0 };
|
||||
pocsag::POCSAGPacket packet { };
|
||||
|
||||
|
||||
@@ -140,7 +140,8 @@ private:
|
||||
}
|
||||
};
|
||||
PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder_fsk_4800_Vaisala {
|
||||
{ 0b00001000011011010101001110001000, 32, 1 },
|
||||
{ 0b00001000011011010101001110001000, 32, 1 }, //euquiq Header detects 4 of 8 bytes 0x10B6CA11 /this is in raw format) (these bits are not passed at the beginning of packet)
|
||||
//{ 0b0000100001101101010100111000100001000100011010010100100000011111, 64, 1 }, //euquiq whole header detection would be 8 bytes.
|
||||
{ },
|
||||
{ 320 * 8 },
|
||||
[this](const baseband::Packet& packet) {
|
||||
|
||||
@@ -65,7 +65,7 @@ size_t StreamInput::write(const void* const data, const size_t length) {
|
||||
break;
|
||||
}
|
||||
active_buffer = nullptr;
|
||||
creg::m4txevent::assert();
|
||||
creg::m4txevent::assert_event();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ size_t StreamOutput::read(void* const data, const size_t length) {
|
||||
}
|
||||
// Tell M0 (IRQ) that a buffer has been consumed.
|
||||
active_buffer = nullptr;
|
||||
creg::m4txevent::assert();
|
||||
creg::m4txevent::assert_event();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -300,8 +300,8 @@ void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint
|
||||
|
||||
v_rate_coded = (v_rate / 64) + 1;
|
||||
|
||||
velo_ew_abs = abs(velo_ew);
|
||||
velo_ns_abs = abs(velo_ns);
|
||||
velo_ew_abs = abs(velo_ew) + 1;
|
||||
velo_ns_abs = abs(velo_ns) + 1;
|
||||
v_rate_coded_abs = abs(v_rate_coded);
|
||||
|
||||
make_frame_adsb(frame, ICAO_address);
|
||||
@@ -317,4 +317,52 @@ void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint
|
||||
frame.make_CRC();
|
||||
}
|
||||
|
||||
// Decoding method from dump1090
|
||||
adsb_vel decode_frame_velo(ADSBFrame& frame){
|
||||
adsb_vel velo {false, 0, 0};
|
||||
|
||||
uint8_t * frame_data = frame.get_raw_data();
|
||||
uint8_t velo_type = frame.get_msg_sub();
|
||||
|
||||
if(velo_type >= 1 && velo_type <= 4){ //vertical rate is always present
|
||||
|
||||
velo.v_rate = (((frame_data[8] & 0x07 ) << 6) | ((frame_data[9]) >> 2) - 1) * 64;
|
||||
|
||||
if((frame_data[8] & 0x8) >> 3) velo.v_rate *= -1; //check v_rate sign
|
||||
}
|
||||
|
||||
if(velo_type == 1 || velo_type == 2){ //Ground Speed
|
||||
int32_t raw_ew = ((frame_data[5] & 0x03) << 8) | frame_data[6];
|
||||
int32_t velo_ew = raw_ew - 1; //velocities are all offset by one (this is part of the spec)
|
||||
|
||||
int32_t raw_ns = ((frame_data[7] & 0x7f) << 3) | (frame_data[8] >> 5);
|
||||
int32_t velo_ns = raw_ns - 1;
|
||||
|
||||
if (velo_type == 2){ // supersonic indicator so multiply by 4
|
||||
velo_ew = velo_ew << 2;
|
||||
velo_ns = velo_ns << 2;
|
||||
}
|
||||
|
||||
if(frame_data[5]&0x04) velo_ew *= -1; //check ew direction sign
|
||||
if(frame_data[7]&0x80) velo_ns *= -1; //check ns direction sign
|
||||
|
||||
velo.speed = sqrt(velo_ns*velo_ns + velo_ew*velo_ew);
|
||||
|
||||
if(velo.speed){
|
||||
//calculate heading in degrees from ew/ns velocities
|
||||
int16_t heading_temp = (int16_t)(atan2(velo_ew,velo_ns) * 180.0 / pi);
|
||||
// We don't want negative values but a 0-360 scale.
|
||||
if (heading_temp < 0) heading_temp += 360.0;
|
||||
velo.heading = (uint16_t)heading_temp;
|
||||
}
|
||||
|
||||
}else if(velo_type == 3 || velo_type == 4){ //Airspeed
|
||||
velo.valid = frame_data[5] & (1<<2);
|
||||
velo.heading = ((((frame_data[5] & 0x03)<<8) | frame_data[6]) * 45) << 7;
|
||||
}
|
||||
|
||||
return velo;
|
||||
|
||||
}
|
||||
|
||||
} /* namespace adsb */
|
||||
|
||||
@@ -56,6 +56,13 @@ struct adsb_pos {
|
||||
int32_t altitude;
|
||||
};
|
||||
|
||||
struct adsb_vel {
|
||||
bool valid;
|
||||
int32_t speed; //knot
|
||||
uint16_t heading; //degree
|
||||
int32_t v_rate; //ft/min
|
||||
};
|
||||
|
||||
const float CPR_MAX_VALUE = 131072.0;
|
||||
|
||||
const float adsb_lat_lut[58] = {
|
||||
@@ -89,6 +96,8 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd);
|
||||
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
|
||||
const float angle, const int32_t v_rate);
|
||||
|
||||
adsb_vel decode_frame_velo(ADSBFrame& frame);
|
||||
|
||||
//void encode_frame_emergency(ADSBFrame& frame, const uint32_t ICAO_address, const uint8_t code);
|
||||
|
||||
void encode_frame_squawk(ADSBFrame& frame, const uint32_t squawk);
|
||||
|
||||
@@ -41,6 +41,10 @@ public:
|
||||
return (raw_data[4] >> 3);
|
||||
}
|
||||
|
||||
uint8_t get_msg_sub() {
|
||||
return (raw_data[4] & 7);
|
||||
}
|
||||
|
||||
uint32_t get_ICAO_address() {
|
||||
return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
|
||||
}
|
||||
|
||||
@@ -313,6 +313,31 @@ constexpr fir_taps_complex<64> taps_2k8_lsb_channel {
|
||||
} },
|
||||
};
|
||||
|
||||
// USB AM 700Hz filter: fs=12000, start=600, end=800, width=200, stop=40db, decim=1, fout=12000
|
||||
|
||||
constexpr fir_taps_complex<64> taps_0k7_usb_channel {
|
||||
.pass_frequency_normalized = 3000.0f / 12000.0f,
|
||||
.stop_frequency_normalized = 3300.0f / 12000.0f,
|
||||
.taps = { {
|
||||
{ 531, 0 }, { 192, 73 }, { 181, 163 }, { 129, 254 },
|
||||
{ 34, 328 }, { -97, 364 }, { -251, 345 }, { -403, 261 },
|
||||
{ -524, 111 }, { -585, -92 }, { -564, -326 }, { -448, -554 },
|
||||
{ -239, -737 }, { 43, -836 }, { 366, -822 }, { 681, -681 },
|
||||
{ 936, -417 }, { 1085, -56 }, { 1090, 354 }, { 935, 757 },
|
||||
{ 629, 1090 }, { 205, 1296 }, { -283, 1331 }, { -766, 1180 },
|
||||
{ -1172, 851 }, { -1435, 384 }, { -1510, -158 }, { -1377, -702 },
|
||||
{ -1049, -1165 }, { -568, -1480 }, { 0, -1596 }, { 574, -1496 },
|
||||
{ 1072, -1191 }, { 1422, -724 }, { 1576, -165 }, { 1515, 406 },
|
||||
{ 1251, 908 }, { 827, 1273 }, { 309, 1453 }, { -226, 1431 },
|
||||
{ -703, 1218 }, { -1058, 856 }, { -1248, 405 }, { -1257, -65 },
|
||||
{ -1100, -489 }, { -810, -810 }, { -441, -992 }, { -53, -1024 },
|
||||
{ 297, -916 }, { 566, -699 }, { 725, -418 }, { 765, -121 },
|
||||
{ 697, 148 }, { 546, 355 }, { 348, 479 }, { 138, 517 },
|
||||
{ -50, 477 }, { -194, 381 }, { -280, 252 }, { -308, 118 },
|
||||
{ -285, 0 }, { -228, -87 }, { -153, -138 }, { -241, -473 },
|
||||
} },
|
||||
};
|
||||
|
||||
// WFM 200KF8E emission type //////////////////////////////////////////////
|
||||
|
||||
// IFIR image-reject filter: fs=3072000, pass=100000, stop=484000, decim=4, fout=768000
|
||||
|
||||
@@ -69,7 +69,7 @@ inline void disable() {
|
||||
#endif
|
||||
|
||||
#if defined(LPC43XX_M4)
|
||||
inline void assert() {
|
||||
inline void assert_event() {
|
||||
__SEV();
|
||||
}
|
||||
#endif
|
||||
@@ -93,7 +93,7 @@ inline void disable() {
|
||||
#endif
|
||||
|
||||
#if defined(LPC43XX_M0)
|
||||
inline void assert() {
|
||||
inline void assert_event() {
|
||||
__SEV();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -989,13 +989,16 @@ public:
|
||||
class POCSAGConfigureMessage : public Message {
|
||||
public:
|
||||
constexpr POCSAGConfigureMessage(
|
||||
const pocsag::BitRate bitrate
|
||||
const pocsag::BitRate bitrate,
|
||||
const bool phase
|
||||
) : Message { ID::POCSAGConfigure },
|
||||
bitrate(bitrate)
|
||||
bitrate(bitrate),
|
||||
phase(phase)
|
||||
{
|
||||
}
|
||||
|
||||
const pocsag::BitRate bitrate;
|
||||
const bool phase;
|
||||
};
|
||||
|
||||
class ADSBConfigureMessage : public Message {
|
||||
|
||||
@@ -26,12 +26,12 @@ using namespace lpc43xx;
|
||||
|
||||
#if defined(LPC43XX_M0)
|
||||
void MessageQueue::signal() {
|
||||
creg::m0apptxevent::assert();
|
||||
creg::m0apptxevent::assert_event();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LPC43XX_M4)
|
||||
void MessageQueue::signal() {
|
||||
creg::m4txevent::assert();
|
||||
creg::m4txevent::assert_event();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -218,10 +218,17 @@ void set_playdead_sequence(const uint32_t new_value) {
|
||||
data->playdead_magic = playdead_magic;
|
||||
}
|
||||
|
||||
bool config_speaker() {
|
||||
return (data->ui_config & 0x10000000UL) ? false : true; // Default true
|
||||
}
|
||||
bool stealth_mode() {
|
||||
return (data->ui_config & 0x20000000UL) ? true : false;
|
||||
}
|
||||
|
||||
void set_config_speaker(bool new_value) {
|
||||
data->ui_config = (data->ui_config & ~0x10000000UL) | (!new_value << 28);
|
||||
}
|
||||
|
||||
void set_stealth_mode(const bool v) {
|
||||
data->ui_config = (data->ui_config & ~0x20000000UL) | (v << 29);
|
||||
}
|
||||
@@ -235,7 +242,7 @@ bool config_login() {
|
||||
}
|
||||
|
||||
uint32_t config_backlight_timer() {
|
||||
const uint32_t timer_seconds[8] = { 0, 5, 15, 60, 300, 600, 600, 600 };
|
||||
const uint32_t timer_seconds[8] = { 0, 5, 15, 30, 60, 180, 300, 600 };
|
||||
|
||||
return timer_seconds[data->ui_config & 0x00000007UL];
|
||||
}
|
||||
|
||||
@@ -76,10 +76,12 @@ void set_stealth_mode(const bool v);
|
||||
|
||||
bool config_splash();
|
||||
bool config_login();
|
||||
bool config_speaker();
|
||||
uint32_t config_backlight_timer();
|
||||
|
||||
void set_config_splash(bool v);
|
||||
void set_config_login(bool v);
|
||||
void set_config_speaker(bool new_value);
|
||||
void set_config_backlight_timer(uint32_t i);
|
||||
|
||||
//uint8_t ui_config_textentry();
|
||||
|
||||
@@ -22,9 +22,29 @@
|
||||
|
||||
#include "sonde_packet.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include <cstring>
|
||||
//#include <complex>
|
||||
|
||||
namespace sonde {
|
||||
|
||||
//Defines for Vaisala RS41, from https://github.com/rs1729/RS/blob/master/rs41/rs41sg.c
|
||||
#define MASK_LEN 64
|
||||
|
||||
//Following values include the 4 bytes less shift, consumed in detecting the header on proc_sonde
|
||||
#define block_status 0x35 //0x039 // 40 bytes
|
||||
#define block_gpspos 0x10E //0x112 // 21 bytes
|
||||
#define block_meas 0x61 //0x65 // 42 bytes
|
||||
#define pos_FrameNb 0x37 //0x03B // 2 byte
|
||||
#define pos_SondeID 0x39 //0x03D // 8 byte
|
||||
#define pos_Voltage 0x041 //0x045 // 3 bytes (but first one is the important one) voltage x 10 ie: 26 = 2.6v
|
||||
#define pos_CalData 0x04E //0x052 // 1 byte, counter 0x00..0x32
|
||||
#define pos_temp 0x063 //0x067 // 3 bytes (uint24_t)
|
||||
#define pos_GPSecefX 0x110 //0x114 // 4 byte
|
||||
#define pos_GPSecefY 0x114 //0x118 // 4 byte (not actually used since Y and Z are following X, and grabbed in that same loop)
|
||||
#define pos_GPSecefZ 0x118 //0x11C // 4 byte (same as Y)
|
||||
|
||||
#define PI 3.1415926535897932384626433832795 //3.1416 //(3.1415926535897932384626433832795)
|
||||
|
||||
Packet::Packet(
|
||||
const baseband::Packet& packet,
|
||||
const Type type
|
||||
@@ -48,10 +68,6 @@ size_t Packet::length() const {
|
||||
return decoder_.symbols_count();
|
||||
}
|
||||
|
||||
bool Packet::is_valid() const {
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
Timestamp Packet::received_at() const {
|
||||
return packet_.timestamp();
|
||||
}
|
||||
@@ -60,93 +76,346 @@ Packet::Type Packet::type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
/*uint8_t Packet::vaisala_descramble(const uint32_t pos) {
|
||||
return reader_raw.read(pos * 8, 8) ^ vaisala_mask[pos & 63];
|
||||
};*/
|
||||
//euquiq here:
|
||||
//RS41SG 320 bits header, 320bytes frame (or more if it is an "extended frame")
|
||||
//The raw data is xor-scrambled with the values in the 64 bytes vaisala_mask (see.hpp)
|
||||
//from 0x008 to 0x037 (48 bytes reed-solomon error correction data)
|
||||
|
||||
uint32_t Packet::GPS_altitude() const {
|
||||
uint8_t Packet::vaisala_descramble(const uint32_t pos) const
|
||||
{ //vaisala_descramble(const uint32_t pos) const {
|
||||
// packet_[i]; its a bit; packet_.size the total (should be 2560 bits)
|
||||
uint8_t value = 0;
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
value = (value << 1) | packet_[(pos * 8) + (7 - i)]; //get the byte from the bits collection
|
||||
|
||||
//packetReader reader { packet_ }; //This works just as above.
|
||||
//value = reader.read(pos * 8,8);
|
||||
//shift pos because first 4 bytes are consumed by proc_sonde in finding the vaisala signature
|
||||
uint32_t mask_pos = pos + 4;
|
||||
value = value ^ vaisala_mask[mask_pos % MASK_LEN]; //descramble with the xor pseudorandom table
|
||||
return value;
|
||||
};
|
||||
|
||||
GPS_data Packet::get_GPS_data() const
|
||||
{
|
||||
GPS_data result;
|
||||
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
|
||||
return (reader_bi_m.read(22 * 8, 32) / 1000) - 48;
|
||||
else if (type_ == Type::Vaisala_RS41_SG) {
|
||||
/*uint32_t altitude_ecef = 0;
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
altitude_ecef = (altitude_ecef << 8) + vaisala_descramble(0x11C + i);*/
|
||||
// TODO: and a bunch of maths (see ecef2elli() from RS1729)
|
||||
return 0;
|
||||
} else
|
||||
return 0; // Unknown
|
||||
{
|
||||
|
||||
result.alt = (reader_bi_m.read(22 * 8, 32) / 1000) - 48;
|
||||
result.lat = reader_bi_m.read(14 * 8, 32) / ((1ULL << 32) / 360.0);
|
||||
result.lon = reader_bi_m.read(18 * 8, 32) / ((1ULL << 32) / 360.0);
|
||||
}
|
||||
else if (type_ == Type::Vaisala_RS41_SG)
|
||||
{
|
||||
|
||||
uint8_t XYZ_bytes[4];
|
||||
int32_t XYZ; // 32bit
|
||||
double_t X[3];
|
||||
for (int32_t k = 0; k < 3; k++)
|
||||
{ //Get X,Y,Z ECEF position from GPS
|
||||
for (int32_t i = 0; i < 4; i++) //each one is 4 bytes (32 bits)
|
||||
XYZ_bytes[i] = vaisala_descramble(pos_GPSecefX + (4 * k) + i);
|
||||
memcpy(&XYZ, XYZ_bytes, 4);
|
||||
X[k] = XYZ / 100.0;
|
||||
}
|
||||
|
||||
double_t a = 6378137.0;
|
||||
double_t b = 6356752.31424518;
|
||||
double_t e = sqrt((a * a - b * b) / (a * a));
|
||||
double_t ee = sqrt((a * a - b * b) / (b * b));
|
||||
|
||||
double_t lam = atan2(X[1], X[0]);
|
||||
double_t p = sqrt(X[0] * X[0] + X[1] * X[1]);
|
||||
double_t t = atan2(X[2] * a, p * b);
|
||||
double_t phi = atan2(X[2] + ee * ee * b * sin(t) * sin(t) * sin(t),
|
||||
p - e * e * a * cos(t) * cos(t) * cos(t));
|
||||
|
||||
double_t R = a / sqrt(1 - e * e * sin(phi) * sin(phi));
|
||||
|
||||
result.alt = p / cos(phi) - R;
|
||||
result.lat = phi * 180 / PI;
|
||||
result.lon = lam * 180 / PI;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float Packet::GPS_latitude() const {
|
||||
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
|
||||
return reader_bi_m.read(14 * 8, 32) / ((1ULL << 32) / 360.0);
|
||||
//else if (type_ == Type::Vaisala_RS41_SG)
|
||||
// return vaisala_descramble();
|
||||
else
|
||||
return 0; // Unknown
|
||||
}
|
||||
|
||||
float Packet::GPS_longitude() const {
|
||||
if ((type_ == Type::Meteomodem_M10) || (type_ == Type::Meteomodem_M2K2))
|
||||
return reader_bi_m.read(18 * 8, 32) / ((1ULL << 32) / 360.0);
|
||||
else
|
||||
return 0; // Unknown
|
||||
}
|
||||
|
||||
uint32_t Packet::battery_voltage() const {
|
||||
uint32_t Packet::battery_voltage() const
|
||||
{
|
||||
if (type_ == Type::Meteomodem_M10)
|
||||
return (reader_bi_m.read(69 * 8, 8) + (reader_bi_m.read(70 * 8, 8) << 8)) * 1000 / 150;
|
||||
else if (type_ == Type::Meteomodem_M2K2)
|
||||
return reader_bi_m.read(69 * 8, 8) * 66; // Actually 65.8
|
||||
return reader_bi_m.read(69 * 8, 8) * 66; // Actually 65.8
|
||||
else if (type_ == Type::Vaisala_RS41_SG)
|
||||
{
|
||||
uint32_t voltage = vaisala_descramble(pos_Voltage) * 100; //byte 69 = voltage * 10 (check if this value needs to be multiplied)
|
||||
return voltage;
|
||||
}
|
||||
else
|
||||
return 0; // Unknown
|
||||
}
|
||||
|
||||
std::string Packet::type_string() const {
|
||||
switch (type_) {
|
||||
case Type::Unknown: return "Unknown";
|
||||
case Type::Meteomodem_unknown: return "Meteomodem ???";
|
||||
case Type::Meteomodem_M10: return "Meteomodem M10";
|
||||
case Type::Meteomodem_M2K2: return "Meteomodem M2K2";
|
||||
case Type::Vaisala_RS41_SG: return "Vaisala RS41-SG";
|
||||
default: return "? 0x" + symbols_formatted().data.substr(0, 6);
|
||||
{
|
||||
return 0; // Unknown
|
||||
}
|
||||
}
|
||||
|
||||
std::string Packet::serial_number() const {
|
||||
if (type() == Type::Meteomodem_M10) {
|
||||
uint32_t Packet::frame() const
|
||||
{
|
||||
if (type_ == Type::Vaisala_RS41_SG)
|
||||
{
|
||||
uint32_t frame_number = vaisala_descramble(pos_FrameNb) | (vaisala_descramble(pos_FrameNb + 1) << 8);
|
||||
return frame_number;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; // Unknown
|
||||
}
|
||||
}
|
||||
|
||||
temp_humid Packet::get_temp_humid() const
|
||||
{
|
||||
temp_humid result;
|
||||
result.humid = 0;
|
||||
result.temp = 0;
|
||||
|
||||
if ( type_ == Type::Vaisala_RS41_SG && crc_ok_RS41() ) //Only process if packet is healthy
|
||||
{
|
||||
//memset(calfrchk, 0, 51); // is this necessary ? only if the sondeID changes (new sonde)
|
||||
//original code from https://github.com/rs1729/RS/blob/master/rs41/rs41ptu.c
|
||||
float Rf1, // ref-resistor f1 (750 Ohm)
|
||||
Rf2, // ref-resistor f2 (1100 Ohm)
|
||||
co1[3], // { -243.911 , 0.187654 , 8.2e-06 }
|
||||
calT1[3], // calibration T1
|
||||
co2[3], // { -243.911 , 0.187654 , 8.2e-06 }
|
||||
calT2[3], // calibration T2-Hum
|
||||
calH[2]; // calibration Hum
|
||||
|
||||
uint32_t meas[12], i;
|
||||
|
||||
//-------------- get_CalData
|
||||
|
||||
//-------------- populate calibytes (from getFrameConf)
|
||||
|
||||
uint8_t calfr = vaisala_descramble(pos_CalData); //get subframe #slot
|
||||
|
||||
for (i = 0; i < 16; i++) //Load subrfame calibration page (16 bytes) into #slot
|
||||
calibytes[calfr * 16 + i] = vaisala_descramble(pos_CalData + 1 + i); //pos = pos_CalData + 1 + i ; vaisala_descramble(pos)
|
||||
|
||||
calfrchk[calfr] = 1; //flag this #slot as populated
|
||||
|
||||
memcpy(&Rf1, calibytes + 61, 4); // 0x03*0x10+13
|
||||
memcpy(&Rf2, calibytes + 65, 4); // 0x04*0x10+ 1
|
||||
|
||||
memcpy(co1 + 0, calibytes + 77, 4); // 0x04*0x10+13
|
||||
memcpy(co1 + 1, calibytes + 81, 4); // 0x05*0x10+ 1
|
||||
memcpy(co1 + 2, calibytes + 85, 4); // 0x05*0x10+ 5
|
||||
|
||||
memcpy(calT1 + 0, calibytes + 89, 4); // 0x05*0x10+ 9
|
||||
memcpy(calT1 + 1, calibytes + 93, 4); // 0x05*0x10+13
|
||||
memcpy(calT1 + 2, calibytes + 97, 4); // 0x06*0x10+ 1
|
||||
|
||||
memcpy(calH + 0, calibytes + 117, 4); // 0x07*0x10+ 5
|
||||
memcpy(calH + 1, calibytes + 121, 4); // 0x07*0x10+ 9
|
||||
|
||||
memcpy(co2 + 0, calibytes + 293, 4); // 0x12*0x10+ 5
|
||||
memcpy(co2 + 1, calibytes + 297, 4); // 0x12*0x10+ 9
|
||||
memcpy(co2 + 2, calibytes + 301, 4); // 0x12*0x10+13
|
||||
|
||||
memcpy(calT2 + 0, calibytes + 305, 4); // 0x13*0x10+ 1
|
||||
memcpy(calT2 + 1, calibytes + 309, 4); // 0x13*0x10+ 5
|
||||
memcpy(calT2 + 2, calibytes + 313, 4); // 0x13*0x10+ 9
|
||||
//---------------------------------------
|
||||
for (i = 0; i < 12; i++)
|
||||
meas[i] = vaisala_descramble(pos_temp + (3 * i)) |
|
||||
(vaisala_descramble(pos_temp + (3 * i) + 1) << 8) |
|
||||
(vaisala_descramble(pos_temp + (3 * i) + 2) << 16);
|
||||
|
||||
//----Check if necessary calibytes are already present for calculation
|
||||
|
||||
if (calfrchk[0x03] && calfrchk[0x04] && calfrchk[0x04] && calfrchk[0x05] && calfrchk[0x05] && calfrchk[0x06]) //Calibites OK for Temperature
|
||||
{
|
||||
//----------get_Tc------------------------
|
||||
float *p = co1;
|
||||
float *c = calT1;
|
||||
float g = (float)(meas[2] - meas[1]) / (Rf2 - Rf1), // gain
|
||||
Rb = (meas[1] * Rf2 - meas[2] * Rf1) / (float)(meas[2] - meas[1]), // ofs
|
||||
Rc = meas[0] / g - Rb,
|
||||
R = Rc * c[0],
|
||||
T = (p[0] + p[1] * R + p[2] * R * R + c[1]) * (1.0 + c[2]);
|
||||
result.temp = T;
|
||||
}
|
||||
|
||||
if (calfrchk[0x07])
|
||||
{
|
||||
//----------get_RH------------------------
|
||||
float a0 = 7.5; // empirical
|
||||
float a1 = 350.0 / calH[0]; // empirical
|
||||
float fh = (meas[3] - meas[4]) / (float)(meas[5] - meas[4]);
|
||||
float rh = 100.0 * (a1 * fh - a0);
|
||||
float T0 = 0.0, T1 = -25.0; // T/C
|
||||
rh += T0 - result.temp / 5.5; // empir. temperature compensation
|
||||
if (result.temp < T1)
|
||||
rh *= 1.0 + (T1 - result.temp) / 90.0; // empir. temperature compensation
|
||||
if (rh < 0.0)
|
||||
rh = 0.0;
|
||||
if (rh > 100.0)
|
||||
rh = 100.0;
|
||||
if (result.temp < -273.0)
|
||||
rh = -1.0;
|
||||
result.humid = rh;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Packet::type_string() const
|
||||
{
|
||||
switch (type_)
|
||||
{
|
||||
case Type::Unknown:
|
||||
return "Unknown";
|
||||
case Type::Meteomodem_unknown:
|
||||
return "Meteomodem ???";
|
||||
case Type::Meteomodem_M10:
|
||||
return "Meteomodem M10";
|
||||
case Type::Meteomodem_M2K2:
|
||||
return "Meteomodem M2K2";
|
||||
case Type::Vaisala_RS41_SG:
|
||||
return "Vaisala RS41-SG";
|
||||
default:
|
||||
return "? 0x" + symbols_formatted().data.substr(0, 6);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Packet::serial_number() const
|
||||
{
|
||||
if (type_ == Type::Meteomodem_M10)
|
||||
{
|
||||
// See https://github.com/rs1729/RS/blob/master/m10/m10x.c line 606
|
||||
// Starting at byte #93: 00000000 11111111 22222222 33333333 44444444
|
||||
// CCCC AAAABBBB
|
||||
// 44444444 33333333
|
||||
// DDDEEEEE EEEEEEEE
|
||||
|
||||
|
||||
return to_string_hex(reader_bi_m.read(93 * 8 + 16, 4), 1) +
|
||||
to_string_dec_uint(reader_bi_m.read(93 * 8 + 20, 4), 2, '0') + " " +
|
||||
to_string_hex(reader_bi_m.read(93 * 8 + 4, 4), 1) + " " +
|
||||
to_string_dec_uint(reader_bi_m.read(93 * 8 + 24, 3), 1) +
|
||||
to_string_dec_uint(reader_bi_m.read(93 * 8 + 27, 13), 4, '0');
|
||||
|
||||
} else
|
||||
to_string_dec_uint(reader_bi_m.read(93 * 8 + 20, 4), 2, '0') + " " +
|
||||
to_string_hex(reader_bi_m.read(93 * 8 + 4, 4), 1) + " " +
|
||||
to_string_dec_uint(reader_bi_m.read(93 * 8 + 24, 3), 1) +
|
||||
to_string_dec_uint(reader_bi_m.read(93 * 8 + 27, 13), 4, '0');
|
||||
}
|
||||
else if (type_ == Type::Vaisala_RS41_SG)
|
||||
{
|
||||
std::string serial_id = "";
|
||||
uint8_t achar;
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{ //euquiq: Serial ID is 8 bytes long, each byte a char
|
||||
achar = vaisala_descramble(pos_SondeID + i);
|
||||
if (achar < 32 || achar > 126)
|
||||
return "?"; //Maybe there are ids with less than 8 bytes and this is not OK.
|
||||
serial_id += (char)achar;
|
||||
}
|
||||
return serial_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "?";
|
||||
}
|
||||
|
||||
FormattedSymbols Packet::symbols_formatted() const {
|
||||
return format_symbols(decoder_);
|
||||
}
|
||||
|
||||
bool Packet::crc_ok() const {
|
||||
switch(type()) {
|
||||
case Type::Meteomodem_M10: return crc_ok_M10();
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Packet::crc_ok_M10() const {
|
||||
uint16_t cs { 0 };
|
||||
uint32_t c0, c1, t, t6, t7, s,b ;
|
||||
|
||||
for (size_t i = 0; i < packet_.size(); i++) {
|
||||
FormattedSymbols Packet::symbols_formatted() const
|
||||
{
|
||||
if (type_ == Type::Vaisala_RS41_SG)
|
||||
{ //Euquiq: now we distinguish different types
|
||||
uint32_t bytes = packet_.size() / 8; //Need the byte amount, which if full, it SHOULD be 320 size() should return 2560
|
||||
std::string hex_data;
|
||||
std::string hex_error;
|
||||
hex_data.reserve(bytes * 2); //2 hexa chars per byte
|
||||
hex_error.reserve(1);
|
||||
for (uint32_t i = 0; i < bytes; i++) //log will show the packet starting on the last 4 bytes from signature 93DF1A60
|
||||
hex_data += to_string_hex(vaisala_descramble(i), 2);
|
||||
return {hex_data, hex_error};
|
||||
}
|
||||
else
|
||||
{
|
||||
return format_symbols(decoder_);
|
||||
}
|
||||
}
|
||||
|
||||
bool Packet::crc_ok() const
|
||||
{
|
||||
switch (type_)
|
||||
{
|
||||
case Type::Meteomodem_M10:
|
||||
return crc_ok_M10();
|
||||
case Type::Vaisala_RS41_SG:
|
||||
return crc_ok_RS41();
|
||||
default:
|
||||
return true; //euquiq: it was false, but if no crc routine, then no way to check
|
||||
}
|
||||
}
|
||||
|
||||
//each data block has a 2 byte header, data, and 2 byte tail:
|
||||
// 1st byte: block ID
|
||||
// 2nd byte: data length (without header or tail)
|
||||
// <data>
|
||||
// 2 bytes CRC16 over the data.
|
||||
bool Packet::crc_ok_RS41() const //check CRC for the data blocks we need
|
||||
{
|
||||
if (!crc16rs41(block_status))
|
||||
return false;
|
||||
|
||||
if (!crc16rs41(block_gpspos))
|
||||
return false;
|
||||
|
||||
if (!crc16rs41(block_meas))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Checks CRC16 on a RS41 field:
|
||||
bool Packet::crc16rs41(uint32_t field_start) const
|
||||
{
|
||||
int crc16poly = 0x1021;
|
||||
int rem = 0xFFFF, b, j;
|
||||
int xbyte;
|
||||
uint32_t pos = field_start + 1;
|
||||
uint8_t length = vaisala_descramble(pos);
|
||||
|
||||
if (pos + length + 2 > packet_.size() / 8)
|
||||
return false; //Out of packet!
|
||||
|
||||
for (b = 0; b < length; b++)
|
||||
{
|
||||
pos++;
|
||||
xbyte = vaisala_descramble(pos);
|
||||
rem = rem ^ (xbyte << 8);
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if (rem & 0x8000)
|
||||
{
|
||||
rem = (rem << 1) ^ crc16poly;
|
||||
}
|
||||
else
|
||||
{
|
||||
rem = (rem << 1);
|
||||
}
|
||||
rem &= 0xFFFF;
|
||||
}
|
||||
}
|
||||
//Check calculated CRC against packet's one
|
||||
pos++;
|
||||
int crcok = vaisala_descramble(pos) | (vaisala_descramble(pos + 1) << 8);
|
||||
if (crcok != rem)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Packet::crc_ok_M10() const
|
||||
{
|
||||
uint16_t cs{0};
|
||||
uint32_t c0, c1, t, t6, t7, s, b;
|
||||
|
||||
for (size_t i = 0; i < packet_.size(); i++)
|
||||
{
|
||||
b = packet_[i];
|
||||
c1 = cs & 0xFF;
|
||||
|
||||
@@ -165,9 +434,9 @@ bool Packet::crc_ok_M10() const {
|
||||
|
||||
c0 = b ^ t ^ s;
|
||||
|
||||
cs = ((c1<<8) | c0) & 0xFFFF;
|
||||
}
|
||||
|
||||
cs = ((c1 << 8) | c0) & 0xFFFF;
|
||||
}
|
||||
|
||||
return ((cs & 0xFFFF) == ((packet_[0x63] << 8) | (packet_[0x63 + 1])));
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,20 @@
|
||||
|
||||
namespace sonde {
|
||||
|
||||
static uint8_t calibytes[51*16]; //need these vars to survive
|
||||
static uint8_t calfrchk[51]; //so subframes are preserved while populated
|
||||
|
||||
struct GPS_data {
|
||||
uint32_t alt { 0 };
|
||||
float lat { 0 };
|
||||
float lon { 0 };
|
||||
};
|
||||
|
||||
struct temp_humid {
|
||||
float temp { 0 };
|
||||
float humid { 0 };
|
||||
};
|
||||
|
||||
class Packet {
|
||||
public:
|
||||
enum class Type : uint32_t {
|
||||
@@ -41,13 +55,11 @@ public:
|
||||
Meteomodem_M2K2 = 3,
|
||||
Vaisala_RS41_SG = 4,
|
||||
};
|
||||
|
||||
|
||||
Packet(const baseband::Packet& packet, const Type type);
|
||||
|
||||
size_t length() const;
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
Timestamp received_at() const;
|
||||
|
||||
Type type() const;
|
||||
@@ -55,10 +67,9 @@ public:
|
||||
|
||||
std::string serial_number() const;
|
||||
uint32_t battery_voltage() const;
|
||||
|
||||
uint32_t GPS_altitude() const;
|
||||
float GPS_latitude() const;
|
||||
float GPS_longitude() const;
|
||||
GPS_data get_GPS_data() const;
|
||||
uint32_t frame() const;
|
||||
temp_humid get_temp_humid() const;
|
||||
|
||||
FormattedSymbols symbols_formatted() const;
|
||||
|
||||
@@ -75,17 +86,23 @@ private:
|
||||
0xD0, 0xBC, 0xB4, 0xB6, 0x06, 0xAA, 0xF4, 0x23,
|
||||
0x78, 0x6E, 0x3B, 0xAE, 0xBF, 0x7B, 0x4C, 0xC1
|
||||
};
|
||||
|
||||
GPS_data ecef_to_gps() const;
|
||||
|
||||
//uint8_t vaisala_descramble(const uint32_t pos);
|
||||
uint8_t vaisala_descramble(uint32_t pos) const;
|
||||
|
||||
const baseband::Packet packet_;
|
||||
const BiphaseMDecoder decoder_;
|
||||
const FieldReader<BiphaseMDecoder, BitRemapNone> reader_bi_m;
|
||||
Type type_;
|
||||
|
||||
using packetReader = FieldReader<baseband::Packet, BitRemapByteReverse>; //baseband::Packet instead of BiphaseMDecoder
|
||||
|
||||
bool crc_ok_M10() const;
|
||||
bool crc_ok_RS41() const;
|
||||
bool crc16rs41(uint32_t field_start) const;
|
||||
};
|
||||
|
||||
} /* namespace sonde */
|
||||
|
||||
#endif/*__SONDE_PACKET_H__*/
|
||||
#endif/*__SONDE_PACKET_H__*/
|
||||
@@ -91,7 +91,9 @@ Rect& Rect::operator-=(const Point& p) {
|
||||
}
|
||||
|
||||
Point polar_to_point(float angle, uint32_t distance) {
|
||||
return Point(sin_f32(DEG_TO_RAD(angle) + (pi / 2)) * distance, -sin_f32(DEG_TO_RAD(angle)) * distance);
|
||||
//polar to compass with y negated for screen drawing
|
||||
return Point(sin_f32(DEG_TO_RAD(-angle) + pi) * distance,
|
||||
sin_f32(DEG_TO_RAD(-angle) - (pi / 2)) * distance);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -409,10 +409,26 @@ void Labels::paint(Painter& painter) {
|
||||
|
||||
void LiveDateTime::on_tick_second() {
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
text = "";
|
||||
|
||||
text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " " +
|
||||
to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
|
||||
if(date_enabled){
|
||||
text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " ";
|
||||
}
|
||||
|
||||
text = text + to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
|
||||
|
||||
if(seconds_enabled){
|
||||
text += ":";
|
||||
|
||||
if(init_delay==0)
|
||||
text += to_string_dec_uint(datetime.second(), 2, '0');
|
||||
else
|
||||
{
|
||||
// Placeholder while the seconds are not updated
|
||||
text += "XX";
|
||||
init_delay--;
|
||||
}
|
||||
}
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
@@ -444,6 +460,14 @@ void LiveDateTime::paint(Painter& painter) {
|
||||
);
|
||||
}
|
||||
|
||||
void LiveDateTime::set_date_enabled(bool new_value){
|
||||
this->date_enabled = new_value;
|
||||
}
|
||||
|
||||
void LiveDateTime::set_seconds_enabled(bool new_value) {
|
||||
this->seconds_enabled = new_value;
|
||||
}
|
||||
|
||||
/* BigFrequency **********************************************************/
|
||||
|
||||
BigFrequency::BigFrequency(
|
||||
@@ -570,7 +594,10 @@ Console::Console(
|
||||
{
|
||||
}
|
||||
|
||||
void Console::clear() {
|
||||
void Console::clear(bool clear_buffer = false) {
|
||||
if(clear_buffer)
|
||||
buffer.clear();
|
||||
|
||||
display.fill_rectangle(
|
||||
screen_rect(),
|
||||
Color::black()
|
||||
@@ -622,7 +649,8 @@ void Console::write(std::string message) {
|
||||
|
||||
void Console::writeln(std::string message) {
|
||||
write(message);
|
||||
crlf();
|
||||
write("\n");
|
||||
//crlf();
|
||||
}
|
||||
|
||||
void Console::paint(Painter&) {
|
||||
@@ -799,9 +827,11 @@ bool Checkbox::on_touch(const TouchEvent event) {
|
||||
|
||||
Button::Button(
|
||||
Rect parent_rect,
|
||||
std::string text
|
||||
std::string text,
|
||||
bool instant_exec
|
||||
) : Widget { parent_rect },
|
||||
text_ { text }
|
||||
text_ { text },
|
||||
instant_exec_ { instant_exec }
|
||||
{
|
||||
set_focusable(true);
|
||||
}
|
||||
@@ -871,15 +901,24 @@ bool Button::on_touch(const TouchEvent event) {
|
||||
case TouchEvent::Type::Start:
|
||||
set_highlighted(true);
|
||||
set_dirty();
|
||||
if( on_touch_press) {
|
||||
on_touch_press(*this);
|
||||
}
|
||||
if( on_select && instant_exec_ ) {
|
||||
on_select(*this);
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
case TouchEvent::Type::End:
|
||||
set_highlighted(false);
|
||||
set_dirty();
|
||||
if( on_select ) {
|
||||
if( on_select && !instant_exec_ ) {
|
||||
on_select(*this);
|
||||
}
|
||||
if( on_touch_release) {
|
||||
on_touch_release(*this);
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
@@ -1756,13 +1795,13 @@ void VuMeter::paint(Painter& painter) {
|
||||
lit = true;
|
||||
|
||||
if (bar == 0)
|
||||
color = lit ? Color::red() : Color::dark_red();
|
||||
color = lit ? Color::red() : Color::dark_grey();
|
||||
else if (bar == 1)
|
||||
color = lit ? Color::orange() : Color::dark_orange();
|
||||
color = lit ? Color::orange() : Color::dark_grey();
|
||||
else if ((bar == 2) || (bar == 3))
|
||||
color = lit ? Color::yellow() : Color::dark_yellow();
|
||||
color = lit ? Color::yellow() : Color::dark_grey();
|
||||
else
|
||||
color = lit ? Color::green() : Color::dark_green();
|
||||
color = lit ? Color::green() : Color::dark_grey();
|
||||
|
||||
painter.fill_rectangle({ pos.x(), pos.y() + (Coord)(bar * (LED_height + 1)), width, (Coord)LED_height }, color);
|
||||
}
|
||||
|
||||
@@ -243,7 +243,10 @@ public:
|
||||
~LiveDateTime();
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
|
||||
void set_seconds_enabled(bool new_value);
|
||||
void set_date_enabled(bool new_value);
|
||||
|
||||
std::string& string() {
|
||||
return text;
|
||||
}
|
||||
@@ -251,6 +254,10 @@ public:
|
||||
private:
|
||||
void on_tick_second();
|
||||
|
||||
uint16_t init_delay = 4;
|
||||
bool date_enabled = true;
|
||||
bool seconds_enabled = false;
|
||||
|
||||
rtc::RTC datetime { };
|
||||
SignalToken signal_token_tick_second { };
|
||||
std::string text { };
|
||||
@@ -312,7 +319,7 @@ class Console : public Widget {
|
||||
public:
|
||||
Console(Rect parent_rect);
|
||||
|
||||
void clear();
|
||||
void clear(bool clear_buffer);
|
||||
void write(std::string message);
|
||||
void writeln(std::string message);
|
||||
|
||||
@@ -371,10 +378,18 @@ private:
|
||||
class Button : public Widget {
|
||||
public:
|
||||
std::function<void(Button&)> on_select { };
|
||||
std::function<void(Button&)> on_touch_release { }; // Executed when releasing touch, after on_select.
|
||||
std::function<void(Button&)> on_touch_press { }; // Executed when touching, before on_select.
|
||||
std::function<bool(Button&, KeyEvent)> on_dir { };
|
||||
std::function<void(Button&)> on_highlight { };
|
||||
|
||||
Button(Rect parent_rect, std::string text);
|
||||
Button(Rect parent_rect, std::string text, bool instant_exec); // instant_exec: Execute on_select when you touching instead of releasing
|
||||
Button(
|
||||
Rect parent_rect,
|
||||
std::string text
|
||||
) : Button { parent_rect, text, false }
|
||||
{
|
||||
}
|
||||
|
||||
Button(
|
||||
) : Button { { }, { } }
|
||||
@@ -392,6 +407,7 @@ public:
|
||||
|
||||
private:
|
||||
std::string text_;
|
||||
bool instant_exec_ { false };
|
||||
};
|
||||
|
||||
class NewButton : public Widget {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user