mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-14 18:43:01 +00:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a4c2e155e5 | |||
| c90f0944b1 | |||
| 7a38b04192 | |||
| 9f84ccbe1f | |||
| cb3774ad81 | |||
| cc7123b28d | |||
| 8e945024c5 | |||
| 7d28e495c2 | |||
| 48129cdf8d | |||
| 66aa20161d | |||
| 1b3359b050 | |||
| 8d1fb7cb66 | |||
| e01a184721 | |||
| 26b830b816 | |||
| a223bd1f21 | |||
| 023cee2c3c | |||
| fcc52e83de | |||
| dcaa02c1e1 | |||
| 5a0066963e | |||
| 99d8fbdff0 | |||
| 09c2c43be0 | |||
| b9771b2350 | |||
| 83b65ba6ce | |||
| d4edb5f5f9 | |||
| 536d25db64 | |||
| eca1db26e4 | |||
| 7d96bc4efe | |||
| b0c92d9baf | |||
| c1af935022 | |||
| e75fb59169 | |||
| 2d1314a3fa | |||
| a398ed1634 | |||
| 105742acbc | |||
| b43eaa8786 | |||
| b19ed5fec5 | |||
| 419bc75d2f | |||
| b3a0ad018c | |||
| a21e9ca1af | |||
| 20f45e88f3 | |||
| 967506fb97 | |||
| 24ab2f29fa | |||
| 572776bb9e | |||
| 073c4ed9f2 | |||
| 42233e62df | |||
| 9390317a75 | |||
| 89b51095bf | |||
| 9438c9a574 | |||
| 7feef9d38b | |||
| 582bb02a75 | |||
| bfa7f3ca6b | |||
| 21facd9cc3 | |||
| d30234aaa6 | |||
| d45a17236e | |||
| 281e52d143 | |||
| 1f78646054 | |||
| 31c844b48e | |||
| 87069f11e5 | |||
| e6afd7744d | |||
| 76763b9bab | |||
| 02b75f567a | |||
| a2c4fefe34 | |||
| 121352b149 | |||
| 0ae7768f20 |
@@ -1 +1 @@
|
||||
v2.0.0
|
||||
v2.0.1
|
||||
|
||||
@@ -1 +1 @@
|
||||
v2.0.1
|
||||
v2.0.2
|
||||
|
||||
+24
-7
@@ -23,6 +23,12 @@ cmake_policy(SET CMP0005 NEW)
|
||||
|
||||
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/firmware/toolchain-arm-cortex-m.cmake)
|
||||
|
||||
set(CMAKE_COLOR_MAKEFILE ON)
|
||||
|
||||
add_compile_options(-fdiagnostics-color=always)
|
||||
|
||||
option(USE_CCACHE "Enable ccache, please keep an eye on this because sometimes it's not quite stable and generated unusable binary" OFF)
|
||||
|
||||
project(portapack-h1)
|
||||
|
||||
set(EXPECTED_GCC_VERSION "9.2.1")
|
||||
@@ -72,13 +78,24 @@ set(HACKRF_CPLD_XSVF_PATH ${HACKRF_PATH}/firmware/cpld/sgpio_if/${HACKRF_CPLD_XS
|
||||
set(HACKRF_FIRMWARE_DFU_IMAGE ${hackrf_usb_BINARY_DIR}/${HACKRF_FIRMWARE_DFU_FILENAME})
|
||||
set(HACKRF_FIRMWARE_BIN_IMAGE ${hackrf_usb_BINARY_DIR}/${HACKRF_FIRMWARE_BIN_FILENAME})
|
||||
|
||||
# this seems causing some issues (ref. in discord discussions), so temporarily disabled, until figure out the pros and cons and bugs of this tool.
|
||||
#find_program(CCACHE "ccache")
|
||||
#if(CCACHE)
|
||||
# set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})
|
||||
# set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
|
||||
# set(ENV{CCACHE_SLOPPINESS} pch_defines,time_macros)
|
||||
#endif(CCACHE)
|
||||
# this seems causing some issues (ref. in discord discussions), but it sometimes do helps, so you have your choice to use. it's default disabled, unless you use such command:
|
||||
# cmake -DUSE_CCACHE=ON ..
|
||||
# `make` or `make -j` or `make -j10` etc
|
||||
# the default behavior `cmake ..` isn't changed (aka don't use ccache)
|
||||
message(STATUS "-------v ccache info--------")
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_FOUND})
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_FOUND})
|
||||
message(STATUS "Using ccache, please keep an eye on this because sometimes it's not quite stable and generated unusable binary.\n-- use `cmake -DUSE_CCACHE=OFF ..` to turn off ccache")
|
||||
else()
|
||||
message(WARNING "ccache is enabled but not found on the system.")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Not using ccache, use `cmake -DUSE_CCACHE=ON ..` to turn on ccache")
|
||||
endif()
|
||||
message(STATUS "-------^ ccache info--------")
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(firmware)
|
||||
|
||||
@@ -11,15 +11,15 @@ This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmw
|
||||
|
||||
[<img src="https://raw.githubusercontent.com/wiki/portapack-mayhem/mayhem-firmware/img/hw_overview_h2_front.png" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Hardware-overview) [<img src="https://raw.githubusercontent.com/wiki/portapack-mayhem/mayhem-firmware/img/hw_overview_h2_inside.png" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Hardware-overview#portapack-internals)
|
||||
|
||||
*[PortaPack H2+HackRF+battery](https://grabify.link/7T28JP) (clone) with a custom [3d printed case](https://github.com/portapack-mayhem/mayhem-firmware/wiki/H2-Enclosure)*
|
||||
*[PortaPack H2+HackRF+battery](https://grabify.link/ZYYPLB) (clone) with a custom [3d printed case](https://github.com/portapack-mayhem/mayhem-firmware/wiki/H2-Enclosure)*
|
||||
|
||||
# What is this?
|
||||
|
||||
If you are new to *HackRF+PortaPack+Mayhem*, check these:
|
||||
|
||||
[<img alt="What is the HackRF One Portapack H2+?" src="https://img.youtube.com/vi/alrFbY5vxt4/maxresdefault.jpg" width="512">](https://grabify.link/9UZGEW)
|
||||
[<img alt="The new HackRF Portapack H4M" src="https://img.youtube.com/vi/onQRdCITmuk/maxresdefault.jpg" width="701">](https://grabify.link/0JUHZ6)
|
||||
|
||||
[<img alt="Beginner's Guide To The HackRF & Portapak With Mayhem" src="https://img.youtube.com/vi/H-bqdWfbhpg/maxresdefault.jpg" width="254">](https://grabify.link/5MU2VH) [<img alt="HackRF 101 : Everything You Need to Know to Get Started!" src="https://img.youtube.com/vi/xGR_PMD9LeU/maxresdefault.jpg" width="254">](https://grabify.link/C0J6ZR)
|
||||
[<img alt="It’s TOO Easy to Accidentally Do Illegal Stuff with This" src="https://img.youtube.com/vi/OPckpjBSAOw/maxresdefault.jpg" width="172">](https://grabify.link/X4D5TF) [<img alt="What is the HackRF One Portapack H2+?" src="https://img.youtube.com/vi/alrFbY5vxt4/maxresdefault.jpg" width="172">](https://grabify.link/9UZGEW) [<img alt="Beginner's Guide To The HackRF & Portapak With Mayhem" src="https://img.youtube.com/vi/H-bqdWfbhpg/maxresdefault.jpg" width="172">](https://grabify.link/5MU2VH) [<img alt="HackRF 101 : Everything You Need to Know to Get Started!" src="https://img.youtube.com/vi/xGR_PMD9LeU/maxresdefault.jpg" width="172">](https://grabify.link/C0J6ZR)
|
||||
|
||||
# Frequently Asked Questions
|
||||
|
||||
@@ -27,11 +27,11 @@ This repository expands upon the previous work by many people and aims to consta
|
||||
|
||||
## What to buy?
|
||||
|
||||
:heavy_check_mark: A recommended one is this [PortaPack H2](https://grabify.link/7T28JP), that includes everything you need with the plastic case "inspired" on [this](https://github.com/portapack-mayhem/mayhem-firmware/wiki/H2-Enclosure).
|
||||
:heavy_check_mark:  The fabulous [PortaPack H4M Mayhem](https://grabify.link/VPMPSL), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://grabify.link/99SAMT). Join their giveaways on discord (check the badge on top).
|
||||
|
||||
:heavy_check_mark: Some individuals lean towards the [H2 with a metal enclosure](https://grabify.link/HTDXG5), but its advantages remain debated. Share your insights on our [wiki](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Hardware-overview).
|
||||
:heavy_check_mark: A recommended one is this [PortaPack H2](https://grabify.link/ZYYPLB), that includes everything you need with the plastic case "inspired" on [this](https://github.com/portapack-mayhem/mayhem-firmware/wiki/H2-Enclosure).
|
||||
|
||||
:heavy_check_mark: Our friends at OpenSourceSDRLab give away five units every three months in our discord (check the badge on top) of one of their [PortaPack H2 bundle](https://grabify.link/T328XL) or [only metal case kits](https://grabify.link/LG0OUY), you can support them too by ordering.
|
||||
:heavy_check_mark: Some individuals lean towards the [H2 with a metal enclosure](https://grabify.link/XNGTAP), but its advantages remain debated. Share your insights on our [wiki](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Hardware-overview).
|
||||
|
||||
:warning: Be cautious , *ask* the seller about compatibility with the latest releases. Look out for the description of the item, if they provide the firmware files for an older version or they have custom setup instructions, this means it might be **NOT compatible**, for example:
|
||||
|
||||
@@ -55,13 +55,7 @@ Consider that the hardware and firmware has been created and maintain by a [lot]
|
||||
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).
|
||||
|
||||
## What if I really want something specific?
|
||||
If what you need can be relevant in general, you can [request a feature](https://github.com/portapack-mayhem/mayhem-firmware/issues/new?labels=enhancement&template=feature_request.md).
|
||||
|
||||
<del>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/portapack-mayhem/mayhem-firmware/issues/new/choose) or [choosing](https://github.com/portapack-mayhem/mayhem-firmware/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).</del>
|
||||
|
||||
<del>Promote your bounty over our Discord by clicking the chat badge on [top](#portapack-mayhem).</del>
|
||||
|
||||
Bountysource has not been reliable lately, so until this changes, please **DO NOT** post a bounty there. Go to our Discord by clicking the chat badge on [top](#portapack-mayhem) and discuss there.
|
||||
If what you need can be relevant in general, you can [request a feature](https://github.com/portapack-mayhem/mayhem-firmware/issues/new?labels=enhancement&template=feature_request.md). Alternatively, go to our Discord by clicking the chat badge on [top](#portapack-mayhem) and discuss there.
|
||||
|
||||
## What if I need help?
|
||||
First, check the [documentation](https://github.com/portapack-mayhem/mayhem-firmware/wiki). If you find a bug or you think the problem is related to the current repository, please open an [issue](https://github.com/portapack-mayhem/mayhem-firmware/issues/new/choose).
|
||||
|
||||
@@ -125,12 +125,14 @@ set(CSRC
|
||||
${CHIBIOS}/os/various/chprintf.c
|
||||
)
|
||||
|
||||
#look for all i2cdev_ files
|
||||
file(GLOB I2CDEV_SOURCES ${COMMON}/i2cdev_*.cpp)
|
||||
|
||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
set(CPPSRC
|
||||
main.cpp
|
||||
shell.cpp
|
||||
${COMMON}/acars_packet.cpp
|
||||
${COMMON}/adsb.cpp
|
||||
${COMMON}/adsb_frame.cpp
|
||||
${COMMON}/ais_baseband.cpp
|
||||
@@ -176,8 +178,8 @@ set(CPPSRC
|
||||
${COMMON}/ui_language.cpp
|
||||
${COMMON}/utility.cpp
|
||||
${COMMON}/wm8731.cpp
|
||||
${COMMON}/ads1110.cpp
|
||||
${COMMON}/max17055.cpp
|
||||
${COMMON}/i2cdevmanager.cpp
|
||||
${I2CDEV_SOURCES}
|
||||
${COMMON}/battery.cpp
|
||||
${COMMON}/performance_counter.cpp
|
||||
${COMMON}/bmpfile.cpp
|
||||
@@ -189,7 +191,6 @@ set(CPPSRC
|
||||
core_control.cpp
|
||||
database.cpp
|
||||
de_bruijn.cpp
|
||||
#emu_cc1101.cpp
|
||||
rfm69.cpp
|
||||
event_m0.cpp
|
||||
file_reader.cpp
|
||||
@@ -206,6 +207,7 @@ set(CPPSRC
|
||||
irq_rtc.cpp
|
||||
log_file.cpp
|
||||
metadata_file.cpp
|
||||
flipper_subfile.cpp
|
||||
portapack.cpp
|
||||
usb_serial_shell.cpp
|
||||
usb_serial_shell_filesystem.cpp
|
||||
@@ -243,7 +245,6 @@ set(CPPSRC
|
||||
hw/touch_adc.cpp
|
||||
ui_baseband_stats_view.cpp
|
||||
ui_navigation.cpp
|
||||
ui_playdead.cpp
|
||||
ui_record_view.cpp
|
||||
ui_sd_card_status_view.cpp
|
||||
ui/ui_alphanum.cpp
|
||||
@@ -265,49 +266,37 @@ set(CPPSRC
|
||||
ui/ui_tone_key.cpp
|
||||
ui/ui_transmitter.cpp
|
||||
ui/ui_bmpview.cpp
|
||||
apps/acars_app.cpp
|
||||
apps/ais_app.cpp
|
||||
apps/analog_audio_app.cpp
|
||||
# apps/analog_tv_app.cpp
|
||||
apps/ble_comm_app.cpp
|
||||
apps/ble_rx_app.cpp
|
||||
apps/ble_tx_app.cpp
|
||||
apps/capture_app.cpp
|
||||
apps/ert_app.cpp
|
||||
# apps/gps_sim_app.cpp
|
||||
# apps/lge_app.cpp
|
||||
apps/pocsag_app.cpp
|
||||
# apps/replay_app.cpp
|
||||
apps/soundboard_app.cpp
|
||||
# apps/tpms_app.cpp
|
||||
apps/ui_about_simple.cpp
|
||||
apps/ui_adsb_rx.cpp
|
||||
# apps/ui_adsb_tx.cpp #moved to ext
|
||||
apps/ui_aprs_rx.cpp
|
||||
apps/ui_aprs_tx.cpp
|
||||
apps/ui_battinfo.cpp
|
||||
apps/ui_bht_tx.cpp
|
||||
apps/ui_bmp_file_viewer.cpp
|
||||
apps/ui_btle_rx.cpp
|
||||
# apps/ui_coasterp.cpp
|
||||
apps/ui_debug.cpp
|
||||
apps/ui_debug_max17055.cpp
|
||||
apps/ui_dfu_menu.cpp
|
||||
apps/ui_encoders.cpp
|
||||
apps/ui_external_module_view.cpp
|
||||
apps/ui_fileman.cpp
|
||||
apps/ui_flash_utility.cpp
|
||||
apps/ui_freqman.cpp
|
||||
apps/ui_fsk_rx.cpp
|
||||
apps/ui_iq_trim.cpp
|
||||
# apps/ui_jammer.cpp
|
||||
# apps/ui_keyfob.cpp
|
||||
# apps/ui_lcr.cpp
|
||||
apps/ui_level.cpp
|
||||
apps/ui_looking_glass_app.cpp
|
||||
apps/ui_mictx.cpp
|
||||
apps/ui_modemsetup.cpp
|
||||
apps/ui_morse.cpp
|
||||
# apps/ui_nrf_rx.cpp
|
||||
# apps/ui_nuoptix.cpp
|
||||
apps/ui_playlist.cpp
|
||||
apps/ui_pocsag_tx.cpp
|
||||
apps/ui_rds.cpp
|
||||
@@ -321,16 +310,11 @@ set(CPPSRC
|
||||
apps/ui_settings.cpp
|
||||
apps/ui_siggen.cpp
|
||||
apps/ui_sonde.cpp
|
||||
# apps/ui_spectrum_painter_image.cpp
|
||||
# apps/ui_spectrum_painter_text.cpp
|
||||
# apps/ui_spectrum_painter.cpp
|
||||
apps/ui_ss_viewer.cpp
|
||||
apps/ui_sstvtx.cpp
|
||||
apps/ui_standalone_view.cpp
|
||||
apps/ui_subghzd.cpp
|
||||
# apps/ui_test.cpp
|
||||
apps/ui_text_editor.cpp
|
||||
apps/ui_tone_search.cpp
|
||||
apps/ui_touch_calibration.cpp
|
||||
apps/ui_touchtunes.cpp
|
||||
apps/ui_view_wav.cpp
|
||||
@@ -341,14 +325,8 @@ set(CPPSRC
|
||||
protocols/bht.cpp
|
||||
protocols/dcs.cpp
|
||||
protocols/encoders.cpp
|
||||
# protocols/lcr.cpp
|
||||
protocols/modems.cpp
|
||||
protocols/rds.cpp
|
||||
# ui_handwrite.cpp
|
||||
# ui_loadmodule.cpp
|
||||
# ui_numbers.cpp
|
||||
# ui_replay_view.cpp
|
||||
# ui_script.cpp
|
||||
ui_sd_card_debug.cpp
|
||||
config_mode.cpp
|
||||
${CPLD_20150901_DATA_CPP}
|
||||
|
||||
@@ -435,4 +435,7 @@ void AnalogAudioView::handle_coded_squelch(uint32_t value) {
|
||||
text_ctcss.set(tone_key_string_by_value(value, text_ctcss.parent_rect().width() / 8));
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -247,12 +247,21 @@ class AnalogAudioView : public View {
|
||||
|
||||
void handle_coded_squelch(uint32_t value);
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
|
||||
MessageHandlerRegistration message_handler_coded_squelch{
|
||||
Message::ID::CodedSquelch,
|
||||
[this](const Message* p) {
|
||||
const auto message = *reinterpret_cast<const CodedSquelchMessage*>(p);
|
||||
this->handle_coded_squelch(message.value);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -428,6 +428,7 @@ BLERxView::BLERxView(NavigationView& nav)
|
||||
&text_found_count,
|
||||
&check_serial_log,
|
||||
&button_filter,
|
||||
&options_filter,
|
||||
&button_save_list,
|
||||
&button_clear_list,
|
||||
&button_switch,
|
||||
@@ -499,6 +500,7 @@ BLERxView::BLERxView(NavigationView& nav)
|
||||
|
||||
check_name.on_select = [this](Checkbox&, bool v) {
|
||||
name_enable = v;
|
||||
// update the include_name instance variable value of each entry in recent entries
|
||||
setAllMembersToValue(recent, &BleRecentEntry::include_name, v);
|
||||
recent_entries_view.set_dirty();
|
||||
};
|
||||
@@ -525,8 +527,14 @@ BLERxView::BLERxView(NavigationView& nav)
|
||||
handle_entries_sort(v);
|
||||
};
|
||||
|
||||
options_filter.on_change = [this](size_t index, int32_t v) {
|
||||
filter_index = (uint8_t)index;
|
||||
handle_filter_options(v);
|
||||
};
|
||||
|
||||
options_channel.set_selected_index(channel_index, true);
|
||||
options_sort.set_selected_index(sort_index, true);
|
||||
options_filter.set_selected_index(filter_index, true);
|
||||
|
||||
button_find.on_select = [this](Button&) {
|
||||
auto open_view = nav_.push<FileLoadView>(".TXT");
|
||||
@@ -716,10 +724,11 @@ void BLERxView::on_data(BlePacketData* packet) {
|
||||
updateEntry(packet, entry, (ADV_PDU_TYPE)packet->type);
|
||||
|
||||
// Add entries if they meet the criteria.
|
||||
auto value = filter;
|
||||
resetFilteredEntries(recent, [&value](const BleRecentEntry& entry) {
|
||||
return (entry.dataString.find(value) == std::string::npos) && (entry.nameString.find(value) == std::string::npos);
|
||||
});
|
||||
// auto value = filter;
|
||||
// resetFilteredEntries(recent, [&value](const BleRecentEntry& entry) {
|
||||
// return (entry.dataString.find(value) == std::string::npos) && (entry.nameString.find(value) == std::string::npos);
|
||||
// });
|
||||
handle_filter_options(options_filter.selected_index());
|
||||
|
||||
handle_entries_sort(options_sort.selected_index());
|
||||
|
||||
@@ -756,12 +765,13 @@ void BLERxView::on_data(BlePacketData* packet) {
|
||||
void BLERxView::on_filter_change(std::string value) {
|
||||
// New filter? Reset list from recent entries.
|
||||
if (filter != value) {
|
||||
resetFilteredEntries(recent, [&value](const BleRecentEntry& entry) {
|
||||
return (entry.dataString.find(value) == std::string::npos) && (entry.nameString.find(value) == std::string::npos);
|
||||
});
|
||||
// resetFilteredEntries(recent, [&value](const BleRecentEntry& entry) {
|
||||
// // return (entry.dataString.find(value) == std::string::npos) && (entry.nameString.find(value) == std::string::npos);
|
||||
// return (entry.dataString.find(value) == std::string::npos) && (entry.nameString.find(value) == std::string::npos) && (to_string_mac_address(entry.packetData.macAddress, 6, false).find(value) == std::string::npos);
|
||||
// });
|
||||
filter = value;
|
||||
handle_filter_options(options_filter.selected_index());
|
||||
}
|
||||
|
||||
filter = value;
|
||||
}
|
||||
|
||||
void BLERxView::on_file_changed(const std::filesystem::path& new_file_path) {
|
||||
@@ -852,6 +862,24 @@ void BLERxView::handle_entries_sort(uint8_t index) {
|
||||
recent_entries_view.set_dirty();
|
||||
}
|
||||
|
||||
void BLERxView::handle_filter_options(uint8_t index) {
|
||||
auto value = filter;
|
||||
switch (index) {
|
||||
case 0: // filter by Data
|
||||
resetFilteredEntries(recent, [&value](const BleRecentEntry& entry) {
|
||||
return (entry.dataString.find(value) == std::string::npos) && (entry.nameString.find(value) == std::string::npos);
|
||||
});
|
||||
break;
|
||||
case 1: // filter by MAC address (All caps: e.g. AA:BB:CC:DD:EE:FF)
|
||||
resetFilteredEntries(recent, [&value](const BleRecentEntry& entry) {
|
||||
return (to_string_mac_address(entry.packetData.macAddress, 6, false).find(value) == std::string::npos);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BLERxView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
const Rect content_rect{0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height - switch_button_height};
|
||||
@@ -914,6 +942,7 @@ void BLERxView::updateEntry(const BlePacketData* packet, BleRecentEntry& entry,
|
||||
|
||||
// Subtract 1 because type is part of the length.
|
||||
for (int i = 0; i < length - 1; i++) {
|
||||
// parse the name of bluetooth device: 0x08->Shortened Local Name; 0x09->Complete Local Name
|
||||
if (type == 0x08 || type == 0x09) {
|
||||
decoded_data += (char)advertiseData->Data[currentByte];
|
||||
}
|
||||
|
||||
@@ -203,6 +203,7 @@ class BLERxView : public View {
|
||||
void file_error();
|
||||
void on_timer();
|
||||
void handle_entries_sort(uint8_t index);
|
||||
void handle_filter_options(uint8_t index);
|
||||
void updateEntry(const BlePacketData* packet, BleRecentEntry& entry, ADV_PDU_TYPE pdu_type);
|
||||
|
||||
NavigationView& nav_;
|
||||
@@ -214,6 +215,7 @@ class BLERxView : public View {
|
||||
|
||||
uint8_t channel_index{0};
|
||||
uint8_t sort_index{0};
|
||||
uint8_t filter_index{0};
|
||||
std::string filter{};
|
||||
bool logging{false};
|
||||
bool serial_logging{false};
|
||||
@@ -227,6 +229,7 @@ class BLERxView : public View {
|
||||
{"sort_index"sv, &sort_index},
|
||||
{"filter"sv, &filter},
|
||||
{"log"sv, &logging},
|
||||
{"filter_index"sv, &filter_index},
|
||||
// disabled to always start without USB serial activated until we can make it non blocking if not connected
|
||||
// {"serial_log"sv, &serial_logging},
|
||||
{"name"sv, &name_enable},
|
||||
@@ -255,13 +258,13 @@ class BLERxView : public View {
|
||||
std::filesystem::path log_packets_path{blerx_dir / u"Logs/????.TXT"};
|
||||
std::filesystem::path packet_save_path{blerx_dir / u"Lists/????.csv"};
|
||||
|
||||
static constexpr auto header_height = 4 * 16;
|
||||
static constexpr auto header_height = 9 * 8;
|
||||
static constexpr auto switch_button_height = 3 * 16;
|
||||
|
||||
OptionsField options_channel{
|
||||
{0 * 8, 0 * 8},
|
||||
5,
|
||||
{{"Ch.37 ", 37},
|
||||
{{"Ch.37", 37},
|
||||
{"Ch.38", 38},
|
||||
{"Ch.39", 39},
|
||||
{"Auto", 40}}};
|
||||
@@ -286,10 +289,10 @@ class BLERxView : public View {
|
||||
{24 * 8, 5, 6 * 8, 4}};
|
||||
|
||||
Labels label_sort{
|
||||
{{0 * 8, 3 * 8}, "Sort:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{0 * 8, 2 * 8}, "Sort:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_sort{
|
||||
{5 * 8, 3 * 8},
|
||||
{5 * 8, 2 * 8},
|
||||
4,
|
||||
{{"MAC", 0},
|
||||
{"Hits", 1},
|
||||
@@ -298,40 +301,46 @@ class BLERxView : public View {
|
||||
{"Name", 4}}};
|
||||
|
||||
Button button_filter{
|
||||
{11 * 8, 3 * 8, 4 * 8, 16},
|
||||
"Filter"};
|
||||
{11 * 8, 2 * 8, 7 * 8, 16},
|
||||
"Filter:"};
|
||||
|
||||
OptionsField options_filter{
|
||||
{18 * 8 + 2, 2 * 8},
|
||||
4,
|
||||
{{"Data", 0},
|
||||
{"MAC", 1}}};
|
||||
|
||||
Checkbox check_log{
|
||||
{17 * 8, 3 * 8},
|
||||
{10 * 8, 4 * 8 + 2},
|
||||
3,
|
||||
"Log",
|
||||
true};
|
||||
|
||||
Checkbox check_name{
|
||||
{23 * 8, 3 * 8},
|
||||
{0 * 8, 4 * 8 + 2},
|
||||
3,
|
||||
"Name",
|
||||
true};
|
||||
|
||||
Button button_find{
|
||||
{0 * 8, 6 * 8, 4 * 8, 16},
|
||||
{0 * 8, 7 * 8 - 2, 4 * 8, 16},
|
||||
"Find"};
|
||||
|
||||
Labels label_found{
|
||||
{{5 * 8, 6 * 8}, "Found:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{5 * 8, 7 * 8 - 2}, "Found:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_found_count{
|
||||
{11 * 8, 3 * 16, 20 * 8, 16},
|
||||
{11 * 8, 7 * 8 - 2, 20 * 8, 16},
|
||||
"0/0"};
|
||||
|
||||
Checkbox check_serial_log{
|
||||
{17 * 8, 3 * 16 - 2},
|
||||
{18 * 8 + 2, 4 * 8 + 2},
|
||||
7,
|
||||
"USB Log",
|
||||
true};
|
||||
|
||||
Console console{
|
||||
{0, 4 * 16, 240, 240}};
|
||||
// Console console{
|
||||
// {0, 10 * 8, 240, 240}};
|
||||
|
||||
Button button_clear_list{
|
||||
{2 * 8, 320 - (16 + 32), 7 * 8, 32},
|
||||
@@ -371,7 +380,7 @@ class BLERxView : public View {
|
||||
[this](const Message* const) {
|
||||
this->on_timer();
|
||||
}};
|
||||
};
|
||||
}; /* BLERxView */
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
|
||||
@@ -128,4 +128,8 @@ void CaptureAppView::focus() {
|
||||
record_view.focus();
|
||||
}
|
||||
|
||||
void CaptureAppView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -108,6 +108,15 @@ class CaptureAppView : public View {
|
||||
3};
|
||||
|
||||
spectrum::WaterfallView waterfall{};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -178,4 +178,8 @@ void ERTAppView::on_show_list() {
|
||||
recent_entries_view.focus();
|
||||
}
|
||||
|
||||
void ERTAppView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -176,6 +176,14 @@ class ERTAppView : public View {
|
||||
this->on_packet(packet);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
void on_packet(const ert::Packet& packet);
|
||||
void on_show_list();
|
||||
};
|
||||
|
||||
@@ -321,6 +321,10 @@ void POCSAGAppView::on_stats(const POCSAGStatsMessage* stats) {
|
||||
widget_frames.set_sync(stats->has_sync);
|
||||
}
|
||||
|
||||
void POCSAGAppView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
void BaudIndicator::paint(Painter& painter) {
|
||||
auto p = screen_pos();
|
||||
char top = '-';
|
||||
|
||||
@@ -292,6 +292,15 @@ class POCSAGAppView : public View {
|
||||
Console console{
|
||||
{0, 2 * 16 + 6, screen_width, screen_height - 54}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::POCSAGPacket,
|
||||
[this](Message* const p) {
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyleft (ↄ) 2022 NotPike
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "replay_app.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "ui_fileman.hpp"
|
||||
#include "io_file.hpp"
|
||||
#include "io_convert.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "metadata_file.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void ReplayAppView::set_ready() {
|
||||
ready_signal = true;
|
||||
}
|
||||
|
||||
void ReplayAppView::on_file_changed(const fs::path& new_file_path) {
|
||||
file_path = new_file_path;
|
||||
File::Size file_size{};
|
||||
|
||||
{ // Get the size of the data file.
|
||||
File data_file;
|
||||
auto error = data_file.open(file_path);
|
||||
if (error) {
|
||||
file_error();
|
||||
return;
|
||||
}
|
||||
|
||||
file_size = data_file.size();
|
||||
}
|
||||
|
||||
// Get original record frequency if available.
|
||||
auto metadata_path = get_metadata_path(file_path);
|
||||
auto metadata = read_metadata_file(metadata_path);
|
||||
|
||||
if (metadata) {
|
||||
field_frequency.set_value(metadata->center_frequency);
|
||||
sample_rate = metadata->sample_rate;
|
||||
} else {
|
||||
// TODO: This is interesting because it implies that the
|
||||
// The capture will just be replayed at the freq set on the
|
||||
// FrequencyField. Is that an intentional behavior?
|
||||
sample_rate = 500000;
|
||||
}
|
||||
|
||||
// UI Fixup.
|
||||
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 0) + "Hz");
|
||||
progressbar.set_max(file_size);
|
||||
text_filename.set(truncate(file_path.filename().string(), 12));
|
||||
|
||||
uint8_t sample_size = capture_file_sample_size(current()->path);
|
||||
auto duration = ms_duration(file_size, sample_rate, sample_size);
|
||||
text_duration.set(to_string_time_ms(duration));
|
||||
|
||||
button_play.focus();
|
||||
}
|
||||
|
||||
void ReplayAppView::on_tx_progress(const uint32_t progress) {
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void ReplayAppView::focus() {
|
||||
button_open.focus();
|
||||
}
|
||||
|
||||
void ReplayAppView::file_error() {
|
||||
nav_.display_modal("Error", "File read error.");
|
||||
}
|
||||
|
||||
bool ReplayAppView::is_active() const {
|
||||
return (bool)replay_thread;
|
||||
}
|
||||
|
||||
void ReplayAppView::toggle() {
|
||||
if (is_active()) {
|
||||
stop(false);
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
void ReplayAppView::start() {
|
||||
stop(false);
|
||||
|
||||
std::unique_ptr<stream::Reader> reader;
|
||||
|
||||
auto p = std::make_unique<FileConvertReader>();
|
||||
auto open_error = p->open(file_path);
|
||||
if (open_error.is_valid()) {
|
||||
file_error();
|
||||
return; // Fixes TX bug if there's a file error
|
||||
} else {
|
||||
reader = std::move(p);
|
||||
}
|
||||
|
||||
if (reader) {
|
||||
button_play.set_bitmap(&bitmap_stop);
|
||||
baseband::set_sample_rate(sample_rate, OversampleRate::x8);
|
||||
|
||||
replay_thread = std::make_unique<ReplayThread>(
|
||||
std::move(reader),
|
||||
read_size, buffer_count,
|
||||
&ready_signal,
|
||||
[](uint32_t return_code) {
|
||||
ReplayThreadDoneMessage message{return_code};
|
||||
EventDispatcher::send_message(message);
|
||||
});
|
||||
}
|
||||
|
||||
transmitter_model.set_sampling_rate(sample_rate * toUType(OversampleRate::x8));
|
||||
transmitter_model.set_baseband_bandwidth(baseband_bandwidth);
|
||||
transmitter_model.enable();
|
||||
|
||||
if (portapack::persistent_memory::stealth_mode()) {
|
||||
DisplaySleepMessage message;
|
||||
EventDispatcher::send_message(message);
|
||||
}
|
||||
}
|
||||
|
||||
void ReplayAppView::stop(const bool do_loop) {
|
||||
if (is_active())
|
||||
replay_thread.reset();
|
||||
|
||||
if (do_loop && check_loop.value()) {
|
||||
start();
|
||||
} else {
|
||||
transmitter_model.disable();
|
||||
button_play.set_bitmap(&bitmap_play);
|
||||
}
|
||||
|
||||
ready_signal = false;
|
||||
}
|
||||
|
||||
void ReplayAppView::handle_replay_thread_done(const uint32_t return_code) {
|
||||
if (return_code == ReplayThread::END_OF_FILE) {
|
||||
stop(true);
|
||||
} else if (return_code == ReplayThread::READ_ERROR) {
|
||||
stop(false);
|
||||
file_error();
|
||||
}
|
||||
|
||||
progressbar.set_value(0);
|
||||
}
|
||||
|
||||
ReplayAppView::ReplayAppView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_replay);
|
||||
|
||||
add_children({
|
||||
&button_open,
|
||||
&text_filename,
|
||||
&text_sample_rate,
|
||||
&text_duration,
|
||||
&progressbar,
|
||||
&field_frequency,
|
||||
&tx_view, // now it handles previous rfgain, rfamp.
|
||||
&check_loop,
|
||||
&button_play,
|
||||
&waterfall,
|
||||
});
|
||||
|
||||
button_play.on_select = [this](ImageButton&) {
|
||||
this->toggle();
|
||||
};
|
||||
|
||||
button_open.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".C*");
|
||||
open_view->on_changed = [this](fs::path new_file_path) {
|
||||
on_file_changed(new_file_path);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
ReplayAppView::~ReplayAppView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
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();
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
void ReplayAppView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
const ui::Rect waterfall_rect{0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height};
|
||||
waterfall.set_parent_rect(waterfall_rect);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __REPLAY_APP_HPP__
|
||||
#define __REPLAY_APP_HPP__
|
||||
|
||||
#include "app_settings.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_freq_field.hpp"
|
||||
#include "replay_thread.hpp"
|
||||
#include "ui_spectrum.hpp"
|
||||
#include "ui_transmitter.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ReplayAppView : public View {
|
||||
public:
|
||||
ReplayAppView(NavigationView& nav);
|
||||
~ReplayAppView();
|
||||
|
||||
void on_hide() override;
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Replay"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
TxRadioState radio_state_{};
|
||||
app_settings::SettingsManager settings_{
|
||||
"tx_replay", app_settings::Mode::TX};
|
||||
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
uint32_t sample_rate = 0;
|
||||
int32_t tx_gain{47};
|
||||
bool rf_amp{true}; // aux private var to store temporal, Replay App rf_amp user selection.
|
||||
static constexpr uint32_t baseband_bandwidth = 2500000;
|
||||
const size_t read_size{16384};
|
||||
const size_t buffer_count{3};
|
||||
|
||||
void on_file_changed(const std::filesystem::path& new_file_path);
|
||||
void on_tx_progress(const uint32_t progress);
|
||||
|
||||
void toggle();
|
||||
void start();
|
||||
void stop(const bool do_loop);
|
||||
bool is_active() const;
|
||||
void set_ready();
|
||||
void handle_replay_thread_done(const uint32_t return_code);
|
||||
void file_error();
|
||||
|
||||
std::filesystem::path file_path{};
|
||||
std::unique_ptr<ReplayThread> replay_thread{};
|
||||
bool ready_signal{false};
|
||||
|
||||
Button button_open{
|
||||
{0 * 8, 0 * 16, 10 * 8, 2 * 16},
|
||||
"Open file"};
|
||||
|
||||
Text text_filename{
|
||||
{11 * 8, 0 * 16, 12 * 8, 16},
|
||||
"-"};
|
||||
Text text_sample_rate{
|
||||
{24 * 8, 0 * 16, 6 * 8, 16},
|
||||
"-"};
|
||||
|
||||
Text text_duration{
|
||||
{11 * 8, 1 * 16, 6 * 8, 16},
|
||||
"-"};
|
||||
ProgressBar progressbar{
|
||||
{18 * 8, 1 * 16, 12 * 8, 16}};
|
||||
|
||||
TxFrequencyField field_frequency{
|
||||
{0 * 8, 2 * 16},
|
||||
nav_};
|
||||
|
||||
TransmitterView2 tx_view{
|
||||
{11 * 8, 2 * 16},
|
||||
/*short_ui*/ true};
|
||||
|
||||
Checkbox check_loop{
|
||||
{21 * 8, 2 * 16},
|
||||
4,
|
||||
"Loop",
|
||||
true};
|
||||
ImageButton button_play{
|
||||
{28 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
spectrum::WaterfallView waterfall{};
|
||||
|
||||
MessageHandlerRegistration message_handler_replay_thread_error{
|
||||
Message::ID::ReplayThreadDone,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
|
||||
this->handle_replay_thread_done(message.return_code);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal{
|
||||
Message::ID::RequestSignal,
|
||||
[this](const Message* const p) {
|
||||
const auto message = static_cast<const RequestSignalMessage*>(p);
|
||||
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
|
||||
this->set_ready();
|
||||
}
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_tx_progress{
|
||||
Message::ID::TXProgress,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||
this->on_tx_progress(message.progress);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__REPLAY_APP_HPP__*/
|
||||
@@ -35,6 +35,8 @@ using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
#define FILE_PER_PAGE 50
|
||||
|
||||
bool SoundBoardView::is_active() const {
|
||||
return (bool)replay_thread;
|
||||
}
|
||||
@@ -178,9 +180,9 @@ void SoundBoardView::refresh_list() {
|
||||
if ((reader->channels() == 1) && ((reader->bits_per_sample() == 8) || (reader->bits_per_sample() == 16))) {
|
||||
// sounds[c].ms_duration = reader->ms_duration();
|
||||
// sounds[c].path = u"WAV/" + entry.path().native();
|
||||
if (count >= (page - 1) * 100 && count < page * 100) {
|
||||
if (count >= (page - 1) * FILE_PER_PAGE && count < page * FILE_PER_PAGE) {
|
||||
file_list.push_back(entry.path());
|
||||
if (file_list.size() == 100) {
|
||||
if (file_list.size() == FILE_PER_PAGE) {
|
||||
page++;
|
||||
break;
|
||||
}
|
||||
@@ -225,7 +227,7 @@ void SoundBoardView::refresh_list() {
|
||||
menu_view.set_highlighted(0); // Refresh
|
||||
}
|
||||
|
||||
if (file_list.size() < 100) {
|
||||
if (file_list.size() < FILE_PER_PAGE) {
|
||||
page = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "cpld_update.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "ui_about.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace lpc43xx;
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
// This is pretty much WaterfallView but in the opposite direction
|
||||
CreditsWidget::CreditsWidget(
|
||||
Rect parent_rect)
|
||||
: Widget{parent_rect} {
|
||||
}
|
||||
|
||||
void CreditsWidget::paint(Painter&) {
|
||||
}
|
||||
|
||||
void CreditsWidget::on_show() {
|
||||
clear();
|
||||
|
||||
const auto screen_r = screen_rect();
|
||||
display.scroll_set_area(screen_r.top(), screen_r.bottom());
|
||||
}
|
||||
|
||||
void CreditsWidget::on_hide() {
|
||||
display.scroll_disable();
|
||||
}
|
||||
|
||||
void CreditsWidget::new_row(
|
||||
const std::array<Color, 240>& pixel_row) {
|
||||
// Glitch be here (see comment in main.cpp)
|
||||
const auto draw_y = display.scroll(-1);
|
||||
|
||||
display.draw_pixels(
|
||||
{{0, draw_y - 1}, {240, 1}},
|
||||
pixel_row);
|
||||
}
|
||||
|
||||
void CreditsWidget::clear() {
|
||||
display.fill_rectangle(
|
||||
screen_rect(),
|
||||
Theme::getInstance()->bg_darkest->background);
|
||||
}
|
||||
|
||||
void AboutView::update() {
|
||||
size_t i = 0;
|
||||
std::array<Color, 240> pixel_row;
|
||||
|
||||
slow_down++;
|
||||
if (slow_down % 3 < 2) return;
|
||||
|
||||
if (!timer) {
|
||||
if (loop) {
|
||||
credits_index = 0;
|
||||
loop = false;
|
||||
}
|
||||
|
||||
text = credits[credits_index].text;
|
||||
timer = credits[credits_index].delay;
|
||||
start_pos = credits[credits_index].start_pos;
|
||||
|
||||
if (timer < 0) {
|
||||
timer = 240;
|
||||
loop = true;
|
||||
} else
|
||||
timer += 16;
|
||||
|
||||
render_line = 0;
|
||||
credits_index++;
|
||||
} else
|
||||
timer--;
|
||||
|
||||
if (render_line < 16) {
|
||||
for (const auto c : text) {
|
||||
const auto glyph = style().font.glyph(c);
|
||||
|
||||
const size_t start = (glyph.size().width() / 8) * render_line;
|
||||
for (Dim c = 0; c < glyph.size().width(); c++) {
|
||||
const auto pixel = glyph.pixels()[start + (c >> 3)] & (1U << (c & 0x7));
|
||||
pixel_row[start_pos + i + c] = pixel ? Theme::getInstance()->bg_darkest->foreground : Theme::getInstance()->bg_darkest->background;
|
||||
}
|
||||
|
||||
const auto advance = glyph.advance();
|
||||
i += advance.x();
|
||||
}
|
||||
render_line++;
|
||||
}
|
||||
|
||||
credits_display.new_row(pixel_row);
|
||||
}
|
||||
|
||||
AboutView::AboutView(
|
||||
NavigationView& nav) {
|
||||
add_children({&credits_display,
|
||||
&button_ok});
|
||||
|
||||
button_ok.on_select = [&nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
void AboutView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_ABOUT_H__
|
||||
#define __UI_ABOUT_H__
|
||||
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class CreditsWidget : public Widget {
|
||||
public:
|
||||
CreditsWidget(Rect parent_rect);
|
||||
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
|
||||
void paint(Painter&) override;
|
||||
|
||||
void new_row(const std::array<Color, 240>& pixel_row);
|
||||
|
||||
private:
|
||||
void clear();
|
||||
};
|
||||
|
||||
class AboutView : public View {
|
||||
public:
|
||||
AboutView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "About"; };
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
uint8_t credits_index{0};
|
||||
uint8_t render_line{0};
|
||||
Coord start_pos{0};
|
||||
uint8_t slow_down{0};
|
||||
int32_t timer{0};
|
||||
bool loop{false};
|
||||
|
||||
std::string text{};
|
||||
|
||||
typedef struct credits_t {
|
||||
size_t start_pos;
|
||||
std::string text;
|
||||
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},
|
||||
{11 * 8, "Gurus J. Boone", 0},
|
||||
{18 * 8, "M. Ossmann", 16},
|
||||
{11 * 8, "HAVOC Furrtek", 16},
|
||||
{7 * 8, "POCSAG rx T. Sailer", 0},
|
||||
{18 * 8, "E. Oenal", 16},
|
||||
{0 * 8, "Radiosonde infos F4GMU", 0},
|
||||
{18 * 8, "RS1729", 16},
|
||||
{4 * 8, "RDS waveform C. Jacquet", 16},
|
||||
{7 * 8, "Xy. infos cLx", 16},
|
||||
{2 * 8, "OOK scan trick Samy Kamkar", 16},
|
||||
{7 * 8, "World map NASA", 16},
|
||||
{0 * 8, "TouchTunes infos Notpike", 16},
|
||||
{4 * 8, "Subaru infos Tom", 0},
|
||||
{18 * 8, "Wimmenhove", 16},
|
||||
{1 * 8, "GPS,TV,BTLE,NRF Shao", 24},
|
||||
{6 * 8, "Thanks & donators", 16},
|
||||
{1 * 8, "Rainer Matla Keld Norman", 0},
|
||||
{1 * 8, " Giorgio C. DC1RDB", 0},
|
||||
{1 * 8, " Sigmounte Waax", 0},
|
||||
{1 * 8, " Windyoona Channels", 0},
|
||||
{1 * 8, " F4GEV Pyr3x", 0},
|
||||
{1 * 8, " HB3YOE", 24},
|
||||
{11 * 8, "MMXVIII", -1}};
|
||||
|
||||
CreditsWidget credits_display{
|
||||
{0, 16, 240, 240}};
|
||||
|
||||
Button button_ok{
|
||||
{72, 272, 96, 24},
|
||||
"OK"};
|
||||
|
||||
MessageHandlerRegistration message_handler_update{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->update();
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_ABOUT_H__*/
|
||||
@@ -1,413 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <ch.h>
|
||||
|
||||
#include "demofont.hpp"
|
||||
#include "ymdata.hpp"
|
||||
|
||||
#include "cpld_update.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "ui_about.hpp"
|
||||
#include "touch.hpp"
|
||||
#include "sine_table.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace lpc43xx;
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void AboutView::on_show() {
|
||||
transmitter_model.set_target_frequency(1337000000); // TODO: Change
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 1536000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_audiotx_data(32, 50, false, 0);
|
||||
|
||||
// audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max);
|
||||
}
|
||||
|
||||
void AboutView::render_video() {
|
||||
uint8_t p, r, luma, chroma, cy;
|
||||
ui::Color cc;
|
||||
char ch;
|
||||
float s;
|
||||
|
||||
// Send framebuffer to LCD. Gotta go fast !
|
||||
display.render_box({30, 112}, {180, 72}, framebuffer);
|
||||
|
||||
// Clear framebuffer to black
|
||||
memset(framebuffer, 0, 180 * 72 * sizeof(ui::Color));
|
||||
|
||||
// Drum hit palette animation
|
||||
if (drum > 1) drum--;
|
||||
|
||||
// Render copper bars from Y buffer
|
||||
for (p = 0; p < 72; p++) {
|
||||
luma = copperbuffer[p] & 0x0F; // 0 is transparent
|
||||
if (luma) {
|
||||
chroma = copperbuffer[p] >> 4;
|
||||
cc = ui::Color(std::min((coppercolor[chroma][0] / luma) * drum, 255), std::min((coppercolor[chroma][1] / luma) * drum, 255), std::min((coppercolor[chroma][2] / luma) * drum, 255));
|
||||
for (r = 0; r < 180; r++)
|
||||
framebuffer[(p * 180) + r] = cc;
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll in/out state machine
|
||||
if (anim_state == 0) {
|
||||
// Scroll in
|
||||
if (ofy < 8) {
|
||||
ofy++;
|
||||
anim_state = 0;
|
||||
} else {
|
||||
anim_state = 1;
|
||||
}
|
||||
if (ofx < (int16_t)(180 - (strlen(credits[credits_index].name) * 16) - 8)) {
|
||||
ofx += 8;
|
||||
anim_state = 0;
|
||||
}
|
||||
} else if (anim_state == 1) {
|
||||
// Just wait
|
||||
if (credits_timer == (30 * 3)) {
|
||||
credits_timer = 0;
|
||||
anim_state = 2;
|
||||
} else {
|
||||
credits_timer++;
|
||||
}
|
||||
} else {
|
||||
// Scroll out
|
||||
if (credits[credits_index].change == true) {
|
||||
if (ofy > -24) {
|
||||
ofy--;
|
||||
anim_state = 2;
|
||||
} else {
|
||||
anim_state = 0;
|
||||
}
|
||||
} else {
|
||||
anim_state = 0;
|
||||
}
|
||||
if (ofx < 180) {
|
||||
ofx += 8;
|
||||
anim_state = 2;
|
||||
}
|
||||
|
||||
// Switch to next text
|
||||
if (anim_state == 0) {
|
||||
if (credits_index == 9)
|
||||
credits_index = 0;
|
||||
else
|
||||
credits_index++;
|
||||
ofx = -(strlen(credits[credits_index].name) * 16) - 16;
|
||||
}
|
||||
}
|
||||
|
||||
// Sine text ("role")
|
||||
p = 0;
|
||||
while ((ch = credits[credits_index].role[p])) {
|
||||
draw_demoglyph({(ui::Coord)(8 + (p * 16)), (ui::Coord)(ofy + (sine_table_f32[((p * 16) + (phase >> 5)) & 0xFF] * 8))}, ch, paletteA);
|
||||
p++;
|
||||
}
|
||||
|
||||
// Scroll text (name)
|
||||
p = 0;
|
||||
while ((ch = credits[credits_index].name[p])) {
|
||||
draw_demoglyph({(ui::Coord)(ofx + (p * 16)), 56}, ch, paletteB);
|
||||
p++;
|
||||
}
|
||||
|
||||
// Clear bars Y buffer
|
||||
memset(copperbuffer, 0, 72);
|
||||
|
||||
// Render bars to Y buffer
|
||||
for (p = 0; p < 5; p++) {
|
||||
cy = copperbars[p];
|
||||
for (r = 0; r < 16; r++)
|
||||
copperbuffer[cy + r] = copperluma[r] + (p << 4);
|
||||
}
|
||||
|
||||
// Animate bars positions
|
||||
for (p = 0; p < 5; p++) {
|
||||
s = sine_table_f32[((p * 32) + (phase / 24)) & 0xFF];
|
||||
s += sine_table_f32[((p * 16) + (phase / 35)) & 0xFF];
|
||||
copperbars[p] = 28 + (uint8_t)(s * 14);
|
||||
}
|
||||
|
||||
phase += 128;
|
||||
}
|
||||
|
||||
void AboutView::draw_demoglyph(ui::Point p, char ch, ui::Color* pal) {
|
||||
uint8_t x, y, c, cl, cr;
|
||||
uint16_t che;
|
||||
int16_t lbx, il;
|
||||
|
||||
// Map ASCII to font bitmap
|
||||
if ((ch >= 32) && (ch < 96))
|
||||
che = char_map[ch - 32];
|
||||
else
|
||||
che = 0xFF;
|
||||
|
||||
if (che < 0xFF) {
|
||||
che = (che * 128) + 48; // Start in bitmap
|
||||
|
||||
il = (180 * p.y) + p.x; // Start il framebuffer
|
||||
|
||||
for (y = 0; y < 16; y++) {
|
||||
if (p.y + y >= 72) break; // Over bottom of framebuffer, abort
|
||||
if (p.y + y >= 0) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
c = demofont_bin[x + (y * 8) + che]; // Split byte in 2 4BPP pixels
|
||||
cl = c >> 4;
|
||||
cr = c & 0x0F;
|
||||
lbx = p.x + (x * 2);
|
||||
if (cl && (lbx < 180) && (lbx >= 0)) framebuffer[il] = pal[cl];
|
||||
lbx++;
|
||||
il++;
|
||||
if (cr && (lbx < 180) && (lbx >= 0)) framebuffer[il] = pal[cr];
|
||||
il++;
|
||||
}
|
||||
il += 180 - 16;
|
||||
} else {
|
||||
il += 180;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AboutView::render_audio() {
|
||||
uint8_t i, ymdata;
|
||||
uint16_t ym_render_cnt;
|
||||
|
||||
// This is heavily inspired by MAME's ay8910.cpp and the YM2149's datasheet
|
||||
|
||||
// Render 1024 music samples
|
||||
for (ym_render_cnt = 0; ym_render_cnt < 1024; ym_render_cnt++) {
|
||||
// Update registers at 48000/960 = 50Hz
|
||||
if (ym_sample_cnt == 0) {
|
||||
// "Decompress" on the fly and update YM registers
|
||||
for (i = 0; i < 14; i++) {
|
||||
if (!ym_regs[i].cnt) {
|
||||
// New run
|
||||
ymdata = ymdata_bin[ym_regs[i].ptr++];
|
||||
ym_regs[i].cnt = ymdata & 0x7F;
|
||||
if (ymdata & 0x80) {
|
||||
ym_regs[i].same = true;
|
||||
ym_regs[i].value = ymdata_bin[ym_regs[i].ptr++];
|
||||
} else {
|
||||
ym_regs[i].same = false;
|
||||
}
|
||||
// Detect drum on channel B
|
||||
if (i == 3)
|
||||
if (ym_regs[3].value > 2) drum = 4;
|
||||
}
|
||||
if (ym_regs[i].same == false) {
|
||||
ym_regs[i].value = ymdata_bin[ym_regs[i].ptr++];
|
||||
if (i == 13) {
|
||||
// Update envelope attributes
|
||||
ym_env_att = (ym_regs[13].value & 4) ? 0x1F : 0x00;
|
||||
if (!(ym_regs[13].value & 8)) {
|
||||
ym_env_hold = 1;
|
||||
ym_env_alt = ym_env_att;
|
||||
} else {
|
||||
ym_env_hold = ym_regs[13].value & 1;
|
||||
ym_env_alt = ym_regs[13].value & 2;
|
||||
}
|
||||
// Reset envelope counter
|
||||
ym_env_step = 0x1F;
|
||||
ym_env_holding = 0;
|
||||
ym_env_vol = (ym_env_step ^ ym_env_att);
|
||||
}
|
||||
}
|
||||
ym_regs[i].cnt--;
|
||||
}
|
||||
ym_frame++;
|
||||
}
|
||||
|
||||
// Square wave oscillators
|
||||
// 2457600/16/48000 = 3.2, but 4 sounds better than 3...
|
||||
for (i = 0; i < 3; i++) {
|
||||
ym_osc_cnt[i] += 4;
|
||||
if (ym_osc_cnt[i] >= (ym_regs[i * 2].value | ((ym_regs[(i * 2) + 1].value & 0x0f) << 8))) {
|
||||
ym_osc_cnt[i] = 0;
|
||||
ym_osc_out[i] ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Noise generator
|
||||
ym_noise_cnt += 4;
|
||||
if (ym_noise_cnt >= ((ym_regs[6].value & 0x1F) * 2)) {
|
||||
ym_noise_cnt = 0;
|
||||
ym_rng ^= (((ym_rng & 1) ^ ((ym_rng >> 3) & 1)) << 17);
|
||||
ym_rng >>= 1;
|
||||
}
|
||||
|
||||
// Mix tones and noise
|
||||
for (i = 0; i < 3; i++)
|
||||
ym_ch[i] = (ym_osc_out[i] | ((ym_regs[7].value >> i) & 1)) & ((ym_rng & 1) | ((ym_regs[7].value >> (i + 3)) & 1));
|
||||
|
||||
// Envelope generator
|
||||
if (!ym_env_holding) {
|
||||
ym_env_cnt += 8;
|
||||
if (ym_env_cnt >= (ym_regs[11].value | (ym_regs[12].value << 8))) {
|
||||
ym_env_cnt = 0;
|
||||
ym_env_step--;
|
||||
if (ym_env_step < 0) {
|
||||
if (ym_env_hold) {
|
||||
if (ym_env_alt)
|
||||
ym_env_att ^= 0x1F;
|
||||
ym_env_holding = 1;
|
||||
ym_env_step = 0;
|
||||
} else {
|
||||
if (ym_env_alt && (ym_env_step & 0x20))
|
||||
ym_env_att ^= 0x1F;
|
||||
ym_env_step &= 0x1F;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ym_env_vol = (ym_env_step ^ ym_env_att);
|
||||
|
||||
ym_out = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (ym_regs[i + 8].value & 0x10) {
|
||||
// Envelope mode
|
||||
ym_out += (ym_ch[i] ? ym_env_vol : 0);
|
||||
} else {
|
||||
// Fixed mode
|
||||
ym_out += (ym_ch[i] ? (ym_regs[i + 8].value & 0x0F) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
ym_buffer[ym_render_cnt] = (ym_out * 2) - 45;
|
||||
|
||||
if (ym_sample_cnt < 960) {
|
||||
ym_sample_cnt++;
|
||||
} else {
|
||||
ym_sample_cnt = 0;
|
||||
}
|
||||
|
||||
// Loop
|
||||
if (ym_frame == ym_frames) ym_init();
|
||||
}
|
||||
}
|
||||
|
||||
void AboutView::update() {
|
||||
if (framebuffer) {
|
||||
// Update 1 out of 2 frames, 60Hz is very laggy
|
||||
if (refresh_cnt & 1) render_video();
|
||||
refresh_cnt++;
|
||||
}
|
||||
|
||||
// Slowly increase volume to avoid jumpscare
|
||||
if (headphone_vol < (70 << 2)) {
|
||||
audio::headphone::set_volume(volume_t::decibel((headphone_vol / 4) - 99) + audio::headphone::volume_range().max);
|
||||
headphone_vol++;
|
||||
}
|
||||
}
|
||||
|
||||
void AboutView::ym_init() {
|
||||
uint8_t reg;
|
||||
|
||||
for (reg = 0; reg < 14; reg++) {
|
||||
ym_regs[reg].cnt = 0;
|
||||
// Pick up start pointers for each YM registers RLE blocks
|
||||
ym_regs[reg].ptr = ((uint16_t)(ymdata_bin[(reg * 2) + 3]) << 8) + ymdata_bin[(reg * 2) + 2];
|
||||
ym_regs[reg].same = false; // Useless ?
|
||||
ym_regs[reg].value = 0; // Useless ?
|
||||
}
|
||||
|
||||
ym_frame = 0;
|
||||
}
|
||||
|
||||
AboutView::AboutView(
|
||||
NavigationView& nav) {
|
||||
uint8_t p, c;
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||
|
||||
add_children({{
|
||||
&text_title,
|
||||
&text_firmware,
|
||||
&text_cpld_hackrf,
|
||||
&text_cpld_hackrf_status,
|
||||
&button_ok,
|
||||
}});
|
||||
|
||||
if (cpld_hackrf_verify_eeprom()) {
|
||||
text_cpld_hackrf_status.set(" OK");
|
||||
} else {
|
||||
text_cpld_hackrf_status.set("BAD");
|
||||
}
|
||||
|
||||
// Politely ask for about 26kB
|
||||
framebuffer = (ui::Color*)chHeapAlloc(0x0, 180 * 72 * sizeof(ui::Color));
|
||||
|
||||
if (framebuffer) {
|
||||
memset(framebuffer, 0, 180 * 72 * sizeof(ui::Color));
|
||||
|
||||
// Copy original font palette
|
||||
c = 0;
|
||||
for (p = 0; p < 48; p += 3)
|
||||
paletteA[c++] = ui::Color(demofont_bin[p], demofont_bin[p + 1], demofont_bin[p + 2]);
|
||||
|
||||
// Increase red in another one
|
||||
c = 0;
|
||||
for (p = 0; p < 48; p += 3)
|
||||
paletteB[c++] = ui::Color(std::min(demofont_bin[p] + 64, 255), demofont_bin[p + 1], demofont_bin[p + 2]);
|
||||
}
|
||||
|
||||
// Init YM synth
|
||||
ym_frames = ((uint16_t)(ymdata_bin[1]) << 8) + ymdata_bin[0];
|
||||
ym_init();
|
||||
|
||||
button_ok.on_select = [this, &nav](Button&) {
|
||||
if (framebuffer) chHeapFree(framebuffer); // Do NOT forget this
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
AboutView::~AboutView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void AboutView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_ABOUT_H__
|
||||
#define __UI_ABOUT_H__
|
||||
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "transmitter_model.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class AboutView : public View {
|
||||
public:
|
||||
AboutView(NavigationView& nav);
|
||||
~AboutView();
|
||||
|
||||
void on_show() override;
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
void ym_init();
|
||||
void update();
|
||||
void render_video();
|
||||
void render_audio();
|
||||
void draw_demoglyph(ui::Point p, char ch, ui::Color* pal);
|
||||
uint16_t debug_cnt = 0;
|
||||
|
||||
typedef struct ymreg_t {
|
||||
uint8_t value;
|
||||
uint8_t cnt;
|
||||
uint16_t ptr;
|
||||
bool same;
|
||||
} ymreg_t;
|
||||
|
||||
uint16_t headphone_vol = 5 << 2;
|
||||
|
||||
ymreg_t ym_regs[14];
|
||||
uint16_t ym_frames;
|
||||
uint16_t ym_frame;
|
||||
uint8_t drum = 0;
|
||||
uint16_t ym_osc_cnt[3];
|
||||
uint32_t ym_rng = 1;
|
||||
uint16_t ym_noise_cnt;
|
||||
uint8_t ym_env_att, ym_env_hold, ym_env_alt, ym_env_holding, ym_env_vol;
|
||||
int8_t ym_env_step;
|
||||
uint16_t ym_env_cnt;
|
||||
uint8_t ym_osc_out[3];
|
||||
uint8_t ym_ch[3];
|
||||
uint8_t ym_out;
|
||||
uint16_t ym_sample_cnt = 0;
|
||||
|
||||
int8_t ym_buffer[1024];
|
||||
|
||||
uint8_t refresh_cnt;
|
||||
ui::Color paletteA[16];
|
||||
ui::Color paletteB[16];
|
||||
ui::Color* framebuffer;
|
||||
uint32_t phase = 0;
|
||||
uint8_t copperbars[5] = {0};
|
||||
uint8_t copperbuffer[72] = {0};
|
||||
|
||||
uint8_t anim_state = 0;
|
||||
uint8_t credits_index = 0;
|
||||
uint16_t credits_timer = 0;
|
||||
|
||||
int16_t ofx = -180, ofy = -24;
|
||||
|
||||
const uint8_t char_map[64] = {0xFF, 27, 46, 0xFF, 0xFF, 0xFF, 28, 45,
|
||||
58, 59, 0xFF, 43, 40, 57, 26, 42,
|
||||
29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 41, 0xFF, 0xFF, 0xFF, 0xFF, 44,
|
||||
0xFF, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22,
|
||||
23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
const uint8_t copperluma[16] = {8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
const uint8_t coppercolor[5][3] = {{255, 0, 0},
|
||||
{0, 255, 0},
|
||||
{0, 0, 255},
|
||||
{255, 0, 255},
|
||||
{255, 255, 0}};
|
||||
|
||||
typedef struct credits_t {
|
||||
char role[12];
|
||||
char name[12];
|
||||
bool change;
|
||||
} credits_t;
|
||||
|
||||
// 0123456789A 0123456789A
|
||||
const credits_t credits[10] = {{"GURUS", "J. BOONE", false},
|
||||
{"GURUS", "M. OSSMANN", true},
|
||||
{"BUGS", "FURRTEK", true},
|
||||
{"RDS WAVE", "C. JACQUET", true},
|
||||
{"POCSAG RX", "T. SAILER", false},
|
||||
{"POCSAG RX", "E. OENAL", true},
|
||||
{"XYLOS DATA", "CLX", true},
|
||||
{"GREETS TO", "SIGMOUNTE", false},
|
||||
{"GREETS TO", "WINDYOONA", true},
|
||||
{"THIS MUSIC", "BIG ALEC", true}};
|
||||
|
||||
Text text_title{
|
||||
{100, 32, 40, 16},
|
||||
"About",
|
||||
};
|
||||
|
||||
Text text_firmware{
|
||||
{0, 236, 240, 16},
|
||||
"Version " VERSION_STRING,
|
||||
};
|
||||
|
||||
Text text_cpld_hackrf{
|
||||
{0, 252, 11 * 8, 16},
|
||||
"HackRF CPLD",
|
||||
};
|
||||
|
||||
Text text_cpld_hackrf_status{
|
||||
{240 - 3 * 8, 252, 3 * 8, 16},
|
||||
"???"};
|
||||
|
||||
Button button_ok{
|
||||
{72, 272, 96, 24},
|
||||
"OK"};
|
||||
|
||||
MessageHandlerRegistration message_handler_update{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->update();
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal{
|
||||
Message::ID::FIFOSignal,
|
||||
[this](const Message* const p) {
|
||||
const auto message = static_cast<const FIFOSignalMessage*>(p);
|
||||
if (message->signaltype == 1) {
|
||||
this->render_audio();
|
||||
baseband::set_fifo_data(ym_buffer);
|
||||
}
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_ABOUT_H__*/
|
||||
@@ -12,17 +12,25 @@ const std::string authors_list[] = {
|
||||
"johnelder,jwetzell,nnemanjan00",
|
||||
"N0vaPixel,klockee,gullradriel",
|
||||
"jamesshao8,ITAxReal,rascafr",
|
||||
"mcules,dqs105,strijar",
|
||||
"mcules,dqs105,strijar,fossum",
|
||||
"zhang00963,RedFox-Fr,aldude999",
|
||||
"East2West,fossum,ArjanOnwezen",
|
||||
"vXxOinvizioNxX,teixeluis",
|
||||
"Brumi-2021,texasyojimbo",
|
||||
"East2West,ArjanOnwezen,jLynx",
|
||||
"vXxOinvizioNxX,teixeluis,n0xa",
|
||||
"Brumi-2021,texasyojimbo,zigad",
|
||||
"heurist1,intoxsick,ckuethe",
|
||||
"notpike,jLynx,zigad",
|
||||
"MichalLeonBorsuk,jimilinuxguy",
|
||||
"kallanreed,bernd-herzog",
|
||||
"NotherNgineer,zxkmm,u-foka",
|
||||
"Netro,HTotoo",
|
||||
"notpike,MichalLeonBorsuk",
|
||||
"kallanreed,bernd-herzog,zxkmm",
|
||||
"NotherNgineer,jimilinuxguy",
|
||||
"iNetro,HTotoo,BehleZebub,dc2dc",
|
||||
"arneluehrs,u-foka,Maescool",
|
||||
"nnesetto,formtapez,F33RNI",
|
||||
"rusty-labs,andrej-mk,taskinen",
|
||||
"MatiasFernandez,TQMatvey,KimIV",
|
||||
"RobertoD91,RndmNmbr,OpCode1300",
|
||||
"alex10791,GitClo,GermanAizek",
|
||||
"JimiHFord,jstockdale,aSmig",
|
||||
"KillerTurtleSoftware,Lpd738",
|
||||
"MattLodge,z3r0l1nk,joyel24",
|
||||
" ",
|
||||
"#Havoc:",
|
||||
"furrtek,mrmookie,NotPike",
|
||||
|
||||
@@ -122,6 +122,10 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
void APRSRxView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
void APRSRxView::on_packet(const APRSPacketMessage* message) {
|
||||
std::string str_console = "\x1B";
|
||||
|
||||
|
||||
@@ -185,6 +185,7 @@ class APRSRxView : public View {
|
||||
|
||||
std::string title() const override { return "APRS RX"; };
|
||||
void on_packet(const APRSPacketMessage* message);
|
||||
void on_freqchg(int64_t freq);
|
||||
|
||||
private:
|
||||
void on_data(uint32_t value, bool is_data);
|
||||
@@ -271,6 +272,13 @@ class APRSRXView : public View {
|
||||
this->view_stream.on_packet(message);
|
||||
this->view_table.on_pkt(message);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->view_stream.on_freqchg(message->freq);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -49,6 +50,10 @@ void BattinfoView::update_result() {
|
||||
text_voltage.set("UNKNOWN");
|
||||
text_current.set("-");
|
||||
text_charge.set("-");
|
||||
text_cycles.set("-");
|
||||
text_ttef.set("-");
|
||||
text_method.set("-");
|
||||
text_warn.set("");
|
||||
return;
|
||||
}
|
||||
bool uichg = false;
|
||||
@@ -72,11 +77,59 @@ void BattinfoView::update_result() {
|
||||
text_current.set(to_string_dec_int(current) + " mA");
|
||||
text_charge.set(current >= 0 ? "Charging" : "Discharging");
|
||||
labels_opt.hidden(false);
|
||||
|
||||
text_ttef.hidden(false);
|
||||
} else {
|
||||
if (!labels_opt.hidden()) uichg = true;
|
||||
labels_opt.hidden(true);
|
||||
text_current.hidden(true);
|
||||
text_charge.hidden(true);
|
||||
text_cycles.hidden(true);
|
||||
text_ttef.hidden(true);
|
||||
text_warn.set("");
|
||||
}
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_CYCLES) == battery::BatteryManagement::BATT_VALID_CYCLES) {
|
||||
text_cycles.hidden(false);
|
||||
uint16_t cycles = battery::BatteryManagement::get_cycles();
|
||||
if (cycles < 2)
|
||||
text_warn.set("SoC improves after 2 cycles");
|
||||
else
|
||||
text_warn.set("");
|
||||
text_cycles.set(to_string_dec_uint(cycles));
|
||||
} else {
|
||||
text_cycles.hidden(true);
|
||||
text_warn.set("");
|
||||
}
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_TTEF) == battery::BatteryManagement::BATT_VALID_TTEF) {
|
||||
text_ttef.hidden(false);
|
||||
float ttef = 0;
|
||||
if (current <= 0) {
|
||||
ttef = battery::BatteryManagement::get_tte();
|
||||
} else {
|
||||
ttef = battery::BatteryManagement::get_ttf();
|
||||
}
|
||||
|
||||
// Convert ttef to hours and minutes
|
||||
uint8_t hours = static_cast<uint8_t>(ttef);
|
||||
uint8_t minutes = static_cast<uint8_t>((ttef - hours) * 60 + 0.5); // +0.5 for rounding
|
||||
|
||||
// Create the formatted string
|
||||
std::string formatted_time;
|
||||
if (hours > 0) {
|
||||
formatted_time += to_string_dec_uint(hours) + "h ";
|
||||
}
|
||||
formatted_time += to_string_dec_uint(minutes) + "m";
|
||||
|
||||
text_ttef.set(formatted_time);
|
||||
} else {
|
||||
text_ttef.hidden(true);
|
||||
}
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_PERCENT) == battery::BatteryManagement::BATT_VALID_PERCENT) {
|
||||
text_method.set("IC");
|
||||
button_mode.set_text("Volt");
|
||||
} else {
|
||||
text_method.set("Voltage");
|
||||
button_mode.set_text("IC");
|
||||
}
|
||||
if (uichg) set_dirty();
|
||||
// to update status bar too, send message in behalf of batt manager
|
||||
@@ -92,12 +145,27 @@ BattinfoView::BattinfoView(NavigationView& nav)
|
||||
&text_voltage,
|
||||
&text_current,
|
||||
&text_charge,
|
||||
&button_exit});
|
||||
&text_method,
|
||||
&button_mode,
|
||||
&button_exit,
|
||||
&text_cycles,
|
||||
&text_warn,
|
||||
&text_ttef});
|
||||
|
||||
button_exit.on_select = [this, &nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
button_mode.on_select = [this, &nav](Button&) {
|
||||
if (button_mode.text() == "IC") {
|
||||
battery::BatteryManagement::set_calc_override(false);
|
||||
persistent_memory::set_ui_override_batt_calc(false);
|
||||
button_mode.set_text("Volt");
|
||||
} else {
|
||||
battery::BatteryManagement::set_calc_override(true);
|
||||
persistent_memory::set_ui_override_batt_calc(true);
|
||||
button_mode.set_text("IC");
|
||||
}
|
||||
};
|
||||
update_result();
|
||||
if (thread == nullptr) thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, BattinfoView::static_fn, this);
|
||||
}
|
||||
@@ -118,4 +186,4 @@ BattinfoView::~BattinfoView() {
|
||||
thread = nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace ui
|
||||
} // namespace ui
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -27,6 +28,7 @@
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "i2cdevmanager.hpp"
|
||||
|
||||
namespace ui {
|
||||
class BattinfoView : public View {
|
||||
@@ -53,11 +55,17 @@ class BattinfoView : public View {
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 1 * 16}, "Percent:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 2 * 16}, "Voltage:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{2 * 8, 2 * 16}, "Voltage:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 3 * 16}, "Method:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Labels labels_opt{
|
||||
{{2 * 8, 3 * 16}, "Current:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 4 * 16}, "Charge:", Theme::getInstance()->fg_light->foreground}};
|
||||
{{2 * 8, 4 * 16}, "Current:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 5 * 16}, "Charge:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 6 * 16}, "TTF/E:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 7 * 16}, "Cycles:", Theme::getInstance()->fg_light->foreground},
|
||||
{{2 * 8, 10 * 16}, "Change method:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Text text_percent{
|
||||
{13 * 8, 1 * 16, 10 * 16, 16},
|
||||
@@ -65,12 +73,29 @@ class BattinfoView : public View {
|
||||
Text text_voltage{
|
||||
{13 * 8, 2 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Text text_current{
|
||||
Text text_method{
|
||||
{13 * 8, 3 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Text text_charge{
|
||||
Text text_current{
|
||||
{13 * 8, 4 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Text text_charge{
|
||||
{13 * 8, 5 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Text text_ttef{
|
||||
{13 * 8, 6 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Text text_cycles{
|
||||
{13 * 8, 7 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
|
||||
Text text_warn{
|
||||
{2 * 8, 8 * 16, 30 * 8, 2 * 16},
|
||||
""};
|
||||
|
||||
Button button_mode{
|
||||
{2 * 8, 11 * 16 + 5, 5 * 16, 32},
|
||||
"Volt"};
|
||||
|
||||
Button button_exit{
|
||||
{72, 17 * 16, 96, 32},
|
||||
@@ -81,4 +106,4 @@ class BattinfoView : public View {
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_BATTINFO__*/
|
||||
#endif /*__UI_BATTINFO__*/
|
||||
@@ -36,6 +36,8 @@
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_external_items_menu_loader.hpp"
|
||||
#include "ui_debug_max17055.hpp"
|
||||
#include "ui_external_module_view.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
@@ -225,8 +227,10 @@ uint32_t RegistersWidget::reg_read(const uint32_t register_number) {
|
||||
return radio::debug::second_if::register_read(register_number);
|
||||
case CT_SI5351:
|
||||
return portapack::clock_generator.read_register(register_number);
|
||||
case CT_BATTERY:
|
||||
return battery::BatteryManagement::read_register(register_number);
|
||||
case CT_MAX17055: {
|
||||
i2cdev::I2cDev_MAX17055* dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||
return dev->read_register(register_number);
|
||||
}
|
||||
case CT_AUDIO:
|
||||
return audio::debug::reg_read(register_number);
|
||||
}
|
||||
@@ -248,9 +252,11 @@ void RegistersWidget::reg_write(const uint32_t register_number, const uint32_t v
|
||||
case CT_SI5351:
|
||||
portapack::clock_generator.write_register(register_number, value);
|
||||
break;
|
||||
case CT_BATTERY:
|
||||
battery::BatteryManagement::write_register(register_number, value);
|
||||
case CT_MAX17055: {
|
||||
i2cdev::I2cDev_MAX17055* dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||
dev->write_register(register_number, value);
|
||||
break;
|
||||
}
|
||||
case CT_AUDIO:
|
||||
audio::debug::reg_write(register_number, value);
|
||||
break;
|
||||
@@ -464,9 +470,9 @@ void DebugPeripheralsMenuView::on_populate() {
|
||||
{si5351x, Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this, si5351x]() { nav_.push<RegistersView>(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }},
|
||||
{audio::debug::codec_name(), Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_count(), audio::debug::reg_bits()}); }},
|
||||
});
|
||||
if (battery::BatteryManagement::detectedModule() == battery::BatteryManagement::BatteryModules::BATT_MAX17055) {
|
||||
if (i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055)) {
|
||||
add_item(
|
||||
{"MAX17055", Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>("MAX17055", RegistersWidgetConfig{CT_BATTERY, 256, 16, 16}); }});
|
||||
{"MAX17055", Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>("MAX17055", RegistersWidgetConfig{CT_MAX17055, 256, 16, 16}); }});
|
||||
}
|
||||
set_max_rows(2); // allow wider buttons
|
||||
}
|
||||
@@ -509,8 +515,14 @@ void DebugMenuView::on_populate() {
|
||||
{"Temperature", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_temperature, [this]() { nav_.push<TemperatureView>(); }},
|
||||
{"Touch Test", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_notepad, [this]() { nav_.push<DebugScreenTest>(); }},
|
||||
{"Reboot", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
|
||||
{"Ext Module", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals_details, [this]() { nav_.push<ExternalModuleView>(); }},
|
||||
});
|
||||
|
||||
if (i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055)) {
|
||||
add_item(
|
||||
{"Battery", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_batt_icon, [this]() { nav_.push<BatteryCapacityView>(); }});
|
||||
}
|
||||
|
||||
for (auto const& gridItem : ExternalItemsMenuLoader::load_external_items(app_location_t::DEBUG, nav_)) {
|
||||
add_item(gridItem);
|
||||
};
|
||||
|
||||
@@ -139,7 +139,7 @@ typedef enum {
|
||||
CT_MAX283X,
|
||||
CT_SI5351,
|
||||
CT_AUDIO,
|
||||
CT_BATTERY,
|
||||
CT_MAX17055,
|
||||
} chip_type_t;
|
||||
|
||||
struct RegistersWidgetConfig {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#include "ui_debug_max17055.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
BatteryCapacityView::RegisterEntry BatteryCapacityView::get_entry(size_t index) {
|
||||
if (index < i2cdev::I2cDev_MAX17055::entries_count) {
|
||||
return i2cdev::I2cDev_MAX17055::entries[index];
|
||||
}
|
||||
return {"", 0, "", 0, false, "", false, 0, false, false, false, 0, false};
|
||||
}
|
||||
|
||||
BatteryCapacityView::BatteryCapacityView(NavigationView& nav) {
|
||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||
name_texts[i].set_parent_rect({0 * 8, static_cast<int>((i + 1) * 16), 8 * 8, 16});
|
||||
addr_texts[i].set_parent_rect({9 * 8, static_cast<int>((i + 1) * 16), 4 * 8, 16});
|
||||
hex_texts[i].set_parent_rect({14 * 8, static_cast<int>((i + 1) * 16), 6 * 8, 16});
|
||||
value_texts[i].set_parent_rect({21 * 8, static_cast<int>((i + 1) * 16), 10 * 8, 16});
|
||||
|
||||
add_child(&name_texts[i]);
|
||||
add_child(&addr_texts[i]);
|
||||
add_child(&hex_texts[i]);
|
||||
add_child(&value_texts[i]);
|
||||
}
|
||||
|
||||
add_children({&labels, &page_text, &button_done});
|
||||
|
||||
button_done.on_select = [&nav](Button&) { nav.pop(); };
|
||||
|
||||
auto dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||
if (!dev) { // dev not found
|
||||
nav.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
populate_page(0);
|
||||
update_page_text();
|
||||
}
|
||||
|
||||
void BatteryCapacityView::focus() {
|
||||
button_done.focus();
|
||||
}
|
||||
|
||||
bool BatteryCapacityView::on_encoder(const EncoderEvent delta) {
|
||||
int32_t new_page = current_page + delta;
|
||||
if (new_page >= 0 && new_page < ((int32_t)i2cdev::I2cDev_MAX17055::entries_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE) {
|
||||
current_page = new_page;
|
||||
populate_page(current_page * ENTRIES_PER_PAGE);
|
||||
update_page_text();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BatteryCapacityView::update_values() {
|
||||
i2cdev::I2cDev_MAX17055* dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||
size_t entry_index = current_page * ENTRIES_PER_PAGE + i;
|
||||
if (entry_index < i2cdev::I2cDev_MAX17055::entries_count) {
|
||||
const auto entry = get_entry(entry_index);
|
||||
uint16_t raw_value = dev->read_register(entry.address);
|
||||
|
||||
hex_texts[i].set("0x" + to_string_hex(raw_value, 4));
|
||||
|
||||
float scaled_value;
|
||||
if (entry.is_signed) {
|
||||
int16_t signed_value = static_cast<int16_t>(raw_value);
|
||||
scaled_value = signed_value * entry.scalar;
|
||||
} else {
|
||||
scaled_value = raw_value * entry.scalar;
|
||||
}
|
||||
|
||||
// Format the value with appropriate decimal places
|
||||
std::string formatted_value;
|
||||
if (entry.resolution > 0) {
|
||||
formatted_value = to_string_decimal(scaled_value, std::min(entry.resolution, 3));
|
||||
} else {
|
||||
formatted_value = to_string_dec_int(scaled_value); // Show up to 3 decimal places
|
||||
}
|
||||
|
||||
value_texts[i].set(formatted_value + " " + entry.unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BatteryCapacityView::populate_page(int start_index) {
|
||||
for (size_t i = 0; i < ENTRIES_PER_PAGE; ++i) {
|
||||
size_t entry_index = start_index + i;
|
||||
if (entry_index < i2cdev::I2cDev_MAX17055::entries_count) {
|
||||
const auto entry = get_entry(entry_index);
|
||||
name_texts[i].set(entry.name);
|
||||
addr_texts[i].set("0x" + to_string_hex(entry.address, 2));
|
||||
name_texts[i].hidden(false);
|
||||
addr_texts[i].hidden(false);
|
||||
hex_texts[i].hidden(false);
|
||||
value_texts[i].hidden(false);
|
||||
} else {
|
||||
name_texts[i].hidden(true);
|
||||
addr_texts[i].hidden(true);
|
||||
hex_texts[i].hidden(true);
|
||||
value_texts[i].hidden(true);
|
||||
}
|
||||
}
|
||||
update_values();
|
||||
}
|
||||
|
||||
void BatteryCapacityView::update_page_text() {
|
||||
int total_pages = (i2cdev::I2cDev_MAX17055::entries_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
|
||||
page_text.set("Page " + to_string_dec_uint(current_page + 1) + "/" + to_string_dec_uint(total_pages));
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef __UI_DEBUG_BATTERY_HPP__
|
||||
#define __UI_DEBUG_BATTERY_HPP__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "battery.hpp"
|
||||
#include "i2cdevmanager.hpp"
|
||||
#include "i2cdev_max17055.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class BatteryCapacityView : public View {
|
||||
public:
|
||||
BatteryCapacityView(NavigationView& nav);
|
||||
void focus() override;
|
||||
std::string title() const override { return "Battery Registers"; }
|
||||
|
||||
bool on_encoder(const EncoderEvent delta) override;
|
||||
|
||||
using RegisterEntry = i2cdev::I2cDev_MAX17055::RegisterEntry;
|
||||
|
||||
private:
|
||||
static RegisterEntry get_entry(size_t index);
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Reg", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{9 * 8, 0 * 16}, "Addr", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{14 * 8, 0 * 16}, "Hex", Theme::getInstance()->fg_yellow->foreground},
|
||||
{{21 * 8, 0 * 16}, "Value", Theme::getInstance()->fg_yellow->foreground},
|
||||
};
|
||||
std::array<Text, 16> name_texts = {};
|
||||
std::array<Text, 16> addr_texts = {};
|
||||
std::array<Text, 16> hex_texts = {};
|
||||
std::array<Text, 16> value_texts = {};
|
||||
|
||||
Text page_text{{144, 284, 80, 16}, "Page 1/1"};
|
||||
Button button_done{{16, 280, 96, 24}, "Done"};
|
||||
|
||||
void update_values();
|
||||
void populate_page(int start_index);
|
||||
void update_page_text();
|
||||
int current_page = 0;
|
||||
static constexpr int ENTRIES_PER_PAGE = 16;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif // __UI_DEBUG_BATTERY_HPP__
|
||||
@@ -41,11 +41,6 @@ DfuMenu::DfuMenu(NavigationView& nav)
|
||||
&text_info_line_8,
|
||||
&text_info_line_9,
|
||||
&text_info_line_10});
|
||||
|
||||
if (battery::BatteryManagement::isDetected()) {
|
||||
add_child(&voltage_label);
|
||||
add_child(&text_info_line_11);
|
||||
}
|
||||
}
|
||||
|
||||
void DfuMenu::paint(Painter& painter) {
|
||||
@@ -53,7 +48,7 @@ void DfuMenu::paint(Painter& painter) {
|
||||
size_t m0_fragmented_free_space = 0;
|
||||
const auto m0_fragments = chHeapStatus(NULL, &m0_fragmented_free_space);
|
||||
|
||||
auto lines = (battery::BatteryManagement::isDetected() ? 11 : 10) + 2;
|
||||
auto lines = 10 + 2;
|
||||
|
||||
text_info_line_1.set(to_string_dec_uint(chCoreStatus(), 6));
|
||||
text_info_line_2.set(to_string_dec_uint(m0_fragmented_free_space, 6));
|
||||
@@ -65,9 +60,6 @@ void DfuMenu::paint(Painter& painter) {
|
||||
text_info_line_8.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6));
|
||||
text_info_line_9.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
|
||||
text_info_line_10.set(to_string_dec_uint(chTimeNow() / 1000, 6));
|
||||
if (battery::BatteryManagement::isDetected()) {
|
||||
text_info_line_11.set(to_string_decimal_padding((float)battery::BatteryManagement::getVoltage() / 1000.0, 3, 6));
|
||||
}
|
||||
|
||||
constexpr auto margin = 5;
|
||||
|
||||
|
||||
@@ -60,8 +60,6 @@ class DfuMenu : public View {
|
||||
{{6 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "M4 miss:", Theme::getInstance()->fg_darkcyan->foreground},
|
||||
{{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "Uptime:", Theme::getInstance()->fg_darkcyan->foreground}};
|
||||
|
||||
Labels voltage_label{{{6 * CHARACTER_WIDTH, 15 * LINE_HEIGHT}, "Voltage:", Theme::getInstance()->fg_darkcyan->foreground}};
|
||||
|
||||
Text text_info_line_1{{15 * CHARACTER_WIDTH, 5 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_2{{15 * CHARACTER_WIDTH, 6 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_3{{15 * CHARACTER_WIDTH, 7 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
@@ -72,7 +70,6 @@ class DfuMenu : public View {
|
||||
Text text_info_line_8{{15 * CHARACTER_WIDTH, 12 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_9{{15 * CHARACTER_WIDTH, 13 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_10{{15 * CHARACTER_WIDTH, 14 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
Text text_info_line_11{{15 * CHARACTER_WIDTH, 15 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
|
||||
};
|
||||
|
||||
class DfuMenu2 : public View {
|
||||
|
||||
@@ -58,6 +58,7 @@ EncodersConfigView::EncodersConfigView(
|
||||
|
||||
options_enctype.on_change = [this](size_t index, int32_t) {
|
||||
on_type_change(index);
|
||||
set_dirty();
|
||||
};
|
||||
|
||||
options_enctype.set_options(enc_options);
|
||||
@@ -104,7 +105,18 @@ void EncodersConfigView::on_type_change(size_t index) {
|
||||
|
||||
// Add new SymFields.
|
||||
Point pos{2 * 8, 9 * 8};
|
||||
std::string format_string;
|
||||
std::string format_string = encoder_def->word_format;
|
||||
|
||||
/*important notes of this format_String
|
||||
* previously before PR#1444, this code using the for loop below to generate the format_string, which MAYBE to prevent showing the S symble.
|
||||
* but after PR#1444, the entireh of symfield code not compatible with this design anymore.
|
||||
* however the encoder_def struct itself has a field called word_format, which exactly be avle to use as the format_string,
|
||||
* because itself is ONLY a hint text, not impact protocol things.
|
||||
* When you find OOK protocol is broken and see this commit from git blame, please be aware that it's not from here.
|
||||
* previously me and @cusspvz already found it broken, this commit is just to fix the broken that from PR#1444.
|
||||
* @zxkmm
|
||||
*/
|
||||
|
||||
uint8_t word_length = encoder_def->word_length;
|
||||
auto on_change_handler = [this](SymField&) {
|
||||
generate_frame();
|
||||
@@ -119,11 +131,9 @@ void EncodersConfigView::on_type_change(size_t index) {
|
||||
switch (symbol_type) {
|
||||
case 'A':
|
||||
symfield->set_symbol_list(encoder_def->address_symbols);
|
||||
format_string += 'A';
|
||||
break;
|
||||
case 'D':
|
||||
symfield->set_symbol_list(encoder_def->data_symbols);
|
||||
format_string += 'D';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -131,8 +141,8 @@ void EncodersConfigView::on_type_change(size_t index) {
|
||||
pos += Point{8, 0};
|
||||
}
|
||||
|
||||
// Ugly :( Pad to erase
|
||||
format_string.append(24 - format_string.size(), ' ');
|
||||
// cut the S, cuz sync bit isn't in symfield for user to chage/edit.
|
||||
format_string.erase(std::remove(format_string.begin(), format_string.end(), 'S'), format_string.end());
|
||||
text_format.set(format_string);
|
||||
|
||||
generate_frame();
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_external_module_view.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "ui_standalone_view.hpp"
|
||||
|
||||
#include "i2cdevmanager.hpp"
|
||||
#include "i2cdev_ppmod.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace ui {
|
||||
|
||||
void ExternalModuleView::focus() {
|
||||
dummy.focus();
|
||||
}
|
||||
|
||||
void ExternalModuleView::on_tick_second() {
|
||||
i2cdev::I2CDevManager::manual_scan();
|
||||
|
||||
auto dev = (i2cdev::I2cDev_PPmod*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDECMDL_PPMOD);
|
||||
|
||||
if (!dev) {
|
||||
text_header.set("No module connected");
|
||||
text_name.set("");
|
||||
text_version.set("");
|
||||
text_number_apps.set("");
|
||||
text_app1_name.set("");
|
||||
text_app2_name.set("");
|
||||
text_app3_name.set("");
|
||||
text_app4_name.set("");
|
||||
text_app5_name.set("");
|
||||
return;
|
||||
}
|
||||
|
||||
auto device_info = dev->readDeviceInfo();
|
||||
|
||||
if (device_info.has_value() == false) {
|
||||
text_header.set("No module connected");
|
||||
text_name.set("");
|
||||
text_version.set("");
|
||||
text_number_apps.set("");
|
||||
text_app1_name.set("");
|
||||
text_app2_name.set("");
|
||||
text_app3_name.set("");
|
||||
text_app4_name.set("");
|
||||
text_app5_name.set("");
|
||||
return;
|
||||
}
|
||||
|
||||
text_header.set("Module found");
|
||||
|
||||
std::string btnText = (std::string) "Module: " + device_info->module_name;
|
||||
text_name.set(btnText);
|
||||
text_version.set("Version: " + std::to_string(device_info->module_version));
|
||||
text_number_apps.set("No# Apps: " + std::to_string(device_info->application_count));
|
||||
|
||||
for (uint32_t i = 0; i < device_info->application_count && i < 5; i++) {
|
||||
auto appInfo = dev->getStandaloneAppInfo(i);
|
||||
if (appInfo.has_value() == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string btnText = (std::string) "App " + std::to_string(device_info->application_count) + ": " + (const char*)appInfo->app_name;
|
||||
|
||||
switch (appInfo->menu_location) {
|
||||
case app_location_t::UTILITIES:
|
||||
btnText += " (Utilities)";
|
||||
break;
|
||||
case app_location_t::RX:
|
||||
btnText += " (RX)";
|
||||
break;
|
||||
case app_location_t::TX:
|
||||
btnText += " (TX)";
|
||||
break;
|
||||
case app_location_t::DEBUG:
|
||||
btnText += " (Debug)";
|
||||
break;
|
||||
case app_location_t::HOME:
|
||||
btnText += " (Home)";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
text_app1_name.set(btnText);
|
||||
break;
|
||||
case 1:
|
||||
text_app2_name.set(btnText);
|
||||
break;
|
||||
case 2:
|
||||
text_app3_name.set(btnText);
|
||||
break;
|
||||
case 3:
|
||||
text_app4_name.set(btnText);
|
||||
break;
|
||||
case 4:
|
||||
text_app5_name.set(btnText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace ui
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_EXTERNAL_MODULE_VIEW_H
|
||||
#define __UI_EXTERNAL_MODULE_VIEW_H
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
#include "rffc507x.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "memory_map.hpp"
|
||||
#include "irq_controls.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include "i2cdevmanager.hpp"
|
||||
#include "i2cdev_ppmod.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ExternalModuleView : public View {
|
||||
public:
|
||||
ExternalModuleView(NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
add_children({&text_header,
|
||||
&text_name,
|
||||
&text_version,
|
||||
&text_number_apps,
|
||||
&text_app1_name,
|
||||
&text_app2_name,
|
||||
&text_app3_name,
|
||||
&text_app4_name,
|
||||
&text_app5_name,
|
||||
&dummy});
|
||||
|
||||
text_header.set("No module connected");
|
||||
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
on_tick_second();
|
||||
};
|
||||
}
|
||||
|
||||
~ExternalModuleView() {
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
}
|
||||
|
||||
std::string title() const override { return "Ext Module"; };
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
Text text_header{{16, 16, 208, 16}};
|
||||
Text text_name{{24, 32, 200, 16}};
|
||||
Text text_version{{24, 48, 200, 16}};
|
||||
Text text_number_apps{{24, 64, 200, 16}};
|
||||
|
||||
Text text_app1_name{{24, 96, 200, 16}};
|
||||
Text text_app2_name{{24, 112, 200, 16}};
|
||||
Text text_app3_name{{24, 128, 200, 16}};
|
||||
Text text_app4_name{{24, 144, 200, 16}};
|
||||
Text text_app5_name{{24, 160, 200, 16}};
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
""};
|
||||
|
||||
SignalToken signal_token_tick_second{};
|
||||
|
||||
void on_tick_second();
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif
|
||||
@@ -323,4 +323,9 @@ void LevelView::handle_coded_squelch(const uint32_t value) {
|
||||
text_ctcss.set(" ");
|
||||
}
|
||||
|
||||
void LevelView::on_freqchg(int64_t freq) {
|
||||
receiver_model.set_target_frequency(freq);
|
||||
button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>");
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -188,6 +188,15 @@ class LevelView : public View {
|
||||
|
||||
void handle_coded_squelch(const uint32_t value);
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_coded_squelch{
|
||||
Message::ID::CodedSquelch,
|
||||
[this](const Message* const p) {
|
||||
|
||||
@@ -98,7 +98,6 @@ rf::Frequency GlassView::get_freq_from_bin_pos(uint8_t pos) {
|
||||
freq_at_pos = f_center_ini + ((pos - 120) * ((looking_glass_range - ((16 * looking_glass_range) / SPEC_NB_BINS)) / 2)) / (SCREEN_W / 2);
|
||||
} else
|
||||
freq_at_pos = f_min + (2 * offset * each_bin_size) + (pos * looking_glass_range) / SCREEN_W;
|
||||
|
||||
return freq_at_pos;
|
||||
}
|
||||
|
||||
@@ -257,7 +256,7 @@ void GlassView::on_range_changed() {
|
||||
bin_length = SCREEN_W;
|
||||
ignore_dc = 0;
|
||||
looking_glass_bandwidth = looking_glass_range;
|
||||
looking_glass_sampling_rate = looking_glass_bandwidth;
|
||||
looking_glass_sampling_rate = looking_glass_range;
|
||||
each_bin_size = looking_glass_bandwidth / SCREEN_W;
|
||||
looking_glass_step = looking_glass_bandwidth;
|
||||
f_center_ini = f_min + (looking_glass_bandwidth / 2); // Initial center frequency for sweep
|
||||
@@ -265,7 +264,7 @@ void GlassView::on_range_changed() {
|
||||
// view is made in multiple pass, use original bin picking
|
||||
mode = scan_type.selected_index_value();
|
||||
looking_glass_bandwidth = LOOKING_GLASS_SLICE_WIDTH_MAX;
|
||||
looking_glass_sampling_rate = LOOKING_GLASS_SLICE_WIDTH_MAX;
|
||||
looking_glass_sampling_rate = LOOKING_GLASS_MAX_SAMPLERATE;
|
||||
each_bin_size = LOOKING_GLASS_SLICE_WIDTH_MAX / SPEC_NB_BINS;
|
||||
if (mode == LOOKING_GLASS_FASTSCAN) {
|
||||
offset = 2;
|
||||
@@ -315,8 +314,8 @@ void GlassView::update_min(int32_t v) {
|
||||
int32_t min_size = steps;
|
||||
if (locked_range)
|
||||
min_size = search_span;
|
||||
if (min_size < 2)
|
||||
min_size = 2;
|
||||
if (min_size < 1)
|
||||
min_size = 1;
|
||||
if (v > 7200 - min_size) {
|
||||
v = 7200 - min_size;
|
||||
}
|
||||
@@ -332,8 +331,8 @@ void GlassView::update_max(int32_t v) {
|
||||
int32_t min_size = steps;
|
||||
if (locked_range)
|
||||
min_size = search_span;
|
||||
if (min_size < 2)
|
||||
min_size = 2;
|
||||
if (min_size < 1)
|
||||
min_size = 1;
|
||||
if (v < min_size) {
|
||||
v = min_size;
|
||||
}
|
||||
@@ -487,7 +486,12 @@ GlassView::GlassView(
|
||||
range_presets.set_selected_index(preset_index);
|
||||
|
||||
field_marker.on_encoder_change = [this](TextField&, EncoderEvent delta) {
|
||||
marker_pixel_index = clip<uint8_t>(marker_pixel_index + delta, 0, SCREEN_W);
|
||||
if ((marker_pixel_index + delta) < 0)
|
||||
marker_pixel_index = marker_pixel_index + delta + SCREEN_W;
|
||||
else if ((marker_pixel_index + delta) > SCREEN_W)
|
||||
marker_pixel_index = marker_pixel_index + delta - SCREEN_W;
|
||||
else
|
||||
marker_pixel_index = marker_pixel_index + delta;
|
||||
on_marker_change();
|
||||
};
|
||||
|
||||
@@ -561,6 +565,17 @@ GlassView::GlassView(
|
||||
update_display_beep();
|
||||
}
|
||||
|
||||
void GlassView::on_freqchg(int64_t freq) {
|
||||
int64_t half_range = abs(field_frequency_max.value() - field_frequency_max.value()) / 2;
|
||||
if (half_range < 1) {
|
||||
half_range = 1;
|
||||
}
|
||||
range_presets.set_selected_index(0); // Manual
|
||||
update_min(freq - half_range);
|
||||
update_max(freq + half_range);
|
||||
on_range_changed();
|
||||
}
|
||||
|
||||
uint8_t GlassView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read & write real iq_phase_calibration_value
|
||||
return iq_phase_calibration_value;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
namespace ui {
|
||||
|
||||
#define LOOKING_GLASS_SLICE_WIDTH_MAX 20000000
|
||||
#define LOOKING_GLASS_MAX_SAMPLERATE 20000000
|
||||
#define MHZ_DIV 1000000
|
||||
|
||||
// blanked DC (16 centered bins ignored ) and top left and right (2 bins ignored on each side )
|
||||
@@ -109,6 +110,7 @@ class GlassView : public View {
|
||||
std::string label{};
|
||||
};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh);
|
||||
std::vector<preset_entry> presets_db{};
|
||||
void manage_beep_audio();
|
||||
@@ -307,6 +309,7 @@ class GlassView : public View {
|
||||
const auto message = *reinterpret_cast<const ChannelSpectrumConfigMessage*>(p);
|
||||
this->fifo = message.fifo;
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
@@ -317,6 +320,13 @@ class GlassView : public View {
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
};
|
||||
} // namespace ui
|
||||
#endif
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_numbers.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
// TODO: This app takes way too much space, find a way to shrink/simplify or make it an SD card module (loadable)
|
||||
|
||||
void NumbersStationView::focus() {
|
||||
if (file_error)
|
||||
nav_.display_modal("No voices", "No valid voices found in\nthe /numbers directory.", ABORT);
|
||||
else
|
||||
button_exit.focus();
|
||||
}
|
||||
|
||||
NumbersStationView::~NumbersStationView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
NumbersStationView::wav_file_t* NumbersStationView::get_wav(uint32_t index) {
|
||||
return ¤t_voice->available_wavs[index];
|
||||
}
|
||||
|
||||
void NumbersStationView::prepare_audio() {
|
||||
uint8_t code;
|
||||
wav_file_t* wav_file;
|
||||
|
||||
if (sample_counter >= sample_length) {
|
||||
if (segment == ANNOUNCE) {
|
||||
if (!announce_loop) {
|
||||
code_index = 0;
|
||||
segment = MESSAGE;
|
||||
} else {
|
||||
wav_file = get_wav(11);
|
||||
reader->open(current_voice->dir + file_names[wav_file->index].name + ".wav");
|
||||
sample_length = wav_file->length;
|
||||
announce_loop--;
|
||||
}
|
||||
}
|
||||
|
||||
if (segment == MESSAGE) {
|
||||
if (code_index == 25) {
|
||||
transmitter_model.disable();
|
||||
return;
|
||||
}
|
||||
|
||||
code = symfield_code.get_offset(code_index);
|
||||
|
||||
if (code >= 10) {
|
||||
memset(audio_buffer, 0, 1024);
|
||||
if (code == 10) {
|
||||
pause = 11025; // p: 0.25s @ 44100Hz
|
||||
} else if (code == 11) {
|
||||
pause = 33075; // P: 0.75s @ 44100Hz
|
||||
} else if (code == 12) {
|
||||
transmitter_model.disable();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
wav_file = get_wav(code);
|
||||
reader->open(current_voice->dir + file_names[code].name + ".wav");
|
||||
sample_length = wav_file->length;
|
||||
}
|
||||
code_index++;
|
||||
}
|
||||
sample_counter = 0;
|
||||
}
|
||||
|
||||
if (!pause) {
|
||||
auto bytes_read = reader->read(audio_buffer, 1024).value();
|
||||
|
||||
// Unsigned to signed, pretty stupid :/
|
||||
for (size_t n = 0; n < bytes_read; n++)
|
||||
audio_buffer[n] -= 0x80;
|
||||
for (size_t n = bytes_read; n < 1024; n++)
|
||||
audio_buffer[n] = 0;
|
||||
|
||||
sample_counter += 1024;
|
||||
} else {
|
||||
if (pause >= 1024) {
|
||||
pause -= 1024;
|
||||
} else {
|
||||
sample_counter = sample_length;
|
||||
pause = 0;
|
||||
}
|
||||
}
|
||||
|
||||
baseband::set_fifo_data(audio_buffer);
|
||||
}
|
||||
|
||||
void NumbersStationView::start_tx() {
|
||||
// sample_length = sound_sizes[10]; // Announce
|
||||
sample_counter = sample_length;
|
||||
|
||||
code_index = 0;
|
||||
announce_loop = 2;
|
||||
segment = ANNOUNCE;
|
||||
|
||||
prepare_audio();
|
||||
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_audiotx_data(
|
||||
(1536000 / 44100) - 1, // TODO: Read wav file's samplerate
|
||||
12000,
|
||||
1,
|
||||
false,
|
||||
0);
|
||||
}
|
||||
|
||||
void NumbersStationView::on_tick_second() {
|
||||
armed_blink = not armed_blink;
|
||||
|
||||
if (armed_blink)
|
||||
check_armed.set_style(Theme::getInstance()->fg_red);
|
||||
else
|
||||
check_armed.set_style(&style());
|
||||
|
||||
check_armed.set_dirty();
|
||||
}
|
||||
|
||||
void NumbersStationView::on_voice_changed(size_t index) {
|
||||
std::string code_list;
|
||||
|
||||
for (const auto& wavs : voices[index].available_wavs)
|
||||
code_list += wavs.code;
|
||||
|
||||
symfield_code.set_symbol_list(code_list);
|
||||
current_voice = &voices[index];
|
||||
}
|
||||
|
||||
bool NumbersStationView::check_wav_validity(const std::string dir, const std::string file) {
|
||||
if (reader->open("/numbers/" + dir + "/" + file)) {
|
||||
// Check format (mono, 8 bits)
|
||||
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
NumbersStationView::NumbersStationView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
std::vector<std::filesystem::path> directory_list;
|
||||
using option_t = std::pair<std::string, int32_t>;
|
||||
using options_t = std::vector<option_t>;
|
||||
options_t voice_options;
|
||||
voice_t temp_voice{};
|
||||
bool valid;
|
||||
uint32_t c;
|
||||
// uint8_t y, m, d, dayofweek;
|
||||
|
||||
reader = std::make_unique<WAVFileReader>();
|
||||
|
||||
// Search for valid voice directories
|
||||
directory_list = scan_root_directories("/numbers");
|
||||
if (!directory_list.size()) {
|
||||
file_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& dir : directory_list) {
|
||||
c = 0;
|
||||
for (const auto& file_name : file_names) {
|
||||
valid = check_wav_validity(dir.string(), file_name.name + ".wav");
|
||||
if ((!valid) && (file_name.required)) {
|
||||
temp_voice.available_wavs.clear();
|
||||
break; // Invalid required file means invalid voice
|
||||
} else if (valid) {
|
||||
temp_voice.available_wavs.push_back({file_name.code, c++, 0, 0}); // TODO: Needs length and samplerate
|
||||
}
|
||||
}
|
||||
if (!temp_voice.available_wavs.empty()) {
|
||||
// Voice can be used, are there accent files ?
|
||||
c = 0;
|
||||
for (const auto& file_name : file_names) {
|
||||
valid = check_wav_validity(dir.string(), file_name.name + "a.wav");
|
||||
if ((!valid) && (file_name.required)) {
|
||||
c = 0;
|
||||
break; // Invalid required file means accents can't be used
|
||||
} else if (valid) {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
temp_voice.accent = c ? true : false;
|
||||
temp_voice.dir = dir.string();
|
||||
|
||||
voices.push_back(temp_voice);
|
||||
}
|
||||
}
|
||||
|
||||
if (voices.empty()) {
|
||||
file_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||
|
||||
add_children({&labels,
|
||||
&symfield_code,
|
||||
&check_armed,
|
||||
&options_voices,
|
||||
&text_voice_flags,
|
||||
//&button_tx_now,
|
||||
&button_exit});
|
||||
|
||||
for (const auto& voice : voices)
|
||||
voice_options.emplace_back(voice.dir.substr(0, 4), 0);
|
||||
|
||||
options_voices.set_options(voice_options);
|
||||
options_voices.on_change = [this](size_t i, int32_t) {
|
||||
this->on_voice_changed(i);
|
||||
};
|
||||
options_voices.set_selected_index(0);
|
||||
|
||||
check_armed.set_value(false);
|
||||
|
||||
check_armed.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) {
|
||||
armed_blink = false;
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
this->on_tick_second();
|
||||
};
|
||||
} else {
|
||||
check_armed.set_style(&style());
|
||||
rtc_time::signal_tick_second -= signal_token_tick_second;
|
||||
}
|
||||
};
|
||||
|
||||
// DEBUG
|
||||
symfield_code.set_offset(0, 10);
|
||||
symfield_code.set_offset(1, 3);
|
||||
symfield_code.set_offset(2, 4);
|
||||
symfield_code.set_offset(3, 11);
|
||||
symfield_code.set_offset(4, 6);
|
||||
symfield_code.set_offset(5, 1);
|
||||
symfield_code.set_offset(6, 9);
|
||||
symfield_code.set_offset(7, 7);
|
||||
symfield_code.set_offset(8, 8);
|
||||
symfield_code.set_offset(9, 0);
|
||||
symfield_code.set_offset(10, 12); // End
|
||||
|
||||
/*
|
||||
dayofweek = rtc_time::current_day_of_week();
|
||||
text_title.set(day_of_week[dayofweek]);
|
||||
*/
|
||||
|
||||
button_exit.on_select = [&nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_NUMBERS_H__
|
||||
#define __UI_NUMBERS_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "message.hpp"
|
||||
#include "file.hpp"
|
||||
#include "io_wave.hpp"
|
||||
#include "radio_state.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class NumbersStationView : public View {
|
||||
public:
|
||||
NumbersStationView(NavigationView& nav);
|
||||
~NumbersStationView();
|
||||
|
||||
NumbersStationView(const NumbersStationView&) = delete;
|
||||
NumbersStationView(NumbersStationView&&) = delete;
|
||||
NumbersStationView& operator=(const NumbersStationView&) = delete;
|
||||
NumbersStationView& operator=(NumbersStationView&&) = delete;
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Station"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
TxRadioState radio_state_{
|
||||
0 /* frequency */,
|
||||
1750000 /* bandwidth */,
|
||||
1536000 /* sampling rate */
|
||||
};
|
||||
|
||||
// Sequencing state machine
|
||||
enum segments {
|
||||
IDLE = 0,
|
||||
ANNOUNCE,
|
||||
MESSAGE,
|
||||
SIGNOFF
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char code;
|
||||
uint32_t index;
|
||||
uint32_t length;
|
||||
uint32_t samplerate;
|
||||
} wav_file_t;
|
||||
|
||||
struct voice_t {
|
||||
std::string dir;
|
||||
std::vector<wav_file_t> available_wavs;
|
||||
bool accent;
|
||||
};
|
||||
|
||||
std::vector<voice_t> voices{};
|
||||
voice_t* current_voice{};
|
||||
|
||||
struct wav_file_list_t {
|
||||
std::string name;
|
||||
bool required;
|
||||
char code;
|
||||
};
|
||||
|
||||
const std::vector<wav_file_list_t> file_names = {
|
||||
{"0", true, '0'},
|
||||
{"1", true, '1'},
|
||||
{"2", true, '2'},
|
||||
{"3", true, '3'},
|
||||
{"4", true, '4'},
|
||||
{"5", true, '5'},
|
||||
{"6", true, '6'},
|
||||
{"7", true, '7'},
|
||||
{"8", true, '8'},
|
||||
{"9", true, '9'},
|
||||
{"announce", false, 'A'}};
|
||||
|
||||
segments segment{IDLE};
|
||||
bool armed{false};
|
||||
bool file_error{false};
|
||||
|
||||
// const uint8_t month_table[12] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
|
||||
// const char * day_of_week[7] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
|
||||
|
||||
std::unique_ptr<WAVFileReader> reader{};
|
||||
|
||||
uint8_t code_index{0}, announce_loop{0};
|
||||
uint32_t sample_counter{0};
|
||||
uint32_t sample_length{0};
|
||||
int8_t audio_buffer[1024]{};
|
||||
uint32_t pause{0};
|
||||
bool armed_blink{false};
|
||||
SignalToken signal_token_tick_second{};
|
||||
|
||||
wav_file_t* get_wav(uint32_t index);
|
||||
bool check_wav_validity(const std::string dir, const std::string file);
|
||||
void on_voice_changed(size_t index);
|
||||
void on_tick_second();
|
||||
void prepare_audio();
|
||||
void start_tx();
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 5 * 8}, "Voice: Flags:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 8 * 8}, "Code:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_voices{
|
||||
{8 * 8, 1 * 8},
|
||||
4,
|
||||
{}};
|
||||
Text text_voice_flags{
|
||||
{19 * 8, 1 * 8, 2 * 8, 16},
|
||||
""};
|
||||
|
||||
SymField symfield_code{
|
||||
{1 * 8, 10 * 8},
|
||||
25,
|
||||
SymField::Type::Custom};
|
||||
|
||||
Checkbox check_armed{
|
||||
{2 * 8, 13 * 16},
|
||||
5,
|
||||
"Armed"};
|
||||
|
||||
/*
|
||||
Button button_tx_now {
|
||||
{ 18 * 8, 13 * 16, 10 * 8, 32 },
|
||||
"TX now"};
|
||||
*/
|
||||
|
||||
Button button_exit{
|
||||
{21 * 8, 16 * 16, 64, 32},
|
||||
"Exit"};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal{
|
||||
Message::ID::RequestSignal,
|
||||
[this](const Message* const p) {
|
||||
const auto message = static_cast<const RequestSignalMessage*>(p);
|
||||
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
|
||||
this->prepare_audio();
|
||||
}
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_NUMBERS_H__*/
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_nuoptix.hpp"
|
||||
|
||||
#include "ch.h"
|
||||
#include "portapack.hpp"
|
||||
#include "lfsr_random.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void NuoptixView::focus() {
|
||||
number_timecode.focus();
|
||||
}
|
||||
|
||||
NuoptixView::~NuoptixView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void NuoptixView::on_tx_progress(const uint32_t progress, const bool done) {
|
||||
if (done)
|
||||
transmit(false);
|
||||
else
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
void NuoptixView::transmit(bool setup) {
|
||||
uint8_t mod, tone_code;
|
||||
uint8_t c;
|
||||
uint8_t dtmf_message[6];
|
||||
rtc::RTC datetime;
|
||||
|
||||
if (!tx_mode) {
|
||||
transmitter_model.disable();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tx_mode == IMPROVISE)
|
||||
timecode = lfsr_iterate(timecode) % 1999; // Could be 9999 but that would be one long audio track !
|
||||
|
||||
if (setup) {
|
||||
progressbar.set_max(6 * 2);
|
||||
|
||||
if (tx_mode == IMPROVISE) {
|
||||
// Seed from RTC
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
timecode = datetime.day() + datetime.second();
|
||||
} else {
|
||||
timecode = number_timecode.value();
|
||||
}
|
||||
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.enable();
|
||||
|
||||
dtmf_message[0] = '*'; // "Pre-tone for restart" method #1
|
||||
dtmf_message[1] = 'A'; // "Restart" method #1
|
||||
} else {
|
||||
dtmf_message[0] = '#';
|
||||
dtmf_message[1] = (timecode / 1000) % 10;
|
||||
chThdSleepMilliseconds(92); // 141-49ms
|
||||
number_timecode.set_value(timecode);
|
||||
}
|
||||
|
||||
progressbar.set_value(0);
|
||||
|
||||
dtmf_message[2] = (timecode / 100) % 10;
|
||||
dtmf_message[3] = (timecode / 10) % 10;
|
||||
dtmf_message[4] = timecode % 10;
|
||||
|
||||
mod = 0;
|
||||
for (c = 1; c < 5; c++)
|
||||
if (dtmf_message[c] <= 9)
|
||||
mod += dtmf_message[c];
|
||||
|
||||
mod = 10 - (mod % 10);
|
||||
if (mod == 10) mod = 0; // Is this right ?
|
||||
|
||||
text_mod.set("Mod: " + to_string_dec_uint(mod));
|
||||
|
||||
dtmf_message[5] = mod;
|
||||
|
||||
for (c = 0; c < 6; c++) {
|
||||
tone_code = dtmf_message[c];
|
||||
|
||||
if (tone_code == 'A')
|
||||
tone_code = 10;
|
||||
else if (tone_code == 'B')
|
||||
tone_code = 11;
|
||||
else if (tone_code == 'C')
|
||||
tone_code = 12;
|
||||
else if (tone_code == 'D')
|
||||
tone_code = 13;
|
||||
else if (tone_code == '#')
|
||||
tone_code = 14;
|
||||
else if (tone_code == '*')
|
||||
tone_code = 15;
|
||||
|
||||
shared_memory.bb_data.tones_data.message[c * 2] = tone_code;
|
||||
shared_memory.bb_data.tones_data.message[c * 2 + 1] = 0xFF; // Silence
|
||||
}
|
||||
|
||||
for (c = 0; c < 16; c++) {
|
||||
baseband::set_tone(c * 2, dtmf_deltas[c][0], NUOPTIX_TONE_LENGTH);
|
||||
baseband::set_tone(c * 2 + 1, dtmf_deltas[c][1], NUOPTIX_TONE_LENGTH);
|
||||
}
|
||||
shared_memory.bb_data.tones_data.silence = NUOPTIX_TONE_LENGTH; // 49ms tone, 49ms space
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
|
||||
baseband::set_tones_config(transmitter_model.channel_bandwidth(), 0, 6 * 2, true, true);
|
||||
|
||||
timecode++;
|
||||
}
|
||||
|
||||
NuoptixView::NuoptixView(
|
||||
NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_tones);
|
||||
|
||||
add_children({&number_timecode,
|
||||
&text_timecode,
|
||||
&text_mod,
|
||||
&progressbar,
|
||||
&tx_view});
|
||||
|
||||
number_timecode.set_value(1);
|
||||
|
||||
tx_view.on_edit_frequency = [this, &nav]() {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
transmitter_model.set_target_frequency(f);
|
||||
};
|
||||
};
|
||||
|
||||
tx_view.on_start = [this]() {
|
||||
tx_view.set_transmitting(true);
|
||||
tx_mode = NORMAL;
|
||||
transmit(true);
|
||||
};
|
||||
|
||||
tx_view.on_stop = [this]() {
|
||||
tx_view.set_transmitting(false);
|
||||
tx_mode = IDLE;
|
||||
};
|
||||
|
||||
/*button_impro.on_select = [this](Button&){
|
||||
if (tx_mode == IMPROVISE) {
|
||||
tx_mode = IDLE;
|
||||
button_impro.set_text("IMPROVISE");
|
||||
} else if (tx_mode == IDLE) {
|
||||
tx_mode = IMPROVISE;
|
||||
button_impro.set_text("STOP");
|
||||
transmit(true);
|
||||
}
|
||||
};*/
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_NUOPTIX_H__
|
||||
#define __UI_NUOPTIX_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_transmitter.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "tonesets.hpp"
|
||||
#include "message.hpp"
|
||||
#include "volume.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "radio_state.hpp"
|
||||
|
||||
#define NUOPTIX_TONE_LENGTH ((TONES_SAMPLERATE * 0.049) - 1) // 49ms
|
||||
|
||||
namespace ui {
|
||||
|
||||
class NuoptixView : public View {
|
||||
public:
|
||||
NuoptixView(NavigationView& nav);
|
||||
~NuoptixView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Nuoptix sync"; };
|
||||
|
||||
private:
|
||||
enum tx_modes {
|
||||
IDLE = 0,
|
||||
NORMAL,
|
||||
IMPROVISE
|
||||
};
|
||||
|
||||
TxRadioState radio_state_{
|
||||
0 /* frequency */,
|
||||
1750000 /* bandwidth */,
|
||||
1536000 /* sampling rate */
|
||||
};
|
||||
|
||||
tx_modes tx_mode{IDLE};
|
||||
|
||||
void transmit(bool setup);
|
||||
void on_tx_progress(const uint32_t progress, const bool done);
|
||||
|
||||
uint32_t timecode{0};
|
||||
|
||||
Text text_timecode{
|
||||
{10 * 8, 2 * 16, 9 * 8, 16},
|
||||
"Timecode:"};
|
||||
|
||||
NumberField number_timecode{
|
||||
{13 * 8, 3 * 16},
|
||||
4,
|
||||
{1, 9999},
|
||||
1,
|
||||
'0'};
|
||||
|
||||
Text text_mod{
|
||||
{10 * 8, 5 * 16, 6 * 8, 16},
|
||||
"Mod: "};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{16, 14 * 16, 208, 16}};
|
||||
|
||||
/*Button button_impro {
|
||||
{ 64, 184, 112, 40 },
|
||||
"IMPROVISE"
|
||||
};*/
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
10000,
|
||||
15};
|
||||
|
||||
MessageHandlerRegistration message_handler_tx_progress{
|
||||
Message::ID::TXProgress,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||
this->on_tx_progress(message.progress, message.done);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_NUOPTIX_H__*/
|
||||
@@ -33,6 +33,8 @@ using namespace pocsag;
|
||||
|
||||
namespace ui {
|
||||
|
||||
#define MAX_POCSAG_LENGTH 80
|
||||
|
||||
void POCSAGTXView::focus() {
|
||||
field_address.focus();
|
||||
}
|
||||
@@ -57,6 +59,7 @@ void POCSAGTXView::on_remote(const PocsagTosendMessage data) {
|
||||
options_phase.set_selected_index(data.phase == 'P' ? 0 : 1);
|
||||
field_address.set_value(data.addr);
|
||||
message = (char*)data.msg;
|
||||
buffer = message;
|
||||
text_message.set(message);
|
||||
options_bitrate.dirty();
|
||||
options_type.dirty();
|
||||
@@ -105,9 +108,9 @@ bool POCSAGTXView::start_tx() {
|
||||
|
||||
progressbar.set_max(total_frames);
|
||||
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_tx_gain(40);
|
||||
// We left exactly same TX LPF settings as previous fw 1.7.4, TX LPF= 1M75 (min). It is fine even in max FM dev. 150khz and 2400 bauds.
|
||||
// transmitter_model.set_rf_amp(true);
|
||||
// transmitter_model.set_tx_gain(40);
|
||||
// We left exactly same TX LPF settings as previous fw 1.7.4, TX LPF= 1M75 (min). It is fine even in max FM dev. 150khz and 2400 bauds.
|
||||
transmitter_model.set_baseband_bandwidth(1'750'000); // Min TX LPF . Pocsag is NBFM , using BW channel 25khz or 12khz
|
||||
transmitter_model.enable();
|
||||
|
||||
@@ -139,11 +142,18 @@ bool POCSAGTXView::start_tx() {
|
||||
|
||||
void POCSAGTXView::paint(Painter&) {
|
||||
message = buffer;
|
||||
text_message.set(message);
|
||||
text_message.set(message); // the whole message, but it may not fit.
|
||||
if (message.length() > 30 && message.length() <= 60) {
|
||||
text_message_l2.set(message.substr(29)); // remaining to 2nd line
|
||||
} else if (message.length() > 60) {
|
||||
text_message_l2.set(message.substr(29, 27) + "...");
|
||||
} else {
|
||||
text_message_l2.set("");
|
||||
}
|
||||
}
|
||||
|
||||
void POCSAGTXView::on_set_text(NavigationView& nav) {
|
||||
text_prompt(nav, buffer, 30);
|
||||
text_prompt(nav, buffer, MAX_POCSAG_LENGTH);
|
||||
}
|
||||
|
||||
POCSAGTXView::POCSAGTXView(
|
||||
@@ -158,6 +168,7 @@ POCSAGTXView::POCSAGTXView(
|
||||
&options_function,
|
||||
&options_phase,
|
||||
&text_message,
|
||||
&text_message_l2,
|
||||
&button_message,
|
||||
&progressbar,
|
||||
&tx_view});
|
||||
|
||||
@@ -122,15 +122,18 @@ class POCSAGTXView : public View {
|
||||
}};
|
||||
|
||||
Text text_message{
|
||||
{0 * 8, 16 * 8, 16 * 8, 16},
|
||||
{0 * 8, 16 * 8, 30 * 8, 16},
|
||||
""};
|
||||
Text text_message_l2{
|
||||
{0 * 8, 18 * 8, 30 * 8, 16},
|
||||
""};
|
||||
|
||||
Button button_message{
|
||||
{0 * 8, 18 * 8, 14 * 8, 32},
|
||||
{0 * 8, 20 * 8, 14 * 8, 32},
|
||||
"Set message"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{16, 200, 208, 16}};
|
||||
{16, 210, 208, 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "file.hpp"
|
||||
#include "file_reader.hpp"
|
||||
#include "tone_key.hpp"
|
||||
#include "replay_app.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
#include "io_file.hpp"
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_script.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void ScriptView::on_frequency_select() {
|
||||
// button_edit_freq.focus();
|
||||
}
|
||||
|
||||
void ScriptView::on_edit_freq(rf::Frequency f) {
|
||||
(void)f;
|
||||
// frequencies[menu_view.highlighted()].value = f;
|
||||
setup_list();
|
||||
}
|
||||
|
||||
void ScriptView::on_edit_desc(NavigationView& nav) {
|
||||
(void)nav;
|
||||
}
|
||||
|
||||
void ScriptView::on_delete() {
|
||||
// frequencies.erase(frequencies.begin() + menu_view.highlighted());
|
||||
setup_list();
|
||||
}
|
||||
|
||||
void ScriptView::setup_list() {
|
||||
// size_t n;
|
||||
|
||||
menu_view.clear();
|
||||
|
||||
/*for (n = 0; n < frequencies.size(); n++) {
|
||||
menu_view.add_item({ freqman_item_string(frequencies[n]), Theme::getInstance()->bg_darkest->foreground, nullptr, [this](){ on_frequency_select(); } });
|
||||
}*/
|
||||
|
||||
menu_view.set_parent_rect({0, 0, 240, 168});
|
||||
menu_view.set_highlighted(menu_view.highlighted()); // Refresh
|
||||
}
|
||||
|
||||
void ScriptView::focus() {
|
||||
menu_view.focus();
|
||||
}
|
||||
|
||||
ScriptView::ScriptView(
|
||||
NavigationView& nav) {
|
||||
add_children({&menu_view,
|
||||
&text_edit,
|
||||
&button_edit_freq,
|
||||
&button_edit_desc,
|
||||
&button_del,
|
||||
&button_exit});
|
||||
|
||||
setup_list();
|
||||
|
||||
button_edit_freq.on_select = [this, &nav](Button&) {
|
||||
/*auto new_view = nav.push<FrequencyKeypadView>(frequencies[menu_view.highlighted()].value);
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
on_edit_freq(f);
|
||||
};*/
|
||||
};
|
||||
|
||||
button_edit_desc.on_select = [this, &nav](Button&) {
|
||||
on_edit_desc(nav);
|
||||
};
|
||||
|
||||
button_del.on_select = [this, &nav](Button&) {
|
||||
nav.push<ModalMessageView>("Confirm", "Are you sure?", YESNO,
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
on_delete();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
button_exit.on_select = [this, &nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
enum script_keyword {
|
||||
STOP = 0,
|
||||
WAIT_N,
|
||||
WAIT_RTC,
|
||||
IF,
|
||||
LOOP,
|
||||
END,
|
||||
TX,
|
||||
RX
|
||||
};
|
||||
|
||||
struct script_line {
|
||||
script_keyword keyword;
|
||||
};
|
||||
|
||||
class ScriptView : public View {
|
||||
public:
|
||||
ScriptView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Script editor"; };
|
||||
|
||||
private:
|
||||
void on_frequency_select();
|
||||
void on_edit_freq(rf::Frequency f);
|
||||
void on_edit_desc(NavigationView& nav);
|
||||
void on_delete();
|
||||
void setup_list();
|
||||
|
||||
std::vector<script_line> script{};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 0, 240, 168},
|
||||
true};
|
||||
|
||||
Text text_edit{
|
||||
{16, 194, 5 * 8, 16},
|
||||
"Edit:"};
|
||||
Button button_edit_freq{
|
||||
{16, 194 + 16, 88, 32},
|
||||
"Frequency"};
|
||||
Button button_edit_desc{
|
||||
{16, 194 + 16 + 34, 88, 32},
|
||||
"Description"};
|
||||
Button button_del{
|
||||
{160, 192, 72, 64},
|
||||
"Delete"};
|
||||
|
||||
Button button_exit{
|
||||
{160, 264, 72, 32},
|
||||
"Exit"};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
* Copyright (C) 2024 u-foka
|
||||
* Copyright (C) 2024 HTotoo
|
||||
* Copyleft (ɔ) 2024 zxkmm under GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
@@ -49,6 +50,8 @@ namespace fs = std::filesystem;
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "cpld_update.hpp"
|
||||
#include "config_mode.hpp"
|
||||
#include "i2cdevmanager.hpp"
|
||||
#include "i2cdev_max17055.hpp"
|
||||
|
||||
extern ui::SystemView* system_view_ptr;
|
||||
|
||||
@@ -774,34 +777,148 @@ void SetConfigModeView::focus() {
|
||||
button_save.focus();
|
||||
}
|
||||
|
||||
/* SetFakeBrightnessView ************************************/
|
||||
/* SetDisplayView ************************************/
|
||||
|
||||
SetFakeBrightnessView::SetFakeBrightnessView(NavigationView& nav) {
|
||||
SetDisplayView::SetDisplayView(NavigationView& nav) {
|
||||
add_children({&labels,
|
||||
&field_fake_brightness,
|
||||
&button_save,
|
||||
&button_cancel,
|
||||
&checkbox_invert_switch,
|
||||
&checkbox_brightness_switch});
|
||||
|
||||
field_fake_brightness.set_by_value(pmem::fake_brightness_level());
|
||||
checkbox_brightness_switch.set_value(pmem::apply_fake_brightness());
|
||||
checkbox_invert_switch.set_value(pmem::config_lcd_inverted_mode());
|
||||
|
||||
button_save.on_select = [&nav, this](Button&) {
|
||||
pmem::set_apply_fake_brightness(checkbox_brightness_switch.value());
|
||||
pmem::set_fake_brightness_level(field_fake_brightness.selected_index_value());
|
||||
if (checkbox_invert_switch.value() != pmem::config_lcd_inverted_mode()) {
|
||||
display.set_inverted(checkbox_invert_switch.value());
|
||||
pmem::set_lcd_inverted_mode(checkbox_invert_switch.value());
|
||||
}
|
||||
send_system_refresh();
|
||||
nav.pop();
|
||||
};
|
||||
// only enable invert OR fake brightness
|
||||
checkbox_invert_switch.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) checkbox_brightness_switch.set_value(false);
|
||||
};
|
||||
checkbox_brightness_switch.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) checkbox_invert_switch.set_value(false);
|
||||
};
|
||||
|
||||
button_cancel.on_select = [&nav, this](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
void SetFakeBrightnessView::focus() {
|
||||
void SetDisplayView::focus() {
|
||||
button_save.focus();
|
||||
}
|
||||
|
||||
/* SetTouchscreenSensitivityView ************************************/
|
||||
/* sample max: 1023 sample_t AKA uint16_t
|
||||
* touch_sensitivity: range: 1 to 128
|
||||
* threshold = 1023 / sensitive
|
||||
* threshold range: 1023/1 to 1023/128 = 1023 to 8
|
||||
*/
|
||||
SetTouchscreenThresholdView::SetTouchscreenThresholdView(NavigationView& nav) {
|
||||
add_children({&labels,
|
||||
&field_threshold,
|
||||
&button_autodetect,
|
||||
&button_reset,
|
||||
&button_save,
|
||||
&button_cancel,
|
||||
&text_hint,
|
||||
&text_wait_timer});
|
||||
|
||||
set_dirty();
|
||||
org_threshold = portapack::touch_threshold;
|
||||
field_threshold.set_value(pmem::touchscreen_threshold());
|
||||
text_hint.set_style(Theme::getInstance()->error_dark);
|
||||
text_hint.hidden(true);
|
||||
text_wait_timer.set_style(Theme::getInstance()->error_dark);
|
||||
text_wait_timer.hidden(true);
|
||||
// clang-format off
|
||||
button_autodetect.on_select = [this, &nav](Button&) {
|
||||
nav.display_modal("NOTICE",
|
||||
"Now on don't touch screen;\n"
|
||||
"Use arrow keys to operate.\n"
|
||||
"Follow instructions.\n"
|
||||
"Press YES to continue",
|
||||
YESNO, [this, &nav](bool choice) {
|
||||
if (choice){
|
||||
time_start_auto_detect = chTimeNow();
|
||||
text_hint.hidden(false);
|
||||
text_wait_timer.hidden(false);
|
||||
text_wait_timer.set("ETA " + to_string_dec_uint(10) + "s");
|
||||
in_auto_detect = true;
|
||||
field_threshold.set_value(1);
|
||||
portapack::touch_threshold = 1;
|
||||
set_dirty(); } }, TRUE);
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
button_reset.on_select = [this](Button&) {
|
||||
field_threshold.set_value(32);
|
||||
portapack::touch_threshold = 32;
|
||||
};
|
||||
|
||||
button_save.on_select = [&nav, this](Button&) {
|
||||
pmem::set_touchscreen_threshold(field_threshold.value());
|
||||
portapack::touch_threshold = field_threshold.value();
|
||||
send_system_refresh();
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
button_cancel.on_select = [&nav, this](Button&) {
|
||||
portapack::touch_threshold = org_threshold;
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
void SetTouchscreenThresholdView::focus() {
|
||||
button_autodetect.focus();
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void SetTouchscreenThresholdView::on_frame_sync() {
|
||||
if (!in_auto_detect) return;
|
||||
uint32_t time_now = chTimeNow();
|
||||
int32_t time_diff = time_now - time_start_auto_detect;
|
||||
text_wait_timer.set("ETA " + to_string_dec_uint((10 - time_diff / 1000) <= 0 ? 0 : 10 - time_diff / 1000) + "s");
|
||||
if (time_diff >= 10001 && !auto_detect_succeed_consumed) { // 10s
|
||||
in_auto_detect = false;
|
||||
text_wait_timer.hidden(true);
|
||||
text_hint.set("OK, press save and reboot");
|
||||
portapack::touch_threshold = org_threshold;
|
||||
pmem::set_touchscreen_threshold(org_threshold);
|
||||
set_dirty();
|
||||
auto_detect_succeed_consumed = true;
|
||||
button_save.focus();
|
||||
return;
|
||||
}
|
||||
if (get_touch_frame().touch) {
|
||||
if (in_auto_detect) {
|
||||
uint16_t sen = field_threshold.value();
|
||||
sen++;
|
||||
portapack::touch_threshold = sen;
|
||||
field_threshold.set_value(sen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetTouchscreenThresholdView::~SetTouchscreenThresholdView() {
|
||||
// it seems that sometimes in the msg handler func it would enter the condi that not possible to entered,
|
||||
// so added this workaround.
|
||||
// TODO: find out why
|
||||
in_auto_detect = false;
|
||||
auto_detect_succeed_consumed = false;
|
||||
time_start_auto_detect = 0;
|
||||
}
|
||||
|
||||
/* SetMenuColorView ************************************/
|
||||
|
||||
void SetMenuColorView::paint_sample() {
|
||||
@@ -863,6 +980,7 @@ SetAutostartView::SetAutostartView(NavigationView& nav) {
|
||||
add_children({&labels,
|
||||
&button_save,
|
||||
&button_cancel,
|
||||
&button_reset,
|
||||
&options});
|
||||
|
||||
button_save.on_select = [&nav, this](Button&) {
|
||||
@@ -879,6 +997,12 @@ SetAutostartView::SetAutostartView(NavigationView& nav) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
button_reset.on_select = [this](Button&) {
|
||||
selected = 0;
|
||||
options.set_selected_index(0);
|
||||
autostart_app = "";
|
||||
};
|
||||
|
||||
// options
|
||||
i = 0;
|
||||
OptionsField::option_t o{"-none-", i};
|
||||
@@ -948,6 +1072,42 @@ void SetThemeView::focus() {
|
||||
options.focus();
|
||||
}
|
||||
|
||||
/* SetBatteryView ************************************/
|
||||
|
||||
SetBatteryView::SetBatteryView(NavigationView& nav) {
|
||||
add_children({&labels,
|
||||
&button_save,
|
||||
&button_cancel,
|
||||
&checkbox_overridebatt});
|
||||
|
||||
if (i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055)) add_children({&button_reset, &labels2});
|
||||
|
||||
button_save.on_select = [&nav, this](Button&) {
|
||||
pmem::set_ui_override_batt_calc(checkbox_overridebatt.value());
|
||||
battery::BatteryManagement::set_calc_override(checkbox_overridebatt.value());
|
||||
send_system_refresh();
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
button_reset.on_select = [&nav, this](Button&) {
|
||||
auto dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055);
|
||||
if (dev->reset_learned())
|
||||
nav.display_modal("Reset", "Battery parameters reset");
|
||||
else
|
||||
nav.display_modal("Error", "Error parameter reset");
|
||||
};
|
||||
|
||||
checkbox_overridebatt.set_value(pmem::ui_override_batt_calc());
|
||||
|
||||
button_cancel.on_select = [&nav, this](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
void SetBatteryView::focus() {
|
||||
button_cancel.focus();
|
||||
}
|
||||
|
||||
/* SettingsMenuView **************************************/
|
||||
|
||||
SettingsMenuView::SettingsMenuView(NavigationView& nav)
|
||||
@@ -963,6 +1123,7 @@ void SettingsMenuView::on_populate() {
|
||||
{"App Settings", ui::Color::dark_cyan(), &bitmap_icon_notepad, [this]() { nav_.push<AppSettingsView>(); }},
|
||||
{"Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [this]() { nav_.push<SetAudioView>(); }},
|
||||
{"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [this]() { nav_.push<TouchCalibrationView>(); }},
|
||||
{"TouchThreshold", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [this]() { nav_.push<SetTouchscreenThresholdView>(); }},
|
||||
{"Config Mode", ui::Color::dark_cyan(), &bitmap_icon_clk_ext, [this]() { nav_.push<SetConfigModeView>(); }},
|
||||
{"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push<SetConverterSettingsView>(); }},
|
||||
{"Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [this]() { nav_.push<SetDateTimeView>(); }},
|
||||
@@ -973,11 +1134,12 @@ void SettingsMenuView::on_populate() {
|
||||
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [this]() { nav_.push<SetSDCardView>(); }},
|
||||
{"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [this]() { nav_.push<SetUIView>(); }},
|
||||
//{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push<SetQRCodeView>(); }},
|
||||
{"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push<SetFakeBrightnessView>(); }},
|
||||
{"Display", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push<SetDisplayView>(); }},
|
||||
{"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push<SetMenuColorView>(); }},
|
||||
{"Theme", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push<SetThemeView>(); }},
|
||||
{"Autostart", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push<SetAutostartView>(); }},
|
||||
});
|
||||
if (battery::BatteryManagement::isDetected()) add_item({"Battery", ui::Color::dark_cyan(), &bitmap_icon_batt_icon, [this]() { nav_.push<SetBatteryView>(); }});
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "bitmap.hpp"
|
||||
#include "ff.h"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "irq_controls.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -711,13 +712,13 @@ class SetConfigModeView : public View {
|
||||
|
||||
using portapack::persistent_memory::fake_brightness_level_options;
|
||||
|
||||
class SetFakeBrightnessView : public View {
|
||||
class SetDisplayView : public View {
|
||||
public:
|
||||
SetFakeBrightnessView(NavigationView& nav);
|
||||
SetDisplayView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Brightness"; };
|
||||
std::string title() const override { return "Display"; };
|
||||
|
||||
private:
|
||||
Labels labels{
|
||||
@@ -739,6 +740,11 @@ class SetFakeBrightnessView : public View {
|
||||
16,
|
||||
"Enable brightness adjust"};
|
||||
|
||||
Checkbox checkbox_invert_switch{
|
||||
{1 * 8, 10 * 16},
|
||||
23,
|
||||
"Invert colors (For IPS)"};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Save"};
|
||||
@@ -749,6 +755,77 @@ class SetFakeBrightnessView : public View {
|
||||
};
|
||||
};
|
||||
|
||||
using portapack::persistent_memory::touchscreen_threshold;
|
||||
|
||||
class SetTouchscreenThresholdView : public View {
|
||||
public:
|
||||
SetTouchscreenThresholdView(NavigationView& nav);
|
||||
~SetTouchscreenThresholdView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Touch S"; };
|
||||
|
||||
private:
|
||||
bool in_auto_detect = false;
|
||||
uint16_t org_threshold = 0;
|
||||
uint8_t auto_detect_succeed_consumed = false; // prevent screen flash but can still change text content
|
||||
uint32_t time_start_auto_detect = 0;
|
||||
|
||||
Labels labels{
|
||||
{{1 * 8, 1 * 16}, "Set touchscreen sensitivity", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 2 * 16}, "Or press auto detect button", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 3 * 16}, "FOLLOW INSTRUCTIONS", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 4 * 16}, "REBOOT TO APPLY", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 11 * 16}, "Threshold:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
Text text_hint{
|
||||
{1 * 8, 7 * 16, screen_width - 2 * 8, 1 * 16},
|
||||
"DON'T TOUCH SCREEN"};
|
||||
|
||||
Text text_wait_timer{
|
||||
{1 * 8, 8 * 16, screen_width - 2 * 8, 1 * 16},
|
||||
"ETA 00:00"};
|
||||
|
||||
void on_frame_sync();
|
||||
|
||||
/* sample max: 1023 sample_t AKA uint16_t
|
||||
* touch_sensitivity: range: 1 to 128
|
||||
* threshold range: 1023/1 to 1023/128 = 1023 to 8
|
||||
*/
|
||||
NumberField field_threshold{
|
||||
{1 * 8 + sizeof("Threshold:") * 8 + 8, 11 * 16},
|
||||
4,
|
||||
{1, 1023},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
Button button_autodetect{
|
||||
{2 * 8, 13 * 16, 12 * 8, 32},
|
||||
"Auto Detect"};
|
||||
Button button_reset{
|
||||
{16 * 8, 13 * 16, 12 * 8, 32},
|
||||
"Reset",
|
||||
};
|
||||
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->on_frame_sync();
|
||||
}};
|
||||
};
|
||||
|
||||
class SetMenuColorView : public View {
|
||||
public:
|
||||
SetMenuColorView(NavigationView& nav);
|
||||
@@ -838,14 +915,19 @@ class SetAutostartView : public View {
|
||||
"Save"};
|
||||
|
||||
OptionsField options{
|
||||
{8 * 8, 4 * 16},
|
||||
30,
|
||||
{}};
|
||||
{0 * 8, 4 * 16},
|
||||
screen_width / 8,
|
||||
{},
|
||||
true};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
|
||||
Button button_reset{
|
||||
{2 * 8, 6 * 16, screen_width - 4 * 8, 32},
|
||||
"Reset"};
|
||||
};
|
||||
|
||||
class SetThemeView : public View {
|
||||
@@ -867,15 +949,16 @@ class SetThemeView : public View {
|
||||
"Save"};
|
||||
|
||||
OptionsField options{
|
||||
{8 * 8, 4 * 16},
|
||||
30,
|
||||
{0 * 8, 4 * 16},
|
||||
screen_width / 8,
|
||||
{
|
||||
{"Default - Grey", 0},
|
||||
{"Yellow", 1},
|
||||
{"Aqua", 2},
|
||||
{"Green", 3},
|
||||
{"Red", 4},
|
||||
}};
|
||||
},
|
||||
true};
|
||||
|
||||
Checkbox checkbox_menuset{
|
||||
{2 * 8, 6 * 16},
|
||||
@@ -888,6 +971,41 @@ class SetThemeView : public View {
|
||||
};
|
||||
};
|
||||
|
||||
class SetBatteryView : public View {
|
||||
public:
|
||||
SetBatteryView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Battery"; };
|
||||
|
||||
private:
|
||||
int32_t selected = 0;
|
||||
Labels labels{
|
||||
{{1 * 8, 1 * 16}, "Override batt calculation", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 2 * 16}, "method to voltage based", Theme::getInstance()->fg_light->foreground}};
|
||||
Labels labels2{
|
||||
{{1 * 8, 6 * 16}, "Reset IC's learned params.", Theme::getInstance()->fg_light->foreground}};
|
||||
Button button_save{
|
||||
{2 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Save"};
|
||||
|
||||
Checkbox checkbox_overridebatt{
|
||||
{2 * 8, 4 * 16},
|
||||
23,
|
||||
"Override"};
|
||||
|
||||
Button button_cancel{
|
||||
{16 * 8, 16 * 16, 12 * 8, 32},
|
||||
"Cancel",
|
||||
};
|
||||
|
||||
Button button_reset{
|
||||
{2 * 8, 8 * 16, 12 * 8, 32},
|
||||
"Reset",
|
||||
};
|
||||
};
|
||||
|
||||
class SettingsMenuView : public BtnGridView {
|
||||
public:
|
||||
SettingsMenuView(NavigationView& nav);
|
||||
|
||||
@@ -187,4 +187,8 @@ void SondeView::on_packet(const sonde::Packet& packet) {
|
||||
}
|
||||
}
|
||||
|
||||
void SondeView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -195,6 +195,14 @@ class SondeView : public View {
|
||||
const auto message = static_cast<const OrientationDataMessage*>(p);
|
||||
this->on_orientation(message);
|
||||
}};
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
|
||||
void on_gps(const GPSPosDataMessage* msg);
|
||||
void on_orientation(const OrientationDataMessage* msg);
|
||||
|
||||
@@ -22,6 +22,12 @@
|
||||
#include "ui_standalone_view.hpp"
|
||||
#include "irq_controls.hpp"
|
||||
|
||||
#include "i2cdevmanager.hpp"
|
||||
#include "i2cdev_ppmod.hpp"
|
||||
|
||||
#include "ui_font_fixed_5x8.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
void create_thread(int32_t (*fn)(void*), void* arg, size_t stack_size, int priority) {
|
||||
@@ -34,6 +40,16 @@ void fill_rectangle(int x, int y, int width, int height, uint16_t color) {
|
||||
painter.fill_rectangle({x, y, width, height}, ui::Color(color));
|
||||
}
|
||||
|
||||
void fill_rectangle_unrolled8(int x, int y, int width, int height, uint16_t color) {
|
||||
ui::Painter painter;
|
||||
painter.fill_rectangle_unrolled8({x, y, width, height}, ui::Color(color));
|
||||
}
|
||||
|
||||
void draw_bitmap(int x, int y, int width, int height, const uint8_t* pixels, uint16_t foreground, uint16_t background) {
|
||||
ui::Painter painter;
|
||||
painter.draw_bitmap({x, y}, {{width, height}, pixels}, ui::Color(foreground), ui::Color(background));
|
||||
}
|
||||
|
||||
void* alloc(size_t size) {
|
||||
void* p = chHeapAlloc(0x0, size);
|
||||
if (p == nullptr)
|
||||
@@ -45,6 +61,45 @@ uint64_t get_switches_state_ulong() {
|
||||
return get_switches_state().to_ulong();
|
||||
}
|
||||
|
||||
ui::Coord scroll_area_y(const ui::Coord y) {
|
||||
return portapack::display.scroll_area_y(y);
|
||||
}
|
||||
|
||||
void scroll_set_area(const ui::Coord top_y, const ui::Coord bottom_y) {
|
||||
portapack::display.scroll_set_area(top_y, bottom_y);
|
||||
}
|
||||
|
||||
void scroll_disable() {
|
||||
portapack::display.scroll_disable();
|
||||
}
|
||||
|
||||
ui::Coord scroll_set_position(const ui::Coord position) {
|
||||
return portapack::display.scroll_set_position(position);
|
||||
}
|
||||
|
||||
ui::Coord scroll(const int32_t delta) {
|
||||
return portapack::display.scroll(delta);
|
||||
}
|
||||
|
||||
bool i2c_read(uint8_t* cmd, size_t cmd_len, uint8_t* data, size_t data_len) {
|
||||
auto dev = (i2cdev::I2cDev_PPmod*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDECMDL_PPMOD);
|
||||
if (!dev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data_len == 0 || data == nullptr)
|
||||
return dev->i2c_write(nullptr, 0, cmd, cmd_len);
|
||||
|
||||
return dev->i2c_read(cmd, cmd_len, data, data_len);
|
||||
}
|
||||
|
||||
StandaloneView* standaloneView = nullptr;
|
||||
|
||||
void set_dirty() {
|
||||
if (standaloneView != nullptr)
|
||||
standaloneView->set_dirty();
|
||||
}
|
||||
|
||||
standalone_application_api_t api = {
|
||||
/* .malloc = */ &alloc,
|
||||
/* .calloc = */ &calloc,
|
||||
@@ -54,20 +109,78 @@ standalone_application_api_t api = {
|
||||
/* .fill_rectangle = */ &fill_rectangle,
|
||||
/* .swizzled_switches = */ &swizzled_switches,
|
||||
/* .get_switches_state = */ &get_switches_state_ulong,
|
||||
/* .fixed_5x8_glyph_data = */ ui::font::fixed_5x8.get_data(),
|
||||
/* .fixed_8x16_glyph_data = */ ui::font::fixed_8x16.get_data(),
|
||||
/* .fill_rectangle_unrolled8 = */ &fill_rectangle_unrolled8,
|
||||
/* .draw_bitmap = */ &draw_bitmap,
|
||||
/* .scroll_area_y = */ &scroll_area_y,
|
||||
/* .scroll_set_area = */ &scroll_set_area,
|
||||
/* .scroll_disable = */ &scroll_disable,
|
||||
/* .scroll_set_position = */ &scroll_set_position,
|
||||
/* .scroll = */ &scroll,
|
||||
/* .i2c_read = */ &i2c_read,
|
||||
/* .panic = */ &chDbgPanic,
|
||||
/* .set_dirty = */ &set_dirty,
|
||||
};
|
||||
|
||||
StandaloneView::StandaloneView(NavigationView& nav, std::unique_ptr<uint8_t[]> app_image)
|
||||
: nav_(nav), _app_image(std::move(app_image)) {
|
||||
get_application_information()->initialize(api);
|
||||
add_children({&dummy});
|
||||
StandaloneView::StandaloneView(NavigationView& nav, uint8_t* app_image)
|
||||
: nav_(nav),
|
||||
_app_image(*app_image) {
|
||||
if (app_image == nullptr) {
|
||||
chDbgPanic("Invalid application image");
|
||||
}
|
||||
|
||||
set_focusable(true);
|
||||
|
||||
standaloneView = this;
|
||||
}
|
||||
|
||||
void StandaloneView::focus() {
|
||||
dummy.focus();
|
||||
View::focus();
|
||||
}
|
||||
|
||||
void StandaloneView::paint(Painter& painter) {
|
||||
(void)painter;
|
||||
|
||||
if (initialized &&
|
||||
get_application_information()->header_version > 1) {
|
||||
get_application_information()->PaintViewMirror();
|
||||
}
|
||||
}
|
||||
|
||||
void StandaloneView::on_focus() {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
get_application_information()->OnFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool StandaloneView::on_key(const KeyEvent key) {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
return get_application_information()->OnKeyEvent((uint8_t)key);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StandaloneView::on_encoder(const EncoderEvent event) {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
return get_application_information()->OnEncoder((int32_t)event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StandaloneView::on_touch(const TouchEvent event) {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
get_application_information()->OnTouchEvent(event.point.x(), event.point.y(), (uint32_t)event.type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandaloneView::on_keyboard(const KeyboardEvent event) {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
return get_application_information()->OnKeyboard((uint8_t)event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StandaloneView::frame_sync() {
|
||||
@@ -79,4 +192,14 @@ void StandaloneView::frame_sync() {
|
||||
}
|
||||
}
|
||||
|
||||
void StandaloneView::on_after_attach() {
|
||||
context().focus_manager().setMirror(this);
|
||||
get_application_information()->initialize(api);
|
||||
}
|
||||
|
||||
void StandaloneView::on_before_detach() {
|
||||
get_application_information()->shutdown();
|
||||
context().focus_manager().clearMirror();
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
||||
@@ -31,28 +31,34 @@ namespace ui {
|
||||
|
||||
class StandaloneView : public View {
|
||||
public:
|
||||
StandaloneView(NavigationView& nav, std::unique_ptr<uint8_t[]> app_image);
|
||||
virtual ~StandaloneView() override { get_application_information()->shutdown(); }
|
||||
|
||||
void focus() override;
|
||||
StandaloneView(NavigationView& nav, uint8_t* app_image);
|
||||
virtual ~StandaloneView() override {
|
||||
}
|
||||
|
||||
std::string title() const override { return (const char*)get_application_information()->app_name; };
|
||||
|
||||
void focus() override;
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
void on_focus() override;
|
||||
bool on_key(const KeyEvent key) override;
|
||||
bool on_encoder(const EncoderEvent event) override;
|
||||
bool on_touch(const TouchEvent event) override;
|
||||
bool on_keyboard(const KeyboardEvent event) override;
|
||||
|
||||
void on_after_attach() override;
|
||||
void on_before_detach() override;
|
||||
|
||||
void frame_sync();
|
||||
|
||||
private:
|
||||
bool initialized = false;
|
||||
NavigationView& nav_;
|
||||
std::unique_ptr<uint8_t[]> _app_image;
|
||||
uint8_t& _app_image;
|
||||
standalone_application_information_t* get_application_information() const {
|
||||
return reinterpret_cast<standalone_application_information_t*>(_app_image.get());
|
||||
return reinterpret_cast<standalone_application_information_t*>(&_app_image);
|
||||
}
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_sample{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
|
||||
@@ -212,7 +212,10 @@ const char* SubGhzDView::getSensorTypeName(FPROTO_SUBGHZD_SENSOR type) {
|
||||
return "Somify Keytis";
|
||||
case FPS_SOMIFY_TELIS:
|
||||
return "Somify Telis";
|
||||
|
||||
case FPS_GANGQI:
|
||||
return "GangQi";
|
||||
case FPS_MARANTEC24:
|
||||
return "Marantec24";
|
||||
case FPS_Invalid:
|
||||
default:
|
||||
return "Unknown";
|
||||
@@ -224,6 +227,10 @@ std::string SubGhzDView::pad_string_with_spaces(int snakes) {
|
||||
return paddedStr;
|
||||
}
|
||||
|
||||
void SubGhzDView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
template <>
|
||||
void RecentEntriesTable<ui::SubGhzDRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
@@ -713,5 +720,18 @@ void SubGhzDRecentEntryDetailView::parseProtocol() {
|
||||
serial = dataa & 0xFFFFFF; // address}
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry_.sensorType == FPS_GANGQI) {
|
||||
btn = 0; // parser needs some time i think in flipper side.
|
||||
cnt = (uint8_t)(entry_.data >> 32);
|
||||
serial = (entry_.data & 0xFFFFFFFF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry_.sensorType == FPS_MARANTEC24) {
|
||||
serial = (entry_.data >> 4);
|
||||
btn = entry_.data & 0xf;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // namespace ui
|
||||
@@ -127,6 +127,14 @@ class SubGhzDView : public View {
|
||||
}};
|
||||
SubGhzDRecentEntriesView recent_entries_view{columns, recent};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::SubGhzDData,
|
||||
[this](Message* const p) {
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui_tone_search.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void ToneSearchView::focus() {
|
||||
// field_frequency_min.focus();
|
||||
}
|
||||
|
||||
ToneSearchView::~ToneSearchView() {
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
ToneSearchView::ToneSearchView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
// baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_rf_amp,
|
||||
});
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "receiver_model.hpp"
|
||||
|
||||
#include "ui_receiver.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ToneSearchView : public View {
|
||||
public:
|
||||
ToneSearchView(NavigationView& nav);
|
||||
~ToneSearchView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Tone search"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 8}, "LNA: VGA: AMP:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{4 * 8, 0 * 16}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{11 * 8, 0 * 16}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{18 * 8, 0 * 16}};
|
||||
|
||||
/*
|
||||
MessageHandlerRegistration message_handler_frame_sync {
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
if( this->fifo ) {
|
||||
ChannelSpectrum channel_spectrum;
|
||||
while( fifo->out(channel_spectrum) ) {
|
||||
this->on_channel_spectrum(channel_spectrum);
|
||||
}
|
||||
}
|
||||
this->do_timers();
|
||||
}
|
||||
};*/
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "../baseband/fprotos/fprotogeneral.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace ui;
|
||||
@@ -138,7 +139,8 @@ void WeatherView::on_tick_second() {
|
||||
}
|
||||
|
||||
void WeatherView::on_data(const WeatherDataMessage* data) {
|
||||
WeatherRecentEntry key{data->sensorType, data->id, data->temp, data->humidity, data->channel, data->battery_low};
|
||||
WeatherRecentEntry key = process_data(data);
|
||||
// WeatherRecentEntry key{data->sensorType, data->id, data->temp, data->humidity, data->channel, data->battery_low};
|
||||
auto matching_recent = find(recent, key.key());
|
||||
if (matching_recent != std::end(recent)) {
|
||||
// Found within. Move to front of list, increment counter.
|
||||
@@ -209,6 +211,13 @@ const char* WeatherView::getWeatherSensorTypeName(FPROTO_WEATHER_SENSOR type) {
|
||||
return "Acurite5in1";
|
||||
case FPW_EmosE601x:
|
||||
return "EmosE601x";
|
||||
case FPW_SolightTE44:
|
||||
return "SolightTE44";
|
||||
case FPW_Bresser3CH:
|
||||
case FPW_Bresser3CH_V1:
|
||||
return "Bresser3CH";
|
||||
case FPW_Vauno_EN8822:
|
||||
return "Vauno EN8822";
|
||||
case FPW_Invalid:
|
||||
default:
|
||||
return "Unknown";
|
||||
@@ -220,6 +229,10 @@ std::string WeatherView::pad_string_with_spaces(int snakes) {
|
||||
return paddedStr;
|
||||
}
|
||||
|
||||
void WeatherView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
template <>
|
||||
void RecentEntriesTable<ui::WeatherRecentEntries>::draw(
|
||||
const Entry& entry,
|
||||
@@ -250,4 +263,323 @@ void RecentEntriesTable<ui::WeatherRecentEntries>::draw(
|
||||
painter.draw_string(target_rect.location(), style, line);
|
||||
}
|
||||
|
||||
#define LACROSSE_TX_MSG_TYPE_TEMP 0x00
|
||||
#define LACROSSE_TX_MSG_TYPE_HUM 0x0E
|
||||
|
||||
WeatherRecentEntry WeatherView::process_data(const WeatherDataMessage* data) {
|
||||
WeatherRecentEntry ret = {};
|
||||
ret.sensorType = data->sensorType;
|
||||
int16_t i16 = 0;
|
||||
uint16_t u16 = 0;
|
||||
uint64_t u64 = 0;
|
||||
uint8_t u8 = 0;
|
||||
uint8_t channel_3021[] = {3, 0, 2, 1};
|
||||
float flo = 0.0;
|
||||
switch (data->sensorType) {
|
||||
case FPW_NexusTH:
|
||||
ret.id = (data->decode_data >> 28) & 0xFF;
|
||||
ret.battery_low = !((data->decode_data >> 27) & 1);
|
||||
ret.channel = ((data->decode_data >> 24) & 0x03) + 1;
|
||||
if (!((data->decode_data >> 23) & 1)) {
|
||||
ret.temp = (float)((data->decode_data >> 12) & 0x07FF) / 10.0f;
|
||||
} else {
|
||||
ret.temp = (float)((~(data->decode_data >> 12) & 0x07FF) + 1) / -10.0f;
|
||||
}
|
||||
ret.humidity = data->decode_data & 0xFF;
|
||||
if (ret.humidity > 95)
|
||||
ret.humidity = 95;
|
||||
else if (ret.humidity < 20)
|
||||
ret.humidity = 20;
|
||||
break;
|
||||
case FPW_Acurite592TXR:
|
||||
|
||||
u8 = ((data->decode_data >> 54) & 0x03);
|
||||
ret.channel = channel_3021[u8];
|
||||
ret.id = (data->decode_data >> 40) & 0x3FFF;
|
||||
ret.battery_low = !((data->decode_data >> 38) & 1);
|
||||
ret.humidity = (data->decode_data >> 24) & 0x7F;
|
||||
u16 = ((data->decode_data >> 9) & 0xF80) | ((data->decode_data >> 8) & 0x7F);
|
||||
ret.temp = ((float)(u16)-1000) / 10.0f;
|
||||
break;
|
||||
case FPW_Acurite606TX:
|
||||
ret.id = (data->decode_data >> 24) & 0xFF;
|
||||
ret.battery_low = (data->decode_data >> 23) & 1;
|
||||
if (!((data->decode_data >> 19) & 1)) {
|
||||
ret.temp = (float)((data->decode_data >> 8) & 0x07FF) / 10.0f;
|
||||
} else {
|
||||
ret.temp = (float)((~(data->decode_data >> 8) & 0x07FF) + 1) / -10.0f;
|
||||
}
|
||||
break;
|
||||
case FPW_Acurite609TX:
|
||||
ret.id = (data->decode_data >> 32) & 0xFF;
|
||||
ret.battery_low = (data->decode_data >> 31) & 1;
|
||||
ret.channel = WS_NO_CHANNEL;
|
||||
// Temperature in Celsius is encoded as a 12 bit integer value
|
||||
// multiplied by 10 using the 4th - 6th nybbles (bytes 1 & 2)
|
||||
// negative values are recovered by sign extend from int16_t.
|
||||
i16 = (int16_t)(((data->decode_data >> 12) & 0xf000) | ((data->decode_data >> 16) << 4));
|
||||
ret.temp = (i16 >> 4) * 0.1f;
|
||||
ret.humidity = (data->decode_data >> 8) & 0xff;
|
||||
break;
|
||||
case FPW_Ambient:
|
||||
id = (data->decode_data >> 32) & 0xFF;
|
||||
ret.battery_low = (data->decode_data >> 31) & 1;
|
||||
ret.channel = ((data->decode_data >> 28) & 0x07) + 1;
|
||||
ret.temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)((data->decode_data >> 16) & 0x0FFF) - 400.0f) / 10.0f);
|
||||
ret.humidity = (data->decode_data >> 8) & 0xFF;
|
||||
break;
|
||||
case FPW_AuriolAhfl:
|
||||
ret.id = data->decode_data >> 34;
|
||||
ret.battery_low = (data->decode_data >> 33) & 1;
|
||||
// btn = (data >> 32) & 1;
|
||||
ret.channel = ((data->decode_data >> 30) & 0x3) + 1;
|
||||
if (!((data->decode_data >> 29) & 1)) {
|
||||
ret.temp = (float)((data->decode_data >> 18) & 0x07FF) / 10.0f;
|
||||
} else {
|
||||
ret.temp = (float)((~(data->decode_data >> 18) & 0x07FF) + 1) / -10.0f;
|
||||
}
|
||||
ret.humidity = (data->decode_data >> 11) & 0x7F;
|
||||
break;
|
||||
case FPW_AuriolTH:
|
||||
ret.id = (data->decode_data >> 31) & 0xFF;
|
||||
ret.battery_low = ((data->decode_data >> 30) & 1);
|
||||
ret.channel = ((data->decode_data >> 25) & 0x03) + 1;
|
||||
if (!((data->decode_data >> 23) & 1)) {
|
||||
ret.temp = (float)((data->decode_data >> 13) & 0x07FF) / 10.0f;
|
||||
} else {
|
||||
ret.temp = (float)((~(data->decode_data >> 13) & 0x07FF) + 1) / -10.0f;
|
||||
}
|
||||
ret.humidity = (data->decode_data >> 1) & 0x7F;
|
||||
break;
|
||||
case FPW_GTWT02:
|
||||
ret.id = (data->decode_data >> 29) & 0xFF;
|
||||
ret.battery_low = (data->decode_data >> 28) & 1;
|
||||
// btn = (data->decode_data >> 27) & 1;
|
||||
ret.channel = ((data->decode_data >> 25) & 0x3) + 1;
|
||||
|
||||
if (!((data->decode_data >> 24) & 1)) {
|
||||
ret.temp = (float)((data->decode_data >> 13) & 0x07FF) / 10.0f;
|
||||
} else {
|
||||
ret.temp = (float)((~(data->decode_data >> 13) & 0x07FF) + 1) / -10.0f;
|
||||
}
|
||||
ret.humidity = (data->decode_data >> 6) & 0x7F;
|
||||
if (ret.humidity <= 10) // actually the sensors sends 10 below working range of 20%
|
||||
ret.humidity = 0;
|
||||
else if (ret.humidity > 90) // actually the sensors sends 110 above working range of 90%
|
||||
ret.humidity = 100;
|
||||
break;
|
||||
case FPW_GTWT03:
|
||||
ret.id = data->decode_data >> 33;
|
||||
ret.humidity = (data->decode_data >> 25) & 0xFF;
|
||||
if (ret.humidity <= 10) { // actually the sensors sends 10 below working range of 20%
|
||||
ret.humidity = 0;
|
||||
} else if (ret.humidity > 95) { // actually the sensors sends 110 above working range of 90%
|
||||
ret.humidity = 100;
|
||||
}
|
||||
ret.battery_low = (data->decode_data >> 24) & 1;
|
||||
// (data->decode_data >> 23) & 1;
|
||||
ret.channel = ((data->decode_data >> 21) & 0x03) + 1;
|
||||
if (!((data->decode_data >> 20) & 1)) {
|
||||
ret.temp = (float)((data->decode_data >> 9) & 0x07FF) / 10.0f;
|
||||
} else {
|
||||
ret.temp = (float)((~(data->decode_data >> 9) & 0x07FF) + 1) / -10.0f;
|
||||
}
|
||||
break;
|
||||
case FPW_INFACTORY:
|
||||
ret.id = data->decode_data >> 32;
|
||||
ret.battery_low = (data->decode_data >> 26) & 1;
|
||||
ret.temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)((data->decode_data >> 12) & 0x0FFF) - 900.0f) / 10.0f);
|
||||
ret.humidity = (((data->decode_data >> 8) & 0x0F) * 10) + ((data->decode_data >> 4) & 0x0F); // BCD, 'A0'=100%rH
|
||||
ret.channel = data->decode_data & 0x03;
|
||||
break;
|
||||
case FPW_LACROSSETX:
|
||||
u8 = (data->decode_data >> 32) & 0x0F;
|
||||
ret.id = (((data->decode_data >> 28) & 0x0F) << 3) | (((data->decode_data >> 24) & 0x0F) >> 1);
|
||||
flo = (float)((data->decode_data >> 20) & 0x0F) * 10.0f + (float)((data->decode_data >> 16) & 0x0F) + (float)((data->decode_data >> 12) & 0x0F) * 0.1f;
|
||||
if (u8 == LACROSSE_TX_MSG_TYPE_TEMP) { //-V1051
|
||||
ret.temp = flo - 50.0f;
|
||||
ret.humidity = WS_NO_HUMIDITY;
|
||||
} else if (u8 == LACROSSE_TX_MSG_TYPE_HUM) {
|
||||
// ToDo for verification, records are needed with sensors maintaining temperature and temperature for this standard
|
||||
ret.humidity = (uint8_t)flo;
|
||||
}
|
||||
break;
|
||||
case FPW_LACROSSETX141thbv2:
|
||||
ret.id = data->decode_data >> 32;
|
||||
ret.battery_low = (data->decode_data >> 31) & 1;
|
||||
// btn = (data->decode_data >> 30) & 1;
|
||||
ret.channel = ((data->decode_data >> 28) & 0x03) + 1;
|
||||
ret.temp = ((float)((data->decode_data >> 16) & 0x0FFF) - 500.0f) / 10.0f;
|
||||
ret.humidity = (data->decode_data >> 8) & 0xFF;
|
||||
break;
|
||||
case FPW_OREGON2:
|
||||
i16 = ((data->decode_data >> 4) & 0xF) * 10 + (((data->decode_data >> 4) >> 4) & 0xF);
|
||||
i16 *= 10;
|
||||
i16 += (data->decode_data >> 12) & 0xF;
|
||||
if (data->decode_data & 0xF) i16 = -i16;
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
// todo fix missing parts.
|
||||
break;
|
||||
case FPW_OREGON3:
|
||||
// todo check
|
||||
ret.humidity = ((data->decode_data >> 4) & 0xF) * 10 + (((data->decode_data >> 4) >> 4) & 0xF);
|
||||
i16 = (((data->decode_data >> 12) >> 4) & 0xF) * 10 + ((((data->decode_data >> 12) >> 4) >> 4) & 0xF); // ws_oregon3_bcd_decode_short((data->decode_data >> 12) >> 4);
|
||||
i16 *= 10;
|
||||
i16 += ((data->decode_data >> 12) >> 12) & 0xF;
|
||||
if ((data->decode_data >> 12) & 0xF) i16 = -i16;
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
break;
|
||||
case FPW_OREGONv1:
|
||||
u64 = FProtoGeneral::subghz_protocol_blocks_reverse_key(data->decode_data, 32);
|
||||
id = u64 & 0xFF;
|
||||
ret.channel = ((u64 >> 6) & 0x03) + 1;
|
||||
ret.temp = ((u64 >> 8) & 0x0F) * 0.1f + ((u64 >> 12) & 0x0F) + ((u64 >> 16) & 0x0F) * 10.0f;
|
||||
if (!((u64 >> 21) & 1)) {
|
||||
ret.temp = ret.temp;
|
||||
} else {
|
||||
ret.temp = -ret.temp;
|
||||
}
|
||||
ret.battery_low = !((u64 >> 23) & 1ULL);
|
||||
break;
|
||||
case FPW_THERMOPROTX4:
|
||||
ret.id = (data->decode_data >> 25) & 0xFF;
|
||||
ret.battery_low = (data->decode_data >> 24) & 1;
|
||||
// btn = (data->decode_data >> 23) & 1;
|
||||
ret.channel = ((data->decode_data >> 21) & 0x03) + 1;
|
||||
if (!((data->decode_data >> 20) & 1)) {
|
||||
ret.temp = (float)((data->decode_data >> 9) & 0x07FF) / 10.0f;
|
||||
} else {
|
||||
ret.temp = (float)((~(data->decode_data >> 9) & 0x07FF) + 1) / -10.0f;
|
||||
}
|
||||
ret.humidity = (data->decode_data >> 1) & 0xFF;
|
||||
break;
|
||||
case FPW_TX_8300:
|
||||
ret.humidity = (((data->decode_data >> 28) & 0x0F) * 10) + ((data->decode_data >> 24) & 0x0F);
|
||||
if (!((data->decode_data >> 22) & 0x03))
|
||||
ret.battery_low = 0;
|
||||
else
|
||||
ret.battery_low = 1;
|
||||
ret.channel = (data->decode_data >> 20) & 0x03;
|
||||
ret.id = (data->decode_data >> 12) & 0x7F;
|
||||
ret.temp = ((data->decode_data >> 8) & 0x0F) * 10.0f + ((data->decode_data >> 4) & 0x0F) +
|
||||
(data->decode_data & 0x0F) * 0.1f;
|
||||
if (!((data->decode_data >> 19) & 1)) {
|
||||
ret.temp = ret.temp;
|
||||
} else {
|
||||
ret.temp = -ret.temp;
|
||||
}
|
||||
break;
|
||||
case FPW_WENDOX_W6726:
|
||||
ret.id = (data->decode_data >> 24) & 0xFF;
|
||||
ret.battery_low = (data->decode_data >> 6) & 1;
|
||||
if (((data->decode_data >> 23) & 1)) {
|
||||
ret.temp = (float)(((data->decode_data >> 14) & 0x1FF) + 12) / 10.0f;
|
||||
} else {
|
||||
ret.temp = (float)((~(data->decode_data >> 14) & 0x1FF) + 1 - 12) / -10.0f;
|
||||
}
|
||||
if (ret.temp < -50.0f) {
|
||||
ret.temp = -50.0f;
|
||||
} else if (ret.temp > 70.0f) {
|
||||
ret.temp = 70.0f;
|
||||
}
|
||||
break;
|
||||
case FPW_Acurite986:
|
||||
ret.id = FProtoGeneral::subghz_protocol_blocks_reverse_key(data->decode_data >> 24, 8);
|
||||
ret.id = (id << 8) | FProtoGeneral::subghz_protocol_blocks_reverse_key(data->decode_data >> 16, 8);
|
||||
ret.battery_low = (data->decode_data >> 14) & 1;
|
||||
ret.channel = ((data->decode_data >> 15) & 1) + 1;
|
||||
i16 = FProtoGeneral::subghz_protocol_blocks_reverse_key(data->decode_data >> 32, 8);
|
||||
if (i16 & 0x80) {
|
||||
i16 = -(i16 & 0x7F);
|
||||
}
|
||||
ret.temp = FProtoGeneral::locale_fahrenheit_to_celsius((float)i16);
|
||||
break;
|
||||
case FPW_KEDSUM:
|
||||
ret.id = data->decode_data >> 32;
|
||||
if ((data->decode_data >> 30) & 0x3) {
|
||||
ret.battery_low = 0;
|
||||
} else {
|
||||
ret.battery_low = 1;
|
||||
}
|
||||
ret.channel = ((data->decode_data >> 28) & 0x3) + 1;
|
||||
u16 = ((data->decode_data >> 16) & 0x0f) << 8 | ((data->decode_data >> 20) & 0x0f) << 4 | ((data->decode_data >> 24) & 0x0f);
|
||||
ret.temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)u16 - 900.0f) / 10.0f);
|
||||
ret.humidity = ((data->decode_data >> 8) & 0x0f) << 4 | ((data->decode_data >> 12) & 0x0f);
|
||||
break;
|
||||
case FPW_Acurite5in1:
|
||||
u8 = ((data->decode_data >> 62) & 0x03);
|
||||
ret.channel = channel_3021[u8];
|
||||
ret.id = (data->decode_data >> 48) & 0x3FFF;
|
||||
ret.battery_low = !((data->decode_data >> 46) & 1);
|
||||
ret.humidity = (data->decode_data >> 8) & 0x7F;
|
||||
u16 = ((data->decode_data >> (24 - 7)) & 0x780) | ((data->decode_data >> 16) & 0x7F);
|
||||
ret.temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)(u16)-400) / 10.0f);
|
||||
break;
|
||||
case FPW_EmosE601x:
|
||||
ret.id = 0xffff; //(upper_decode_data >> 24) & 0xff; //todo maybe with oregon, and +64bit usage/message
|
||||
ret.battery_low = (data->decode_data >> 10) & 1;
|
||||
i16 = (data->decode_data >> 40) & 0xfff;
|
||||
/* Handle signed data */
|
||||
if (i16 & 0x800) {
|
||||
i16 |= 0xf000;
|
||||
}
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
ret.humidity = (data->decode_data >> 32) & 0xff;
|
||||
ret.channel = (data->decode_data >> 52) & 0x03;
|
||||
break;
|
||||
case FPW_SolightTE44:
|
||||
ret.id = (data->decode_data >> 28) & 0xff;
|
||||
ret.battery_low = !(data->decode_data >> 27) & 0x01;
|
||||
ret.channel = ((data->decode_data >> 24) & 0x03) + 1;
|
||||
i16 = (data->decode_data >> 12) & 0x0fff;
|
||||
/* Handle signed data */
|
||||
if (i16 & 0x0800) {
|
||||
i16 |= 0xf000;
|
||||
}
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
break;
|
||||
case FPW_Bresser3CH:
|
||||
ret.id = (data->decode_data >> 28) & 0xff;
|
||||
ret.channel = ((data->decode_data >> 27) & 0x01) | (((data->decode_data >> 26) & 0x01) << 1);
|
||||
// ret.btn = ((data->decode_data >> 25) & 0x1);
|
||||
ret.battery_low = ((data->decode_data >> 24) & 0x1);
|
||||
i16 = (data->decode_data >> 12) & 0x0fff;
|
||||
/* Handle signed data */
|
||||
if (i16 & 0x0800) {
|
||||
i16 |= 0xf000;
|
||||
}
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
ret.humidity = data->decode_data & 0xff;
|
||||
break;
|
||||
case FPW_Bresser3CH_V1:
|
||||
ret.id = (data->decode_data >> 32) & 0xff;
|
||||
ret.battery_low = ((data->decode_data >> 31) & 0x1);
|
||||
// ret.btn = (data->decode_data >> 30) & 0x1;
|
||||
ret.channel = (data->decode_data >> 28) & 0x3;
|
||||
ret.temp = (data->decode_data >> 16) & 0xfff;
|
||||
ret.temp = FProtoGeneral::locale_fahrenheit_to_celsius((float)(ret.temp - 900) / 10.0);
|
||||
ret.humidity = (data->decode_data >> 8) & 0xff;
|
||||
break;
|
||||
|
||||
case FPW_Vauno_EN8822:
|
||||
ret.id = (data->decode_data >> 34) & 0xff;
|
||||
ret.battery_low = (data->decode_data >> 33) & 0x01;
|
||||
ret.channel = ((data->decode_data >> 30) & 0x03);
|
||||
i16 = (data->decode_data >> 18) & 0x0fff;
|
||||
/* Handle signed data */
|
||||
if (i16 & 0x0800) {
|
||||
i16 |= 0xf000;
|
||||
}
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
ret.humidity = (data->decode_data >> 11) & 0x7f;
|
||||
|
||||
break;
|
||||
case FPW_Invalid:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
||||
@@ -96,7 +96,7 @@ class WeatherView : public View {
|
||||
private:
|
||||
void on_tick_second();
|
||||
void on_data(const WeatherDataMessage* data);
|
||||
|
||||
WeatherRecentEntry process_data(const WeatherDataMessage* data);
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{
|
||||
433'920'000 /* frequency */,
|
||||
@@ -151,6 +151,14 @@ class WeatherView : public View {
|
||||
}};
|
||||
WeatherRecentEntriesView recent_entries_view{columns, recent};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::WeatherData,
|
||||
[this](Message* const p) {
|
||||
|
||||
@@ -1,321 +1,327 @@
|
||||
// converted by bmp_to_hex_cpp_arr.py at the firmware/tools dir
|
||||
// fake transparent px should be the exact color rgb dec(41,24,22), then use true for the last arg when drawing bmp with the draw func
|
||||
|
||||
const unsigned char splash_bmp[] = {
|
||||
0x42, 0x4d, 0xf4, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00,
|
||||
0x42, 0x4d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00,
|
||||
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x32, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x82, 0x0e,
|
||||
0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9c, 0x0e,
|
||||
0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x0f, 0x00,
|
||||
0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x19, 0xf6, 0x00, 0x00, 0x14,
|
||||
0xc9, 0x00, 0x00, 0x0c, 0x78, 0x00, 0x16, 0x18, 0x29, 0x00, 0xfd, 0xfd,
|
||||
0xfd, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0xe7, 0xe7, 0xe7, 0x00, 0xda, 0xda,
|
||||
0xda, 0x00, 0xcd, 0xcd, 0xcd, 0x00, 0xc7, 0xc7, 0xc7, 0x00, 0xba, 0xba,
|
||||
0xba, 0x00, 0xad, 0xad, 0xad, 0x00, 0x96, 0x96, 0x96, 0x00, 0x5c, 0x5c,
|
||||
0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xee, 0x00, 0x00, 0xe6, 0xee,
|
||||
0x00, 0x00, 0xe6, 0xee, 0x00, 0x00, 0xe6, 0xee, 0x00, 0x00, 0x00, 0x18,
|
||||
0xee, 0x44, 0x44, 0x47, 0x3e, 0xee, 0xee, 0xee, 0xe3, 0xd5, 0x44, 0x7d,
|
||||
0x08, 0xee, 0x00, 0x14, 0xe3, 0x44, 0x44, 0x48, 0x3e, 0xea, 0x44, 0x44,
|
||||
0x44, 0xde, 0x12, 0xee, 0x00, 0x08, 0xa4, 0x44, 0x45, 0x9d, 0x08, 0xee,
|
||||
0x00, 0x08, 0xc4, 0x44, 0x45, 0xce, 0x10, 0xee, 0x00, 0x08, 0x34, 0x44,
|
||||
0x44, 0x6d, 0x16, 0xee, 0x00, 0x12, 0x34, 0x44, 0x44, 0x6d, 0xee, 0xee,
|
||||
0xee, 0xe3, 0xd5, 0x00, 0x1a, 0x44, 0x00, 0x1c, 0x45, 0xce, 0xee, 0x44,
|
||||
0x44, 0x47, 0x3e, 0xee, 0xee, 0xee, 0xe3, 0xd5, 0x44, 0x7d, 0x08, 0xee,
|
||||
0x00, 0x0a, 0xe3, 0x44, 0x44, 0x48, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x34,
|
||||
0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xee, 0xd4, 0x46, 0x89, 0x98,
|
||||
0xb3, 0xee, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0xed, 0x79, 0x99,
|
||||
0x99, 0x73, 0x10, 0xee, 0x00, 0x0a, 0xed, 0x47, 0x99, 0x95, 0xae, 0x00,
|
||||
0x08, 0xee, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xae, 0x10, 0xee, 0x00, 0x08,
|
||||
0x34, 0x99, 0x99, 0x7c, 0x16, 0xee, 0x00, 0x14, 0x34, 0x99, 0x99, 0x7c,
|
||||
0xee, 0xee, 0xee, 0xb4, 0x56, 0x89, 0x18, 0x99, 0x00, 0x2e, 0x97, 0xae,
|
||||
0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xee, 0xd4, 0x46, 0x89, 0x98,
|
||||
0xb3, 0xee, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x34, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xe3, 0x55, 0x99,
|
||||
0x99, 0x99, 0x9b, 0xee, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0xee,
|
||||
0xb9, 0x99, 0x99, 0x8d, 0x10, 0xee, 0x00, 0x0a, 0xe7, 0x69, 0x99, 0x74,
|
||||
0xde, 0x00, 0x08, 0xee, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xae, 0x10, 0xee,
|
||||
0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0xee, 0x00, 0x10, 0x34, 0x99,
|
||||
0x99, 0x7c, 0xee, 0xee, 0xea, 0x47, 0x1c, 0x99, 0x00, 0x2e, 0x97, 0xae,
|
||||
0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xe3, 0x55, 0x99, 0x99, 0x99,
|
||||
0x9b, 0xee, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x36, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xea, 0x48, 0x99,
|
||||
0x99, 0x99, 0x98, 0xde, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0xee,
|
||||
0xd7, 0x99, 0x99, 0x98, 0x3e, 0x00, 0x0e, 0xee, 0x00, 0x08, 0xd4, 0x89,
|
||||
0x99, 0x5a, 0x0a, 0xee, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xae, 0x10, 0xee,
|
||||
0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0xee, 0x00, 0x10, 0x34, 0x99,
|
||||
0x99, 0x7c, 0xee, 0xee, 0xb4, 0x79, 0x1c, 0x99, 0x00, 0x2e, 0x97, 0xae,
|
||||
0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xea, 0x48, 0x99, 0x99, 0x99,
|
||||
0x98, 0xde, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x12, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xd4, 0x79, 0x00,
|
||||
0x08, 0x99, 0x00, 0x1c, 0x73, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e,
|
||||
0xee, 0xeb, 0x99, 0x99, 0x99, 0xce, 0x0c, 0xee, 0x00, 0x0a, 0xe3, 0x56,
|
||||
0x99, 0x97, 0x4d, 0x00, 0x0a, 0xee, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xae,
|
||||
0x10, 0xee, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0xee, 0x00, 0x0e,
|
||||
0x34, 0x99, 0x99, 0x7c, 0xee, 0xed, 0x47, 0x00, 0x1e, 0x99, 0x00, 0x16,
|
||||
0x97, 0xae, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xd4, 0x79, 0x00,
|
||||
0x08, 0x99, 0x00, 0x10, 0x73, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x10, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xa5,
|
||||
0x0a, 0x99, 0x00, 0x1c, 0x8d, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e,
|
||||
0xee, 0xed, 0x79, 0x99, 0x99, 0x73, 0x0c, 0xee, 0x00, 0x0a, 0xec, 0x48,
|
||||
0x99, 0x95, 0xae, 0x00, 0x0a, 0xee, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xae,
|
||||
0x10, 0xee, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0xee, 0x00, 0x0e,
|
||||
0x34, 0x99, 0x99, 0x7c, 0xee, 0xe7, 0x69, 0x00, 0x1e, 0x99, 0x00, 0x14,
|
||||
0x97, 0xae, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xee, 0xa5, 0x0a, 0x99,
|
||||
0x00, 0x10, 0x8d, 0xee, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00,
|
||||
0x00, 0x36, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xed, 0x47, 0x99, 0x97,
|
||||
0x89, 0x99, 0x99, 0x97, 0x3e, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0xee,
|
||||
0xee, 0xb9, 0x99, 0x99, 0x9d, 0x00, 0x0c, 0xee, 0x00, 0x0a, 0x34, 0x69,
|
||||
0x99, 0x74, 0xde, 0x00, 0x0a, 0xee, 0x00, 0x08, 0xc7, 0x99, 0x98, 0xae,
|
||||
0x10, 0xee, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0xee, 0x00, 0x12,
|
||||
0x34, 0x99, 0x99, 0x7c, 0xee, 0x34, 0x89, 0x99, 0x64, 0x00, 0x1c, 0x44,
|
||||
0x00, 0x2c, 0xae, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xed, 0x47, 0x99,
|
||||
0x97, 0x89, 0x99, 0x99, 0x97, 0x3e, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x38, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0xec, 0x59,
|
||||
0x99, 0x95, 0xbc, 0x99, 0x99, 0x98, 0xde, 0xee, 0xe3, 0x49, 0x99, 0x94,
|
||||
0x3e, 0xee, 0xee, 0xd7, 0x99, 0x99, 0x99, 0x74, 0x0c, 0x44, 0x00, 0x06,
|
||||
0x99, 0x99, 0x4b, 0x00, 0x0c, 0xee, 0x00, 0x08, 0xb7, 0x99, 0x99, 0xae,
|
||||
0x10, 0xee, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0xee, 0x00, 0x12,
|
||||
0x34, 0x99, 0x99, 0x7c, 0xee, 0xd5, 0x99, 0x99, 0x6d, 0x00, 0x20, 0xee,
|
||||
0x00, 0x28, 0x49, 0x99, 0x95, 0xde, 0xee, 0xec, 0x59, 0x99, 0x95, 0xbc,
|
||||
0x99, 0x99, 0x98, 0xde, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00,
|
||||
0x00, 0x30, 0xee, 0x49, 0x99, 0x95, 0xde, 0xee, 0x34, 0x79, 0x99, 0x84,
|
||||
0xdd, 0x89, 0x99, 0x99, 0x8e, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0xee,
|
||||
0xee, 0xeb, 0x16, 0x99, 0x02, 0x97, 0x02, 0x43, 0x0a, 0xee, 0x00, 0x0a,
|
||||
0xed, 0x47, 0x99, 0x99, 0x9d, 0x00, 0x10, 0xee, 0x00, 0x08, 0x34, 0x99,
|
||||
0x99, 0x9d, 0x16, 0xee, 0x00, 0x12, 0x34, 0x99, 0x99, 0x7c, 0xee, 0xd6,
|
||||
0x99, 0x99, 0x6d, 0x00, 0x20, 0xee, 0x00, 0x28, 0x49, 0x99, 0x95, 0xde,
|
||||
0xee, 0x34, 0x79, 0x99, 0x84, 0xdd, 0x89, 0x99, 0x99, 0x8e, 0xee, 0xe3,
|
||||
0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00, 0x32, 0xee, 0x49, 0x99, 0x95,
|
||||
0xde, 0xee, 0xc4, 0x99, 0x99, 0x67, 0xee, 0x79, 0x99, 0x99, 0x8d, 0xee,
|
||||
0xe3, 0x49, 0x99, 0x94, 0x3e, 0xee, 0xee, 0xed, 0x79, 0x00, 0x14, 0x99,
|
||||
0x02, 0x94, 0x02, 0xce, 0x0a, 0xee, 0x00, 0x0c, 0x35, 0x59, 0x99, 0x99,
|
||||
0x98, 0x3e, 0x0e, 0xee, 0x00, 0x0a, 0x34, 0x99, 0x99, 0x99, 0x74, 0x00,
|
||||
0x16, 0x44, 0x00, 0x10, 0x99, 0x99, 0x7c, 0xee, 0xd6, 0x99, 0x99, 0x9d,
|
||||
0x20, 0xee, 0x00, 0x28, 0x49, 0x99, 0x95, 0xde, 0xee, 0xc4, 0x99, 0x99,
|
||||
0x67, 0xee, 0x79, 0x99, 0x99, 0x8d, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x32, 0xee, 0x49, 0x99, 0x95, 0xde, 0xe3, 0x57, 0x99,
|
||||
0x99, 0x4d, 0xee, 0xd8, 0x99, 0x99, 0x98, 0xee, 0xe3, 0x49, 0x99, 0x94,
|
||||
0x3e, 0xee, 0xee, 0xee, 0xc9, 0x00, 0x14, 0x99, 0x02, 0x74, 0x02, 0x3e,
|
||||
0x08, 0xee, 0x00, 0x0e, 0xe3, 0x84, 0x89, 0x99, 0x99, 0x99, 0xa3, 0x00,
|
||||
0x0e, 0xee, 0x02, 0x34, 0x22, 0x99, 0x00, 0x0e, 0x7c, 0xee, 0xd6, 0x99,
|
||||
0x99, 0x99, 0x64, 0x00, 0x18, 0x44, 0x00, 0x2e, 0x45, 0xce, 0xee, 0x49,
|
||||
0x99, 0x95, 0xde, 0xe3, 0x57, 0x99, 0x99, 0x4d, 0xee, 0xd8, 0x99, 0x99,
|
||||
0x98, 0xee, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x32,
|
||||
0xee, 0x49, 0x99, 0x95, 0xde, 0xed, 0x48, 0x99, 0x97, 0x43, 0xee, 0x37,
|
||||
0x99, 0x99, 0x97, 0xde, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0xee, 0xee, 0xee,
|
||||
0x37, 0x00, 0x14, 0x99, 0x02, 0x4c, 0x0a, 0xee, 0x02, 0xeb, 0x02, 0x48,
|
||||
0x08, 0x99, 0x02, 0x9b, 0x0e, 0xee, 0x02, 0x34, 0x22, 0x99, 0x00, 0x06,
|
||||
0x7c, 0xee, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x2e, 0x97, 0xae, 0xee, 0x49,
|
||||
0x99, 0x95, 0xde, 0xed, 0x48, 0x99, 0x97, 0x43, 0xee, 0x37, 0x99, 0x99,
|
||||
0x97, 0xde, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x32,
|
||||
0xee, 0x49, 0x99, 0x95, 0xde, 0x35, 0x69, 0x99, 0x95, 0xce, 0xee, 0xec,
|
||||
0x89, 0x99, 0x99, 0xbe, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0xee, 0xee, 0xee,
|
||||
0xec, 0x00, 0x12, 0x99, 0x02, 0x97, 0x02, 0x43, 0x0a, 0xee, 0x02, 0xd4,
|
||||
0x02, 0x79, 0x0a, 0x99, 0x02, 0xde, 0x0c, 0xee, 0x02, 0x34, 0x22, 0x99,
|
||||
0x00, 0x06, 0x7c, 0xee, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x2e, 0x97, 0xae,
|
||||
0xee, 0x49, 0x99, 0x95, 0xde, 0x35, 0x69, 0x99, 0x95, 0xce, 0xee, 0xec,
|
||||
0x89, 0x99, 0x99, 0xbe, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x48, 0xee, 0x49, 0x99, 0x95, 0xde, 0xd4, 0x89, 0x99, 0x74, 0x3e,
|
||||
0xee, 0xe3, 0x79, 0x99, 0x99, 0x7d, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0xee,
|
||||
0xee, 0xee, 0xe3, 0x79, 0x99, 0x99, 0x64, 0x44, 0x44, 0x89, 0x99, 0x99,
|
||||
0x94, 0xce, 0x08, 0xee, 0x00, 0x12, 0xed, 0x46, 0x99, 0x98, 0x59, 0x99,
|
||||
0x99, 0x99, 0x8d, 0x00, 0x0c, 0xee, 0x02, 0x34, 0x22, 0x99, 0x00, 0x06,
|
||||
0x7c, 0xee, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x2e, 0x97, 0xae, 0xee, 0x49,
|
||||
0x99, 0x95, 0xde, 0xd4, 0x89, 0x99, 0x74, 0x3e, 0xee, 0xe3, 0x79, 0x99,
|
||||
0x99, 0x7d, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x2a,
|
||||
0xee, 0x49, 0x99, 0x95, 0xde, 0x76, 0x99, 0x99, 0x6a, 0xee, 0xee, 0xee,
|
||||
0xa9, 0x99, 0x99, 0x9b, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x08, 0xee,
|
||||
0x00, 0x16, 0xc9, 0x99, 0x99, 0x9c, 0xee, 0xee, 0x3b, 0x99, 0x99, 0x74,
|
||||
0x3e, 0x00, 0x08, 0xee, 0x00, 0x14, 0x35, 0x59, 0x99, 0x95, 0x7d, 0x99,
|
||||
0x99, 0x99, 0x9a, 0x3e, 0x0a, 0xee, 0x02, 0x34, 0x22, 0x99, 0x00, 0x06,
|
||||
0x7c, 0xee, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x2e, 0x97, 0xae, 0xee, 0x49,
|
||||
0x99, 0x95, 0xde, 0x76, 0x99, 0x99, 0x6a, 0xee, 0xee, 0xee, 0xa9, 0x99,
|
||||
0x99, 0x9b, 0xe3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x2a,
|
||||
0xee, 0x49, 0x99, 0x95, 0x3d, 0x48, 0x99, 0x98, 0x4d, 0xee, 0xee, 0xee,
|
||||
0xd7, 0x99, 0x99, 0x97, 0xd3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x08, 0xee,
|
||||
0x00, 0x14, 0x37, 0x99, 0x99, 0x97, 0x3e, 0xee, 0xc4, 0x89, 0x99, 0x4c,
|
||||
0x08, 0xee, 0x00, 0x16, 0xe3, 0x84, 0x89, 0x99, 0x64, 0x3e, 0xd9, 0x99,
|
||||
0x99, 0x99, 0xa3, 0x00, 0x0a, 0xee, 0x00, 0x08, 0x34, 0x99, 0x99, 0x64,
|
||||
0x16, 0x44, 0x00, 0x0c, 0x99, 0x99, 0x99, 0x7c, 0xee, 0xd6, 0x20, 0x99,
|
||||
0x00, 0x2e, 0x97, 0xae, 0xee, 0x49, 0x99, 0x95, 0x3d, 0x48, 0x99, 0x98,
|
||||
0x4d, 0xee, 0xee, 0xee, 0xd7, 0x99, 0x99, 0x97, 0xd3, 0x49, 0x99, 0x94,
|
||||
0x3e, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xee, 0x49, 0x99, 0x96, 0x3b, 0x69,
|
||||
0x99, 0x96, 0x5e, 0xee, 0xee, 0xee, 0xe8, 0x99, 0x99, 0x99, 0xc3, 0x49,
|
||||
0x99, 0x94, 0x3e, 0x00, 0x08, 0xee, 0x00, 0x14, 0xec, 0x99, 0x99, 0x99,
|
||||
0xbe, 0xe3, 0x46, 0x99, 0x96, 0x43, 0x08, 0xee, 0x00, 0x16, 0xeb, 0x48,
|
||||
0x99, 0x97, 0x4d, 0xee, 0xed, 0x99, 0x99, 0x99, 0x9c, 0x00, 0x0a, 0xee,
|
||||
0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0xee, 0x00, 0x12, 0x39, 0x99,
|
||||
0x99, 0x7c, 0xee, 0xd6, 0x99, 0x99, 0x54, 0x00, 0x1c, 0x44, 0x00, 0x2c,
|
||||
0xae, 0xee, 0x49, 0x99, 0x96, 0x3b, 0x69, 0x99, 0x96, 0x5e, 0xee, 0xee,
|
||||
0xee, 0xe8, 0x99, 0x99, 0x99, 0xc3, 0x49, 0x99, 0x94, 0x3e, 0x00, 0x00,
|
||||
0x00, 0x2a, 0xee, 0x49, 0x99, 0x98, 0xd5, 0x79, 0x99, 0x94, 0xde, 0xee,
|
||||
0xee, 0xee, 0xed, 0x89, 0x99, 0x99, 0x73, 0x49, 0x99, 0x94, 0x3e, 0x00,
|
||||
0x08, 0xee, 0x00, 0x14, 0xe3, 0x79, 0x99, 0x99, 0x8d, 0xea, 0x59, 0x99,
|
||||
0x84, 0xde, 0x08, 0xee, 0x00, 0x18, 0xd4, 0x79, 0x99, 0x84, 0xbe, 0xee,
|
||||
0xee, 0xb9, 0x99, 0x99, 0x99, 0xde, 0x08, 0xee, 0x00, 0x08, 0x34, 0x99,
|
||||
0x99, 0x6d, 0x16, 0xee, 0x00, 0x12, 0x34, 0x99, 0x99, 0x7c, 0xee, 0xd6,
|
||||
0x99, 0x99, 0x5d, 0x00, 0x20, 0xee, 0x00, 0x28, 0x49, 0x99, 0x98, 0xd5,
|
||||
0x79, 0x99, 0x94, 0xde, 0xee, 0xee, 0xee, 0xed, 0x89, 0x99, 0x99, 0x73,
|
||||
0x49, 0x99, 0x94, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0xee, 0x49, 0x99, 0x99,
|
||||
0xa6, 0x99, 0x99, 0x74, 0x3e, 0xee, 0xee, 0xee, 0xe3, 0x79, 0x99, 0x99,
|
||||
0x9c, 0x59, 0x99, 0x94, 0x3e, 0x00, 0x0a, 0xee, 0x00, 0x32, 0xc9, 0x99,
|
||||
0x99, 0x9a, 0xd4, 0x79, 0x99, 0x65, 0x3e, 0xee, 0xee, 0xee, 0xed, 0x46,
|
||||
0x99, 0x98, 0x48, 0x3e, 0xee, 0xee, 0x3a, 0x99, 0x99, 0x99, 0x83, 0x00,
|
||||
0x08, 0xee, 0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0xee, 0x00, 0x12,
|
||||
0x34, 0x99, 0x99, 0x7c, 0xee, 0xd6, 0x99, 0x99, 0x93, 0x00, 0x20, 0xee,
|
||||
0x00, 0x28, 0x49, 0x99, 0x99, 0xa6, 0x99, 0x99, 0x74, 0x3e, 0xee, 0xee,
|
||||
0xee, 0xe3, 0x79, 0x99, 0x99, 0x9c, 0x59, 0x99, 0x94, 0x3e, 0x00, 0x00,
|
||||
0x00, 0x10, 0xee, 0x49, 0x99, 0x99, 0x98, 0x99, 0x99, 0x5c, 0x0a, 0xee,
|
||||
0x00, 0x10, 0xd8, 0x99, 0x99, 0x99, 0x79, 0x99, 0x84, 0x3e, 0x0a, 0xee,
|
||||
0x00, 0x10, 0x37, 0x99, 0x99, 0x99, 0x86, 0x99, 0x98, 0x4d, 0x08, 0xee,
|
||||
0x00, 0x2a, 0x35, 0x59, 0x99, 0x95, 0x53, 0xee, 0xee, 0xee, 0xe3, 0x89,
|
||||
0x99, 0x99, 0x9a, 0x3e, 0xee, 0xee, 0xee, 0x34, 0x99, 0x99, 0x6d, 0x00,
|
||||
0x16, 0xee, 0x00, 0x14, 0x34, 0x99, 0x99, 0x7c, 0xee, 0x36, 0x99, 0x99,
|
||||
0x99, 0x54, 0x18, 0x44, 0x00, 0x14, 0x45, 0xce, 0xee, 0x49, 0x99, 0x99,
|
||||
0x98, 0x99, 0x99, 0x5c, 0x0a, 0xee, 0x00, 0x10, 0xd8, 0x99, 0x99, 0x99,
|
||||
0x79, 0x99, 0x84, 0x3e, 0x00, 0x00, 0x02, 0xee, 0x02, 0x59, 0x08, 0x99,
|
||||
0x02, 0x97, 0x02, 0x4d, 0x0a, 0xee, 0x02, 0x36, 0x0a, 0x99, 0x02, 0x75,
|
||||
0x0c, 0xee, 0x02, 0xec, 0x0a, 0x99, 0x00, 0x16, 0x96, 0x53, 0xee, 0xee,
|
||||
0xee, 0xe3, 0x84, 0x89, 0x99, 0x64, 0xde, 0x00, 0x08, 0xee, 0x00, 0x18,
|
||||
0xd9, 0x99, 0x99, 0x99, 0xbe, 0xee, 0xee, 0xee, 0x34, 0x99, 0x99, 0x6d,
|
||||
0x16, 0xee, 0x00, 0x0c, 0x34, 0x99, 0x99, 0x7c, 0xee, 0xe6, 0x20, 0x99,
|
||||
0x00, 0x08, 0x97, 0xae, 0xee, 0x59, 0x08, 0x99, 0x02, 0x97, 0x02, 0x4d,
|
||||
0x0a, 0xee, 0x02, 0x36, 0x0a, 0x99, 0x02, 0x75, 0x02, 0xee, 0x00, 0x00,
|
||||
0x02, 0xee, 0x02, 0xa8, 0x08, 0x99, 0x02, 0x95, 0x02, 0xae, 0x0a, 0xee,
|
||||
0x02, 0xec, 0x0a, 0x99, 0x02, 0x5b, 0x0c, 0xee, 0x02, 0xe3, 0x02, 0x89,
|
||||
0x08, 0x99, 0x00, 0x14, 0x84, 0xde, 0xee, 0xee, 0xee, 0xeb, 0x48, 0x99,
|
||||
0x97, 0x4c, 0x0a, 0xee, 0x00, 0x18, 0xed, 0x99, 0x99, 0x99, 0x9d, 0xee,
|
||||
0xee, 0xee, 0x34, 0x99, 0x99, 0x6d, 0x16, 0xee, 0x00, 0x0e, 0x34, 0x99,
|
||||
0x99, 0x7c, 0xee, 0xed, 0x89, 0x00, 0x1e, 0x99, 0x00, 0x08, 0x97, 0xae,
|
||||
0xee, 0xa8, 0x08, 0x99, 0x02, 0x95, 0x02, 0xae, 0x0a, 0xee, 0x02, 0xec,
|
||||
0x0a, 0x99, 0x02, 0x5b, 0x02, 0xee, 0x00, 0x00, 0x02, 0xee, 0x02, 0xd7,
|
||||
0x08, 0x99, 0x02, 0x64, 0x02, 0x3e, 0x0a, 0xee, 0x00, 0x0e, 0xe3, 0x79,
|
||||
0x99, 0x99, 0x99, 0x96, 0x4d, 0x00, 0x0e, 0xee, 0x00, 0x0c, 0xd8, 0x99,
|
||||
0x99, 0x99, 0x98, 0x48, 0x08, 0xee, 0x00, 0x0a, 0xd4, 0x79, 0x99, 0x84,
|
||||
0xbe, 0x00, 0x0c, 0xee, 0x00, 0x16, 0xb9, 0x99, 0x99, 0x98, 0xde, 0xee,
|
||||
0xee, 0x34, 0x99, 0x99, 0x6d, 0x00, 0x16, 0xee, 0x00, 0x0c, 0x34, 0x99,
|
||||
0x99, 0x7c, 0xee, 0xe3, 0x20, 0x99, 0x00, 0x08, 0x97, 0xae, 0xee, 0xd7,
|
||||
0x08, 0x99, 0x02, 0x64, 0x02, 0x3e, 0x0a, 0xee, 0x00, 0x10, 0xe3, 0x79,
|
||||
0x99, 0x99, 0x99, 0x96, 0x4d, 0xee, 0x00, 0x00, 0x00, 0x0e, 0xee, 0xec,
|
||||
0x99, 0x99, 0x99, 0x96, 0x4d, 0x00, 0x0e, 0xee, 0x00, 0x0c, 0xd9, 0x99,
|
||||
0x99, 0x99, 0x74, 0xce, 0x0e, 0xee, 0x00, 0x1e, 0xed, 0x99, 0x99, 0x99,
|
||||
0x85, 0x53, 0xee, 0xee, 0xee, 0xed, 0x46, 0x99, 0x99, 0x57, 0x3e, 0x00,
|
||||
0x0c, 0xee, 0x00, 0x16, 0x39, 0x99, 0x99, 0x99, 0xa3, 0xee, 0xee, 0x34,
|
||||
0x99, 0x99, 0x6d, 0x00, 0x16, 0xee, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c,
|
||||
0xee, 0xee, 0x3a, 0x00, 0x1e, 0x99, 0x00, 0x12, 0x97, 0xae, 0xee, 0xec,
|
||||
0x99, 0x99, 0x99, 0x96, 0x4d, 0x00, 0x0e, 0xee, 0x00, 0x0e, 0xd9, 0x99,
|
||||
0x99, 0x99, 0x74, 0xce, 0xee, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xee, 0xe3,
|
||||
0xc8, 0x99, 0x96, 0x44, 0xde, 0x00, 0x0e, 0xee, 0x00, 0x0a, 0xed, 0x79,
|
||||
0x99, 0x76, 0x4b, 0x00, 0x12, 0xee, 0x00, 0x1a, 0xc7, 0x99, 0x96, 0x45,
|
||||
0xde, 0xee, 0xee, 0xee, 0x35, 0x59, 0x99, 0x96, 0x43, 0x00, 0x0e, 0xee,
|
||||
0x00, 0x16, 0xe3, 0x89, 0x99, 0x99, 0x9a, 0x3e, 0xee, 0x34, 0x99, 0x99,
|
||||
0x6d, 0x00, 0x16, 0xee, 0x00, 0x10, 0x34, 0x99, 0x99, 0x7c, 0xee, 0xee,
|
||||
0xe3, 0xa6, 0x1c, 0x99, 0x00, 0x12, 0x97, 0xae, 0xee, 0xe3, 0xc8, 0x99,
|
||||
0x96, 0x44, 0xde, 0x00, 0x0e, 0xee, 0x00, 0x0e, 0xed, 0x79, 0x99, 0x76,
|
||||
0x4b, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xee, 0xee, 0xed, 0x84,
|
||||
0x44, 0xc3, 0x12, 0xee, 0x00, 0x08, 0xdc, 0x44, 0x4a, 0xde, 0x12, 0xee,
|
||||
0x00, 0x1a, 0xed, 0xa4, 0x44, 0xd3, 0xee, 0xee, 0xee, 0xe3, 0xc8, 0x44,
|
||||
0x44, 0x44, 0xde, 0x00, 0x10, 0xee, 0x00, 0x14, 0xd4, 0x44, 0x44, 0x44,
|
||||
0xae, 0xee, 0x38, 0x44, 0x44, 0x4d, 0x16, 0xee, 0x00, 0x12, 0x38, 0x44,
|
||||
0x44, 0x4c, 0xee, 0xee, 0xee, 0xed, 0xc4, 0x00, 0x1c, 0x44, 0x00, 0x0e,
|
||||
0xae, 0xee, 0xee, 0xed, 0x84, 0x44, 0xc3, 0x00, 0x12, 0xee, 0x00, 0x0c,
|
||||
0xdc, 0x44, 0x4a, 0xde, 0xee, 0xee, 0x00, 0x00, 0xe6, 0xee, 0x00, 0x00,
|
||||
0xe6, 0xee, 0x00, 0x00, 0xe6, 0xee, 0x00, 0x00, 0xe6, 0xee, 0x00, 0x00,
|
||||
0xe6, 0xee, 0x00, 0x00, 0x00, 0x1e, 0xee, 0x20, 0x00, 0x2e, 0xe0, 0x00,
|
||||
0x13, 0xe1, 0x00, 0x02, 0xe3, 0x00, 0x01, 0xee, 0xe2, 0x00, 0x08, 0x00,
|
||||
0x00, 0x26, 0x1e, 0xe1, 0x00, 0x02, 0xe3, 0x00, 0x01, 0xee, 0x00, 0x00,
|
||||
0x13, 0xe3, 0x00, 0x00, 0x1e, 0xe2, 0x00, 0x00, 0x2e, 0x00, 0x24, 0xee,
|
||||
0x00, 0x06, 0xe2, 0x00, 0x02, 0x00, 0x08, 0xee, 0x00, 0x50, 0xe2, 0x00,
|
||||
0x00, 0x00, 0x01, 0xee, 0xe1, 0x00, 0x02, 0xe3, 0x00, 0x01, 0xee, 0xee,
|
||||
0xe2, 0x00, 0x02, 0xee, 0xee, 0xe0, 0x00, 0x13, 0xe2, 0x00, 0x02, 0xee,
|
||||
0x00, 0x01, 0x3e, 0xee, 0xee, 0xee, 0x30, 0x00, 0x1e, 0xe1, 0x00, 0x02,
|
||||
0xee, 0x30, 0x08, 0x00, 0x00, 0x10, 0x2e, 0x30, 0x00, 0x1e, 0xe1, 0x00,
|
||||
0x02, 0xee, 0x00, 0x00, 0x00, 0x4c, 0xee, 0x20, 0x11, 0x1e, 0xe0, 0x11,
|
||||
0x03, 0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0x10, 0x10, 0x00, 0x00,
|
||||
0x00, 0x0e, 0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0x01, 0x11, 0x03,
|
||||
0xe3, 0x01, 0x11, 0x1e, 0xe2, 0x01, 0x11, 0x2e, 0x24, 0xee, 0x00, 0x06,
|
||||
0xe2, 0x01, 0x11, 0x00, 0x08, 0xee, 0x00, 0x68, 0x10, 0x10, 0x00, 0x11,
|
||||
0x11, 0x0e, 0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0xee, 0xe2, 0x01,
|
||||
0x11, 0xee, 0xee, 0xe0, 0x11, 0x03, 0xe2, 0x01, 0x11, 0xee, 0x01, 0x10,
|
||||
0x3e, 0xee, 0xee, 0xee, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02, 0xe3, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x2e, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02, 0xee,
|
||||
0x00, 0x00, 0x00, 0x4c, 0xee, 0x20, 0x11, 0x1e, 0xe0, 0x11, 0x03, 0xe1,
|
||||
0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0x11, 0x10, 0x2e, 0xee, 0xee, 0xee,
|
||||
0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0x01, 0x11, 0x13, 0xe3, 0x01,
|
||||
0x10, 0x1e, 0xe2, 0x01, 0x11, 0x2e, 0x24, 0xee, 0x00, 0x06, 0xe2, 0x01,
|
||||
0x11, 0x00, 0x08, 0xee, 0x00, 0x52, 0x11, 0x10, 0x2e, 0x31, 0x11, 0x0e,
|
||||
0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0xee, 0xe2, 0x01, 0x11, 0xee,
|
||||
0xee, 0xe0, 0x11, 0x03, 0xe2, 0x01, 0x11, 0xee, 0x01, 0x10, 0x3e, 0xee,
|
||||
0xee, 0xee, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0x00,
|
||||
0x08, 0xee, 0x00, 0x0e, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02, 0xee, 0x00,
|
||||
0x00, 0x00, 0x00, 0x50, 0xee, 0x20, 0x11, 0x2e, 0xe0, 0x11, 0x03, 0xe1,
|
||||
0x11, 0x12, 0xe3, 0x01, 0x10, 0xee, 0x11, 0x10, 0x2e, 0xee, 0xee, 0xee,
|
||||
0xe1, 0x11, 0x12, 0xe3, 0x01, 0x00, 0xee, 0x01, 0x11, 0x11, 0x00, 0x01,
|
||||
0x12, 0xee, 0xe2, 0x01, 0x11, 0x11, 0x00, 0x2e, 0x20, 0xee, 0x00, 0x06,
|
||||
0xe2, 0x01, 0x12, 0x00, 0x08, 0xee, 0x00, 0x52, 0x11, 0x10, 0x2e, 0x30,
|
||||
0x11, 0x0e, 0xe1, 0x11, 0x12, 0xe3, 0x01, 0x00, 0xee, 0xee, 0xe2, 0x01,
|
||||
0x11, 0xee, 0xee, 0xe0, 0x11, 0x13, 0xe2, 0x01, 0x11, 0xee, 0x01, 0x11,
|
||||
0x3e, 0xee, 0xee, 0xee, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02, 0xe3, 0x01,
|
||||
0x10, 0x00, 0x08, 0xee, 0x00, 0x0e, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02,
|
||||
0xee, 0x00, 0x00, 0x00, 0x00, 0x38, 0xee, 0x20, 0x11, 0x11, 0x00, 0x11,
|
||||
0x03, 0xe1, 0x11, 0x11, 0x00, 0x01, 0x10, 0xee, 0x11, 0x10, 0x2e, 0xee,
|
||||
0xee, 0xee, 0xe1, 0x11, 0x11, 0x00, 0x01, 0x1e, 0xee, 0x01, 0x08, 0x11,
|
||||
0x00, 0x10, 0x12, 0xee, 0xe2, 0x01, 0x11, 0x11, 0x10, 0x2e, 0x20, 0xee,
|
||||
0x00, 0x60, 0xe2, 0x01, 0x11, 0x10, 0x00, 0x03, 0xee, 0x11, 0x10, 0x2e,
|
||||
0x30, 0x11, 0x0e, 0xe1, 0x11, 0x12, 0x22, 0x01, 0x02, 0xee, 0xee, 0xe2,
|
||||
0x01, 0x11, 0xee, 0xee, 0xe0, 0x11, 0x12, 0x21, 0x01, 0x11, 0xee, 0x01,
|
||||
0x11, 0x22, 0x22, 0x23, 0xee, 0x30, 0x11, 0x12, 0x21, 0x11, 0x02, 0xe3,
|
||||
0x01, 0x10, 0x08, 0xee, 0x00, 0x0e, 0x30, 0x11, 0x12, 0x21, 0x10, 0x13,
|
||||
0xee, 0x00, 0x00, 0x00, 0x00, 0x50, 0xee, 0x20, 0x11, 0x00, 0x11, 0x11,
|
||||
0x03, 0xe1, 0x11, 0x00, 0x01, 0x11, 0x10, 0xee, 0x11, 0x10, 0x2e, 0xee,
|
||||
0xee, 0xee, 0xe1, 0x11, 0x00, 0x01, 0x11, 0x1e, 0xee, 0x01, 0x11, 0x00,
|
||||
0x01, 0x11, 0x12, 0xee, 0xe2, 0x01, 0x11, 0x00, 0x00, 0x2e, 0x20, 0xee,
|
||||
0x00, 0x60, 0xe2, 0x01, 0x10, 0x01, 0x11, 0x12, 0x3e, 0x11, 0x10, 0x2e,
|
||||
0x30, 0x11, 0x0e, 0xe1, 0x11, 0x10, 0x10, 0x11, 0x1e, 0xee, 0xee, 0xe2,
|
||||
0x01, 0x11, 0xee, 0xee, 0xe0, 0x11, 0x10, 0x10, 0x11, 0x11, 0xee, 0x01,
|
||||
0x11, 0x01, 0x00, 0x01, 0x2e, 0x30, 0x11, 0x00, 0x10, 0x11, 0x02, 0xe3,
|
||||
0x01, 0x10, 0x08, 0xee, 0x00, 0x0e, 0x30, 0x11, 0x00, 0x10, 0x11, 0x2e,
|
||||
0xee, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xee, 0x20, 0x11, 0x1e, 0xe1, 0x11,
|
||||
0x03, 0xe1, 0x11, 0x02, 0xe3, 0x11, 0x10, 0xee, 0x11, 0x10, 0x2e, 0xee,
|
||||
0xee, 0xee, 0xe1, 0x11, 0x02, 0xe3, 0x11, 0x10, 0xee, 0x01, 0x11, 0x03,
|
||||
0xe3, 0x11, 0x11, 0x1e, 0xe2, 0x01, 0x11, 0x2e, 0x24, 0xee, 0x00, 0x60,
|
||||
0xe2, 0x01, 0x11, 0xee, 0x11, 0x10, 0x3e, 0x11, 0x10, 0x2e, 0x30, 0x11,
|
||||
0x0e, 0xe1, 0x11, 0x01, 0x22, 0x11, 0x12, 0xee, 0xee, 0xe2, 0x01, 0x11,
|
||||
0xee, 0xee, 0xe0, 0x11, 0x02, 0x22, 0x11, 0x11, 0xee, 0x01, 0x10, 0x22,
|
||||
0x21, 0x11, 0x1e, 0x30, 0x11, 0x02, 0x21, 0x11, 0x02, 0xe3, 0x01, 0x10,
|
||||
0x08, 0xee, 0x00, 0x0e, 0x30, 0x11, 0x02, 0x21, 0x11, 0x23, 0xee, 0x00,
|
||||
0x00, 0x00, 0x00, 0x4c, 0xee, 0x20, 0x11, 0x1e, 0xe0, 0x11, 0x03, 0xe1,
|
||||
0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0x11, 0x10, 0x2e, 0xee, 0xee, 0xee,
|
||||
0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0x01, 0x11, 0x13, 0xe3, 0x01,
|
||||
0x11, 0x1e, 0xe2, 0x01, 0x11, 0x2e, 0x24, 0xee, 0x00, 0x60, 0xe2, 0x01,
|
||||
0x11, 0xee, 0x01, 0x10, 0x3e, 0x11, 0x11, 0x2e, 0x30, 0x11, 0x0e, 0xe1,
|
||||
0x11, 0x12, 0xe3, 0x11, 0x10, 0xee, 0xee, 0xe2, 0x01, 0x11, 0xee, 0xee,
|
||||
0xe0, 0x11, 0x13, 0xe2, 0x11, 0x11, 0xee, 0x01, 0x11, 0x3e, 0x21, 0x11,
|
||||
0x1e, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0x08, 0xee,
|
||||
0x00, 0x0e, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02, 0xee, 0x00, 0x00, 0x00,
|
||||
0x00, 0x54, 0xee, 0x20, 0x11, 0x1e, 0xe0, 0x11, 0x03, 0xe1, 0x11, 0x12,
|
||||
0xe3, 0x01, 0x00, 0xee, 0x11, 0x11, 0x2e, 0xee, 0xee, 0xee, 0xe1, 0x11,
|
||||
0x02, 0xe3, 0x01, 0x10, 0xee, 0x01, 0x11, 0x11, 0x00, 0x01, 0x10, 0x1e,
|
||||
0xe2, 0x01, 0x11, 0x11, 0x00, 0x00, 0x01, 0x2e, 0x1c, 0xee, 0x00, 0x60,
|
||||
0xe2, 0x01, 0x12, 0xee, 0x01, 0x00, 0x3e, 0x11, 0x11, 0x22, 0x20, 0x11,
|
||||
0x0e, 0xe1, 0x11, 0x12, 0x22, 0x01, 0x10, 0xee, 0xee, 0xe2, 0x01, 0x12,
|
||||
0xee, 0xee, 0xe0, 0x11, 0x12, 0x21, 0x01, 0x11, 0xee, 0x01, 0x11, 0x22,
|
||||
0x10, 0x11, 0x1e, 0x30, 0x11, 0x12, 0x21, 0x11, 0x02, 0xe3, 0x01, 0x11,
|
||||
0x08, 0xee, 0x00, 0x0e, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02, 0xee, 0x00,
|
||||
0x00, 0x00, 0x00, 0x38, 0xee, 0x20, 0x11, 0x1e, 0xe0, 0x11, 0x03, 0xe2,
|
||||
0x11, 0x11, 0x00, 0x01, 0x02, 0xee, 0x21, 0x11, 0x10, 0x00, 0x00, 0x1e,
|
||||
0xe1, 0x11, 0x02, 0xe3, 0x01, 0x10, 0xee, 0x01, 0x08, 0x11, 0x00, 0x08,
|
||||
0x12, 0xee, 0xe3, 0x21, 0x08, 0x11, 0x02, 0x10, 0x02, 0x2e, 0x1c, 0xee,
|
||||
0x00, 0x76, 0xe2, 0x01, 0x11, 0x10, 0x01, 0x02, 0x3e, 0x11, 0x11, 0x11,
|
||||
0x01, 0x10, 0x0e, 0xe1, 0x11, 0x11, 0x10, 0x11, 0x00, 0xee, 0x10, 0x00,
|
||||
0x01, 0x11, 0x10, 0x1e, 0xe0, 0x11, 0x11, 0x10, 0x11, 0x01, 0xee, 0x01,
|
||||
0x11, 0x11, 0x01, 0x10, 0x1e, 0x30, 0x11, 0x11, 0x00, 0x10, 0x02, 0xe3,
|
||||
0x01, 0x11, 0x10, 0x00, 0x00, 0x2e, 0x30, 0x11, 0x0e, 0xe1, 0x11, 0x02,
|
||||
0xee, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xee, 0x20, 0x00, 0x1e, 0xe1, 0x00,
|
||||
0x03, 0xee, 0x20, 0x00, 0x00, 0x00, 0x1e, 0xee, 0xe2, 0x00, 0x08, 0x00,
|
||||
0x00, 0x12, 0x0e, 0xe2, 0x00, 0x02, 0xe3, 0x10, 0x00, 0xee, 0x10, 0x00,
|
||||
0x08, 0x00, 0x00, 0x08, 0x02, 0xee, 0xee, 0x30, 0x0a, 0x00, 0x02, 0x2e,
|
||||
0x1c, 0xee, 0x02, 0xe2, 0x08, 0x00, 0x00, 0x12, 0x03, 0xee, 0xe2, 0x00,
|
||||
0x00, 0x00, 0x01, 0xee, 0xe2, 0x00, 0x08, 0x00, 0x00, 0x06, 0x1e, 0xee,
|
||||
0x20, 0x00, 0x08, 0x00, 0x00, 0x1e, 0x0e, 0xee, 0x10, 0x00, 0x00, 0x00,
|
||||
0x2e, 0xee, 0x10, 0x00, 0x00, 0x00, 0x02, 0xee, 0xe3, 0x00, 0x08, 0x00,
|
||||
0x00, 0x06, 0x2e, 0xee, 0x30, 0x00, 0x08, 0x00, 0x00, 0x10, 0x2e, 0x31,
|
||||
0x00, 0x0e, 0xe2, 0x00, 0x02, 0xee, 0x00, 0x00, 0xe6, 0xee, 0x00, 0x00,
|
||||
0xe6, 0xee, 0x00, 0x00, 0xe6, 0xee, 0x00, 0x00, 0xe6, 0xee, 0x00, 0x01};
|
||||
unsigned int splash_bmp_len = 3828;
|
||||
0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33,
|
||||
0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0x00, 0x08,
|
||||
0x33, 0x44, 0x44, 0x47, 0x0a, 0x33, 0x00, 0x06, 0xd5, 0x44, 0x7d, 0x00,
|
||||
0x0a, 0x33, 0x00, 0x0a, 0x44, 0x44, 0x48, 0x33, 0x3a, 0x00, 0x06, 0x44,
|
||||
0x02, 0xd3, 0x12, 0x33, 0x00, 0x08, 0xa4, 0x44, 0x45, 0x9d, 0x08, 0x33,
|
||||
0x00, 0x08, 0xc4, 0x44, 0x45, 0xc3, 0x10, 0x33, 0x00, 0x08, 0x34, 0x44,
|
||||
0x44, 0x6d, 0x16, 0x33, 0x00, 0x08, 0x34, 0x44, 0x44, 0x6d, 0x08, 0x33,
|
||||
0x02, 0xd5, 0x1a, 0x44, 0x00, 0x0c, 0x45, 0xc3, 0x33, 0x44, 0x44, 0x47,
|
||||
0x0a, 0x33, 0x00, 0x06, 0xd5, 0x44, 0x7d, 0x00, 0x0a, 0x33, 0x00, 0x08,
|
||||
0x44, 0x44, 0x48, 0x33, 0x00, 0x00, 0x00, 0x0a, 0x33, 0x49, 0x99, 0x95,
|
||||
0xd3, 0x00, 0x06, 0x33, 0x00, 0x0a, 0xd4, 0x46, 0x89, 0x98, 0xb3, 0x00,
|
||||
0x08, 0x33, 0x00, 0x12, 0x49, 0x99, 0x94, 0x33, 0x3d, 0x79, 0x99, 0x99,
|
||||
0x73, 0x00, 0x10, 0x33, 0x00, 0x0a, 0x3d, 0x47, 0x99, 0x95, 0xa3, 0x00,
|
||||
0x08, 0x33, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08,
|
||||
0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c,
|
||||
0x06, 0x33, 0x00, 0x06, 0xb4, 0x56, 0x89, 0x00, 0x18, 0x99, 0x00, 0x0e,
|
||||
0x97, 0xa3, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x00, 0x06, 0x33, 0x00, 0x0a,
|
||||
0xd4, 0x46, 0x89, 0x98, 0xb3, 0x00, 0x08, 0x33, 0x00, 0x08, 0x49, 0x99,
|
||||
0x94, 0x33, 0x00, 0x00, 0x00, 0x0a, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x00,
|
||||
0x06, 0x33, 0x02, 0x55, 0x06, 0x99, 0x02, 0x9b, 0x08, 0x33, 0x00, 0x12,
|
||||
0x49, 0x99, 0x94, 0x33, 0x33, 0xb9, 0x99, 0x99, 0x8d, 0x00, 0x10, 0x33,
|
||||
0x00, 0x0a, 0x37, 0x69, 0x99, 0x74, 0xd3, 0x00, 0x08, 0x33, 0x00, 0x08,
|
||||
0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c,
|
||||
0x16, 0x33, 0x00, 0x10, 0x34, 0x99, 0x99, 0x7c, 0x33, 0x33, 0x3a, 0x47,
|
||||
0x1c, 0x99, 0x00, 0x0e, 0x97, 0xa3, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x00,
|
||||
0x06, 0x33, 0x02, 0x55, 0x06, 0x99, 0x02, 0x9b, 0x08, 0x33, 0x00, 0x08,
|
||||
0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x12, 0x33, 0x49, 0x99, 0x95,
|
||||
0xd3, 0x33, 0x33, 0x3a, 0x48, 0x00, 0x06, 0x99, 0x02, 0x98, 0x02, 0xd3,
|
||||
0x06, 0x33, 0x00, 0x12, 0x49, 0x99, 0x94, 0x33, 0x33, 0xd7, 0x99, 0x99,
|
||||
0x98, 0x00, 0x10, 0x33, 0x00, 0x08, 0xd4, 0x89, 0x99, 0x5a, 0x0a, 0x33,
|
||||
0x00, 0x08, 0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08, 0x34, 0x99,
|
||||
0x99, 0x7c, 0x16, 0x33, 0x00, 0x10, 0x34, 0x99, 0x99, 0x7c, 0x33, 0x33,
|
||||
0xb4, 0x79, 0x1c, 0x99, 0x00, 0x16, 0x97, 0xa3, 0x33, 0x49, 0x99, 0x95,
|
||||
0xd3, 0x33, 0x33, 0x3a, 0x48, 0x00, 0x06, 0x99, 0x02, 0x98, 0x02, 0xd3,
|
||||
0x06, 0x33, 0x00, 0x08, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x12,
|
||||
0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x33, 0xd4, 0x79, 0x00, 0x08, 0x99,
|
||||
0x02, 0x73, 0x06, 0x33, 0x00, 0x0c, 0x49, 0x99, 0x94, 0x33, 0x33, 0x3b,
|
||||
0x06, 0x99, 0x02, 0xc3, 0x0e, 0x33, 0x00, 0x08, 0x56, 0x99, 0x97, 0x4d,
|
||||
0x0a, 0x33, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08,
|
||||
0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c,
|
||||
0x33, 0x3d, 0x47, 0x00, 0x1e, 0x99, 0x00, 0x16, 0x97, 0xa3, 0x33, 0x49,
|
||||
0x99, 0x95, 0xd3, 0x33, 0x33, 0xd4, 0x79, 0x00, 0x08, 0x99, 0x02, 0x73,
|
||||
0x06, 0x33, 0x00, 0x08, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x10,
|
||||
0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x33, 0xa5, 0x0a, 0x99, 0x02, 0x8d,
|
||||
0x06, 0x33, 0x00, 0x14, 0x49, 0x99, 0x94, 0x33, 0x33, 0x3d, 0x79, 0x99,
|
||||
0x99, 0x73, 0x0c, 0x33, 0x00, 0x0a, 0x3c, 0x48, 0x99, 0x95, 0xa3, 0x00,
|
||||
0x0a, 0x33, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08,
|
||||
0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c,
|
||||
0x33, 0x37, 0x69, 0x00, 0x1e, 0x99, 0x00, 0x14, 0x97, 0xa3, 0x33, 0x49,
|
||||
0x99, 0x95, 0xd3, 0x33, 0x33, 0xa5, 0x0a, 0x99, 0x02, 0x8d, 0x06, 0x33,
|
||||
0x00, 0x08, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x1c, 0x33, 0x49,
|
||||
0x99, 0x95, 0xd3, 0x33, 0x3d, 0x47, 0x99, 0x97, 0x89, 0x99, 0x99, 0x97,
|
||||
0x06, 0x33, 0x00, 0x06, 0x49, 0x99, 0x94, 0x00, 0x06, 0x33, 0x00, 0x08,
|
||||
0xb9, 0x99, 0x99, 0x9d, 0x0c, 0x33, 0x00, 0x0a, 0x34, 0x69, 0x99, 0x74,
|
||||
0xd3, 0x00, 0x0a, 0x33, 0x00, 0x08, 0xc7, 0x99, 0x98, 0xa3, 0x10, 0x33,
|
||||
0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x12, 0x34, 0x99,
|
||||
0x99, 0x7c, 0x33, 0x34, 0x89, 0x99, 0x64, 0x00, 0x1c, 0x44, 0x00, 0x1e,
|
||||
0xa3, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x3d, 0x47, 0x99, 0x97, 0x89,
|
||||
0x99, 0x99, 0x97, 0x00, 0x06, 0x33, 0x00, 0x08, 0x49, 0x99, 0x94, 0x33,
|
||||
0x00, 0x00, 0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x3c, 0x59,
|
||||
0x99, 0x95, 0xbc, 0x99, 0x99, 0x98, 0xd3, 0x33, 0x33, 0x49, 0x99, 0x94,
|
||||
0x06, 0x33, 0x02, 0xd7, 0x06, 0x99, 0x02, 0x74, 0x0c, 0x44, 0x00, 0x06,
|
||||
0x99, 0x99, 0x4b, 0x00, 0x0c, 0x33, 0x00, 0x08, 0xb7, 0x99, 0x99, 0xa3,
|
||||
0x10, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x12,
|
||||
0x34, 0x99, 0x99, 0x7c, 0x33, 0xd5, 0x99, 0x99, 0x6d, 0x00, 0x20, 0x33,
|
||||
0x00, 0x28, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x3c, 0x59, 0x99, 0x95, 0xbc,
|
||||
0x99, 0x99, 0x98, 0xd3, 0x33, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00,
|
||||
0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x34, 0x79, 0x99, 0x84,
|
||||
0xdd, 0x89, 0x99, 0x99, 0x83, 0x33, 0x33, 0x49, 0x99, 0x94, 0x06, 0x33,
|
||||
0x02, 0x3b, 0x16, 0x99, 0x02, 0x97, 0x02, 0x43, 0x0a, 0x33, 0x00, 0x0a,
|
||||
0x3d, 0x47, 0x99, 0x99, 0x9d, 0x00, 0x10, 0x33, 0x00, 0x08, 0x34, 0x99,
|
||||
0x99, 0x9d, 0x16, 0x33, 0x00, 0x12, 0x34, 0x99, 0x99, 0x7c, 0x33, 0xd6,
|
||||
0x99, 0x99, 0x6d, 0x00, 0x20, 0x33, 0x00, 0x28, 0x49, 0x99, 0x95, 0xd3,
|
||||
0x33, 0x34, 0x79, 0x99, 0x84, 0xdd, 0x89, 0x99, 0x99, 0x83, 0x33, 0x33,
|
||||
0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x28, 0x33, 0x49, 0x99, 0x95,
|
||||
0xd3, 0x33, 0xc4, 0x99, 0x99, 0x67, 0x33, 0x79, 0x99, 0x99, 0x8d, 0x33,
|
||||
0x33, 0x49, 0x99, 0x94, 0x06, 0x33, 0x02, 0x3d, 0x02, 0x79, 0x14, 0x99,
|
||||
0x02, 0x94, 0x02, 0xc3, 0x0a, 0x33, 0x00, 0x0a, 0x35, 0x59, 0x99, 0x99,
|
||||
0x98, 0x00, 0x10, 0x33, 0x02, 0x34, 0x06, 0x99, 0x02, 0x74, 0x16, 0x44,
|
||||
0x00, 0x10, 0x99, 0x99, 0x7c, 0x33, 0xd6, 0x99, 0x99, 0x9d, 0x20, 0x33,
|
||||
0x00, 0x28, 0x49, 0x99, 0x95, 0xd3, 0x33, 0xc4, 0x99, 0x99, 0x67, 0x33,
|
||||
0x79, 0x99, 0x99, 0x8d, 0x33, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00,
|
||||
0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x57, 0x99, 0x99, 0x4d,
|
||||
0x33, 0xd8, 0x99, 0x99, 0x98, 0x33, 0x33, 0x49, 0x99, 0x94, 0x08, 0x33,
|
||||
0x02, 0xc9, 0x14, 0x99, 0x02, 0x74, 0x0c, 0x33, 0x02, 0x84, 0x02, 0x89,
|
||||
0x06, 0x99, 0x02, 0xa3, 0x0e, 0x33, 0x02, 0x34, 0x22, 0x99, 0x00, 0x06,
|
||||
0x7c, 0x33, 0xd6, 0x00, 0x06, 0x99, 0x02, 0x64, 0x18, 0x44, 0x00, 0x2e,
|
||||
0x45, 0xc3, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x57, 0x99, 0x99, 0x4d,
|
||||
0x33, 0xd8, 0x99, 0x99, 0x98, 0x33, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00,
|
||||
0x00, 0x00, 0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x3d, 0x48, 0x99,
|
||||
0x97, 0x43, 0x33, 0x37, 0x99, 0x99, 0x97, 0xd3, 0x33, 0x49, 0x99, 0x94,
|
||||
0x08, 0x33, 0x02, 0x37, 0x14, 0x99, 0x02, 0x4c, 0x0a, 0x33, 0x02, 0x3b,
|
||||
0x02, 0x48, 0x08, 0x99, 0x02, 0x9b, 0x0e, 0x33, 0x02, 0x34, 0x22, 0x99,
|
||||
0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x2e, 0x97, 0xa3,
|
||||
0x33, 0x49, 0x99, 0x95, 0xd3, 0x3d, 0x48, 0x99, 0x97, 0x43, 0x33, 0x37,
|
||||
0x99, 0x99, 0x97, 0xd3, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00,
|
||||
0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x35, 0x69, 0x99, 0x95, 0xc3,
|
||||
0x33, 0x3c, 0x89, 0x99, 0x99, 0xb3, 0x33, 0x49, 0x99, 0x94, 0x08, 0x33,
|
||||
0x02, 0x3c, 0x12, 0x99, 0x02, 0x97, 0x02, 0x43, 0x0a, 0x33, 0x02, 0xd4,
|
||||
0x02, 0x79, 0x0a, 0x99, 0x02, 0xd3, 0x0c, 0x33, 0x02, 0x34, 0x22, 0x99,
|
||||
0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x2e, 0x97, 0xa3,
|
||||
0x33, 0x49, 0x99, 0x95, 0xd3, 0x35, 0x69, 0x99, 0x95, 0xc3, 0x33, 0x3c,
|
||||
0x89, 0x99, 0x99, 0xb3, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00,
|
||||
0x00, 0x12, 0x33, 0x49, 0x99, 0x95, 0xd3, 0xd4, 0x89, 0x99, 0x74, 0x00,
|
||||
0x06, 0x33, 0x00, 0x10, 0x79, 0x99, 0x99, 0x7d, 0x33, 0x49, 0x99, 0x94,
|
||||
0x0a, 0x33, 0x00, 0x16, 0x79, 0x99, 0x99, 0x64, 0x44, 0x44, 0x89, 0x99,
|
||||
0x99, 0x94, 0xc3, 0x00, 0x08, 0x33, 0x00, 0x0a, 0x3d, 0x46, 0x99, 0x98,
|
||||
0x59, 0x00, 0x06, 0x99, 0x02, 0x8d, 0x0c, 0x33, 0x02, 0x34, 0x22, 0x99,
|
||||
0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x16, 0x97, 0xa3,
|
||||
0x33, 0x49, 0x99, 0x95, 0xd3, 0xd4, 0x89, 0x99, 0x74, 0x00, 0x06, 0x33,
|
||||
0x00, 0x12, 0x79, 0x99, 0x99, 0x7d, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00,
|
||||
0x00, 0x00, 0x00, 0x12, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x76, 0x99, 0x99,
|
||||
0x6a, 0x00, 0x06, 0x33, 0x00, 0x10, 0xa9, 0x99, 0x99, 0x9b, 0x33, 0x49,
|
||||
0x99, 0x94, 0x0a, 0x33, 0x00, 0x14, 0xc9, 0x99, 0x99, 0x9c, 0x33, 0x33,
|
||||
0x3b, 0x99, 0x99, 0x74, 0x0a, 0x33, 0x00, 0x0a, 0x35, 0x59, 0x99, 0x95,
|
||||
0x7d, 0x00, 0x06, 0x99, 0x02, 0x9a, 0x0c, 0x33, 0x02, 0x34, 0x22, 0x99,
|
||||
0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x16, 0x97, 0xa3,
|
||||
0x33, 0x49, 0x99, 0x95, 0xd3, 0x76, 0x99, 0x99, 0x6a, 0x00, 0x06, 0x33,
|
||||
0x00, 0x12, 0xa9, 0x99, 0x99, 0x9b, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00,
|
||||
0x00, 0x00, 0x00, 0x12, 0x33, 0x49, 0x99, 0x95, 0x3d, 0x48, 0x99, 0x98,
|
||||
0x4d, 0x00, 0x06, 0x33, 0x00, 0x10, 0xd7, 0x99, 0x99, 0x97, 0xd3, 0x49,
|
||||
0x99, 0x94, 0x0a, 0x33, 0x00, 0x14, 0x37, 0x99, 0x99, 0x97, 0x33, 0x33,
|
||||
0xc4, 0x89, 0x99, 0x4c, 0x0a, 0x33, 0x00, 0x0c, 0x84, 0x89, 0x99, 0x64,
|
||||
0x33, 0xd9, 0x06, 0x99, 0x02, 0xa3, 0x0a, 0x33, 0x00, 0x08, 0x34, 0x99,
|
||||
0x99, 0x64, 0x16, 0x44, 0x06, 0x99, 0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00,
|
||||
0x20, 0x99, 0x00, 0x16, 0x97, 0xa3, 0x33, 0x49, 0x99, 0x95, 0x3d, 0x48,
|
||||
0x99, 0x98, 0x4d, 0x00, 0x06, 0x33, 0x00, 0x12, 0xd7, 0x99, 0x99, 0x97,
|
||||
0xd3, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x00, 0x12, 0x33, 0x49,
|
||||
0x99, 0x96, 0x3b, 0x69, 0x99, 0x96, 0x53, 0x00, 0x06, 0x33, 0x02, 0x38,
|
||||
0x06, 0x99, 0x00, 0x08, 0xc3, 0x49, 0x99, 0x94, 0x0a, 0x33, 0x02, 0x3c,
|
||||
0x06, 0x99, 0x00, 0x0c, 0xb3, 0x33, 0x46, 0x99, 0x96, 0x43, 0x08, 0x33,
|
||||
0x00, 0x0e, 0x3b, 0x48, 0x99, 0x97, 0x4d, 0x33, 0x3d, 0x00, 0x06, 0x99,
|
||||
0x02, 0x9c, 0x0a, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0x33,
|
||||
0x00, 0x12, 0x39, 0x99, 0x99, 0x7c, 0x33, 0xd6, 0x99, 0x99, 0x54, 0x00,
|
||||
0x1c, 0x44, 0x00, 0x14, 0xa3, 0x33, 0x49, 0x99, 0x96, 0x3b, 0x69, 0x99,
|
||||
0x96, 0x53, 0x06, 0x33, 0x02, 0x38, 0x06, 0x99, 0x00, 0x0a, 0xc3, 0x49,
|
||||
0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x00, 0x12, 0x33, 0x49, 0x99, 0x98,
|
||||
0xd5, 0x79, 0x99, 0x94, 0xd3, 0x00, 0x06, 0x33, 0x00, 0x10, 0x3d, 0x89,
|
||||
0x99, 0x99, 0x73, 0x49, 0x99, 0x94, 0x0c, 0x33, 0x00, 0x12, 0x79, 0x99,
|
||||
0x99, 0x8d, 0x3a, 0x59, 0x99, 0x84, 0xd3, 0x00, 0x08, 0x33, 0x00, 0x10,
|
||||
0xd4, 0x79, 0x99, 0x84, 0xb3, 0x33, 0x33, 0xb9, 0x06, 0x99, 0x02, 0xd3,
|
||||
0x08, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0x33, 0x00, 0x12,
|
||||
0x34, 0x99, 0x99, 0x7c, 0x33, 0xd6, 0x99, 0x99, 0x5d, 0x00, 0x20, 0x33,
|
||||
0x00, 0x10, 0x49, 0x99, 0x98, 0xd5, 0x79, 0x99, 0x94, 0xd3, 0x06, 0x33,
|
||||
0x00, 0x12, 0x3d, 0x89, 0x99, 0x99, 0x73, 0x49, 0x99, 0x94, 0x33, 0x00,
|
||||
0x00, 0x00, 0x00, 0x10, 0x33, 0x49, 0x99, 0x99, 0xa6, 0x99, 0x99, 0x74,
|
||||
0x0a, 0x33, 0x00, 0x0e, 0x79, 0x99, 0x99, 0x9c, 0x59, 0x99, 0x94, 0x00,
|
||||
0x0c, 0x33, 0x00, 0x10, 0xc9, 0x99, 0x99, 0x9a, 0xd4, 0x79, 0x99, 0x65,
|
||||
0x08, 0x33, 0x00, 0x0a, 0x3d, 0x46, 0x99, 0x98, 0x48, 0x00, 0x06, 0x33,
|
||||
0x02, 0x3a, 0x06, 0x99, 0x02, 0x83, 0x08, 0x33, 0x00, 0x08, 0x34, 0x99,
|
||||
0x99, 0x6d, 0x16, 0x33, 0x00, 0x12, 0x34, 0x99, 0x99, 0x7c, 0x33, 0xd6,
|
||||
0x99, 0x99, 0x93, 0x00, 0x20, 0x33, 0x00, 0x0e, 0x49, 0x99, 0x99, 0xa6,
|
||||
0x99, 0x99, 0x74, 0x00, 0x0a, 0x33, 0x00, 0x10, 0x79, 0x99, 0x99, 0x9c,
|
||||
0x59, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x10, 0x33, 0x49, 0x99, 0x99,
|
||||
0x98, 0x99, 0x99, 0x5c, 0x0a, 0x33, 0x02, 0xd8, 0x06, 0x99, 0x00, 0x06,
|
||||
0x79, 0x99, 0x84, 0x00, 0x0c, 0x33, 0x02, 0x37, 0x06, 0x99, 0x00, 0x08,
|
||||
0x86, 0x99, 0x98, 0x4d, 0x08, 0x33, 0x00, 0x0a, 0x35, 0x59, 0x99, 0x95,
|
||||
0x53, 0x00, 0x08, 0x33, 0x00, 0x08, 0x89, 0x99, 0x99, 0x9a, 0x08, 0x33,
|
||||
0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0x33, 0x00, 0x0c, 0x34, 0x99,
|
||||
0x99, 0x7c, 0x33, 0x36, 0x06, 0x99, 0x02, 0x54, 0x18, 0x44, 0x00, 0x14,
|
||||
0x45, 0xc3, 0x33, 0x49, 0x99, 0x99, 0x98, 0x99, 0x99, 0x5c, 0x0a, 0x33,
|
||||
0x02, 0xd8, 0x06, 0x99, 0x00, 0x08, 0x79, 0x99, 0x84, 0x33, 0x00, 0x00,
|
||||
0x02, 0x33, 0x02, 0x59, 0x08, 0x99, 0x02, 0x97, 0x02, 0x4d, 0x0a, 0x33,
|
||||
0x02, 0x36, 0x0a, 0x99, 0x02, 0x75, 0x0c, 0x33, 0x02, 0x3c, 0x0a, 0x99,
|
||||
0x02, 0x96, 0x02, 0x53, 0x08, 0x33, 0x00, 0x0a, 0x84, 0x89, 0x99, 0x64,
|
||||
0xd3, 0x00, 0x08, 0x33, 0x02, 0xd9, 0x06, 0x99, 0x02, 0xb3, 0x06, 0x33,
|
||||
0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0x33, 0x00, 0x0c, 0x34, 0x99,
|
||||
0x99, 0x7c, 0x33, 0x36, 0x20, 0x99, 0x00, 0x08, 0x97, 0xa3, 0x33, 0x59,
|
||||
0x08, 0x99, 0x02, 0x97, 0x02, 0x4d, 0x0a, 0x33, 0x02, 0x36, 0x0a, 0x99,
|
||||
0x02, 0x75, 0x02, 0x33, 0x00, 0x00, 0x02, 0x33, 0x02, 0xa8, 0x08, 0x99,
|
||||
0x02, 0x95, 0x02, 0xa3, 0x0a, 0x33, 0x02, 0x3c, 0x0a, 0x99, 0x02, 0x5b,
|
||||
0x0e, 0x33, 0x02, 0x89, 0x08, 0x99, 0x02, 0x84, 0x02, 0xd3, 0x06, 0x33,
|
||||
0x00, 0x0a, 0x3b, 0x48, 0x99, 0x97, 0x4c, 0x00, 0x0a, 0x33, 0x02, 0x3d,
|
||||
0x06, 0x99, 0x02, 0x9d, 0x06, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x6d,
|
||||
0x16, 0x33, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c, 0x33, 0x3d, 0x89, 0x00,
|
||||
0x1e, 0x99, 0x00, 0x08, 0x97, 0xa3, 0x33, 0xa8, 0x08, 0x99, 0x02, 0x95,
|
||||
0x02, 0xa3, 0x0a, 0x33, 0x02, 0x3c, 0x0a, 0x99, 0x02, 0x5b, 0x02, 0x33,
|
||||
0x00, 0x00, 0x02, 0x33, 0x02, 0xd7, 0x08, 0x99, 0x02, 0x64, 0x0e, 0x33,
|
||||
0x02, 0x79, 0x06, 0x99, 0x02, 0x96, 0x02, 0x4d, 0x0e, 0x33, 0x02, 0xd8,
|
||||
0x06, 0x99, 0x02, 0x98, 0x02, 0x48, 0x08, 0x33, 0x00, 0x0a, 0xd4, 0x79,
|
||||
0x99, 0x84, 0xb3, 0x00, 0x0c, 0x33, 0x00, 0x16, 0xb9, 0x99, 0x99, 0x98,
|
||||
0xd3, 0x33, 0x33, 0x34, 0x99, 0x99, 0x6d, 0x00, 0x16, 0x33, 0x00, 0x0c,
|
||||
0x34, 0x99, 0x99, 0x7c, 0x33, 0x33, 0x20, 0x99, 0x00, 0x08, 0x97, 0xa3,
|
||||
0x33, 0xd7, 0x08, 0x99, 0x02, 0x64, 0x0e, 0x33, 0x02, 0x79, 0x06, 0x99,
|
||||
0x00, 0x06, 0x96, 0x4d, 0x33, 0x00, 0x00, 0x00, 0x02, 0x33, 0x02, 0x3c,
|
||||
0x06, 0x99, 0x02, 0x96, 0x02, 0x4d, 0x0e, 0x33, 0x02, 0xd9, 0x06, 0x99,
|
||||
0x02, 0x74, 0x02, 0xc3, 0x0e, 0x33, 0x02, 0x3d, 0x06, 0x99, 0x02, 0x85,
|
||||
0x02, 0x53, 0x06, 0x33, 0x00, 0x0a, 0x3d, 0x46, 0x99, 0x99, 0x57, 0x00,
|
||||
0x0e, 0x33, 0x02, 0x39, 0x06, 0x99, 0x00, 0x0e, 0xa3, 0x33, 0x33, 0x34,
|
||||
0x99, 0x99, 0x6d, 0x00, 0x16, 0x33, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c,
|
||||
0x33, 0x33, 0x3a, 0x00, 0x1e, 0x99, 0x00, 0x08, 0x97, 0xa3, 0x33, 0x3c,
|
||||
0x06, 0x99, 0x02, 0x96, 0x02, 0x4d, 0x0e, 0x33, 0x02, 0xd9, 0x06, 0x99,
|
||||
0x00, 0x06, 0x74, 0xc3, 0x33, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x33, 0x33,
|
||||
0xc8, 0x99, 0x96, 0x44, 0xd3, 0x00, 0x0e, 0x33, 0x00, 0x0a, 0x3d, 0x79,
|
||||
0x99, 0x76, 0x4b, 0x00, 0x12, 0x33, 0x00, 0x0a, 0xc7, 0x99, 0x96, 0x45,
|
||||
0xd3, 0x00, 0x06, 0x33, 0x00, 0x0a, 0x35, 0x59, 0x99, 0x96, 0x43, 0x00,
|
||||
0x10, 0x33, 0x00, 0x14, 0x89, 0x99, 0x99, 0x9a, 0x33, 0x33, 0x34, 0x99,
|
||||
0x99, 0x6d, 0x16, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x06, 0x33,
|
||||
0x02, 0xa6, 0x1c, 0x99, 0x00, 0x12, 0x97, 0xa3, 0x33, 0x33, 0xc8, 0x99,
|
||||
0x96, 0x44, 0xd3, 0x00, 0x0e, 0x33, 0x00, 0x0e, 0x3d, 0x79, 0x99, 0x76,
|
||||
0x4b, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x33, 0x33, 0x3d, 0x84,
|
||||
0x44, 0xc3, 0x12, 0x33, 0x00, 0x08, 0xdc, 0x44, 0x4a, 0xd3, 0x12, 0x33,
|
||||
0x00, 0x08, 0x3d, 0xa4, 0x44, 0xd3, 0x08, 0x33, 0x02, 0xc8, 0x06, 0x44,
|
||||
0x02, 0xd3, 0x10, 0x33, 0x02, 0xd4, 0x06, 0x44, 0x00, 0x0c, 0xa3, 0x33,
|
||||
0x38, 0x44, 0x44, 0x4d, 0x16, 0x33, 0x00, 0x08, 0x38, 0x44, 0x44, 0x4c,
|
||||
0x06, 0x33, 0x02, 0x3d, 0x02, 0xc4, 0x1c, 0x44, 0x00, 0x0e, 0xa3, 0x33,
|
||||
0x33, 0x3d, 0x84, 0x44, 0xc3, 0x00, 0x12, 0x33, 0x00, 0x0c, 0xdc, 0x44,
|
||||
0x4a, 0xd3, 0x33, 0x33, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33,
|
||||
0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33,
|
||||
0x00, 0x00, 0x00, 0x1e, 0x33, 0x20, 0x00, 0x23, 0x30, 0x00, 0x13, 0x31,
|
||||
0x00, 0x02, 0x33, 0x00, 0x01, 0x33, 0x32, 0x00, 0x08, 0x00, 0x00, 0x26,
|
||||
0x13, 0x31, 0x00, 0x02, 0x33, 0x00, 0x01, 0x33, 0x00, 0x00, 0x13, 0x33,
|
||||
0x00, 0x00, 0x13, 0x32, 0x00, 0x00, 0x23, 0x00, 0x24, 0x33, 0x00, 0x06,
|
||||
0x32, 0x00, 0x02, 0x00, 0x08, 0x33, 0x02, 0x32, 0x06, 0x00, 0x00, 0x30,
|
||||
0x01, 0x33, 0x31, 0x00, 0x02, 0x33, 0x00, 0x01, 0x33, 0x33, 0x32, 0x00,
|
||||
0x02, 0x33, 0x33, 0x30, 0x00, 0x13, 0x32, 0x00, 0x02, 0x33, 0x00, 0x01,
|
||||
0x08, 0x33, 0x00, 0x10, 0x30, 0x00, 0x13, 0x31, 0x00, 0x02, 0x33, 0x30,
|
||||
0x08, 0x00, 0x00, 0x10, 0x23, 0x30, 0x00, 0x13, 0x31, 0x00, 0x02, 0x33,
|
||||
0x00, 0x00, 0x00, 0x20, 0x33, 0x20, 0x11, 0x13, 0x30, 0x11, 0x03, 0x31,
|
||||
0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x10, 0x10, 0x06, 0x00, 0x00, 0x26,
|
||||
0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01, 0x11, 0x03, 0x33,
|
||||
0x01, 0x11, 0x13, 0x32, 0x01, 0x11, 0x23, 0x00, 0x24, 0x33, 0x00, 0x06,
|
||||
0x32, 0x01, 0x11, 0x00, 0x08, 0x33, 0x00, 0x38, 0x10, 0x10, 0x00, 0x11,
|
||||
0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x33, 0x32, 0x01,
|
||||
0x11, 0x33, 0x33, 0x30, 0x11, 0x03, 0x32, 0x01, 0x11, 0x33, 0x01, 0x10,
|
||||
0x08, 0x33, 0x00, 0x12, 0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x00,
|
||||
0x10, 0x00, 0x06, 0x00, 0x00, 0x10, 0x23, 0x30, 0x11, 0x03, 0x31, 0x11,
|
||||
0x02, 0x33, 0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x13, 0x30, 0x11,
|
||||
0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x11, 0x10, 0x23, 0x00,
|
||||
0x06, 0x33, 0x00, 0x24, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01,
|
||||
0x11, 0x13, 0x33, 0x01, 0x10, 0x13, 0x32, 0x01, 0x11, 0x23, 0x24, 0x33,
|
||||
0x00, 0x06, 0x32, 0x01, 0x11, 0x00, 0x08, 0x33, 0x00, 0x38, 0x11, 0x10,
|
||||
0x23, 0x31, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x33,
|
||||
0x32, 0x01, 0x11, 0x33, 0x33, 0x30, 0x11, 0x03, 0x32, 0x01, 0x11, 0x33,
|
||||
0x01, 0x10, 0x08, 0x33, 0x00, 0x12, 0x30, 0x11, 0x03, 0x31, 0x11, 0x02,
|
||||
0x33, 0x01, 0x10, 0x00, 0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x03, 0x31,
|
||||
0x11, 0x02, 0x33, 0x00, 0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x23,
|
||||
0x30, 0x11, 0x03, 0x31, 0x11, 0x12, 0x33, 0x01, 0x10, 0x33, 0x11, 0x10,
|
||||
0x23, 0x00, 0x06, 0x33, 0x00, 0x28, 0x31, 0x11, 0x12, 0x33, 0x01, 0x00,
|
||||
0x33, 0x01, 0x11, 0x11, 0x00, 0x01, 0x12, 0x33, 0x32, 0x01, 0x11, 0x11,
|
||||
0x00, 0x23, 0x20, 0x33, 0x00, 0x06, 0x32, 0x01, 0x12, 0x00, 0x08, 0x33,
|
||||
0x00, 0x38, 0x11, 0x10, 0x23, 0x30, 0x11, 0x03, 0x31, 0x11, 0x12, 0x33,
|
||||
0x01, 0x00, 0x33, 0x33, 0x32, 0x01, 0x11, 0x33, 0x33, 0x30, 0x11, 0x13,
|
||||
0x32, 0x01, 0x11, 0x33, 0x01, 0x11, 0x08, 0x33, 0x00, 0x12, 0x30, 0x11,
|
||||
0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x00, 0x08, 0x33, 0x00, 0x0e,
|
||||
0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x00, 0x00, 0x00, 0x00, 0x22,
|
||||
0x33, 0x20, 0x11, 0x11, 0x00, 0x11, 0x03, 0x31, 0x11, 0x11, 0x00, 0x01,
|
||||
0x10, 0x33, 0x11, 0x10, 0x23, 0x00, 0x06, 0x33, 0x00, 0x10, 0x31, 0x11,
|
||||
0x11, 0x00, 0x01, 0x13, 0x33, 0x01, 0x08, 0x11, 0x00, 0x10, 0x12, 0x33,
|
||||
0x32, 0x01, 0x11, 0x11, 0x10, 0x23, 0x20, 0x33, 0x00, 0x60, 0x32, 0x01,
|
||||
0x11, 0x10, 0x00, 0x03, 0x33, 0x11, 0x10, 0x23, 0x30, 0x11, 0x03, 0x31,
|
||||
0x11, 0x12, 0x22, 0x01, 0x02, 0x33, 0x33, 0x32, 0x01, 0x11, 0x33, 0x33,
|
||||
0x30, 0x11, 0x12, 0x21, 0x01, 0x11, 0x33, 0x01, 0x11, 0x22, 0x22, 0x23,
|
||||
0x33, 0x30, 0x11, 0x12, 0x21, 0x11, 0x02, 0x33, 0x01, 0x10, 0x08, 0x33,
|
||||
0x00, 0x0e, 0x30, 0x11, 0x12, 0x21, 0x10, 0x13, 0x33, 0x00, 0x00, 0x00,
|
||||
0x00, 0x22, 0x33, 0x20, 0x11, 0x00, 0x11, 0x11, 0x03, 0x31, 0x11, 0x00,
|
||||
0x01, 0x11, 0x10, 0x33, 0x11, 0x10, 0x23, 0x00, 0x06, 0x33, 0x00, 0x28,
|
||||
0x31, 0x11, 0x00, 0x01, 0x11, 0x13, 0x33, 0x01, 0x11, 0x00, 0x01, 0x11,
|
||||
0x12, 0x33, 0x32, 0x01, 0x11, 0x00, 0x00, 0x23, 0x20, 0x33, 0x00, 0x60,
|
||||
0x32, 0x01, 0x10, 0x01, 0x11, 0x12, 0x33, 0x11, 0x10, 0x23, 0x30, 0x11,
|
||||
0x03, 0x31, 0x11, 0x10, 0x10, 0x11, 0x13, 0x33, 0x33, 0x32, 0x01, 0x11,
|
||||
0x33, 0x33, 0x30, 0x11, 0x10, 0x10, 0x11, 0x11, 0x33, 0x01, 0x11, 0x01,
|
||||
0x00, 0x01, 0x23, 0x30, 0x11, 0x00, 0x10, 0x11, 0x02, 0x33, 0x01, 0x10,
|
||||
0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x00, 0x10, 0x11, 0x23, 0x33, 0x00,
|
||||
0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x13, 0x31, 0x11, 0x03, 0x31,
|
||||
0x11, 0x02, 0x33, 0x11, 0x10, 0x33, 0x11, 0x10, 0x23, 0x00, 0x06, 0x33,
|
||||
0x00, 0x24, 0x31, 0x11, 0x02, 0x33, 0x11, 0x10, 0x33, 0x01, 0x11, 0x03,
|
||||
0x33, 0x11, 0x11, 0x13, 0x32, 0x01, 0x11, 0x23, 0x24, 0x33, 0x00, 0x60,
|
||||
0x32, 0x01, 0x11, 0x33, 0x11, 0x10, 0x33, 0x11, 0x10, 0x23, 0x30, 0x11,
|
||||
0x03, 0x31, 0x11, 0x01, 0x22, 0x11, 0x12, 0x33, 0x33, 0x32, 0x01, 0x11,
|
||||
0x33, 0x33, 0x30, 0x11, 0x02, 0x22, 0x11, 0x11, 0x33, 0x01, 0x10, 0x22,
|
||||
0x21, 0x11, 0x13, 0x30, 0x11, 0x02, 0x21, 0x11, 0x02, 0x33, 0x01, 0x10,
|
||||
0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x02, 0x21, 0x11, 0x23, 0x33, 0x00,
|
||||
0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x13, 0x30, 0x11, 0x03, 0x31,
|
||||
0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x11, 0x10, 0x23, 0x00, 0x06, 0x33,
|
||||
0x00, 0x24, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01, 0x11, 0x13,
|
||||
0x33, 0x01, 0x11, 0x13, 0x32, 0x01, 0x11, 0x23, 0x24, 0x33, 0x00, 0x60,
|
||||
0x32, 0x01, 0x11, 0x33, 0x01, 0x10, 0x33, 0x11, 0x11, 0x23, 0x30, 0x11,
|
||||
0x03, 0x31, 0x11, 0x12, 0x33, 0x11, 0x10, 0x33, 0x33, 0x32, 0x01, 0x11,
|
||||
0x33, 0x33, 0x30, 0x11, 0x13, 0x32, 0x11, 0x11, 0x33, 0x01, 0x11, 0x33,
|
||||
0x21, 0x11, 0x13, 0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10,
|
||||
0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x00,
|
||||
0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x13, 0x30, 0x11, 0x03, 0x31,
|
||||
0x11, 0x12, 0x33, 0x01, 0x00, 0x33, 0x11, 0x11, 0x23, 0x00, 0x06, 0x33,
|
||||
0x00, 0x2c, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01, 0x11, 0x11,
|
||||
0x00, 0x01, 0x10, 0x13, 0x32, 0x01, 0x11, 0x11, 0x00, 0x00, 0x01, 0x23,
|
||||
0x1c, 0x33, 0x00, 0x60, 0x32, 0x01, 0x12, 0x33, 0x01, 0x00, 0x33, 0x11,
|
||||
0x11, 0x22, 0x20, 0x11, 0x03, 0x31, 0x11, 0x12, 0x22, 0x01, 0x10, 0x33,
|
||||
0x33, 0x32, 0x01, 0x12, 0x33, 0x33, 0x30, 0x11, 0x12, 0x21, 0x01, 0x11,
|
||||
0x33, 0x01, 0x11, 0x22, 0x10, 0x11, 0x13, 0x30, 0x11, 0x12, 0x21, 0x11,
|
||||
0x02, 0x33, 0x01, 0x11, 0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x03, 0x31,
|
||||
0x11, 0x02, 0x33, 0x00, 0x00, 0x00, 0x00, 0x38, 0x33, 0x20, 0x11, 0x13,
|
||||
0x30, 0x11, 0x03, 0x32, 0x11, 0x11, 0x00, 0x01, 0x02, 0x33, 0x21, 0x11,
|
||||
0x10, 0x00, 0x00, 0x13, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01,
|
||||
0x08, 0x11, 0x00, 0x08, 0x12, 0x33, 0x33, 0x21, 0x08, 0x11, 0x02, 0x10,
|
||||
0x02, 0x23, 0x1c, 0x33, 0x00, 0x0e, 0x32, 0x01, 0x11, 0x10, 0x01, 0x02,
|
||||
0x33, 0x00, 0x06, 0x11, 0x00, 0x62, 0x01, 0x10, 0x03, 0x31, 0x11, 0x11,
|
||||
0x10, 0x11, 0x00, 0x33, 0x10, 0x00, 0x01, 0x11, 0x10, 0x13, 0x30, 0x11,
|
||||
0x11, 0x10, 0x11, 0x01, 0x33, 0x01, 0x11, 0x11, 0x01, 0x10, 0x13, 0x30,
|
||||
0x11, 0x11, 0x00, 0x10, 0x02, 0x33, 0x01, 0x11, 0x10, 0x00, 0x00, 0x23,
|
||||
0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x00, 0x00, 0x00, 0x00, 0x12,
|
||||
0x33, 0x20, 0x00, 0x13, 0x31, 0x00, 0x03, 0x33, 0x20, 0x00, 0x06, 0x00,
|
||||
0x00, 0x06, 0x13, 0x33, 0x32, 0x00, 0x08, 0x00, 0x00, 0x12, 0x03, 0x32,
|
||||
0x00, 0x02, 0x33, 0x10, 0x00, 0x33, 0x10, 0x00, 0x08, 0x00, 0x00, 0x08,
|
||||
0x02, 0x33, 0x33, 0x30, 0x0a, 0x00, 0x02, 0x23, 0x1c, 0x33, 0x02, 0x32,
|
||||
0x08, 0x00, 0x00, 0x06, 0x03, 0x33, 0x32, 0x00, 0x06, 0x00, 0x00, 0x06,
|
||||
0x01, 0x33, 0x32, 0x00, 0x08, 0x00, 0x00, 0x06, 0x13, 0x33, 0x20, 0x00,
|
||||
0x08, 0x00, 0x00, 0x06, 0x03, 0x33, 0x10, 0x00, 0x06, 0x00, 0x00, 0x06,
|
||||
0x23, 0x33, 0x10, 0x00, 0x06, 0x00, 0x00, 0x06, 0x02, 0x33, 0x33, 0x00,
|
||||
0x08, 0x00, 0x00, 0x06, 0x23, 0x33, 0x30, 0x00, 0x08, 0x00, 0x00, 0x10,
|
||||
0x23, 0x31, 0x00, 0x03, 0x32, 0x00, 0x02, 0x33, 0x00, 0x00, 0xe6, 0x33,
|
||||
0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33,
|
||||
0x00, 0x01};
|
||||
unsigned int splash_new__new_t_len = 3854;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "emu_cc1101.hpp"
|
||||
|
||||
namespace cc1101 {
|
||||
|
||||
void CC1101Emu::whitening_init() {
|
||||
whitening_pn = 0x1FF;
|
||||
}
|
||||
|
||||
// See TI app note DN509
|
||||
uint8_t CC1101Emu::whiten_byte(uint8_t byte) {
|
||||
uint_fast8_t new_bit;
|
||||
|
||||
byte ^= (whitening_pn & 0xFF);
|
||||
|
||||
for (size_t step = 0; step < 8; step++) {
|
||||
new_bit = (whitening_pn & 1) ^ ((whitening_pn >> 5) & 1);
|
||||
whitening_pn >>= 1;
|
||||
whitening_pn |= (new_bit << 8);
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
} /* namespace cc1101 */
|
||||
Vendored
+34
-47
@@ -20,45 +20,26 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "acars_app.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "file_path.hpp"
|
||||
#include "audio.hpp"
|
||||
|
||||
#include "acars_app.hpp"
|
||||
using namespace portapack;
|
||||
using namespace acars;
|
||||
|
||||
#include "string_format.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
void ACARSLogger::log_raw_data(const acars::Packet& packet, const uint32_t frequency) {
|
||||
(void)frequency;
|
||||
std::string entry{}; //= "Raw: F:" + to_string_dec_uint(frequency) + "Hz ";
|
||||
entry.reserve(256);
|
||||
namespace ui::external_app::acars_rx {
|
||||
|
||||
// Raw hex dump of all the bytes
|
||||
// for (size_t c = 0; c < packet.length(); c += 32)
|
||||
// entry += to_string_hex(packet.read(c, 32), 8) + " ";
|
||||
|
||||
for (size_t c = 0; c < 256; c += 32)
|
||||
entry += to_string_bin(packet.read(c, 32), 32);
|
||||
|
||||
log_file.write_entry(packet.received_at(), entry);
|
||||
void ACARSLogger::log_str(std::string msg) {
|
||||
log_file.write_entry(msg);
|
||||
}
|
||||
|
||||
/*void ACARSLogger::log_decoded(
|
||||
const acars::Packet& packet,
|
||||
const std::string text) {
|
||||
|
||||
log_file.write_entry(packet.timestamp(), text);
|
||||
}*/
|
||||
|
||||
namespace ui {
|
||||
|
||||
ACARSAppView::ACARSAppView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_acars);
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
add_children({&rssi,
|
||||
&channel,
|
||||
@@ -66,6 +47,7 @@ ACARSAppView::ACARSAppView(NavigationView& nav)
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_frequency,
|
||||
&field_volume,
|
||||
&check_log,
|
||||
&console});
|
||||
|
||||
@@ -79,6 +61,9 @@ ACARSAppView::ACARSAppView(NavigationView& nav)
|
||||
logger = std::make_unique<ACARSLogger>();
|
||||
if (logger)
|
||||
logger->append(logs_dir / u"ACARS.TXT");
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
}
|
||||
|
||||
ACARSAppView::~ACARSAppView() {
|
||||
@@ -90,29 +75,31 @@ void ACARSAppView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
void ACARSAppView::on_packet(const acars::Packet& packet) {
|
||||
void ACARSAppView::on_packet(const ACARSPacketMessage* packet) {
|
||||
std::string console_info;
|
||||
|
||||
/*if (!packet.is_valid()) {
|
||||
console_info = to_string_datetime(packet.received_at(), HMS);
|
||||
console_info += " INVALID";
|
||||
|
||||
console.writeln(console_info);
|
||||
} else {
|
||||
console_info = to_string_datetime(packet.received_at(), HMS);
|
||||
console_info += ":" + to_string_bin(packet.read(0, 32), 32);
|
||||
//console_info += " REG:" + packet.registration_number();
|
||||
|
||||
console.writeln(console_info);
|
||||
}*/
|
||||
|
||||
packet_counter++;
|
||||
if (packet_counter % 10 == 0)
|
||||
console.writeln("Block #" + to_string_dec_uint(packet_counter));
|
||||
|
||||
// Log raw data whatever it contains
|
||||
if (logger && logging)
|
||||
logger->log_raw_data(packet, receiver_model.target_frequency());
|
||||
if (packet->state == 255) {
|
||||
// got a packet, parse it, and display
|
||||
rtc::RTC datetime;
|
||||
rtc_time::now(datetime);
|
||||
// todo parity error recovery
|
||||
console_info = to_string_datetime(datetime, HMS);
|
||||
console_info += ": ";
|
||||
console_info += packet->message;
|
||||
console.writeln(console_info);
|
||||
// Log raw data whatever it contains
|
||||
if (logger && logging)
|
||||
logger->log_str(console_info);
|
||||
} else {
|
||||
// debug message arrived
|
||||
console_info = "State: ";
|
||||
console_info += to_string_dec_int(packet->state);
|
||||
console_info += " lastbyte: ";
|
||||
console_info += to_string_dec_uint(packet->message[0]);
|
||||
console.writeln(console_info);
|
||||
if (logger && logging)
|
||||
logger->log_str(console_info);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::acars_rx
|
||||
Vendored
+12
-14
@@ -31,23 +31,19 @@
|
||||
#include "ui_rssi.hpp"
|
||||
#include "log_file.hpp"
|
||||
|
||||
#include "acars_packet.hpp"
|
||||
namespace ui::external_app::acars_rx {
|
||||
|
||||
class ACARSLogger {
|
||||
public:
|
||||
Optional<File::Error> append(const std::filesystem::path& filename) {
|
||||
return log_file.append(filename);
|
||||
}
|
||||
|
||||
void log_raw_data(const acars::Packet& packet, const uint32_t frequency);
|
||||
// void log_decoded(const acars::Packet& packet, const std::string text);
|
||||
void log_str(std::string msg);
|
||||
|
||||
private:
|
||||
LogFile log_file{};
|
||||
};
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ACARSAppView : public View {
|
||||
public:
|
||||
ACARSAppView(NavigationView& nav);
|
||||
@@ -55,12 +51,12 @@ class ACARSAppView : public View {
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "ACARS (WIP)"; };
|
||||
std::string title() const override { return "ACARS"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{
|
||||
131550000 /* frequency */,
|
||||
131825000 /* frequency */,
|
||||
1750000 /* bandwidth */,
|
||||
2457600 /* sampling rate */
|
||||
};
|
||||
@@ -85,7 +81,7 @@ class ACARSAppView : public View {
|
||||
{0 * 8, 0 * 8},
|
||||
nav_};
|
||||
Checkbox check_log{
|
||||
{22 * 8, 21},
|
||||
{16 * 8, 1 * 16},
|
||||
3,
|
||||
"LOG",
|
||||
true};
|
||||
@@ -93,19 +89,21 @@ class ACARSAppView : public View {
|
||||
Console console{
|
||||
{0, 3 * 16, 240, 256}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 1 * 16}};
|
||||
|
||||
std::unique_ptr<ACARSLogger> logger{};
|
||||
|
||||
void on_packet(const acars::Packet& packet);
|
||||
void on_packet(const ACARSPacketMessage* packet);
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::ACARSPacket,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const ACARSPacketMessage*>(p);
|
||||
const acars::Packet packet{message->packet};
|
||||
this->on_packet(packet);
|
||||
this->on_packet(message);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::acars_rx
|
||||
|
||||
#endif /*__ACARS_APP_H__*/
|
||||
#endif /*__ACARS_APP_H__*/
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "acars_app.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::acars_rx {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<ACARSAppView>();
|
||||
}
|
||||
} // namespace ui::external_app::acars_rx
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_acars_rx.application_information"), used)) application_information_t _application_information_acars_rx = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::acars_rx::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "ACARS",
|
||||
/*.bitmap_data = */ {
|
||||
0x80,
|
||||
0x01,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xE0,
|
||||
0x07,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xE0,
|
||||
0x07,
|
||||
0xF0,
|
||||
0x0F,
|
||||
0xF8,
|
||||
0x1F,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::orange().v,
|
||||
/*.menu_location = */ app_location_t::RX,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_acars */ {'P', 'A', 'C', 'A'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
@@ -143,6 +143,10 @@ void AFSKRxView::on_data(uint32_t value, bool is_data) {
|
||||
}
|
||||
}
|
||||
|
||||
void AFSKRxView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
AFSKRxView::~AFSKRxView() {
|
||||
audio::output::stop();
|
||||
receiver_model.disable();
|
||||
|
||||
@@ -117,6 +117,15 @@ class AFSKRxView : public View {
|
||||
const auto message = static_cast<const AFSKDataMessage*>(p);
|
||||
this->on_data(message->value, message->is_data);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::afsk_rx
|
||||
|
||||
@@ -202,4 +202,8 @@ void AnalogTvView::update_modulation(const ReceiverModel::Mode modulation) {
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
void AnalogTvView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::analogtv
|
||||
|
||||
@@ -108,6 +108,15 @@ class AnalogTvView : public View {
|
||||
void set_options_widget(std::unique_ptr<Widget> new_widget);
|
||||
|
||||
void update_modulation(const ReceiverModel::Mode modulation);
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::analogtv
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ __attribute__((section(".external_app.app_blespam.application_information"), use
|
||||
/*.icon_color = */ ui::Color::yellow().v,
|
||||
/*.menu_location = */ app_location_t::TX,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'B', 'T', 'T'},
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_btle_tx */ {'P', 'B', 'T', 'T'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
|
||||
+23
@@ -88,6 +88,25 @@ set(EXTCPPSRC
|
||||
#adsbtx
|
||||
external/adsbtx/main.cpp
|
||||
external/adsbtx/ui_adsb_tx.cpp
|
||||
|
||||
#morse_tx
|
||||
external/morse_tx/main.cpp
|
||||
external/morse_tx/ui_morse.cpp
|
||||
|
||||
#sstvtx
|
||||
external/sstvtx/main.cpp
|
||||
external/sstvtx/ui_sstvtx.cpp
|
||||
|
||||
#random
|
||||
external/random_password/main.cpp
|
||||
external/random_password/ui_random_password.cpp
|
||||
external/random_password/sha512.cpp
|
||||
external/random_password/sha512.h
|
||||
|
||||
#acars
|
||||
external/acars_rx/main.cpp
|
||||
external/acars_rx/acars_app.cpp
|
||||
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -112,4 +131,8 @@ set(EXTAPPLIST
|
||||
tpmsrx
|
||||
protoview
|
||||
adsbtx
|
||||
morse_tx
|
||||
sstvtx
|
||||
random_password
|
||||
#acars_rx
|
||||
)
|
||||
|
||||
+31
@@ -44,6 +44,10 @@ MEMORY
|
||||
ram_external_app_tpmsrx(rwx) : org = 0xADC30000, len = 32k
|
||||
ram_external_app_protoview(rwx) : org = 0xADC40000, len = 32k
|
||||
ram_external_app_adsbtx(rwx) : org = 0xADC50000, len = 32k
|
||||
ram_external_app_morse_tx(rwx) : org = 0xADC60000, len = 32k
|
||||
ram_external_app_sstvtx(rwx) : org = 0xADC70000, len = 32k
|
||||
ram_external_app_random_password(rwx) : org = 0xADC80000, len = 32k
|
||||
ram_external_app_acars_rx(rwx) : org = 0xADC90000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -176,4 +180,31 @@ SECTIONS
|
||||
} > ram_external_app_adsbtx
|
||||
|
||||
|
||||
.external_app_morse_tx : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_morse_tx.application_information));
|
||||
*(*ui*external_app*morse_tx*);
|
||||
} > ram_external_app_morse_tx
|
||||
|
||||
.external_app_sstvtx : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_sstvtx.application_information));
|
||||
*(*ui*external_app*sstvtx*);
|
||||
} > ram_external_app_sstvtx
|
||||
|
||||
.external_app_random_password : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_random_password.application_information));
|
||||
*(*ui*external_app*random_password*);
|
||||
} > ram_external_app_random_password
|
||||
|
||||
.external_app_acars_rx : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_acars_rx.application_information));
|
||||
*(*ui*external_app*acars_rx*);
|
||||
} > ram_external_app_acars_rx
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+33
-4
@@ -22,6 +22,7 @@
|
||||
#include "rtc_time.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "i2cdevmanager.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace ui;
|
||||
@@ -29,7 +30,7 @@ using namespace ui;
|
||||
namespace ui::external_app::extsensors {
|
||||
|
||||
void ExtSensorsView::focus() {
|
||||
text_info.focus();
|
||||
console.focus();
|
||||
}
|
||||
|
||||
ExtSensorsView::ExtSensorsView(NavigationView& nav)
|
||||
@@ -39,10 +40,33 @@ ExtSensorsView::ExtSensorsView(NavigationView& nav)
|
||||
&text_gps,
|
||||
&text_orientation,
|
||||
&text_envl1,
|
||||
&text_envl2});
|
||||
&text_envl2,
|
||||
&text_envl3,
|
||||
&console});
|
||||
|
||||
prev_scan_int = i2cdev::I2CDevManager::get_autoscan_interval();
|
||||
refreshi2c();
|
||||
i2cdev::I2CDevManager::set_autoscan_interval(3); // scan each 3 sec for new i2c devices
|
||||
}
|
||||
|
||||
void ExtSensorsView::on_new_dev() {
|
||||
refreshi2c();
|
||||
}
|
||||
|
||||
void ExtSensorsView::refreshi2c() {
|
||||
console.clear(true);
|
||||
console.writeln("Found I2C devices:");
|
||||
auto addrlist = i2cdev::I2CDevManager::get_gev_list_by_addr();
|
||||
for (size_t i = 0; i < addrlist.size(); ++i) {
|
||||
console.write("0x");
|
||||
console.write(to_string_hex(addrlist[i]));
|
||||
console.write(", ");
|
||||
}
|
||||
if (addrlist.size() == 0) console.writeln("No I2C devs found.");
|
||||
}
|
||||
|
||||
ExtSensorsView::~ExtSensorsView() {
|
||||
i2cdev::I2CDevManager::set_autoscan_interval(prev_scan_int);
|
||||
}
|
||||
|
||||
void ExtSensorsView::on_any() {
|
||||
@@ -78,9 +102,14 @@ void ExtSensorsView::on_environment(const EnvironmentDataMessage* msg) {
|
||||
tmp += "C";
|
||||
tmp += "; H: " + to_string_decimal(msg->humidity, 1) + "%"; // humidity
|
||||
text_envl1.set(tmp);
|
||||
tmp = "P: " + to_string_decimal(msg->pressure, 1) + " hPa; L:"; // pressure
|
||||
tmp += to_string_dec_int(msg->light) + " LUX"; // light
|
||||
tmp = "P: " + to_string_decimal(msg->pressure, 1) + " hPa"; // pressure
|
||||
text_envl2.set(tmp);
|
||||
}
|
||||
|
||||
void ExtSensorsView::on_light(const LightDataMessage* msg) {
|
||||
on_any();
|
||||
std::string tmp = "L: " + to_string_dec_int(msg->light) + " LUX";
|
||||
text_envl3.set(tmp);
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::extsensors
|
||||
@@ -53,6 +53,7 @@ class ExtSensorsView : public View {
|
||||
NavigationView& nav_;
|
||||
|
||||
bool has_data = false;
|
||||
uint16_t prev_scan_int = 0;
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 3 * 16}, "GPS:", Theme::getInstance()->fg_light->foreground},
|
||||
@@ -64,9 +65,15 @@ class ExtSensorsView : public View {
|
||||
Text text_orientation{{5 * 8, 5 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_envl1{{5 * 8, 7 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_envl2{{1 * 8, 9 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_envl3{{1 * 8, 11 * 16, 24 * 8, 16}, "-"};
|
||||
Console console{
|
||||
{1, 13 * 16, screen_width - 1, screen_height - 13 * 16}};
|
||||
|
||||
void refreshi2c();
|
||||
void on_new_dev();
|
||||
void on_any();
|
||||
|
||||
void on_light(const LightDataMessage* msg);
|
||||
void on_gps(const GPSPosDataMessage* msg);
|
||||
void on_orientation(const OrientationDataMessage* msg);
|
||||
void on_environment(const EnvironmentDataMessage* msg);
|
||||
@@ -90,6 +97,20 @@ class ExtSensorsView : public View {
|
||||
const auto message = static_cast<const EnvironmentDataMessage*>(p);
|
||||
this->on_environment(message);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_light{
|
||||
Message::ID::LightData,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const LightDataMessage*>(p);
|
||||
this->on_light(message);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_dev{
|
||||
Message::ID::I2CDevListChanged,
|
||||
[this](Message* const p) {
|
||||
(void)p; // make compiler happy
|
||||
this->on_new_dev();
|
||||
}};
|
||||
};
|
||||
}; // namespace ui::external_app::extsensors
|
||||
|
||||
|
||||
@@ -103,4 +103,8 @@ void FoxhuntRxView::on_orientation(const OrientationDataMessage* msg) {
|
||||
geomap.update_my_orientation(msg->angle, true);
|
||||
}
|
||||
|
||||
void FoxhuntRxView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::foxhunt_rx
|
||||
|
||||
@@ -103,6 +103,14 @@ class FoxhuntRxView : public View {
|
||||
[this](const Message* const p) {
|
||||
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
|
||||
}};
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
|
||||
float my_lat = 200;
|
||||
float my_lon = 200;
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_morse.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::morse_tx {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<MorseView>();
|
||||
}
|
||||
} // namespace ui::external_app::morse_tx
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_morse_tx.application_information"), used)) application_information_t _application_information_morse_tx = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::morse_tx::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "Morse",
|
||||
/*.bitmap_data = */ {
|
||||
0x00,
|
||||
0x00,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xBB,
|
||||
0xD0,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0x0B,
|
||||
0xE1,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xEB,
|
||||
0xD0,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0x70,
|
||||
0x00,
|
||||
0x30,
|
||||
0x00,
|
||||
0x10,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::TX,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_tones */ {'P', 'T', 'O', 'N'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
Vendored
+4
-3
@@ -36,7 +36,7 @@ using namespace portapack;
|
||||
using namespace morse;
|
||||
using namespace hackrf::one;
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::morse_tx {
|
||||
|
||||
static WORKING_AREA(ookthread_wa, 256);
|
||||
|
||||
@@ -194,7 +194,8 @@ void MorseView::set_foxhunt(size_t i) {
|
||||
MorseView::MorseView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_tones);
|
||||
// baseband::run_image(portapack::spi_flash::image_tag_tones);
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
add_children({&labels,
|
||||
&checkbox_foxhunt,
|
||||
@@ -284,4 +285,4 @@ MorseView::MorseView(
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::morse_tx
|
||||
Vendored
+2
-2
@@ -39,7 +39,7 @@
|
||||
|
||||
using namespace morse;
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::morse_tx {
|
||||
|
||||
class MorseView : public View {
|
||||
public:
|
||||
@@ -179,6 +179,6 @@ class MorseView : public View {
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::morse_tx
|
||||
|
||||
#endif /*__MORSE_TX_H__*/
|
||||
@@ -125,6 +125,10 @@ void NRFRxView::on_data(uint32_t value, bool is_data) {
|
||||
}
|
||||
}
|
||||
|
||||
void NRFRxView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
NRFRxView::~NRFRxView() {
|
||||
audio::output::stop();
|
||||
receiver_model.disable();
|
||||
|
||||
@@ -89,6 +89,15 @@ class NRFRxView : public View {
|
||||
const auto message = static_cast<const AFSKDataMessage*>(p);
|
||||
this->on_data(message->value, message->is_data);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
};
|
||||
|
||||
} /* namespace ui::external_app::nrf_rx */
|
||||
|
||||
+54
-7
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2024 HTotoo, zxkmm
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -49,9 +48,12 @@ ProtoView::ProtoView(NavigationView& nav)
|
||||
&field_vga,
|
||||
&field_volume,
|
||||
&field_frequency,
|
||||
&labels,
|
||||
&label_zoom,
|
||||
&label_shift,
|
||||
&options_zoom,
|
||||
&number_shift,
|
||||
&button_reset,
|
||||
&button_pause,
|
||||
&waveform,
|
||||
&waveform2,
|
||||
&waveform3,
|
||||
@@ -63,9 +65,18 @@ ProtoView::ProtoView(NavigationView& nav)
|
||||
draw();
|
||||
draw2();
|
||||
};
|
||||
number_shift.on_change = [this](int32_t value) {
|
||||
waveform_shift = value;
|
||||
draw();
|
||||
draw2();
|
||||
};
|
||||
button_reset.on_select = [this](Button&) {
|
||||
reset();
|
||||
};
|
||||
button_pause.on_select = [this](Button&) {
|
||||
set_pause(!paused);
|
||||
};
|
||||
set_pause(false); // need to use this to default hide shift functionality
|
||||
baseband::set_subghzd_config(0, receiver_model.sampling_rate());
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
@@ -74,6 +85,9 @@ ProtoView::ProtoView(NavigationView& nav)
|
||||
|
||||
void ProtoView::reset() {
|
||||
cnt = 0;
|
||||
set_pause(false);
|
||||
number_shift.set_value(0);
|
||||
waveform_shift = 0;
|
||||
for (uint16_t i = 0; i < MAXSIGNALBUFFER; i++) time_buffer[i] = 0;
|
||||
needCntReset = false;
|
||||
draw();
|
||||
@@ -126,7 +140,18 @@ void ProtoView::draw() {
|
||||
drawcnt = 0;
|
||||
for (uint16_t i = 0; i < MAXDRAWCNT; i++) waveform_buffer[i] = 0; // reset
|
||||
|
||||
for (uint16_t i = 0; i < MAXSIGNALBUFFER; ++i) {
|
||||
// add empty data for padding (so you can shift left/negative)
|
||||
if (waveform_shift < 0) {
|
||||
for (int32_t i = 0; (i < -1 * waveform_shift) && drawcnt < MAXDRAWCNT; // this is for shift negative (move to right)
|
||||
++i) {
|
||||
waveform_buffer[drawcnt++] = 0;
|
||||
}
|
||||
}
|
||||
uint16_t skipped = 0;
|
||||
uint16_t to_skip = ((waveform_shift > 0) ? waveform_shift : 0); // when >0 it'll skip some to move left
|
||||
for (uint16_t i = 0;
|
||||
i < MAXSIGNALBUFFER && drawcnt < MAXDRAWCNT; // prevent out of ranging
|
||||
++i) {
|
||||
state = time_buffer[i] >= 0;
|
||||
int32_t timeabs = state ? time_buffer[i] : -1 * time_buffer[i];
|
||||
int32_t timesize = timeabs / zoom;
|
||||
@@ -145,9 +170,12 @@ void ProtoView::draw() {
|
||||
}
|
||||
remain = 0;
|
||||
lmax = 0;
|
||||
for (int32_t ii = 0; ii < timesize; ++ii) {
|
||||
waveform_buffer[drawcnt++] = state;
|
||||
if (drawcnt >= MAXDRAWCNT) return;
|
||||
for (int32_t ii = 0; ii < timesize && drawcnt < MAXDRAWCNT; ++ii) {
|
||||
if (skipped < to_skip) {
|
||||
skipped++;
|
||||
} else {
|
||||
waveform_buffer[drawcnt++] = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,6 +186,7 @@ void ProtoView::add_time(int32_t time) {
|
||||
}
|
||||
|
||||
void ProtoView::on_data(const ProtoViewDataMessage* message) {
|
||||
if (paused) return;
|
||||
// filter out invalid ones.
|
||||
uint16_t start = 0;
|
||||
uint16_t stop = 0;
|
||||
@@ -186,6 +215,24 @@ void ProtoView::on_data(const ProtoViewDataMessage* message) {
|
||||
draw2();
|
||||
}
|
||||
|
||||
void ProtoView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
void ProtoView::set_pause(bool pause) {
|
||||
paused = pause;
|
||||
if (pause) {
|
||||
label_shift.hidden(false);
|
||||
number_shift.hidden(false);
|
||||
button_pause.set_text(LanguageHelper::currentMessages[LANG_RESUME]);
|
||||
} else {
|
||||
label_shift.hidden(true);
|
||||
number_shift.hidden(true);
|
||||
button_pause.set_text(LanguageHelper::currentMessages[LANG_PAUSE]);
|
||||
}
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
ProtoView::~ProtoView() {
|
||||
audio::output::stop();
|
||||
receiver_model.disable();
|
||||
|
||||
+33
-7
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -75,8 +74,12 @@ class ProtoView : public View {
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
nav_};
|
||||
Labels labels{
|
||||
|
||||
// need to seperate because label shift need to hide independently
|
||||
Labels label_zoom{
|
||||
{{0 * 8, 1 * 16}, "Zoom: ", Theme::getInstance()->fg_light->foreground}};
|
||||
Labels label_shift{
|
||||
{{0 * 8, 2 * 16}, "Shift: ", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_zoom{
|
||||
{7 * 8, 1 * 16},
|
||||
@@ -92,12 +95,23 @@ class ProtoView : public View {
|
||||
{"500", 500},
|
||||
{"1000", 1000}}};
|
||||
|
||||
NumberField number_shift{
|
||||
{7 * 8, 2 * 16},
|
||||
5,
|
||||
{-MAXSIGNALBUFFER, MAXSIGNALBUFFER},
|
||||
1,
|
||||
' '};
|
||||
|
||||
Button button_reset{
|
||||
{screen_width - 12 * 8, 1 * 16, 96, 24},
|
||||
LanguageHelper::currentMessages[LANG_RESET]};
|
||||
|
||||
Button button_pause{
|
||||
{screen_width - 12 * 8, 1 * 16 + 24, 96, 24},
|
||||
LanguageHelper::currentMessages[LANG_PAUSE]};
|
||||
|
||||
Waveform waveform{
|
||||
{0, 5 * 8, 240, 50},
|
||||
{0, 8 * 8, 240, 50},
|
||||
waveform_buffer,
|
||||
0,
|
||||
0,
|
||||
@@ -105,7 +119,7 @@ class ProtoView : public View {
|
||||
Theme::getInstance()->fg_yellow->foreground};
|
||||
|
||||
Waveform waveform2{
|
||||
{0, 5 * 8 + 55, 240, 50},
|
||||
{0, 8 * 8 + 55, 240, 50},
|
||||
&waveform_buffer[MAXDRAWCNTPERWF],
|
||||
0,
|
||||
0,
|
||||
@@ -113,7 +127,7 @@ class ProtoView : public View {
|
||||
Theme::getInstance()->fg_yellow->foreground};
|
||||
|
||||
Waveform waveform3{
|
||||
{0, 5 * 8 + 110, 240, 50},
|
||||
{0, 8 * 8 + 110, 240, 50},
|
||||
&waveform_buffer[MAXDRAWCNTPERWF * 2],
|
||||
0,
|
||||
0,
|
||||
@@ -121,7 +135,7 @@ class ProtoView : public View {
|
||||
Theme::getInstance()->fg_yellow->foreground};
|
||||
|
||||
Waveform waveform4{
|
||||
{0, 5 * 8 + 165, 240, 50},
|
||||
{0, 8 * 8 + 165, 240, 50},
|
||||
&waveform_buffer[MAXDRAWCNTPERWF * 3],
|
||||
0,
|
||||
0,
|
||||
@@ -129,8 +143,10 @@ class ProtoView : public View {
|
||||
Theme::getInstance()->fg_yellow->foreground};
|
||||
|
||||
bool needCntReset = false;
|
||||
bool paused = false;
|
||||
|
||||
int16_t zoom = 1; // one value in ms
|
||||
int16_t waveform_shift = 0;
|
||||
|
||||
uint16_t cnt = 0; // pointer to next element
|
||||
uint16_t drawcnt = 0; // pointer to draw next element
|
||||
@@ -143,6 +159,7 @@ class ProtoView : public View {
|
||||
void on_data(const ProtoViewDataMessage* message);
|
||||
void draw();
|
||||
void draw2();
|
||||
void set_pause(bool pause);
|
||||
void reset();
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
@@ -157,6 +174,15 @@ class ProtoView : public View {
|
||||
[this](const Message* const) {
|
||||
this->on_timer();
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::protoview
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_random_password.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::random_password {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<RandomPasswordView>();
|
||||
}
|
||||
} // namespace ui::external_app::random_password
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_random_password.application_information"), used)) application_information_t _application_information_random_password = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::random_password::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "Random passwd",
|
||||
/*.bitmap_data = */ {
|
||||
0xC0,
|
||||
0x03,
|
||||
0xE0,
|
||||
0x07,
|
||||
0x30,
|
||||
0x0C,
|
||||
0x30,
|
||||
0x0C,
|
||||
0x30,
|
||||
0x0C,
|
||||
0x30,
|
||||
0x0C,
|
||||
0xE0,
|
||||
0x07,
|
||||
0xC0,
|
||||
0x03,
|
||||
0x80,
|
||||
0x01,
|
||||
0x80,
|
||||
0x01,
|
||||
0x80,
|
||||
0x01,
|
||||
0x80,
|
||||
0x01,
|
||||
0x80,
|
||||
0x07,
|
||||
0x80,
|
||||
0x03,
|
||||
0x80,
|
||||
0x07,
|
||||
0x80,
|
||||
0x01,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::yellow().v,
|
||||
/*.menu_location = */ app_location_t::UTILITIES,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'A', 'F', 'R'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/* modified from https://github.com/ulwanski/sha512
|
||||
* copyright @ulwanski
|
||||
* */
|
||||
#include "sha512.h"
|
||||
|
||||
namespace ui::external_app::random_password {
|
||||
|
||||
const unsigned long long SHA512::sha512_k[80] = // ULL = uint64
|
||||
{0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
|
||||
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
|
||||
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
|
||||
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
|
||||
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
|
||||
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
|
||||
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
|
||||
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
|
||||
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
|
||||
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
|
||||
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
|
||||
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
|
||||
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
|
||||
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
|
||||
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
|
||||
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
|
||||
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
|
||||
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
|
||||
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
|
||||
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
|
||||
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
|
||||
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
|
||||
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
|
||||
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
|
||||
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
|
||||
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
|
||||
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
|
||||
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
|
||||
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
|
||||
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
|
||||
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
|
||||
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
|
||||
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
|
||||
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
|
||||
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
|
||||
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
|
||||
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
|
||||
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
|
||||
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
|
||||
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
|
||||
|
||||
void SHA512::transform(const unsigned char* message, unsigned int block_nb) {
|
||||
uint64 w[80];
|
||||
uint64 wv[8];
|
||||
uint64 t1, t2;
|
||||
const unsigned char* sub_block;
|
||||
int i, j;
|
||||
for (i = 0; i < (int)block_nb; i++) {
|
||||
sub_block = message + (i << 7);
|
||||
for (j = 0; j < 16; j++) {
|
||||
SHA2_PACK64(&sub_block[j << 3], &w[j]);
|
||||
}
|
||||
for (j = 16; j < 80; j++) {
|
||||
w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16];
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
wv[j] = m_h[j];
|
||||
}
|
||||
for (j = 0; j < 80; j++) {
|
||||
t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6]) + sha512_k[j] + w[j];
|
||||
t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]);
|
||||
wv[7] = wv[6];
|
||||
wv[6] = wv[5];
|
||||
wv[5] = wv[4];
|
||||
wv[4] = wv[3] + t1;
|
||||
wv[3] = wv[2];
|
||||
wv[2] = wv[1];
|
||||
wv[1] = wv[0];
|
||||
wv[0] = t1 + t2;
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
m_h[j] += wv[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHA512::init() {
|
||||
m_h[0] = 0x6a09e667f3bcc908ULL;
|
||||
m_h[1] = 0xbb67ae8584caa73bULL;
|
||||
m_h[2] = 0x3c6ef372fe94f82bULL;
|
||||
m_h[3] = 0xa54ff53a5f1d36f1ULL;
|
||||
m_h[4] = 0x510e527fade682d1ULL;
|
||||
m_h[5] = 0x9b05688c2b3e6c1fULL;
|
||||
m_h[6] = 0x1f83d9abfb41bd6bULL;
|
||||
m_h[7] = 0x5be0cd19137e2179ULL;
|
||||
m_len = 0;
|
||||
m_tot_len = 0;
|
||||
}
|
||||
|
||||
void SHA512::update(const unsigned char* message, unsigned int len) {
|
||||
unsigned int block_nb;
|
||||
unsigned int new_len, rem_len, tmp_len;
|
||||
const unsigned char* shifted_message;
|
||||
tmp_len = SHA384_512_BLOCK_SIZE - m_len;
|
||||
rem_len = len < tmp_len ? len : tmp_len;
|
||||
memcpy(&m_block[m_len], message, rem_len);
|
||||
if (m_len + len < SHA384_512_BLOCK_SIZE) {
|
||||
m_len += len;
|
||||
return;
|
||||
}
|
||||
new_len = len - rem_len;
|
||||
block_nb = new_len / SHA384_512_BLOCK_SIZE;
|
||||
shifted_message = message + rem_len;
|
||||
transform(m_block, 1);
|
||||
transform(shifted_message, block_nb);
|
||||
rem_len = new_len % SHA384_512_BLOCK_SIZE;
|
||||
memcpy(m_block, &shifted_message[block_nb << 7], rem_len);
|
||||
m_len = rem_len;
|
||||
m_tot_len += (block_nb + 1) << 7;
|
||||
}
|
||||
|
||||
void SHA512::final(unsigned char* digest) {
|
||||
unsigned int block_nb;
|
||||
unsigned int pm_len;
|
||||
unsigned int len_b;
|
||||
int i;
|
||||
block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17) < (m_len % SHA384_512_BLOCK_SIZE));
|
||||
len_b = (m_tot_len + m_len) << 3;
|
||||
pm_len = block_nb << 7;
|
||||
memset(m_block + m_len, 0, pm_len - m_len);
|
||||
m_block[m_len] = 0x80;
|
||||
SHA2_UNPACK32(len_b, m_block + pm_len - 4);
|
||||
transform(m_block, block_nb);
|
||||
for (i = 0; i < 8; i++) {
|
||||
SHA2_UNPACK64(m_h[i], &digest[i << 3]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string sha512(const void* dat, size_t len) {
|
||||
unsigned char digest[SHA512::DIGEST_SIZE];
|
||||
memset(digest, 0, SHA512::DIGEST_SIZE);
|
||||
SHA512 ctx = SHA512();
|
||||
ctx.init();
|
||||
ctx.update((const unsigned char*)dat, len);
|
||||
ctx.final(digest);
|
||||
|
||||
char buf[2 * SHA512::DIGEST_SIZE + 1];
|
||||
buf[2 * SHA512::DIGEST_SIZE] = 0;
|
||||
for (unsigned int i = 0; i < SHA512::DIGEST_SIZE; i++)
|
||||
sprintf(buf + i * 2, "%02x", digest[i]);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
std::string sha512(std::string input) {
|
||||
return sha512((const unsigned char*)input.c_str(), (size_t)input.length());
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::random_password
|
||||
@@ -0,0 +1,76 @@
|
||||
/* modified from https://github.com/ulwanski/sha512
|
||||
* copyright @ulwanski
|
||||
* */
|
||||
|
||||
#ifndef SHA512_H
|
||||
#define SHA512_H
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
std::string sha512(const void* dat, size_t len);
|
||||
std::string sha512(std::string input);
|
||||
|
||||
namespace ui::external_app::random_password {
|
||||
|
||||
class SHA512 {
|
||||
protected:
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned long uint32;
|
||||
typedef unsigned long long uint64;
|
||||
const static uint64 sha512_k[];
|
||||
static const unsigned int SHA384_512_BLOCK_SIZE = (1024 / 8);
|
||||
|
||||
public:
|
||||
void init();
|
||||
void update(const unsigned char* message, unsigned int len);
|
||||
void final(unsigned char* digest);
|
||||
static const unsigned int DIGEST_SIZE = (512 / 8);
|
||||
|
||||
protected:
|
||||
void transform(const unsigned char* message, unsigned int block_nb);
|
||||
unsigned int m_tot_len;
|
||||
unsigned int m_len;
|
||||
unsigned char m_block[2 * SHA384_512_BLOCK_SIZE];
|
||||
uint64 m_h[8];
|
||||
};
|
||||
|
||||
std::string sha512(std::string input);
|
||||
|
||||
#define SHA2_SHFR(x, n) (x >> n)
|
||||
#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
|
||||
#define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
|
||||
#define SHA2_CH(x, y, z) ((x & y) ^ (~x & z))
|
||||
#define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
|
||||
#define SHA512_F1(x) (SHA2_ROTR(x, 28) ^ SHA2_ROTR(x, 34) ^ SHA2_ROTR(x, 39))
|
||||
#define SHA512_F2(x) (SHA2_ROTR(x, 14) ^ SHA2_ROTR(x, 18) ^ SHA2_ROTR(x, 41))
|
||||
#define SHA512_F3(x) (SHA2_ROTR(x, 1) ^ SHA2_ROTR(x, 8) ^ SHA2_SHFR(x, 7))
|
||||
#define SHA512_F4(x) (SHA2_ROTR(x, 19) ^ SHA2_ROTR(x, 61) ^ SHA2_SHFR(x, 6))
|
||||
#define SHA2_UNPACK32(x, str) \
|
||||
{ \
|
||||
*((str) + 3) = (uint8)((x)); \
|
||||
*((str) + 2) = (uint8)((x) >> 8); \
|
||||
*((str) + 1) = (uint8)((x) >> 16); \
|
||||
*((str) + 0) = (uint8)((x) >> 24); \
|
||||
}
|
||||
#define SHA2_UNPACK64(x, str) \
|
||||
{ \
|
||||
*((str) + 7) = (uint8)((x)); \
|
||||
*((str) + 6) = (uint8)((x) >> 8); \
|
||||
*((str) + 5) = (uint8)((x) >> 16); \
|
||||
*((str) + 4) = (uint8)((x) >> 24); \
|
||||
*((str) + 3) = (uint8)((x) >> 32); \
|
||||
*((str) + 2) = (uint8)((x) >> 40); \
|
||||
*((str) + 1) = (uint8)((x) >> 48); \
|
||||
*((str) + 0) = (uint8)((x) >> 56); \
|
||||
}
|
||||
#define SHA2_PACK64(str, x) \
|
||||
{ \
|
||||
*(x) = ((uint64) * ((str) + 7)) | ((uint64) * ((str) + 6) << 8) | ((uint64) * ((str) + 5) << 16) | ((uint64) * ((str) + 4) << 24) | ((uint64) * ((str) + 3) << 32) | ((uint64) * ((str) + 2) << 40) | ((uint64) * ((str) + 1) << 48) | ((uint64) * ((str) + 0) << 56); \
|
||||
}
|
||||
} // namespace ui::external_app::random_password
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2024 zxkmm
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* Notes about safety/randomness:
|
||||
* - Radio data is from nature, so if it's evenly tiled in space, it's random enough, but usually it's not
|
||||
* - A unsafe point is the freq that fetch data is from LCG (from Cpp STL) using time as seed, but should be spread out by later random calculation
|
||||
* - A unsafe point is the init data is still using LCG to generate, but used following methods to spread out:
|
||||
* - - Radio data
|
||||
* - - save a buffer of seeds and generate char by char, this cover all the possible chars combination
|
||||
* - - Rollout with teo seeds and get a final char, this spread out again
|
||||
* - - Hash out the generated password and spread out again if you choose. SHA-512 is proven very spreading out in random space by math
|
||||
* - But still, this isn't meant to become a TRNG generator, don't use at critical/high safety requited/important system, this FOSS has absolutely no warranty
|
||||
*/
|
||||
|
||||
#include "ui_random_password.hpp"
|
||||
#include "ui_modemsetup.hpp"
|
||||
|
||||
#include "modems.hpp"
|
||||
#include "rtc_time.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "file_path.hpp"
|
||||
#include "sha512.h"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace modems;
|
||||
using namespace ui;
|
||||
|
||||
namespace ui::external_app::random_password {
|
||||
|
||||
void RandomPasswordLogger::log_raw_data(const std::string& data) {
|
||||
log_file.write_entry(data);
|
||||
}
|
||||
|
||||
void RandomPasswordView::focus() {
|
||||
button_refresh.focus();
|
||||
}
|
||||
|
||||
RandomPasswordView::RandomPasswordView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
add_children({&rssi,
|
||||
&channel,
|
||||
&field_rf_amp,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_frequency,
|
||||
&check_log,
|
||||
&button_modem_setup,
|
||||
&labels,
|
||||
&text_generated_passwd,
|
||||
&text_char_type_hints,
|
||||
&check_digits,
|
||||
&check_latin_lower,
|
||||
&check_latin_upper,
|
||||
&check_punctuation,
|
||||
&check_show_seeds,
|
||||
&check_auto_send,
|
||||
&button_refresh,
|
||||
&button_show_qr,
|
||||
&button_flood,
|
||||
&button_send,
|
||||
&field_digits,
|
||||
&field_method,
|
||||
&check_allow_confusable_chars,
|
||||
&text_seed,
|
||||
&progressbar});
|
||||
|
||||
// no idea what's these, i copied from afsk rx app and they seems needed'
|
||||
auto def_bell202 = &modem_defs[0];
|
||||
persistent_memory::set_modem_baudrate(def_bell202->baudrate);
|
||||
serial_format_t serial_format;
|
||||
serial_format.data_bits = 7;
|
||||
serial_format.parity = EVEN;
|
||||
serial_format.stop_bits = 1;
|
||||
serial_format.bit_order = LSB_FIRST;
|
||||
persistent_memory::set_serial_format(serial_format);
|
||||
|
||||
progressbar.set_max(MAX_DIGITS * 2);
|
||||
|
||||
check_log.set_value(logging);
|
||||
check_log.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) {
|
||||
nav_.display_modal(
|
||||
"Warning",
|
||||
"Sure?\n"
|
||||
"this will save all generated\n"
|
||||
"password to sdcard\n"
|
||||
"in plain text\n"
|
||||
"those which generated before\n"
|
||||
"you check me, will lost",
|
||||
YESNO,
|
||||
[this, v](bool c) {
|
||||
if (c) {
|
||||
logging = v;
|
||||
} else {
|
||||
check_log.set_value(false);
|
||||
// this is needed to check back to false cuz when trigger by human, the check to true already happened
|
||||
// this blocked interface so won't accidently saved even if user checked but selected no later here,
|
||||
// but take care of here if in the future implemented ticking/auto/batch save etc
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logging = v;
|
||||
}
|
||||
};
|
||||
|
||||
button_modem_setup.on_select = [&nav](Button&) { // copied from afsk rx app
|
||||
nav.push<ModemSetupView>();
|
||||
};
|
||||
|
||||
check_digits.on_select = [this](Checkbox&, bool) {
|
||||
this->new_password();
|
||||
};
|
||||
|
||||
check_latin_lower.on_select = [this](Checkbox&, bool) {
|
||||
this->new_password();
|
||||
};
|
||||
|
||||
check_latin_upper.on_select = [this](Checkbox&, bool) {
|
||||
this->new_password();
|
||||
};
|
||||
|
||||
check_punctuation.on_select = [this](Checkbox&, bool) {
|
||||
this->new_password();
|
||||
};
|
||||
|
||||
check_allow_confusable_chars.on_select = [this](Checkbox&, bool) {
|
||||
this->new_password();
|
||||
};
|
||||
|
||||
button_refresh.on_select = [this](Button&) {
|
||||
this->set_random_freq();
|
||||
this->new_password();
|
||||
};
|
||||
|
||||
button_show_qr.on_select = [this, &nav](Button&) {
|
||||
nav.push<QRCodeView>(password.data());
|
||||
};
|
||||
|
||||
button_flood.on_select = [this](Button&) {
|
||||
if (flooding) {
|
||||
flooding = false;
|
||||
button_flood.set_text(LanguageHelper::currentMessages[LANG_FLOOD]);
|
||||
} else {
|
||||
flooding = true;
|
||||
button_flood.set_text(LanguageHelper::currentMessages[LANG_STOP]);
|
||||
}
|
||||
};
|
||||
button_send.on_select = [this, &nav](Button&) {
|
||||
async_prev_val = portapack::async_tx_enabled;
|
||||
portapack::async_tx_enabled = true;
|
||||
UsbSerialAsyncmsg::asyncmsg(password);
|
||||
portapack::async_tx_enabled = async_prev_val;
|
||||
};
|
||||
|
||||
field_digits.on_change = [this](int32_t) {
|
||||
clean_buffer();
|
||||
this->new_password();
|
||||
};
|
||||
|
||||
/// v check defauly val init
|
||||
check_digits.set_value(true);
|
||||
check_latin_lower.set_value(true);
|
||||
check_latin_upper.set_value(true);
|
||||
check_punctuation.set_value(true);
|
||||
check_show_seeds.set_value(true);
|
||||
field_digits.set_value(16);
|
||||
field_method.set_by_value(Method::RADIO_LCG_ROLL_HASH);
|
||||
///^ check defauly val init
|
||||
|
||||
logger = std::make_unique<RandomPasswordLogger>();
|
||||
if (logger)
|
||||
logger->append(logs_dir / u"random.TXT");
|
||||
|
||||
// Auto-configure modem for LCR RX (will be removed later), copied from afsk rx app
|
||||
baseband::set_afsk(persistent_memory::modem_baudrate(), 8, 0, false);
|
||||
|
||||
receiver_model.enable();
|
||||
receiver_model.set_rf_amp(false);
|
||||
set_random_freq();
|
||||
new_password();
|
||||
}
|
||||
|
||||
void RandomPasswordView::on_data(uint32_t value, bool is_data) {
|
||||
if (is_data) {
|
||||
seed = static_cast<unsigned int>(value);
|
||||
text_seed.set(to_string_dec_uint(check_show_seeds.value() ? seed : 0));
|
||||
|
||||
/// v feed deque
|
||||
seeds_deque.push_back(value);
|
||||
if (seeds_deque.size() > MAX_DIGITS * 2) {
|
||||
seeds_deque.pop_front();
|
||||
}
|
||||
|
||||
///^ feed deque
|
||||
|
||||
progressbar.set_value(seeds_deque.size());
|
||||
|
||||
if (flooding && seeds_deque.size() >= MAX_DIGITS * 2) {
|
||||
new_password();
|
||||
}
|
||||
|
||||
} else {
|
||||
text_generated_passwd.set("Baudrate estimation: ~");
|
||||
text_char_type_hints.set(to_string_dec_uint(value));
|
||||
}
|
||||
}
|
||||
|
||||
void RandomPasswordView::clean_buffer() {
|
||||
seeds_deque = {};
|
||||
}
|
||||
|
||||
void RandomPasswordView::on_freqchg(int64_t freq) {
|
||||
field_frequency.set_value(freq);
|
||||
}
|
||||
|
||||
void RandomPasswordView::set_random_freq() {
|
||||
std::srand(LPC_RTC->CTIME0);
|
||||
// this is only for seed to visit random freq, the radio is still real random
|
||||
|
||||
auto random_freq = 100000000 + (std::rand() % 900000000); // 100mhz to 1ghz
|
||||
receiver_model.set_target_frequency(random_freq);
|
||||
field_frequency.set_value(random_freq);
|
||||
}
|
||||
|
||||
void RandomPasswordView::new_password() {
|
||||
if (seeds_deque.size() < MAX_DIGITS * 2) {
|
||||
seeds_buffer_not_full = true;
|
||||
text_generated_passwd.set("wait seeds buffer full");
|
||||
text_char_type_hints.set("then press generate");
|
||||
return;
|
||||
}
|
||||
password = "";
|
||||
std::string charset = "";
|
||||
std::string char_type_hints = "";
|
||||
std::string initial_password = "";
|
||||
int password_length = field_digits.value();
|
||||
|
||||
/// charset worker
|
||||
if (check_digits.value())
|
||||
charset += "0123456789";
|
||||
if (check_latin_lower.value())
|
||||
charset += "abcdefghijklmnopqrstuvwxyz";
|
||||
if (check_latin_upper.value())
|
||||
charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
if (check_punctuation.value())
|
||||
charset += ".,-!?";
|
||||
|
||||
if (!check_allow_confusable_chars.value()) {
|
||||
charset.erase(std::remove_if(charset.begin(), charset.end(),
|
||||
[](char c) { return c == '0' || c == 'O' || c == 'o' || c == '1' || c == 'l'; }),
|
||||
charset.end());
|
||||
}
|
||||
|
||||
if (charset.empty()) {
|
||||
text_generated_passwd.set("generate failed,");
|
||||
text_char_type_hints.set("select at least 1 type");
|
||||
return;
|
||||
}
|
||||
|
||||
/// roll worker
|
||||
for (int i = 0; i < password_length * 2; i += 2) {
|
||||
unsigned int seed = seeds_deque[i];
|
||||
std::srand(seed);
|
||||
uint8_t rollnum = (uint8_t)(seeds_deque[i + 1] % 128);
|
||||
uint8_t nu = 0;
|
||||
for (uint8_t o = 0; o < rollnum; ++o) nu = std::rand();
|
||||
nu++;
|
||||
char c = charset[std::rand() % charset.length()];
|
||||
initial_password += c;
|
||||
}
|
||||
|
||||
// hash worker
|
||||
std::string hashed_password = sha512(initial_password);
|
||||
|
||||
std::vector<char> password_chars(password_length);
|
||||
for (int i = 0; i < password_length; i++) {
|
||||
unsigned int index = std::stoul(hashed_password.substr(i * 2, 2), nullptr, 16) % charset.length(); // result from 0 to charset.length()-1,should be very evenly tiled in the charset space
|
||||
password_chars[i] = charset[index];
|
||||
}
|
||||
|
||||
/// hint text worker
|
||||
for (char c : password_chars) {
|
||||
password += c;
|
||||
if (std::isdigit(c)) {
|
||||
char_type_hints += "1";
|
||||
} else if (std::islower(c)) {
|
||||
char_type_hints += "a";
|
||||
} else if (std::isupper(c)) {
|
||||
char_type_hints += "A";
|
||||
} else {
|
||||
char_type_hints += ",";
|
||||
}
|
||||
}
|
||||
|
||||
/// decision worker
|
||||
switch (field_method.selected_index_value()) {
|
||||
case Method::RADIO_LCG_ROLL:
|
||||
password = initial_password;
|
||||
break;
|
||||
case Method::RADIO_LCG_ROLL_HASH:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/// give out result worker
|
||||
text_generated_passwd.set(password);
|
||||
text_char_type_hints.set(char_type_hints);
|
||||
|
||||
paint_password_hints();
|
||||
|
||||
if (logger && logging) {
|
||||
str_log += generate_log_line();
|
||||
logger->log_raw_data(str_log);
|
||||
str_log = "";
|
||||
}
|
||||
|
||||
if (check_auto_send.value() || flooding) {
|
||||
async_prev_val = portapack::async_tx_enabled;
|
||||
portapack::async_tx_enabled = true;
|
||||
UsbSerialAsyncmsg::asyncmsg(password);
|
||||
portapack::async_tx_enabled = async_prev_val;
|
||||
}
|
||||
|
||||
clean_buffer();
|
||||
}
|
||||
|
||||
void RandomPasswordView::paint_password_hints() {
|
||||
Painter painter;
|
||||
const int char_width = 8;
|
||||
const int char_height = 16;
|
||||
const int start_y = 6 * char_height;
|
||||
const int rect_height = 4;
|
||||
|
||||
for (size_t i = 0; i < password.length(); i++) {
|
||||
char c = password[i];
|
||||
Color color;
|
||||
if (std::isdigit(c)) {
|
||||
color = Color::red();
|
||||
} else if (std::islower(c)) {
|
||||
color = Color::green();
|
||||
} else if (std::isupper(c)) {
|
||||
color = Color::blue();
|
||||
} else {
|
||||
color = Color::white();
|
||||
}
|
||||
|
||||
painter.fill_rectangle(
|
||||
{{static_cast<int>(i) * char_width, start_y},
|
||||
{char_width, rect_height}},
|
||||
color);
|
||||
}
|
||||
}
|
||||
|
||||
std::string RandomPasswordView::generate_log_line() {
|
||||
std::string seeds_set = "";
|
||||
for (auto seed : seeds_deque) {
|
||||
seeds_set += std::to_string(seed);
|
||||
seeds_set += " ";
|
||||
}
|
||||
std::string line = "\npassword=" + password +
|
||||
"\nseeds=" + seeds_set +
|
||||
"\n";
|
||||
return line;
|
||||
}
|
||||
|
||||
RandomPasswordView::~RandomPasswordView() {
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::random_password
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2024 zxkmm
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_RANDOM_PASSWORD_H__
|
||||
#define __UI_RANDOM_PASSWORD_H__
|
||||
|
||||
#define MAX_DIGITS 30
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_language.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_freq_field.hpp"
|
||||
#include "ui_record_view.hpp"
|
||||
#include "app_settings.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "log_file.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "ui_qrcode.hpp"
|
||||
#include "usb_serial_asyncmsg.hpp"
|
||||
#include "sha512.h"
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
using namespace ui;
|
||||
|
||||
namespace ui::external_app::random_password {
|
||||
|
||||
enum Method {
|
||||
RADIO_LCG_ROLL,
|
||||
RADIO_LCG_ROLL_HASH,
|
||||
};
|
||||
|
||||
class RandomPasswordLogger {
|
||||
public:
|
||||
Optional<File::Error> append(const std::filesystem::path& filename) {
|
||||
return log_file.append(filename);
|
||||
}
|
||||
|
||||
void log_raw_data(const std::string& data);
|
||||
|
||||
private:
|
||||
LogFile log_file{};
|
||||
};
|
||||
|
||||
class RandomPasswordView : public View {
|
||||
public:
|
||||
RandomPasswordView(NavigationView& nav);
|
||||
~RandomPasswordView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "R.passwd"; };
|
||||
|
||||
private:
|
||||
unsigned int seed = 0; // extern void srand (unsigned int __seed) __THROW;
|
||||
std::string password = "";
|
||||
|
||||
std::deque<unsigned int> seeds_deque = {0};
|
||||
bool seeds_buffer_not_full = true;
|
||||
bool in_benchmark = false;
|
||||
bool flooding = false;
|
||||
bool logging = false;
|
||||
bool async_prev_val = false;
|
||||
std::string str_log{""};
|
||||
|
||||
void on_data(uint32_t value, bool is_data);
|
||||
void clean_buffer();
|
||||
void new_password();
|
||||
std::string generate_log_line();
|
||||
void paint_password_hints();
|
||||
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{};
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_passgen", app_settings::Mode::RX};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "------------seeds-------------", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 3 * 16}, "-----------password-----------", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16 - 2}, "digits:", Theme::getInstance()->fg_light->foreground},
|
||||
{{screen_width / 2, 7 * 16 - 2}, "method:", Theme::getInstance()->fg_light->foreground},
|
||||
};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 1 * 16}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 1 * 16}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 1 * 16}};
|
||||
|
||||
RSSI rssi{
|
||||
{21 * 8, 1 * 16 + 0, 6 * 8, 4}};
|
||||
Channel channel{
|
||||
{21 * 8, 1 * 16 + 5, 6 * 8, 4}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 1 * 16},
|
||||
nav_};
|
||||
|
||||
Button button_modem_setup{
|
||||
{screen_width - 12 * 8, 2 * 16 - 1, 96, 16 + 2},
|
||||
LanguageHelper::currentMessages[LANG_MODEM_SETUP]};
|
||||
|
||||
Text text_seed{
|
||||
{0, 2 * 16, 10 * 8, 16},
|
||||
"0000000000"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{10 * 8 + 2, 2 * 16, screen_width - 96 - (10 * 8 + 4) - 1, 16}};
|
||||
|
||||
Text text_generated_passwd{
|
||||
{0, 4 * 16, screen_width, 16},
|
||||
"000000000000000000000000000000"};
|
||||
|
||||
Text text_char_type_hints{
|
||||
{0, 5 * 16 + 4, screen_width, 16},
|
||||
"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"};
|
||||
|
||||
Checkbox check_show_seeds{
|
||||
{17 * 8, 8 * 16},
|
||||
6,
|
||||
"Show seed"};
|
||||
|
||||
Checkbox check_auto_send{
|
||||
{1 * 8, 8 * 16},
|
||||
20,
|
||||
"Auto send"};
|
||||
|
||||
Checkbox check_punctuation{
|
||||
{17 * 8, 12 * 16},
|
||||
6,
|
||||
".,-!?"};
|
||||
|
||||
Checkbox check_allow_confusable_chars{
|
||||
{1 * 8, 10 * 16},
|
||||
20,
|
||||
"0 O o 1 l"};
|
||||
|
||||
Checkbox check_digits{
|
||||
{1 * 8, 12 * 16},
|
||||
3,
|
||||
"123"};
|
||||
|
||||
Checkbox check_latin_lower{
|
||||
{1 * 8, 14 * 16},
|
||||
3,
|
||||
"abc"};
|
||||
|
||||
Checkbox check_latin_upper{
|
||||
{17 * 8, 14 * 16},
|
||||
3,
|
||||
"ABC"};
|
||||
|
||||
Checkbox check_log{
|
||||
{17 * 8, 10 * 16},
|
||||
3,
|
||||
LanguageHelper::currentMessages[LANG_SAVE]};
|
||||
|
||||
Button button_flood{
|
||||
{0 * 8, 15 * 16 + 18, screen_width / 2, 22},
|
||||
LanguageHelper::currentMessages[LANG_FLOOD]};
|
||||
|
||||
Button button_send{
|
||||
{screen_width / 2 + 2, 15 * 16 + 18, screen_width / 2 - 2, 22},
|
||||
"Send pwd"};
|
||||
|
||||
Button button_refresh{
|
||||
{0 * 8, 17 * 16 + 10, screen_width / 2, 22},
|
||||
"Generate"};
|
||||
|
||||
Button button_show_qr{
|
||||
{screen_width / 2 + 2, 17 * 16 + 10, screen_width / 2 - 2, 22},
|
||||
LanguageHelper::currentMessages[LANG_SHOWQR]};
|
||||
|
||||
NumberField field_digits{
|
||||
{0 + (sizeof("digits:") - 1) * 8, 7 * 16 - 2},
|
||||
2,
|
||||
{1, 30},
|
||||
1,
|
||||
' '};
|
||||
|
||||
OptionsField field_method{
|
||||
{(screen_width / 2) + (sizeof("method:") - 1) * 8, 7 * 16 - 2},
|
||||
sizeof("R+L+R+H"),
|
||||
{{"R+L+R", Method::RADIO_LCG_ROLL},
|
||||
{"R+L+R+H", Method::RADIO_LCG_ROLL_HASH}}};
|
||||
|
||||
void on_data_afsk(const AFSKDataMessage& message);
|
||||
|
||||
std::unique_ptr<RandomPasswordLogger> logger{};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::AFSKData,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const AFSKDataMessage*>(p);
|
||||
this->on_data(message->value, message->is_data);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_freqchg{
|
||||
Message::ID::FreqChangeCommand,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
||||
this->on_freqchg(message->freq);
|
||||
}};
|
||||
|
||||
void on_freqchg(int64_t freq);
|
||||
void set_random_freq();
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::random_password
|
||||
|
||||
#endif /*__UI_RANDOM_PASSWORD_H__*/
|
||||
@@ -19,7 +19,8 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __UI_SPECTRUM_PAINTER_H
|
||||
#define __UI_SPECTRUM_PAINTER_H
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_language.hpp"
|
||||
@@ -165,3 +166,5 @@ class SpectrumPainterView : public View {
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::spainter
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __UI_SPECTRUM_PAINTER_IMAGE_H
|
||||
#define __UI_SPECTRUM_PAINTER_IMAGE_H
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
@@ -64,3 +65,5 @@ class SpectrumInputImageView : public View {
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::spainter
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __UI_SPECTRUM_PAINTER_TEXT_H
|
||||
#define __UI_SPECTRUM_PAINTER_TEXT_H
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
@@ -110,3 +111,5 @@ class SpectrumInputTextView : public View {
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::spainter
|
||||
|
||||
#endif
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_sstvtx.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::sstvtx {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<SSTVTXView>();
|
||||
}
|
||||
} // namespace ui::external_app::sstvtx
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_sstvtx.application_information"), used)) application_information_t _application_information_sstvtx = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::sstvtx::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "SSTV",
|
||||
/*.bitmap_data = */ {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x53,
|
||||
0xD5,
|
||||
0xAB,
|
||||
0xCA,
|
||||
0x53,
|
||||
0xD5,
|
||||
0xAB,
|
||||
0xCA,
|
||||
0x53,
|
||||
0xD5,
|
||||
0xAB,
|
||||
0xCA,
|
||||
0x53,
|
||||
0xD5,
|
||||
0x03,
|
||||
0xC0,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFB,
|
||||
0xD7,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0x00,
|
||||
0x00,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::TX,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_sstvtx */ {'P', 'S', 'T', 'X'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
Vendored
+4
-3
@@ -31,7 +31,7 @@
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::sstvtx {
|
||||
|
||||
void SSTVTXView::focus() {
|
||||
if (file_error)
|
||||
@@ -232,7 +232,8 @@ SSTVTXView::SSTVTXView(
|
||||
|
||||
// Maybe this could be merged with proc_tones ? Pretty much the same except lots
|
||||
// of different tones (256+)
|
||||
baseband::run_image(portapack::spi_flash::image_tag_sstv_tx);
|
||||
// baseband::run_image(portapack::spi_flash::image_tag_sstv_tx);
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
add_children({&labels,
|
||||
&options_bitmaps,
|
||||
@@ -283,4 +284,4 @@ SSTVTXView::SSTVTXView(
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::sstvtx
|
||||
Vendored
+2
-2
@@ -38,7 +38,7 @@
|
||||
|
||||
using namespace sstv;
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::sstvtx {
|
||||
|
||||
class SSTVTXView : public View {
|
||||
public:
|
||||
@@ -110,6 +110,6 @@ class SSTVTXView : public View {
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
} /* namespace ui::external_app::sstvtx */
|
||||
|
||||
#endif /*__UI_SSTVTX_H__*/
|
||||
+7
-6
@@ -107,7 +107,7 @@ class TPMSAppView : public View {
|
||||
|
||||
private:
|
||||
RxRadioState radio_state_{
|
||||
314950000 /* frequency*/
|
||||
314900000 /* frequency*/
|
||||
,
|
||||
1750000 /* bandwidth */,
|
||||
2457600 /* sampling rate */
|
||||
@@ -147,20 +147,21 @@ class TPMSAppView : public View {
|
||||
// "315 MHz" TPMS sensors transmit at either 314.9 or 315 MHz but we should pick up either
|
||||
OptionsField options_band{
|
||||
{0 * 8, 0 * 16},
|
||||
3,
|
||||
5,
|
||||
{
|
||||
{"315", 314950000},
|
||||
{"434", 433920000},
|
||||
{"314.9", 314900000},
|
||||
{"315.0", 315000000},
|
||||
{"433.9", 433920000},
|
||||
}};
|
||||
|
||||
OptionsField options_pressure{
|
||||
{5 * 8, 0 * 16},
|
||||
{6 * 8, 0 * 16},
|
||||
3,
|
||||
{{"kPa", 0},
|
||||
{"PSI", 1}}};
|
||||
|
||||
OptionsField options_temperature{
|
||||
{9 * 8, 0 * 16},
|
||||
{10 * 8, 0 * 16},
|
||||
2,
|
||||
{{STR_DEGREES_C, 0},
|
||||
{STR_DEGREES_F, 1}}};
|
||||
|
||||
+80
-18
@@ -23,6 +23,7 @@
|
||||
#include "string_format.hpp"
|
||||
#include "file_path.hpp"
|
||||
#include "metadata_file.hpp"
|
||||
#include "flipper_subfile.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
@@ -36,14 +37,14 @@ void WardriveMapView::focus() {
|
||||
|
||||
// needs to load on every map change, because won't store or draw all while marker is not in the current view.
|
||||
// todo optimize this somehow
|
||||
bool WardriveMapView::load_markers() {
|
||||
uint16_t cnt = 0;
|
||||
void WardriveMapView::load_markers() {
|
||||
uint16_t displayed_cnt = 0;
|
||||
uint16_t cnt = 0;
|
||||
geomap.clear_markers();
|
||||
// serach for files with geotag, and add it to geomap as marker with tag. limit to N bc of mem limit.
|
||||
for (const auto& entry : std::filesystem::directory_iterator(captures_dir, u"*.txt")) {
|
||||
if (std::filesystem::is_regular_file(entry.status())) {
|
||||
if (displayed_cnt > 30) break;
|
||||
if (markers_counted && displayed_cnt > ui::GeoMap::NumMarkerListElements) return; // only if not fist iteration, since then not counted all elements
|
||||
std::filesystem::path pth = captures_dir;
|
||||
pth += u"/" + entry.path();
|
||||
auto metadata_path = get_metadata_path(pth);
|
||||
@@ -51,23 +52,65 @@ bool WardriveMapView::load_markers() {
|
||||
|
||||
if (metadata) {
|
||||
if (metadata.value().latitude != 0 && metadata.value().longitude != 0 && metadata.value().latitude < 400 && metadata.value().longitude < 400) {
|
||||
if (first_init == false) {
|
||||
// move map there before add, so will display this.
|
||||
geopos.set_report_change(false);
|
||||
geopos.set_lat(metadata.value().latitude);
|
||||
geopos.set_lon(metadata.value().longitude);
|
||||
geopos.set_report_change(true);
|
||||
geomap.move(metadata.value().longitude, metadata.value().latitude);
|
||||
first_init = true;
|
||||
// skip nth
|
||||
if (marker_start <= cnt) {
|
||||
if (first_init == false) {
|
||||
// move map there before add, so will display this.
|
||||
geopos.set_report_change(false);
|
||||
geopos.set_lat(metadata.value().latitude);
|
||||
geopos.set_lon(metadata.value().longitude);
|
||||
geopos.set_report_change(true);
|
||||
geomap.move(metadata.value().longitude, metadata.value().latitude);
|
||||
first_init = true;
|
||||
}
|
||||
GeoMarker tmp{metadata.value().latitude, metadata.value().longitude, 400, entry.path().filename().string()};
|
||||
if (geomap.store_marker(tmp) == MapMarkerStored::MARKER_STORED) displayed_cnt++;
|
||||
if (!markers_counted) marker_cntall++;
|
||||
}
|
||||
GeoMarker tmp{metadata.value().latitude, metadata.value().longitude, 400, entry.path().filename().string()};
|
||||
if (geomap.store_marker(tmp) == MapMarkerStored::MARKER_STORED) displayed_cnt++;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (cnt > 0);
|
||||
// load flipper files too
|
||||
for (const auto& entry : std::filesystem::directory_iterator(flippersub_dir, u"*.sub")) {
|
||||
if (std::filesystem::is_regular_file(entry.status())) {
|
||||
if (markers_counted && displayed_cnt > ui::GeoMap::NumMarkerListElements) return; // only if not fist iteration, since then not counted all elements
|
||||
std::filesystem::path pth = flippersub_dir;
|
||||
pth += u"/" + entry.path();
|
||||
auto metadata = read_flippersub_file(pth);
|
||||
|
||||
if (metadata) {
|
||||
if (metadata.value().latitude != 0 && metadata.value().longitude != 0 && metadata.value().latitude < 400 && metadata.value().longitude < 400) {
|
||||
// skip nth
|
||||
if (marker_start <= cnt) {
|
||||
if (first_init == false) {
|
||||
// move map there before add, so will display this.
|
||||
geopos.set_report_change(false);
|
||||
geopos.set_lat(metadata.value().latitude);
|
||||
geopos.set_lon(metadata.value().longitude);
|
||||
geopos.set_report_change(true);
|
||||
geomap.move(metadata.value().longitude, metadata.value().latitude);
|
||||
first_init = true;
|
||||
}
|
||||
GeoMarker tmp{metadata.value().latitude, metadata.value().longitude, 400, entry.path().filename().string()};
|
||||
if (geomap.store_marker(tmp) == MapMarkerStored::MARKER_STORED) displayed_cnt++;
|
||||
if (!markers_counted) marker_cntall++;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
markers_counted = true;
|
||||
// show / hide paginator buttons
|
||||
btn_back.hidden((marker_start == 0) || (marker_cntall == 0));
|
||||
btn_next.hidden(((marker_start + ui::GeoMap::NumMarkerListElements) >= marker_cntall) || (marker_cntall == 0));
|
||||
// update text
|
||||
text_info.set(to_string_dec_uint(marker_start + 1) + " - " + to_string_dec_uint(displayed_cnt + marker_start) + " / " + to_string_dec_uint(marker_cntall));
|
||||
set_dirty();
|
||||
return;
|
||||
}
|
||||
|
||||
WardriveMapView::WardriveMapView(NavigationView& nav)
|
||||
@@ -75,7 +118,9 @@ WardriveMapView::WardriveMapView(NavigationView& nav)
|
||||
add_children({&text_info,
|
||||
&geomap,
|
||||
&geopos,
|
||||
&text_notfound});
|
||||
&text_notfound,
|
||||
&btn_back,
|
||||
&btn_next});
|
||||
|
||||
geomap.set_mode(DISPLAY);
|
||||
geomap.set_manual_panning(false);
|
||||
@@ -100,21 +145,38 @@ WardriveMapView::WardriveMapView(NavigationView& nav)
|
||||
load_markers();
|
||||
geomap.set_dirty();
|
||||
};
|
||||
text_notfound.hidden(true);
|
||||
geomap.init();
|
||||
// load markers
|
||||
if (load_markers()) {
|
||||
load_markers();
|
||||
if (marker_cntall > 0) {
|
||||
text_notfound.hidden(true);
|
||||
geomap.set_dirty();
|
||||
} else {
|
||||
geomap.hidden(true);
|
||||
geopos.hidden(true);
|
||||
text_notfound.hidden(false);
|
||||
text_info.hidden(true);
|
||||
}
|
||||
|
||||
// never move this before the first load() bc that will mess load up
|
||||
geomap.on_move = [this](float lon, float lat) {
|
||||
(void)lon;
|
||||
(void)lat;
|
||||
load_markers();
|
||||
};
|
||||
btn_back.on_select = [this, &nav](Button&) {
|
||||
if (marker_start - ui::GeoMap::NumMarkerListElements >= 0)
|
||||
marker_start = marker_start - ui::GeoMap::NumMarkerListElements;
|
||||
else
|
||||
marker_start = 0;
|
||||
load_markers();
|
||||
};
|
||||
btn_next.on_select = [this, &nav](Button&) {
|
||||
if (marker_start + ui::GeoMap::NumMarkerListElements <= marker_cntall)
|
||||
marker_start = marker_start + ui::GeoMap::NumMarkerListElements;
|
||||
else
|
||||
marker_start = marker_cntall - ui::GeoMap::NumMarkerListElements;
|
||||
load_markers();
|
||||
};
|
||||
}
|
||||
|
||||
WardriveMapView::~WardriveMapView() {
|
||||
|
||||
+12
-10
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -20,10 +19,6 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Code from https://github.com/Flipper-XFW/Xtreme-Apps/tree/04c3a60093e2c2378e79498b4505aa8072980a42/ble_spam/protocols
|
||||
// Thanks for the work of the original creators!
|
||||
// Saying thanks in the main view!
|
||||
|
||||
#ifndef __UI_WARDRIVEMAP_H__
|
||||
#define __UI_WARDRIVEMAP_H__
|
||||
|
||||
@@ -50,22 +45,29 @@ class WardriveMapView : public View {
|
||||
};
|
||||
|
||||
private:
|
||||
const std::filesystem::path flippersub_dir = u"subghz";
|
||||
NavigationView& nav_;
|
||||
|
||||
Text text_info{{0 * 8, 0 * 8, 30 * 8, 16 * 1}, "All GEOTAG from CAPTURES"};
|
||||
Text text_notfound{{0 * 8, 3 * 8, 30 * 8, 16 * 1}, "No GeoTagged captures found"};
|
||||
Text text_info{{0 * 8, 0 * 8, 20 * 8, 16 * 1}, "0 / 30"};
|
||||
Text text_notfound{{0 * 8, 0 * 8, 30 * 8, 16 * 1}, "No GeoTagged captures found"};
|
||||
GeoPos geopos{
|
||||
{0, 20},
|
||||
GeoPos::alt_unit::METERS,
|
||||
GeoPos::spd_unit::HIDDEN};
|
||||
GeoMap geomap{{0, 75, 240, 320 - 75}};
|
||||
|
||||
Button btn_back{{22 * 8, 0 * 8, 3 * 8, 16}, "<-"};
|
||||
Button btn_next{{26 * 8, 0 * 8, 3 * 8, 16}, "->"};
|
||||
|
||||
void on_gps(const GPSPosDataMessage* msg);
|
||||
void on_orientation(const OrientationDataMessage* msg);
|
||||
|
||||
bool load_markers(); // returns true if any exists, false if none.
|
||||
void load_markers(); // returns true if any exists, false if none.
|
||||
|
||||
bool first_init = false;
|
||||
bool first_init = false; // to center map to first marker, before callback is set
|
||||
bool markers_counted = false; // to iterate all files on first, but only on first.
|
||||
uint16_t marker_start = 0; // for paginator, this will be the first displayed
|
||||
uint16_t marker_cntall = 0; // all geotagged marker count
|
||||
|
||||
MessageHandlerRegistration message_handler_gps{
|
||||
Message::ID::GPSPosData,
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "flipper_subfile.hpp"
|
||||
|
||||
#include "convert.hpp"
|
||||
#include "file_reader.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include <string_view>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std::literals;
|
||||
|
||||
const std::string_view filetype_name = "Filetype"sv;
|
||||
const std::string_view frequency_name = "Frequency"sv;
|
||||
const std::string_view latitude_name_old = "Latitute"sv;
|
||||
const std::string_view longitude_name_old = "Longitude"sv;
|
||||
const std::string_view latitude_name = "Lat"sv;
|
||||
const std::string_view longitude_name = "Lon"sv;
|
||||
const std::string_view protocol_name = "Protocol"sv;
|
||||
const std::string_view preset_name = "Preset"sv;
|
||||
const std::string_view te_name = "TE"sv; // only in BinRAW
|
||||
|
||||
/*
|
||||
Filetype: Flipper SubGhz Key File
|
||||
Version: 1
|
||||
Frequency: 433920000
|
||||
Preset: FuriHalSubGhzPresetOok650Async
|
||||
Latitute: nan
|
||||
Longitude: nan
|
||||
Protocol: BinRAW
|
||||
Bit: 1730
|
||||
TE: 495
|
||||
Bit_RAW: 1730
|
||||
Data_RAW: 02 10 84
|
||||
|
||||
te: is the quantization interval, in us.
|
||||
bit: all bit counts in file.
|
||||
bit_raw: the bits stored in the next data_raw. this 2 can repeat
|
||||
data_raw: is an encoded sequence of durations, where each bit in the sequence encodes one TE interval: 1 - high level (there is a carrier), 0 - low (no carrier). For example, TE=100, Bit_RAW=8, Data_RAW=0x37 => 0b00110111, that is, -200 200 -100 300 will be transmitted
|
||||
|
||||
|
||||
|
||||
Filetype: Flipper SubGhz RAW File
|
||||
Version: 1
|
||||
Frequency: 433920000
|
||||
Preset: FuriHalSubGhzPresetOok650Async
|
||||
Protocol: RAW
|
||||
RAW_Data: 5832 -12188 130 -162
|
||||
|
||||
raw_data- positive: carrier for n time, negative: no carrier for n time. (us)
|
||||
*/
|
||||
|
||||
Optional<flippersub_metadata> read_flippersub_file(const fs::path& path) {
|
||||
File f;
|
||||
auto error = f.open(path);
|
||||
|
||||
if (error)
|
||||
return {};
|
||||
|
||||
flippersub_metadata metadata{};
|
||||
|
||||
auto reader = FileLineReader(f);
|
||||
for (const auto& line : reader) {
|
||||
auto cols = split_string(line, ':');
|
||||
|
||||
if (cols.size() != 2)
|
||||
continue; // Bad line.
|
||||
if (cols[1].length() <= 1) continue;
|
||||
std::string fixed = cols[1].data() + 1;
|
||||
fixed = trim(fixed);
|
||||
if (cols[0] == filetype_name) {
|
||||
if (fixed != "Flipper SubGhz Key File" && fixed != "Flipper SubGhz RAW File") return {}; // not supported
|
||||
} else if (cols[0] == frequency_name)
|
||||
parse_int(fixed, metadata.center_frequency);
|
||||
else if (cols[0] == latitude_name)
|
||||
parse_float_meta(fixed, metadata.latitude);
|
||||
else if (cols[0] == longitude_name)
|
||||
parse_float_meta(fixed, metadata.longitude);
|
||||
else if (cols[0] == latitude_name_old)
|
||||
parse_float_meta(fixed, metadata.latitude);
|
||||
else if (cols[0] == longitude_name_old)
|
||||
parse_float_meta(fixed, metadata.longitude);
|
||||
else if (cols[0] == protocol_name) {
|
||||
if (fixed == "RAW") metadata.protocol = FLIPPER_PROTO_RAW;
|
||||
if (fixed == "BinRAW") metadata.protocol = FLIPPER_PROTO_BINRAW;
|
||||
} else if (cols[0] == te_name) {
|
||||
metadata.te = atoi(fixed.c_str());
|
||||
} else if (cols[0] == preset_name) {
|
||||
if (fixed.find("FSK") != std::string::npos) {
|
||||
metadata.preset = FLIPPER_PRESET_2FSK;
|
||||
} else if (fixed.find("Ook") != std::string::npos) {
|
||||
metadata.preset = FLIPPER_PRESET_OOK;
|
||||
} else if (fixed.find("Custom") != std::string::npos) {
|
||||
metadata.preset = FLIPPER_PRESET_CUSTOM;
|
||||
}
|
||||
|
||||
} else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (metadata.center_frequency == 0) return {}; // Parse failed.
|
||||
|
||||
return metadata;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __FLIPPER_SUBFILE_HPP__
|
||||
#define __FLIPPER_SUBFILE_HPP__
|
||||
|
||||
#include "metadata_file.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
FLIPPER_PROTO_UNSUPPORTED = 0,
|
||||
FLIPPER_PROTO_RAW = 1,
|
||||
FLIPPER_PROTO_BINRAW = 2
|
||||
} FlipperProto;
|
||||
|
||||
typedef enum : uint8_t {
|
||||
FLIPPER_PRESET_UNK = 0,
|
||||
FLIPPER_PRESET_CUSTOM = 1,
|
||||
FLIPPER_PRESET_OOK = 2,
|
||||
FLIPPER_PRESET_2FSK = 3,
|
||||
} FlipperPreset;
|
||||
|
||||
struct flippersub_metadata {
|
||||
rf::Frequency center_frequency;
|
||||
float latitude = 0;
|
||||
float longitude = 0;
|
||||
FlipperProto protocol = FLIPPER_PROTO_UNSUPPORTED;
|
||||
FlipperPreset preset = FLIPPER_PRESET_UNK;
|
||||
uint16_t te = 0;
|
||||
};
|
||||
|
||||
Optional<flippersub_metadata> read_flippersub_file(const std::filesystem::path& path);
|
||||
|
||||
// Maybe sometime there will be a data part reader / converter
|
||||
|
||||
#endif // __FLIPPER_SUBFILE_HPP__
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user